--- /srv/reproducible-results/rbuild-debian/r-b-build.v6FyjRhe/b1/openlayers_2.13.1+ds2-11_amd64.changes +++ /srv/reproducible-results/rbuild-debian/r-b-build.v6FyjRhe/b2/openlayers_2.13.1+ds2-11_amd64.changes ├── Files │ @@ -1,2 +1,2 @@ │ │ - 29dfe7b960a8cccf3cd90c017b0f7895 708480 javascript optional libjs-openlayers_2.13.1+ds2-11_all.deb │ + 54748ba5879b99c609994613d9d9d127 781320 javascript optional libjs-openlayers_2.13.1+ds2-11_all.deb ├── libjs-openlayers_2.13.1+ds2-11_all.deb │ ├── file list │ │ @@ -1,3 +1,3 @@ │ │ -rw-r--r-- 0 0 0 4 2025-03-06 18:35:30.000000 debian-binary │ │ --rw-r--r-- 0 0 0 3684 2025-03-06 18:35:30.000000 control.tar.xz │ │ --rw-r--r-- 0 0 0 704604 2025-03-06 18:35:30.000000 data.tar.xz │ │ +-rw-r--r-- 0 0 0 3688 2025-03-06 18:35:30.000000 control.tar.xz │ │ +-rw-r--r-- 0 0 0 777440 2025-03-06 18:35:30.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 {} │ │ │ │ │ @@ -136,14 +136,141 @@ │ │ │ │ │ * (code) │ │ │ │ │ * │ │ │ │ │ * (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. */ │ │ │ │ │ @@ -4426,14 +4426,155 @@ │ │ │ │ │ } else { │ │ │ │ │ str += coordinate < 0 ? OpenLayers.i18n("S") : OpenLayers.i18n("N"); │ │ │ │ │ } │ │ │ │ │ return str; │ │ │ │ │ }; │ │ │ │ │ │ │ │ │ │ /* ====================================================================== │ │ │ │ │ + OpenLayers/Util/vendorPrefix.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/SingleFile.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +OpenLayers.Util = OpenLayers.Util || {}; │ │ │ │ │ +/** │ │ │ │ │ + * Namespace: OpenLayers.Util.vendorPrefix │ │ │ │ │ + * A collection of utility functions to detect vendor prefixed features │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Util.vendorPrefix = (function() { │ │ │ │ │ + "use strict"; │ │ │ │ │ + │ │ │ │ │ + var VENDOR_PREFIXES = ["", "O", "ms", "Moz", "Webkit"], │ │ │ │ │ + divStyle = document.createElement("div").style, │ │ │ │ │ + cssCache = {}, │ │ │ │ │ + jsCache = {}; │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Function: domToCss │ │ │ │ │ + * Converts a upper camel case DOM style property name to a CSS property │ │ │ │ │ + * i.e. transformOrigin -> transform-origin │ │ │ │ │ + * or WebkitTransformOrigin -> -webkit-transform-origin │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * prefixedDom - {String} The property to convert │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {String} The CSS property │ │ │ │ │ + */ │ │ │ │ │ + function domToCss(prefixedDom) { │ │ │ │ │ + if (!prefixedDom) { │ │ │ │ │ + return null; │ │ │ │ │ + } │ │ │ │ │ + return prefixedDom. │ │ │ │ │ + replace(/([A-Z])/g, function(c) { │ │ │ │ │ + return "-" + c.toLowerCase(); │ │ │ │ │ + }). │ │ │ │ │ + replace(/^ms-/, "-ms-"); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: css │ │ │ │ │ + * Detect which property is used for a CSS property │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * property - {String} The standard (unprefixed) CSS property name │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {String} The standard CSS property, prefixed property or null if not │ │ │ │ │ + * supported │ │ │ │ │ + */ │ │ │ │ │ + function css(property) { │ │ │ │ │ + if (cssCache[property] === undefined) { │ │ │ │ │ + var domProperty = property. │ │ │ │ │ + replace(/(-[\s\S])/g, function(c) { │ │ │ │ │ + return c.charAt(1).toUpperCase(); │ │ │ │ │ + }); │ │ │ │ │ + var prefixedDom = style(domProperty); │ │ │ │ │ + cssCache[property] = domToCss(prefixedDom); │ │ │ │ │ + } │ │ │ │ │ + return cssCache[property]; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: js │ │ │ │ │ + * Detect which property is used for a JS property/method │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * obj - {Object} The object to test on │ │ │ │ │ + * property - {String} The standard (unprefixed) JS property name │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {String} The standard JS property, prefixed property or null if not │ │ │ │ │ + * supported │ │ │ │ │ + */ │ │ │ │ │ + function js(obj, property) { │ │ │ │ │ + if (jsCache[property] === undefined) { │ │ │ │ │ + var tmpProp, │ │ │ │ │ + i = 0, │ │ │ │ │ + l = VENDOR_PREFIXES.length, │ │ │ │ │ + prefix, │ │ │ │ │ + isStyleObj = (typeof obj.cssText !== "undefined"); │ │ │ │ │ + │ │ │ │ │ + jsCache[property] = null; │ │ │ │ │ + for (; i < l; i++) { │ │ │ │ │ + prefix = VENDOR_PREFIXES[i]; │ │ │ │ │ + if (prefix) { │ │ │ │ │ + if (!isStyleObj) { │ │ │ │ │ + // js prefix should be lower-case, while style │ │ │ │ │ + // properties have upper case on first character │ │ │ │ │ + prefix = prefix.toLowerCase(); │ │ │ │ │ + } │ │ │ │ │ + tmpProp = prefix + property.charAt(0).toUpperCase() + property.slice(1); │ │ │ │ │ + } else { │ │ │ │ │ + tmpProp = property; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (obj[tmpProp] !== undefined) { │ │ │ │ │ + jsCache[property] = tmpProp; │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return jsCache[property]; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: style │ │ │ │ │ + * Detect which property is used for a DOM style property │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * property - {String} The standard (unprefixed) style property name │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {String} The standard style property, prefixed property or null if not │ │ │ │ │ + * supported │ │ │ │ │ + */ │ │ │ │ │ + function style(property) { │ │ │ │ │ + return js(divStyle, property); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + return { │ │ │ │ │ + css: css, │ │ │ │ │ + js: js, │ │ │ │ │ + style: style, │ │ │ │ │ + │ │ │ │ │ + // used for testing │ │ │ │ │ + cssCache: cssCache, │ │ │ │ │ + jsCache: jsCache │ │ │ │ │ + }; │ │ │ │ │ +}()); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ OpenLayers/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. */ │ │ │ │ │ @@ -5602,6300 +5743,2502 @@ │ │ │ │ │ │ │ │ │ │ OpenLayers.Event.observe(element, 'MSPointerUp', cb); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Events" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Handler.js │ │ │ │ │ + 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/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Events.js │ │ │ │ │ + * @requires OpenLayers/SingleFile.js │ │ │ │ │ + * @requires OpenLayers/Util/vendorPrefix.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. │ │ │ │ │ + * 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.Handler = OpenLayers.Class({ │ │ │ │ │ +OpenLayers.Animation = (function(window) { │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: id │ │ │ │ │ - * {String} │ │ │ │ │ + * Property: isNative │ │ │ │ │ + * {Boolean} true if a native requestAnimationFrame function is available │ │ │ │ │ */ │ │ │ │ │ - id: null, │ │ │ │ │ + var requestAnimationFrame = OpenLayers.Util.vendorPrefix.js(window, "requestAnimationFrame"); │ │ │ │ │ + var isNative = !!(requestAnimationFrame); │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * 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. │ │ │ │ │ */ │ │ │ │ │ - control: null, │ │ │ │ │ + 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]); │ │ │ │ │ + }; │ │ │ │ │ + })(); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: map │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - map: null, │ │ │ │ │ + // private variables for animation loops │ │ │ │ │ + var counter = 0; │ │ │ │ │ + var loops = {}; │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * Function: start │ │ │ │ │ + * Executes a method with in series for some │ │ │ │ │ + * duration. │ │ │ │ │ * │ │ │ │ │ - * Example: │ │ │ │ │ - * (code) │ │ │ │ │ - * // handler only responds if the Shift key is down │ │ │ │ │ - * handler.keyMask = OpenLayers.Handler.MOD_SHIFT; │ │ │ │ │ + * 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. │ │ │ │ │ * │ │ │ │ │ - * // handler only responds if Ctrl-Shift is down │ │ │ │ │ - * handler.keyMask = OpenLayers.Handler.MOD_SHIFT | │ │ │ │ │ - * OpenLayers.Handler.MOD_CTRL; │ │ │ │ │ - * (end) │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Number} Identifier for the animation loop. Used to stop animations with │ │ │ │ │ + * . │ │ │ │ │ */ │ │ │ │ │ - keyMask: null, │ │ │ │ │ + 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; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: active │ │ │ │ │ - * {Boolean} │ │ │ │ │ + * Function: stop │ │ │ │ │ + * Terminates an animation loop started with . │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * id - {Number} Identifier returned from . │ │ │ │ │ */ │ │ │ │ │ - active: false, │ │ │ │ │ + function stop(id) { │ │ │ │ │ + delete loops[id]; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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, │ │ │ │ │ + return { │ │ │ │ │ + isNative: isNative, │ │ │ │ │ + requestFrame: requestFrame, │ │ │ │ │ + start: start, │ │ │ │ │ + stop: stop │ │ │ │ │ + }; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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, │ │ │ │ │ +})(window); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Tween.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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; │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of 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 map = this.map || control.map; │ │ │ │ │ - if (map) { │ │ │ │ │ - this.setMap(map); │ │ │ │ │ - } │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Animation.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ - }, │ │ │ │ │ +/** │ │ │ │ │ + * Namespace: OpenLayers.Tween │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Tween = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: setMap │ │ │ │ │ + * APIProperty: easing │ │ │ │ │ + * {(Function)} Easing equation used for the animation │ │ │ │ │ + * Defaultly set to OpenLayers.Easing.Expo.easeOut │ │ │ │ │ */ │ │ │ │ │ - setMap: function(map) { │ │ │ │ │ - this.map = map; │ │ │ │ │ - }, │ │ │ │ │ + easing: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The keyMask matches the keys down on an event. │ │ │ │ │ + * APIProperty: begin │ │ │ │ │ + * {Object} Values to start the animation with │ │ │ │ │ */ │ │ │ │ │ - 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); │ │ │ │ │ + begin: null, │ │ │ │ │ │ │ │ │ │ - /* if it differs from the handler object's key mask, │ │ │ │ │ - bail out of the event handler */ │ │ │ │ │ - return (keyModifiers == this.keyMask); │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: finish │ │ │ │ │ + * {Object} Values to finish the animation with │ │ │ │ │ + */ │ │ │ │ │ + finish: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: activate │ │ │ │ │ - * Turn on the handler. Returns false if the handler was already active. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The handler was activated. │ │ │ │ │ + * APIProperty: duration │ │ │ │ │ + * {int} duration of the tween (number of steps) │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ - }, │ │ │ │ │ + duration: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: deactivate │ │ │ │ │ - * Turn off the handler. Returns false if the handler was already inactive. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The handler was deactivated. │ │ │ │ │ + * 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. │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ - }, │ │ │ │ │ + callbacks: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * Property: time │ │ │ │ │ + * {int} Step counter │ │ │ │ │ */ │ │ │ │ │ - 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]]); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ + time: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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). │ │ │ │ │ + * 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. │ │ │ │ │ */ │ │ │ │ │ - callback: function(name, args) { │ │ │ │ │ - if (name && this.callbacks[name]) { │ │ │ │ │ - this.callbacks[name].apply(this.control, args); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ + minFrameRate: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: register │ │ │ │ │ - * register an event on the map │ │ │ │ │ + * Property: startTime │ │ │ │ │ + * {Number} The timestamp of the first execution step. Used for skipping │ │ │ │ │ + * frames │ │ │ │ │ */ │ │ │ │ │ - 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); │ │ │ │ │ - }, │ │ │ │ │ + startTime: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: unregister │ │ │ │ │ - * unregister an event from the map │ │ │ │ │ + * Property: animationId │ │ │ │ │ + * {int} Loop id returned by OpenLayers.Animation.start │ │ │ │ │ */ │ │ │ │ │ - unregister: function(name, method) { │ │ │ │ │ - this.map.events.unregister(name, this, method); │ │ │ │ │ - this.map.events.unregister(name, this, this.setEvent); │ │ │ │ │ - }, │ │ │ │ │ + animationId: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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). │ │ │ │ │ + * Property: playing │ │ │ │ │ + * {Boolean} Tells if the easing is currently playing │ │ │ │ │ + */ │ │ │ │ │ + playing: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Tween │ │ │ │ │ + * Creates a Tween. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * evt - {Event} The browser event. │ │ │ │ │ + * easing - {(Function)} easing function method to use │ │ │ │ │ */ │ │ │ │ │ - setEvent: function(evt) { │ │ │ │ │ - this.evt = evt; │ │ │ │ │ - return true; │ │ │ │ │ + initialize: function(easing) { │ │ │ │ │ + this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: destroy │ │ │ │ │ - * Deconstruct the handler. │ │ │ │ │ + * 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) │ │ │ │ │ */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - // unregister event listeners │ │ │ │ │ - this.deactivate(); │ │ │ │ │ - // eliminate circular references │ │ │ │ │ - this.control = this.map = null; │ │ │ │ │ + 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) │ │ │ │ │ + ); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler" │ │ │ │ │ -}); │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * 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; │ │ │ │ │ + /** │ │ │ │ │ + * 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; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Handler.MOD_CTRL │ │ │ │ │ - * If set as the , returns false if Ctrl is down. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Handler.MOD_CTRL = 2; │ │ │ │ │ + if (this.callbacks && this.callbacks.done) { │ │ │ │ │ + this.callbacks.done.call(this, this.finish); │ │ │ │ │ + } │ │ │ │ │ + OpenLayers.Animation.stop(this.animationId); │ │ │ │ │ + this.animationId = null; │ │ │ │ │ + this.playing = false; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Handler.MOD_ALT │ │ │ │ │ - * If set as the , returns false if Alt is down. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Handler.MOD_ALT = 4; │ │ │ │ │ + /** │ │ │ │ │ + * 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'); │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Handler.MOD_META │ │ │ │ │ - * If set as the , returns false if Cmd is down. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Handler.MOD_META = 8; │ │ │ │ │ + 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); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Strategy.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ + if (this.time > this.duration) { │ │ │ │ │ + this.stop(); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ + /** │ │ │ │ │ + * Create empty functions for all easing methods. │ │ │ │ │ + */ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Tween" │ │ │ │ │ +}); │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * Namespace: OpenLayers.Easing │ │ │ │ │ + * │ │ │ │ │ + * Credits: │ │ │ │ │ + * Easing Equations by Robert Penner, │ │ │ │ │ */ │ │ │ │ │ +OpenLayers.Easing = { │ │ │ │ │ + /** │ │ │ │ │ + * Create empty functions for all easing methods. │ │ │ │ │ + */ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Easing" │ │ │ │ │ +}; │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Strategy │ │ │ │ │ - * Abstract vector layer strategy class. Not to be instantiated directly. Use │ │ │ │ │ - * one of the strategy subclasses instead. │ │ │ │ │ + * Namespace: OpenLayers.Easing.Linear │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Strategy = OpenLayers.Class({ │ │ │ │ │ +OpenLayers.Easing.Linear = { │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: layer │ │ │ │ │ - * {} The layer this strategy belongs to. │ │ │ │ │ + * Function: easeIn │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} │ │ │ │ │ */ │ │ │ │ │ - layer: null, │ │ │ │ │ + easeIn: function(t, b, c, d) { │ │ │ │ │ + return c * t / d + b; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: options │ │ │ │ │ - * {Object} Any options sent to the constructor. │ │ │ │ │ - */ │ │ │ │ │ - options: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: active │ │ │ │ │ - * {Boolean} The control is active. │ │ │ │ │ + * Function: easeOut │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} │ │ │ │ │ */ │ │ │ │ │ - active: null, │ │ │ │ │ + easeOut: function(t, b, c, d) { │ │ │ │ │ + return c * t / d + b; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * Function: easeInOut │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} │ │ │ │ │ */ │ │ │ │ │ - autoActivate: true, │ │ │ │ │ + easeInOut: function(t, b, c, d) { │ │ │ │ │ + return c * t / d + b; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Easing.Linear" │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Namespace: OpenLayers.Easing.Expo │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Easing.Expo = { │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: autoDestroy │ │ │ │ │ - * {Boolean} The creator of the strategy can set autoDestroy to false │ │ │ │ │ - * to fully control when the strategy is destroyed. Defaults to │ │ │ │ │ - * true. │ │ │ │ │ + * Function: easeIn │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} │ │ │ │ │ */ │ │ │ │ │ - autoDestroy: true, │ │ │ │ │ + easeIn: function(t, b, c, d) { │ │ │ │ │ + return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Strategy │ │ │ │ │ - * Abstract class for vector strategies. Create instances of a subclass. │ │ │ │ │ - * │ │ │ │ │ + * Function: easeOut │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ - * instance. │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ + easeOut: function(t, b, c, d) { │ │ │ │ │ + return (t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ - * Clean up the strategy. │ │ │ │ │ + * Function: easeInOut │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} │ │ │ │ │ */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - this.deactivate(); │ │ │ │ │ - this.layer = null; │ │ │ │ │ - this.options = null; │ │ │ │ │ + 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 = { │ │ │ │ │ + │ │ │ │ │ /** │ │ │ │ │ - * Method: setLayer │ │ │ │ │ - * Called to set the property. │ │ │ │ │ - * │ │ │ │ │ + * Function: easeIn │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * layer - {} │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} │ │ │ │ │ */ │ │ │ │ │ - setLayer: function(layer) { │ │ │ │ │ - this.layer = layer; │ │ │ │ │ + easeIn: function(t, b, c, d) { │ │ │ │ │ + return c * (t /= d) * t + b; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: activate │ │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ │ + * Function: easeOut │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Boolean} True if the strategy was successfully activated or false if │ │ │ │ │ - * the strategy was already active. │ │ │ │ │ + * {Float} │ │ │ │ │ */ │ │ │ │ │ - activate: function() { │ │ │ │ │ - if (!this.active) { │ │ │ │ │ - this.active = true; │ │ │ │ │ - return true; │ │ │ │ │ - } │ │ │ │ │ - return false; │ │ │ │ │ + easeOut: function(t, b, c, d) { │ │ │ │ │ + return -c * (t /= d) * (t - 2) + b; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: deactivate │ │ │ │ │ - * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ │ - * tear-down. │ │ │ │ │ + * Function: easeInOut │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Boolean} True if the strategy was successfully deactivated or false if │ │ │ │ │ - * the strategy was already inactive. │ │ │ │ │ + * {Float} │ │ │ │ │ */ │ │ │ │ │ - deactivate: function() { │ │ │ │ │ - if (this.active) { │ │ │ │ │ - this.active = false; │ │ │ │ │ - return true; │ │ │ │ │ - } │ │ │ │ │ - return false; │ │ │ │ │ + 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.Strategy" │ │ │ │ │ -}); │ │ │ │ │ + CLASS_NAME: "OpenLayers.Easing.Quad" │ │ │ │ │ +}; │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Feature.js │ │ │ │ │ + OpenLayers/Projection.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ /** │ │ │ │ │ * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ * @requires OpenLayers/Util.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Feature │ │ │ │ │ - * Features are combinations of geography and attributes. The OpenLayers.Feature │ │ │ │ │ - * class specifically combines a marker and a lonlat. │ │ │ │ │ + * Namespace: OpenLayers.Projection │ │ │ │ │ + * Methods for coordinate transforms between coordinate systems. By default, │ │ │ │ │ + * OpenLayers ships with the ability to transform coordinates between │ │ │ │ │ + * geographic (EPSG:4326) and web or spherical mercator (EPSG:900913 et al.) │ │ │ │ │ + * coordinate reference systems. See the method for details │ │ │ │ │ + * on usage. │ │ │ │ │ + * │ │ │ │ │ + * Additional transforms may be added by using the │ │ │ │ │ + * library. If the proj4js library is included, the method │ │ │ │ │ + * will work between any two coordinate reference systems with proj4js │ │ │ │ │ + * definitions. │ │ │ │ │ + * │ │ │ │ │ + * If the proj4js library is not included, or if you wish to allow transforms │ │ │ │ │ + * between arbitrary coordinate reference systems, use the │ │ │ │ │ + * method to register a custom transform method. │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Feature = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: layer │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - layer: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: id │ │ │ │ │ - * {String} │ │ │ │ │ - */ │ │ │ │ │ - id: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: lonlat │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - lonlat: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: data │ │ │ │ │ - * {Object} │ │ │ │ │ - */ │ │ │ │ │ - data: null, │ │ │ │ │ +OpenLayers.Projection = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: marker │ │ │ │ │ - * {} │ │ │ │ │ + /** │ │ │ │ │ + * Property: proj │ │ │ │ │ + * {Object} Proj4js.Proj instance. │ │ │ │ │ */ │ │ │ │ │ - marker: null, │ │ │ │ │ + proj: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: popupClass │ │ │ │ │ - * {} The class which will be used to instantiate │ │ │ │ │ - * a new Popup. Default is . │ │ │ │ │ + * Property: projCode │ │ │ │ │ + * {String} │ │ │ │ │ */ │ │ │ │ │ - popupClass: null, │ │ │ │ │ + projCode: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: popup │ │ │ │ │ - * {} │ │ │ │ │ + /** │ │ │ │ │ + * Property: titleRegEx │ │ │ │ │ + * {RegExp} regular expression to strip the title from a proj4js definition │ │ │ │ │ */ │ │ │ │ │ - popup: null, │ │ │ │ │ + titleRegEx: /\+title=[^\+]*/, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Feature │ │ │ │ │ - * Constructor for features. │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Projection │ │ │ │ │ + * This class offers several methods for interacting with a wrapped │ │ │ │ │ + * pro4js projection object. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * layer - {} │ │ │ │ │ - * lonlat - {} │ │ │ │ │ - * data - {Object} │ │ │ │ │ - * │ │ │ │ │ + * projCode - {String} A string identifying the Well Known Identifier for │ │ │ │ │ + * the projection. │ │ │ │ │ + * options - {Object} An optional object to set additional properties │ │ │ │ │ + * on the projection. │ │ │ │ │ + * │ │ │ │ │ * Returns: │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - 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 │ │ │ │ │ + * {} A projection object. │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ + initialize: function(projCode, options) { │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + this.projCode = projCode; │ │ │ │ │ + if (typeof Proj4js == "object") { │ │ │ │ │ + this.proj = new Proj4js.Proj(projCode); │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: onScreen │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: getCode │ │ │ │ │ + * Get the string SRS code. │ │ │ │ │ + * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Boolean} Whether or not the feature is currently visible on screen │ │ │ │ │ - * (based on its 'lonlat' property) │ │ │ │ │ + * {String} The SRS code. │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ + getCode: function() { │ │ │ │ │ + return this.proj ? this.proj.srsCode : this.projCode; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ /** │ │ │ │ │ - * Method: createMarker │ │ │ │ │ - * Based on the data associated with the Feature, create and return a marker object. │ │ │ │ │ + * APIMethod: getUnits │ │ │ │ │ + * Get the units string for the projection -- returns null if │ │ │ │ │ + * proj4js is not available. │ │ │ │ │ * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} 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 │ │ │ │ │ - * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {String} The units abbreviation. │ │ │ │ │ */ │ │ │ │ │ - createMarker: function() { │ │ │ │ │ - │ │ │ │ │ - if (this.lonlat != null) { │ │ │ │ │ - this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon); │ │ │ │ │ - } │ │ │ │ │ - return this.marker; │ │ │ │ │ + getUnits: function() { │ │ │ │ │ + return this.proj ? this.proj.units : null; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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: toString │ │ │ │ │ + * Convert projection to string (getCode wrapper). │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {String} The projection code. │ │ │ │ │ */ │ │ │ │ │ - destroyMarker: function() { │ │ │ │ │ - this.marker.destroy(); │ │ │ │ │ + toString: function() { │ │ │ │ │ + return this.getCode(); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * Method: equals │ │ │ │ │ + * Test equality of two projection instances. Determines equality based │ │ │ │ │ + * soley on the projection code. │ │ │ │ │ * │ │ │ │ │ - * 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: │ │ │ │ │ - * {} 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 . │ │ │ │ │ - * │ │ │ │ │ + * {Boolean} The two projections are equivalent. │ │ │ │ │ */ │ │ │ │ │ - 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); │ │ │ │ │ + equals: function(projection) { │ │ │ │ │ + var p = projection, │ │ │ │ │ + equals = false; │ │ │ │ │ + if (p) { │ │ │ │ │ + if (!(p instanceof OpenLayers.Projection)) { │ │ │ │ │ + p = new OpenLayers.Projection(p); │ │ │ │ │ } │ │ │ │ │ - if (this.data.overflow != null) { │ │ │ │ │ - this.popup.contentDiv.style.overflow = this.data.overflow; │ │ │ │ │ + if ((typeof Proj4js == "object") && this.proj.defData && p.proj.defData) { │ │ │ │ │ + equals = this.proj.defData.replace(this.titleRegEx, "") == │ │ │ │ │ + p.proj.defData.replace(this.titleRegEx, ""); │ │ │ │ │ + } else if (p.getCode) { │ │ │ │ │ + var source = this.getCode(), │ │ │ │ │ + target = p.getCode(); │ │ │ │ │ + equals = source == target || │ │ │ │ │ + !!OpenLayers.Projection.transforms[source] && │ │ │ │ │ + OpenLayers.Projection.transforms[source][target] === │ │ │ │ │ + OpenLayers.Projection.nullTransform; │ │ │ │ │ } │ │ │ │ │ - │ │ │ │ │ - this.popup.feature = this; │ │ │ │ │ } │ │ │ │ │ - return this.popup; │ │ │ │ │ + return equals; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * 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: destroy │ │ │ │ │ + * Destroy projection object. │ │ │ │ │ */ │ │ │ │ │ - destroyPopup: function() { │ │ │ │ │ - if (this.popup) { │ │ │ │ │ - this.popup.feature = null; │ │ │ │ │ - this.popup.destroy(); │ │ │ │ │ - this.popup = null; │ │ │ │ │ - } │ │ │ │ │ + destroy: function() { │ │ │ │ │ + delete this.proj; │ │ │ │ │ + delete this.projCode; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Feature" │ │ │ │ │ + CLASS_NAME: "OpenLayers.Projection" │ │ │ │ │ }); │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Property: transforms │ │ │ │ │ + * {Object} Transforms is an object, with from properties, each of which may │ │ │ │ │ + * have a to property. This allows you to define projections without │ │ │ │ │ + * requiring support for proj4js to be included. │ │ │ │ │ + * │ │ │ │ │ + * This object has keys which correspond to a 'source' projection object. The │ │ │ │ │ + * keys should be strings, corresponding to the projection.getCode() value. │ │ │ │ │ + * Each source projection object should have a set of destination projection │ │ │ │ │ + * keys included in the object. │ │ │ │ │ + * │ │ │ │ │ + * Each value in the destination object should be a transformation function, │ │ │ │ │ + * where the function is expected to be passed an object with a .x and a .y │ │ │ │ │ + * property. The function should return the object, with the .x and .y │ │ │ │ │ + * transformed according to the transformation function. │ │ │ │ │ + * │ │ │ │ │ + * Note - Properties on this object should not be set directly. To add a │ │ │ │ │ + * transform method to this object, use the method. For an │ │ │ │ │ + * example of usage, see the OpenLayers.Layer.SphericalMercator file. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Projection.transforms = {}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * APIProperty: defaults │ │ │ │ │ + * {Object} Defaults for the SRS codes known to OpenLayers (currently │ │ │ │ │ + * EPSG:4326, CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, EPSG:900913, EPSG:3857, │ │ │ │ │ + * EPSG:102113 and EPSG:102100). Keys are the SRS code, values are units, │ │ │ │ │ + * maxExtent (the validity extent for the SRS) and yx (true if this SRS is │ │ │ │ │ + * known to have a reverse axis order). │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Projection.defaults = { │ │ │ │ │ + "EPSG:4326": { │ │ │ │ │ + units: "degrees", │ │ │ │ │ + maxExtent: [-180, -90, 180, 90], │ │ │ │ │ + yx: true │ │ │ │ │ + }, │ │ │ │ │ + "CRS:84": { │ │ │ │ │ + units: "degrees", │ │ │ │ │ + maxExtent: [-180, -90, 180, 90] │ │ │ │ │ + }, │ │ │ │ │ + "EPSG:900913": { │ │ │ │ │ + units: "m", │ │ │ │ │ + maxExtent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34] │ │ │ │ │ + } │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * APIMethod: addTransform │ │ │ │ │ + * Set a custom transform method between two projections. Use this method in │ │ │ │ │ + * cases where the proj4js lib is not available or where custom projections │ │ │ │ │ + * need to be handled. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * from - {String} The code for the source projection │ │ │ │ │ + * to - {String} the code for the destination projection │ │ │ │ │ + * method - {Function} A function that takes a point as an argument and │ │ │ │ │ + * transforms that point from the source to the destination projection │ │ │ │ │ + * in place. The original point should be modified. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Projection.addTransform = function(from, to, method) { │ │ │ │ │ + if (method === OpenLayers.Projection.nullTransform) { │ │ │ │ │ + var defaults = OpenLayers.Projection.defaults[from]; │ │ │ │ │ + if (defaults && !OpenLayers.Projection.defaults[to]) { │ │ │ │ │ + OpenLayers.Projection.defaults[to] = defaults; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + if (!OpenLayers.Projection.transforms[from]) { │ │ │ │ │ + OpenLayers.Projection.transforms[from] = {}; │ │ │ │ │ + } │ │ │ │ │ + OpenLayers.Projection.transforms[from][to] = method; │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * APIMethod: transform │ │ │ │ │ + * Transform a point coordinate from one projection to another. Note that │ │ │ │ │ + * the input point is transformed in place. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * point - { | Object} An object with x and y │ │ │ │ │ + * properties representing coordinates in those dimensions. │ │ │ │ │ + * source - {OpenLayers.Projection} Source map coordinate system │ │ │ │ │ + * dest - {OpenLayers.Projection} Destination map coordinate system │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * point - {object} A transformed coordinate. The original point is modified. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Projection.transform = function(point, source, dest) { │ │ │ │ │ + if (source && dest) { │ │ │ │ │ + if (!(source instanceof OpenLayers.Projection)) { │ │ │ │ │ + source = new OpenLayers.Projection(source); │ │ │ │ │ + } │ │ │ │ │ + if (!(dest instanceof OpenLayers.Projection)) { │ │ │ │ │ + dest = new OpenLayers.Projection(dest); │ │ │ │ │ + } │ │ │ │ │ + if (source.proj && dest.proj) { │ │ │ │ │ + point = Proj4js.transform(source.proj, dest.proj, point); │ │ │ │ │ + } else { │ │ │ │ │ + var sourceCode = source.getCode(); │ │ │ │ │ + var destCode = dest.getCode(); │ │ │ │ │ + var transforms = OpenLayers.Projection.transforms; │ │ │ │ │ + if (transforms[sourceCode] && transforms[sourceCode][destCode]) { │ │ │ │ │ + transforms[sourceCode][destCode](point); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return point; │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * APIFunction: nullTransform │ │ │ │ │ + * A null transformation - useful for defining projection aliases when │ │ │ │ │ + * proj4js is not available: │ │ │ │ │ + * │ │ │ │ │ + * (code) │ │ │ │ │ + * OpenLayers.Projection.addTransform("EPSG:3857", "EPSG:900913", │ │ │ │ │ + * OpenLayers.Projection.nullTransform); │ │ │ │ │ + * OpenLayers.Projection.addTransform("EPSG:900913", "EPSG:3857", │ │ │ │ │ + * OpenLayers.Projection.nullTransform); │ │ │ │ │ + * (end) │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Projection.nullTransform = function(point) { │ │ │ │ │ + return point; │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Note: Transforms for web mercator <-> geographic │ │ │ │ │ + * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113 and EPSG:102100. │ │ │ │ │ + * OpenLayers originally started referring to EPSG:900913 as web mercator. │ │ │ │ │ + * The EPSG has declared EPSG:3857 to be web mercator. │ │ │ │ │ + * ArcGIS 10 recognizes the EPSG:3857, EPSG:102113, and EPSG:102100 as │ │ │ │ │ + * equivalent. See http://blogs.esri.com/Dev/blogs/arcgisserver/archive/2009/11/20/ArcGIS-Online-moving-to-Google-_2F00_-Bing-tiling-scheme_3A00_-What-does-this-mean-for-you_3F00_.aspx#12084. │ │ │ │ │ + * For geographic, OpenLayers recognizes EPSG:4326, CRS:84 and │ │ │ │ │ + * urn:ogc:def:crs:EPSG:6.6:4326. OpenLayers also knows about the reverse axis │ │ │ │ │ + * order for EPSG:4326. │ │ │ │ │ + */ │ │ │ │ │ +(function() { │ │ │ │ │ + │ │ │ │ │ + var pole = 20037508.34; │ │ │ │ │ + │ │ │ │ │ + function inverseMercator(xy) { │ │ │ │ │ + xy.x = 180 * xy.x / pole; │ │ │ │ │ + xy.y = 180 / Math.PI * (2 * Math.atan(Math.exp((xy.y / pole) * Math.PI)) - Math.PI / 2); │ │ │ │ │ + return xy; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + function forwardMercator(xy) { │ │ │ │ │ + xy.x = xy.x * pole / 180; │ │ │ │ │ + var y = Math.log(Math.tan((90 + xy.y) * Math.PI / 360)) / Math.PI * pole; │ │ │ │ │ + xy.y = Math.max(-20037508.34, Math.min(y, 20037508.34)); │ │ │ │ │ + return xy; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + function map(base, codes) { │ │ │ │ │ + var add = OpenLayers.Projection.addTransform; │ │ │ │ │ + var same = OpenLayers.Projection.nullTransform; │ │ │ │ │ + var i, len, code, other, j; │ │ │ │ │ + for (i = 0, len = codes.length; i < len; ++i) { │ │ │ │ │ + code = codes[i]; │ │ │ │ │ + add(base, code, forwardMercator); │ │ │ │ │ + add(code, base, inverseMercator); │ │ │ │ │ + for (j = i + 1; j < len; ++j) { │ │ │ │ │ + other = codes[j]; │ │ │ │ │ + add(code, other, same); │ │ │ │ │ + add(other, code, same); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // list of equivalent codes for web mercator │ │ │ │ │ + var mercator = ["EPSG:900913", "EPSG:3857", "EPSG:102113", "EPSG:102100"], │ │ │ │ │ + geographic = ["CRS:84", "urn:ogc:def:crs:EPSG:6.6:4326", "EPSG:4326"], │ │ │ │ │ + i; │ │ │ │ │ + for (i = mercator.length - 1; i >= 0; --i) { │ │ │ │ │ + map(mercator[i], geographic); │ │ │ │ │ + } │ │ │ │ │ + for (i = geographic.length - 1; i >= 0; --i) { │ │ │ │ │ + map(geographic[i], mercator); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ +})(); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Feature/Vector.js │ │ │ │ │ + OpenLayers/Map.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ -// TRASH THIS │ │ │ │ │ -OpenLayers.State = { │ │ │ │ │ - /** states */ │ │ │ │ │ - UNKNOWN: 'Unknown', │ │ │ │ │ - INSERT: 'Insert', │ │ │ │ │ - UPDATE: 'Update', │ │ │ │ │ - DELETE: 'Delete' │ │ │ │ │ -}; │ │ │ │ │ - │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Feature.js │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ * @requires OpenLayers/Util.js │ │ │ │ │ + * @requires OpenLayers/Util/vendorPrefix.js │ │ │ │ │ + * @requires OpenLayers/Events.js │ │ │ │ │ + * @requires OpenLayers/Tween.js │ │ │ │ │ + * @requires OpenLayers/Projection.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.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 │ │ │ │ │ - * objects. │ │ │ │ │ + * Class: OpenLayers.Map │ │ │ │ │ + * Instances of OpenLayers.Map are interactive maps embedded in a web page. │ │ │ │ │ + * Create a new map with the constructor. │ │ │ │ │ * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * On their own maps do not provide much functionality. To extend a map │ │ │ │ │ + * it's necessary to add controls () and │ │ │ │ │ + * layers () to the map. │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, { │ │ │ │ │ +OpenLayers.Map = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: fid │ │ │ │ │ - * {String} │ │ │ │ │ + /** │ │ │ │ │ + * Constant: Z_INDEX_BASE │ │ │ │ │ + * {Object} Base z-indexes for different classes of thing │ │ │ │ │ */ │ │ │ │ │ - fid: null, │ │ │ │ │ + Z_INDEX_BASE: { │ │ │ │ │ + BaseLayer: 100, │ │ │ │ │ + Overlay: 325, │ │ │ │ │ + Feature: 725, │ │ │ │ │ + Popup: 750, │ │ │ │ │ + Control: 1000 │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: geometry │ │ │ │ │ - * {} │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: events │ │ │ │ │ + * {} │ │ │ │ │ + * │ │ │ │ │ + * Register a listener for a particular event with the following syntax: │ │ │ │ │ + * (code) │ │ │ │ │ + * map.events.register(type, obj, listener); │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Listeners will be called with a reference to an event object. The │ │ │ │ │ + * properties of this event depends on exactly what happened. │ │ │ │ │ + * │ │ │ │ │ + * All event objects have at least the following properties: │ │ │ │ │ + * object - {Object} A reference to map.events.object. │ │ │ │ │ + * element - {DOMElement} A reference to map.events.element. │ │ │ │ │ + * │ │ │ │ │ + * Browser events have the following additional properties: │ │ │ │ │ + * xy - {} The pixel location of the event (relative │ │ │ │ │ + * to the the map viewport). │ │ │ │ │ + * │ │ │ │ │ + * Supported map event types: │ │ │ │ │ + * preaddlayer - triggered before a layer has been added. The event │ │ │ │ │ + * object will include a *layer* property that references the layer │ │ │ │ │ + * to be added. When a listener returns "false" the adding will be │ │ │ │ │ + * aborted. │ │ │ │ │ + * addlayer - triggered after a layer has been added. The event object │ │ │ │ │ + * will include a *layer* property that references the added layer. │ │ │ │ │ + * preremovelayer - triggered before a layer has been removed. The event │ │ │ │ │ + * object will include a *layer* property that references the layer │ │ │ │ │ + * to be removed. When a listener returns "false" the removal will be │ │ │ │ │ + * aborted. │ │ │ │ │ + * removelayer - triggered after a layer has been removed. The event │ │ │ │ │ + * object will include a *layer* property that references the removed │ │ │ │ │ + * layer. │ │ │ │ │ + * changelayer - triggered after a layer name change, order change, │ │ │ │ │ + * opacity change, params change, visibility change (actual visibility, │ │ │ │ │ + * not the layer's visibility property) or attribution change (due to │ │ │ │ │ + * extent change). Listeners will receive an event object with *layer* │ │ │ │ │ + * and *property* properties. The *layer* property will be a reference │ │ │ │ │ + * to the changed layer. The *property* property will be a key to the │ │ │ │ │ + * changed property (name, order, opacity, params, visibility or │ │ │ │ │ + * attribution). │ │ │ │ │ + * movestart - triggered after the start of a drag, pan, or zoom. The event │ │ │ │ │ + * object may include a *zoomChanged* property that tells whether the │ │ │ │ │ + * zoom has changed. │ │ │ │ │ + * move - triggered after each drag, pan, or zoom │ │ │ │ │ + * moveend - triggered after a drag, pan, or zoom completes │ │ │ │ │ + * zoomend - triggered after a zoom completes │ │ │ │ │ + * mouseover - triggered after mouseover the map │ │ │ │ │ + * mouseout - triggered after mouseout the map │ │ │ │ │ + * mousemove - triggered after mousemove the map │ │ │ │ │ + * changebaselayer - triggered after the base layer changes │ │ │ │ │ + * updatesize - triggered after the method was executed │ │ │ │ │ */ │ │ │ │ │ - geometry: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: attributes │ │ │ │ │ - * {Object} This object holds arbitrary, serializable properties that │ │ │ │ │ - * describe the feature. │ │ │ │ │ + /** │ │ │ │ │ + * Property: id │ │ │ │ │ + * {String} Unique identifier for the map │ │ │ │ │ */ │ │ │ │ │ - attributes: null, │ │ │ │ │ + id: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: bounds │ │ │ │ │ - * {} The box bounding that feature's geometry, that │ │ │ │ │ - * property can be set by an object when │ │ │ │ │ - * deserializing the feature, so in most cases it represents an │ │ │ │ │ - * information set by the server. │ │ │ │ │ + * Property: fractionalZoom │ │ │ │ │ + * {Boolean} For a base layer that supports it, allow the map resolution │ │ │ │ │ + * to be set to a value between one of the values in the resolutions │ │ │ │ │ + * array. Default is false. │ │ │ │ │ + * │ │ │ │ │ + * When fractionalZoom is set to true, it is possible to zoom to │ │ │ │ │ + * an arbitrary extent. This requires a base layer from a source │ │ │ │ │ + * that supports requests for arbitrary extents (i.e. not cached │ │ │ │ │ + * tiles on a regular lattice). This means that fractionalZoom │ │ │ │ │ + * will not work with commercial layers (Google, Yahoo, VE), layers │ │ │ │ │ + * using TileCache, or any other pre-cached data sources. │ │ │ │ │ + * │ │ │ │ │ + * If you are using fractionalZoom, then you should also use │ │ │ │ │ + * instead of layer.resolutions[zoom] as the │ │ │ │ │ + * former works for non-integer zoom levels. │ │ │ │ │ */ │ │ │ │ │ - bounds: null, │ │ │ │ │ + fractionalZoom: false, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: state │ │ │ │ │ - * {String} │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: events │ │ │ │ │ + * {} An events object that handles all │ │ │ │ │ + * events on the map │ │ │ │ │ */ │ │ │ │ │ - state: null, │ │ │ │ │ + events: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: style │ │ │ │ │ - * {Object} │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: allOverlays │ │ │ │ │ + * {Boolean} Allow the map to function with "overlays" only. Defaults to │ │ │ │ │ + * false. If true, the lowest layer in the draw order will act as │ │ │ │ │ + * the base layer. In addition, if set to true, all layers will │ │ │ │ │ + * have isBaseLayer set to false when they are added to the map. │ │ │ │ │ + * │ │ │ │ │ + * Note: │ │ │ │ │ + * If you set map.allOverlays to true, then you *cannot* use │ │ │ │ │ + * map.setBaseLayer or layer.setIsBaseLayer. With allOverlays true, │ │ │ │ │ + * the lowest layer in the draw layer is the base layer. So, to change │ │ │ │ │ + * the base layer, use or to set the layer │ │ │ │ │ + * index to 0. │ │ │ │ │ */ │ │ │ │ │ - style: null, │ │ │ │ │ + allOverlays: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: url │ │ │ │ │ - * {String} If this property is set it will be taken into account by │ │ │ │ │ - * {} when upadting or deleting the feature. │ │ │ │ │ + * APIProperty: div │ │ │ │ │ + * {DOMElement|String} The element that contains the map (or an id for │ │ │ │ │ + * that element). If the constructor is called │ │ │ │ │ + * with two arguments, this should be provided as the first argument. │ │ │ │ │ + * Alternatively, the map constructor can be called with the options │ │ │ │ │ + * object as the only argument. In this case (one argument), a │ │ │ │ │ + * div property may or may not be provided. If the div property │ │ │ │ │ + * is not provided, the map can be rendered to a container later │ │ │ │ │ + * using the method. │ │ │ │ │ + * │ │ │ │ │ + * Note: │ │ │ │ │ + * If you are calling after map construction, do not use │ │ │ │ │ + * auto. Instead, divide your by your │ │ │ │ │ + * maximum expected dimension. │ │ │ │ │ */ │ │ │ │ │ - url: null, │ │ │ │ │ + div: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: renderIntent │ │ │ │ │ - * {String} rendering intent currently being used │ │ │ │ │ + * Property: dragging │ │ │ │ │ + * {Boolean} The map is currently being dragged. │ │ │ │ │ */ │ │ │ │ │ - renderIntent: "default", │ │ │ │ │ + dragging: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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 , and written by │ │ │ │ │ - * , 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 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. │ │ │ │ │ + * Property: size │ │ │ │ │ + * {} Size of the main div (this.div) │ │ │ │ │ */ │ │ │ │ │ - modified: null, │ │ │ │ │ + size: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Feature.Vector │ │ │ │ │ - * Create a vector feature. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * geometry - {} The geometry that this feature │ │ │ │ │ - * represents. │ │ │ │ │ - * attributes - {Object} An optional object that will be mapped to the │ │ │ │ │ - * property. │ │ │ │ │ - * style - {Object} An optional style object. │ │ │ │ │ + /** │ │ │ │ │ + * Property: viewPortDiv │ │ │ │ │ + * {HTMLDivElement} The element that represents the map viewport │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ - }, │ │ │ │ │ + viewPortDiv: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: destroy │ │ │ │ │ - * nullify references to prevent circular references and memory leaks │ │ │ │ │ + /** │ │ │ │ │ + * Property: layerContainerOrigin │ │ │ │ │ + * {} The lonlat at which the later container was │ │ │ │ │ + * re-initialized (on-zoom) │ │ │ │ │ */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - if (this.layer) { │ │ │ │ │ - this.layer.removeFeatures(this); │ │ │ │ │ - this.layer = null; │ │ │ │ │ - } │ │ │ │ │ + layerContainerOrigin: null, │ │ │ │ │ │ │ │ │ │ - this.geometry = null; │ │ │ │ │ - this.modified = null; │ │ │ │ │ - OpenLayers.Feature.prototype.destroy.apply(this, arguments); │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * Property: layerContainerDiv │ │ │ │ │ + * {HTMLDivElement} The element that contains the layers. │ │ │ │ │ + */ │ │ │ │ │ + layerContainerDiv: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: clone │ │ │ │ │ - * Create a clone of this vector feature. Does not set any non-standard │ │ │ │ │ - * properties. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} An exact clone of this vector feature. │ │ │ │ │ + * APIProperty: layers │ │ │ │ │ + * {Array()} Ordered list of layers in the map │ │ │ │ │ */ │ │ │ │ │ - clone: function() { │ │ │ │ │ - return new OpenLayers.Feature.Vector( │ │ │ │ │ - this.geometry ? this.geometry.clone() : null, │ │ │ │ │ - this.attributes, │ │ │ │ │ - this.style); │ │ │ │ │ - }, │ │ │ │ │ + layers: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * APIProperty: controls │ │ │ │ │ + * {Array()} List of controls associated with the map. │ │ │ │ │ * │ │ │ │ │ - * 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). │ │ │ │ │ + * If not provided in the map options at construction, the map will │ │ │ │ │ + * by default be given the following controls if present in the build: │ │ │ │ │ + * - or │ │ │ │ │ + * - or │ │ │ │ │ + * - │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ - }, │ │ │ │ │ + controls: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * Property: popups │ │ │ │ │ + * {Array()} List of popups associated with the map │ │ │ │ │ */ │ │ │ │ │ - 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()); │ │ │ │ │ - }, │ │ │ │ │ + popups: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: createMarker │ │ │ │ │ - * HACK - we need to decide if all vector features should be able to │ │ │ │ │ - * create markers │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} For now just returns null │ │ │ │ │ + * APIProperty: baseLayer │ │ │ │ │ + * {} The currently selected base layer. This determines │ │ │ │ │ + * min/max zoom level, projection, etc. │ │ │ │ │ */ │ │ │ │ │ - createMarker: function() { │ │ │ │ │ - return null; │ │ │ │ │ - }, │ │ │ │ │ + baseLayer: 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 │ │ │ │ │ + * Property: center │ │ │ │ │ + * {} The current center of the map │ │ │ │ │ */ │ │ │ │ │ - destroyMarker: function() { │ │ │ │ │ - // pass │ │ │ │ │ - }, │ │ │ │ │ + center: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: createPopup │ │ │ │ │ - * HACK - we need to decide if all vector features should be able to │ │ │ │ │ - * create popups │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} For now just returns null │ │ │ │ │ + * Property: resolution │ │ │ │ │ + * {Float} The resolution of the map. │ │ │ │ │ */ │ │ │ │ │ - createPopup: function() { │ │ │ │ │ - return null; │ │ │ │ │ - }, │ │ │ │ │ + resolution: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: atPoint │ │ │ │ │ - * Determins whether the feature intersects with the specified location. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * 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 │ │ │ │ │ + * Property: zoom │ │ │ │ │ + * {Integer} The current zoom level of the map │ │ │ │ │ */ │ │ │ │ │ - atPoint: function(lonlat, toleranceLon, toleranceLat) { │ │ │ │ │ - var atPoint = false; │ │ │ │ │ - if (this.geometry) { │ │ │ │ │ - atPoint = this.geometry.atPoint(lonlat, toleranceLon, │ │ │ │ │ - toleranceLat); │ │ │ │ │ - } │ │ │ │ │ - return atPoint; │ │ │ │ │ - }, │ │ │ │ │ + zoom: 0, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: destroyPopup │ │ │ │ │ - * HACK - we need to decide if all vector features should be able to │ │ │ │ │ - * delete popups │ │ │ │ │ + * Property: panRatio │ │ │ │ │ + * {Float} The ratio of the current extent within │ │ │ │ │ + * which panning will tween. │ │ │ │ │ */ │ │ │ │ │ - destroyPopup: function() { │ │ │ │ │ - // pass │ │ │ │ │ - }, │ │ │ │ │ + panRatio: 1.5, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: move │ │ │ │ │ - * Moves the feature and redraws it at its new location │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * location - { or } the │ │ │ │ │ - * location to which to move the feature. │ │ │ │ │ + * APIProperty: options │ │ │ │ │ + * {Object} The options object passed to the class constructor. Read-only. │ │ │ │ │ */ │ │ │ │ │ - move: function(location) { │ │ │ │ │ + options: null, │ │ │ │ │ │ │ │ │ │ - if (!this.layer || !this.geometry.move) { │ │ │ │ │ - //do nothing if no layer or immoveable geometry │ │ │ │ │ - return undefined; │ │ │ │ │ - } │ │ │ │ │ + // Options │ │ │ │ │ │ │ │ │ │ - var pixel; │ │ │ │ │ - if (location.CLASS_NAME == "OpenLayers.LonLat") { │ │ │ │ │ - pixel = this.layer.getViewPortPxFromLonLat(location); │ │ │ │ │ - } else { │ │ │ │ │ - pixel = location; │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: tileSize │ │ │ │ │ + * {} Set in the map options to override the default tile │ │ │ │ │ + * size for this map. │ │ │ │ │ + */ │ │ │ │ │ + tileSize: null, │ │ │ │ │ │ │ │ │ │ - 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; │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: projection │ │ │ │ │ + * {String} Set in the map options to specify the default projection │ │ │ │ │ + * for layers added to this map. When using a projection other than EPSG:4326 │ │ │ │ │ + * (CRS:84, Geographic) or EPSG:3857 (EPSG:900913, Web Mercator), │ │ │ │ │ + * also set maxExtent, maxResolution or resolutions. Default is "EPSG:4326". │ │ │ │ │ + * Note that the projection of the map is usually determined │ │ │ │ │ + * by that of the current baseLayer (see and ). │ │ │ │ │ + */ │ │ │ │ │ + projection: "EPSG:4326", │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: toState │ │ │ │ │ - * Sets the new state │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * state - {String} │ │ │ │ │ + * APIProperty: units │ │ │ │ │ + * {String} The map units. Possible values are 'degrees' (or 'dd'), 'm', │ │ │ │ │ + * 'ft', 'km', 'mi', 'inches'. Normally taken from the projection. │ │ │ │ │ + * Only required if both map and layers do not define a projection, │ │ │ │ │ + * or if they define a projection which does not define units │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ + units: null, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Feature.Vector" │ │ │ │ │ -}); │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: resolutions │ │ │ │ │ + * {Array(Float)} A list of map resolutions (map units per pixel) in │ │ │ │ │ + * descending order. If this is not set in the layer constructor, it │ │ │ │ │ + * will be set based on other resolution related properties │ │ │ │ │ + * (maxExtent, maxResolution, maxScale, etc.). │ │ │ │ │ + */ │ │ │ │ │ + resolutions: null, │ │ │ │ │ │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: maxResolution │ │ │ │ │ + * {Float} Required if you are not displaying the whole world on a tile │ │ │ │ │ + * with the size specified in . │ │ │ │ │ + */ │ │ │ │ │ + maxResolution: null, │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * 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 │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: minResolution │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + minResolution: null, │ │ │ │ │ │ │ │ │ │ - }, │ │ │ │ │ - '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 │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: maxScale │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + maxScale: null, │ │ │ │ │ │ │ │ │ │ - }, │ │ │ │ │ - 'delete': { │ │ │ │ │ - display: "none" │ │ │ │ │ - } │ │ │ │ │ -}; │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Style.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: minScale │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + minScale: 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. */ │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: maxExtent │ │ │ │ │ + * {|Array} If provided as an array, the array │ │ │ │ │ + * should consist of four values (left, bottom, right, top). │ │ │ │ │ + * The maximum extent for the map. │ │ │ │ │ + * Default depends on projection; if this is one of those defined in OpenLayers.Projection.defaults │ │ │ │ │ + * (EPSG:4326 or web mercator), maxExtent will be set to the value defined there; │ │ │ │ │ + * else, defaults to null. │ │ │ │ │ + * To restrict user panning and zooming of the map, use instead. │ │ │ │ │ + * The value for will change calculations for tile URLs. │ │ │ │ │ + */ │ │ │ │ │ + maxExtent: null, │ │ │ │ │ │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: minExtent │ │ │ │ │ + * {|Array} If provided as an array, the array │ │ │ │ │ + * should consist of four values (left, bottom, right, top). │ │ │ │ │ + * The minimum extent for the map. Defaults to null. │ │ │ │ │ + */ │ │ │ │ │ + minExtent: null, │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ │ - * @requires OpenLayers/Feature/Vector.js │ │ │ │ │ - */ │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: restrictedExtent │ │ │ │ │ + * {|Array} If provided as an array, the array │ │ │ │ │ + * should consist of four values (left, bottom, right, top). │ │ │ │ │ + * Limit map navigation to this extent where possible. │ │ │ │ │ + * If a non-null restrictedExtent is set, panning will be restricted │ │ │ │ │ + * to the given bounds. In addition, zooming to a resolution that │ │ │ │ │ + * displays more than the restricted extent will center the map │ │ │ │ │ + * on the restricted extent. If you wish to limit the zoom level │ │ │ │ │ + * or resolution, use maxResolution. │ │ │ │ │ + */ │ │ │ │ │ + restrictedExtent: null, │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Style │ │ │ │ │ - * This class represents a UserStyle obtained │ │ │ │ │ - * from a SLD, containing styling rules. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Style = OpenLayers.Class({ │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: numZoomLevels │ │ │ │ │ + * {Integer} Number of zoom levels for the map. Defaults to 16. Set a │ │ │ │ │ + * different value in the map options if needed. │ │ │ │ │ + */ │ │ │ │ │ + numZoomLevels: 16, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: id │ │ │ │ │ - * {String} A unique id for this session. │ │ │ │ │ + * APIProperty: theme │ │ │ │ │ + * {String} Relative path to a CSS file from which to load theme styles. │ │ │ │ │ + * Specify null in the map options (e.g. {theme: null}) if you │ │ │ │ │ + * want to get cascading style declarations - by putting links to │ │ │ │ │ + * stylesheets or style declarations directly in your page. │ │ │ │ │ */ │ │ │ │ │ - id: null, │ │ │ │ │ + theme: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: displayProjection │ │ │ │ │ + * {} Requires proj4js support for projections other │ │ │ │ │ + * than EPSG:4326 or EPSG:900913/EPSG:3857. Projection used by │ │ │ │ │ + * several controls to display data to user. If this property is set, │ │ │ │ │ + * it will be set on any control which has a null displayProjection │ │ │ │ │ + * property at the time the control is added to the map. │ │ │ │ │ + */ │ │ │ │ │ + displayProjection: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: name │ │ │ │ │ - * {String} │ │ │ │ │ + * APIProperty: tileManager │ │ │ │ │ + * {|Object} By default, and if the build contains │ │ │ │ │ + * TileManager.js, the map will use the TileManager to queue image requests │ │ │ │ │ + * and to cache tile image elements. To create a map without a TileManager │ │ │ │ │ + * configure the map with tileManager: null. To create a TileManager with │ │ │ │ │ + * non-default options, supply the options instead or alternatively supply │ │ │ │ │ + * an instance of {}. │ │ │ │ │ */ │ │ │ │ │ - name: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: title │ │ │ │ │ - * {String} Title of this style (set if included in SLD) │ │ │ │ │ + * APIProperty: fallThrough │ │ │ │ │ + * {Boolean} Should OpenLayers allow events on the map to fall through to │ │ │ │ │ + * other elements on the page, or should it swallow them? (#457) │ │ │ │ │ + * Default is to swallow. │ │ │ │ │ */ │ │ │ │ │ - title: null, │ │ │ │ │ + fallThrough: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: description │ │ │ │ │ - * {String} Description of this style (set if abstract is included in SLD) │ │ │ │ │ + * APIProperty: autoUpdateSize │ │ │ │ │ + * {Boolean} Should OpenLayers automatically update the size of the map │ │ │ │ │ + * when the resize event is fired. Default is true. │ │ │ │ │ */ │ │ │ │ │ - description: null, │ │ │ │ │ + autoUpdateSize: true, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: layerName │ │ │ │ │ - * {} name of the layer that this style belongs to, usually │ │ │ │ │ - * according to the NamedLayer attribute of an SLD document. │ │ │ │ │ + * 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. │ │ │ │ │ */ │ │ │ │ │ - layerName: null, │ │ │ │ │ + eventListeners: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: isDefault │ │ │ │ │ - * {Boolean} │ │ │ │ │ + * Property: panTween │ │ │ │ │ + * {} Animated panning tween object, see panTo() │ │ │ │ │ */ │ │ │ │ │ - isDefault: false, │ │ │ │ │ + panTween: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: rules │ │ │ │ │ - * {Array()} │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: panMethod │ │ │ │ │ + * {Function} The Easing function to be used for tweening. Default is │ │ │ │ │ + * OpenLayers.Easing.Expo.easeOut. Setting this to 'null' turns off │ │ │ │ │ + * animated panning. │ │ │ │ │ */ │ │ │ │ │ - rules: null, │ │ │ │ │ + panMethod: OpenLayers.Easing.Expo.easeOut, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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 │ │ │ │ │ + * Property: panDuration │ │ │ │ │ + * {Integer} The number of steps to be passed to the │ │ │ │ │ + * OpenLayers.Tween.start() method when the map is │ │ │ │ │ + * panned. │ │ │ │ │ + * Default is 50. │ │ │ │ │ */ │ │ │ │ │ - context: null, │ │ │ │ │ + panDuration: 50, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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 is set to │ │ │ │ │ - * true, the defaultStyle will only be taken into account if there are │ │ │ │ │ - * rules defined. │ │ │ │ │ + * Property: zoomTween │ │ │ │ │ + * {} Animated zooming tween object, see zoomTo() │ │ │ │ │ */ │ │ │ │ │ - defaultStyle: null, │ │ │ │ │ + zoomTween: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: defaultsPerSymbolizer │ │ │ │ │ - * {Boolean} If set to true, the will extend the symbolizer │ │ │ │ │ - * of every rule. Properties of the will also be used to set │ │ │ │ │ - * missing symbolizer properties if the symbolizer has stroke, fill or │ │ │ │ │ - * graphic set to true. Default is false. │ │ │ │ │ + * APIProperty: zoomMethod │ │ │ │ │ + * {Function} The Easing function to be used for tweening. Default is │ │ │ │ │ + * OpenLayers.Easing.Quad.easeOut. Setting this to 'null' turns off │ │ │ │ │ + * animated zooming. │ │ │ │ │ */ │ │ │ │ │ - defaultsPerSymbolizer: false, │ │ │ │ │ + zoomMethod: OpenLayers.Easing.Quad.easeOut, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * Property: zoomDuration │ │ │ │ │ + * {Integer} The number of steps to be passed to the │ │ │ │ │ + * OpenLayers.Tween.start() method when the map is zoomed. │ │ │ │ │ + * Default is 20. │ │ │ │ │ */ │ │ │ │ │ - propertyStyles: null, │ │ │ │ │ + zoomDuration: 20, │ │ │ │ │ │ │ │ │ │ + /** │ │ │ │ │ + * Property: paddingForPopups │ │ │ │ │ + * {} Outside margin of the popup. Used to prevent │ │ │ │ │ + * the popup from getting too close to the map border. │ │ │ │ │ + */ │ │ │ │ │ + paddingForPopups: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Style │ │ │ │ │ - * Creates a UserStyle. │ │ │ │ │ + /** │ │ │ │ │ + * Property: layerContainerOriginPx │ │ │ │ │ + * {Object} Cached object representing the layer container origin (in pixels). │ │ │ │ │ + */ │ │ │ │ │ + layerContainerOriginPx: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: minPx │ │ │ │ │ + * {Object} An object with a 'x' and 'y' values that is the lower │ │ │ │ │ + * left of maxExtent in viewport pixel space. │ │ │ │ │ + * Used to verify in moveByPx that the new location we're moving to │ │ │ │ │ + * is valid. It is also used in the getLonLatFromViewPortPx function │ │ │ │ │ + * of Layer. │ │ │ │ │ + */ │ │ │ │ │ + minPx: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: maxPx │ │ │ │ │ + * {Object} An object with a 'x' and 'y' values that is the top │ │ │ │ │ + * right of maxExtent in viewport pixel space. │ │ │ │ │ + * Used to verify in moveByPx that the new location we're moving to │ │ │ │ │ + * is valid. │ │ │ │ │ + */ │ │ │ │ │ + maxPx: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Map │ │ │ │ │ + * Constructor for a new OpenLayers.Map instance. There are two possible │ │ │ │ │ + * ways to call the map constructor. See the examples below. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * 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. │ │ │ │ │ + * div - {DOMElement|String} The element or id of an element in your page │ │ │ │ │ + * that will contain the map. May be omitted if the
option is │ │ │ │ │ + * provided or if you intend to call the method later. │ │ │ │ │ + * options - {Object} Optional object with properties to tag onto the map. │ │ │ │ │ * │ │ │ │ │ - * Valid options: │ │ │ │ │ - * rules - {Array()} List of rules to be added to the │ │ │ │ │ - * style. │ │ │ │ │ + * Valid options (in addition to the listed API properties): │ │ │ │ │ + * center - {|Array} The default initial center of the map. │ │ │ │ │ + * If provided as array, the first value is the x coordinate, │ │ │ │ │ + * and the 2nd value is the y coordinate. │ │ │ │ │ + * Only specify if is provided. │ │ │ │ │ + * Note that if an ArgParser/Permalink control is present, │ │ │ │ │ + * and the querystring contains coordinates, center will be set │ │ │ │ │ + * by that, and this option will be ignored. │ │ │ │ │ + * zoom - {Number} The initial zoom level for the map. Only specify if │ │ │ │ │ + * is provided. │ │ │ │ │ + * Note that if an ArgParser/Permalink control is present, │ │ │ │ │ + * and the querystring contains a zoom level, zoom will be set │ │ │ │ │ + * by that, and this option will be ignored. │ │ │ │ │ + * extent - {|Array} The initial extent of the map. │ │ │ │ │ + * If provided as an array, the array should consist of │ │ │ │ │ + * four values (left, bottom, right, top). │ │ │ │ │ + * Only specify if
and are not provided. │ │ │ │ │ * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} │ │ │ │ │ + * Examples: │ │ │ │ │ + * (code) │ │ │ │ │ + * // create a map with default options in an element with the id "map1" │ │ │ │ │ + * var map = new OpenLayers.Map("map1"); │ │ │ │ │ + * │ │ │ │ │ + * // create a map with non-default options in an element with id "map2" │ │ │ │ │ + * var options = { │ │ │ │ │ + * projection: "EPSG:3857", │ │ │ │ │ + * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000), │ │ │ │ │ + * center: new OpenLayers.LonLat(-12356463.476333, 5621521.4854095) │ │ │ │ │ + * }; │ │ │ │ │ + * var map = new OpenLayers.Map("map2", options); │ │ │ │ │ + * │ │ │ │ │ + * // map with non-default options - same as above but with a single argument, │ │ │ │ │ + * // a restricted extent, and using arrays for bounds and center │ │ │ │ │ + * var map = new OpenLayers.Map({ │ │ │ │ │ + * div: "map_id", │ │ │ │ │ + * projection: "EPSG:3857", │ │ │ │ │ + * maxExtent: [-18924313.432222, -15538711.094146, 18924313.432222, 15538711.094146], │ │ │ │ │ + * restrictedExtent: [-13358338.893333, -9608371.5085962, 13358338.893333, 9608371.5085962], │ │ │ │ │ + * center: [-12356463.476333, 5621521.4854095] │ │ │ │ │ + * }); │ │ │ │ │ + * │ │ │ │ │ + * // create a map without a reference to a container - call render later │ │ │ │ │ + * var map = new OpenLayers.Map({ │ │ │ │ │ + * projection: "EPSG:3857", │ │ │ │ │ + * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000) │ │ │ │ │ + * }); │ │ │ │ │ + * (end) │ │ │ │ │ */ │ │ │ │ │ - initialize: function(style, options) { │ │ │ │ │ + initialize: function(div, options) { │ │ │ │ │ + │ │ │ │ │ + // If only one argument is provided, check if it is an object. │ │ │ │ │ + if (arguments.length === 1 && typeof div === "object") { │ │ │ │ │ + options = div; │ │ │ │ │ + div = options && options.div; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // Simple-type defaults are set in class definition. │ │ │ │ │ + // Now set complex-type defaults │ │ │ │ │ + this.tileSize = new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH, │ │ │ │ │ + OpenLayers.Map.TILE_HEIGHT); │ │ │ │ │ + │ │ │ │ │ + this.paddingForPopups = new OpenLayers.Bounds(15, 15, 15, 15); │ │ │ │ │ + │ │ │ │ │ + this.theme = OpenLayers._getScriptLocation() + │ │ │ │ │ + 'theme/default/style.css'; │ │ │ │ │ │ │ │ │ │ + // backup original options │ │ │ │ │ + this.options = OpenLayers.Util.extend({}, options); │ │ │ │ │ + │ │ │ │ │ + // now override default options │ │ │ │ │ OpenLayers.Util.extend(this, options); │ │ │ │ │ - this.rules = []; │ │ │ │ │ - if (options && options.rules) { │ │ │ │ │ - this.addRules(options.rules); │ │ │ │ │ + │ │ │ │ │ + var projCode = this.projection instanceof OpenLayers.Projection ? │ │ │ │ │ + this.projection.projCode : this.projection; │ │ │ │ │ + OpenLayers.Util.applyDefaults(this, OpenLayers.Projection.defaults[projCode]); │ │ │ │ │ + │ │ │ │ │ + // allow extents and center to be arrays │ │ │ │ │ + if (this.maxExtent && !(this.maxExtent instanceof OpenLayers.Bounds)) { │ │ │ │ │ + this.maxExtent = new OpenLayers.Bounds(this.maxExtent); │ │ │ │ │ + } │ │ │ │ │ + if (this.minExtent && !(this.minExtent instanceof OpenLayers.Bounds)) { │ │ │ │ │ + this.minExtent = new OpenLayers.Bounds(this.minExtent); │ │ │ │ │ + } │ │ │ │ │ + if (this.restrictedExtent && !(this.restrictedExtent instanceof OpenLayers.Bounds)) { │ │ │ │ │ + this.restrictedExtent = new OpenLayers.Bounds(this.restrictedExtent); │ │ │ │ │ + } │ │ │ │ │ + if (this.center && !(this.center instanceof OpenLayers.LonLat)) { │ │ │ │ │ + this.center = new OpenLayers.LonLat(this.center); │ │ │ │ │ } │ │ │ │ │ │ │ │ │ │ - // use the default style from OpenLayers.Feature.Vector if no style │ │ │ │ │ - // was given in the constructor │ │ │ │ │ - this.setDefaultStyle(style || │ │ │ │ │ - OpenLayers.Feature.Vector.style["default"]); │ │ │ │ │ + // initialize layers array │ │ │ │ │ + this.layers = []; │ │ │ │ │ │ │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ - }, │ │ │ │ │ + this.id = OpenLayers.Util.createUniqueID("OpenLayers.Map_"); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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.div = OpenLayers.Util.getElement(div); │ │ │ │ │ + if (!this.div) { │ │ │ │ │ + this.div = document.createElement("div"); │ │ │ │ │ + this.div.style.height = "1px"; │ │ │ │ │ + this.div.style.width = "1px"; │ │ │ │ │ } │ │ │ │ │ - this.rules = null; │ │ │ │ │ - this.defaultStyle = null; │ │ │ │ │ - }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: createSymbolizer │ │ │ │ │ - * creates a style by applying all feature-dependent rules to the base │ │ │ │ │ - * style. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * 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); │ │ │ │ │ + OpenLayers.Element.addClass(this.div, 'olMap'); │ │ │ │ │ │ │ │ │ │ - var rules = this.rules; │ │ │ │ │ + // the viewPortDiv is the outermost div we modify │ │ │ │ │ + var id = this.id + "_OpenLayers_ViewPort"; │ │ │ │ │ + this.viewPortDiv = OpenLayers.Util.createDiv(id, null, null, null, │ │ │ │ │ + "relative", null, │ │ │ │ │ + "hidden"); │ │ │ │ │ + this.viewPortDiv.style.width = "100%"; │ │ │ │ │ + this.viewPortDiv.style.height = "100%"; │ │ │ │ │ + this.viewPortDiv.className = "olMapViewport"; │ │ │ │ │ + this.div.appendChild(this.viewPortDiv); │ │ │ │ │ │ │ │ │ │ - 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); │ │ │ │ │ + this.events = new OpenLayers.Events( │ │ │ │ │ + this, this.viewPortDiv, null, this.fallThrough, { │ │ │ │ │ + includeXY: true │ │ │ │ │ + } │ │ │ │ │ + ); │ │ │ │ │ │ │ │ │ │ - if (applies) { │ │ │ │ │ - if (rule instanceof OpenLayers.Rule && rule.elseFilter) { │ │ │ │ │ - elseRules.push(rule); │ │ │ │ │ - } else { │ │ │ │ │ - appliedRules = true; │ │ │ │ │ - this.applySymbolizer(rule, style, feature); │ │ │ │ │ + if (OpenLayers.TileManager && this.tileManager !== null) { │ │ │ │ │ + if (!(this.tileManager instanceof OpenLayers.TileManager)) { │ │ │ │ │ + this.tileManager = new OpenLayers.TileManager(this.tileManager); │ │ │ │ │ + } │ │ │ │ │ + this.tileManager.addMap(this); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // the layerContainerDiv is the one that holds all the layers │ │ │ │ │ + id = this.id + "_OpenLayers_Container"; │ │ │ │ │ + this.layerContainerDiv = OpenLayers.Util.createDiv(id); │ │ │ │ │ + this.layerContainerDiv.style.zIndex = this.Z_INDEX_BASE['Popup'] - 1; │ │ │ │ │ + this.layerContainerOriginPx = { │ │ │ │ │ + x: 0, │ │ │ │ │ + y: 0 │ │ │ │ │ + }; │ │ │ │ │ + this.applyTransform(); │ │ │ │ │ + │ │ │ │ │ + this.viewPortDiv.appendChild(this.layerContainerDiv); │ │ │ │ │ + │ │ │ │ │ + this.updateSize(); │ │ │ │ │ + if (this.eventListeners instanceof Object) { │ │ │ │ │ + this.events.on(this.eventListeners); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (this.autoUpdateSize === true) { │ │ │ │ │ + // updateSize on catching the window's resize │ │ │ │ │ + // Note that this is ok, as updateSize() does nothing if the │ │ │ │ │ + // map's size has not actually changed. │ │ │ │ │ + this.updateSizeDestroy = OpenLayers.Function.bind(this.updateSize, │ │ │ │ │ + this); │ │ │ │ │ + OpenLayers.Event.observe(window, 'resize', │ │ │ │ │ + this.updateSizeDestroy); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // only append link stylesheet if the theme property is set │ │ │ │ │ + if (this.theme) { │ │ │ │ │ + // check existing links for equivalent url │ │ │ │ │ + var addNode = true; │ │ │ │ │ + var nodes = document.getElementsByTagName('link'); │ │ │ │ │ + for (var i = 0, len = nodes.length; i < len; ++i) { │ │ │ │ │ + if (OpenLayers.Util.isEquivalentUrl(nodes.item(i).href, │ │ │ │ │ + this.theme)) { │ │ │ │ │ + addNode = false; │ │ │ │ │ + break; │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ + // only add a new node if one with an equivalent url hasn't already │ │ │ │ │ + // been added │ │ │ │ │ + if (addNode) { │ │ │ │ │ + var cssNode = document.createElement('link'); │ │ │ │ │ + cssNode.setAttribute('rel', 'stylesheet'); │ │ │ │ │ + cssNode.setAttribute('type', 'text/css'); │ │ │ │ │ + cssNode.setAttribute('href', this.theme); │ │ │ │ │ + document.getElementsByTagName('head')[0].appendChild(cssNode); │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ │ │ │ │ │ - // if 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); │ │ │ │ │ + if (this.controls == null) { // default controls │ │ │ │ │ + this.controls = []; │ │ │ │ │ + if (OpenLayers.Control != null) { // running full or lite? │ │ │ │ │ + // Navigation or TouchNavigation depending on what is in build │ │ │ │ │ + if (OpenLayers.Control.Navigation) { │ │ │ │ │ + this.controls.push(new OpenLayers.Control.Navigation()); │ │ │ │ │ + } else if (OpenLayers.Control.TouchNavigation) { │ │ │ │ │ + this.controls.push(new OpenLayers.Control.TouchNavigation()); │ │ │ │ │ + } │ │ │ │ │ + if (OpenLayers.Control.Zoom) { │ │ │ │ │ + this.controls.push(new OpenLayers.Control.Zoom()); │ │ │ │ │ + } else if (OpenLayers.Control.PanZoom) { │ │ │ │ │ + this.controls.push(new OpenLayers.Control.PanZoom()); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (OpenLayers.Control.ArgParser) { │ │ │ │ │ + this.controls.push(new OpenLayers.Control.ArgParser()); │ │ │ │ │ + } │ │ │ │ │ + if (OpenLayers.Control.Attribution) { │ │ │ │ │ + this.controls.push(new OpenLayers.Control.Attribution()); │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ │ │ │ │ │ - // don't display if there were rules but none applied │ │ │ │ │ - if (rules.length > 0 && appliedRules == false) { │ │ │ │ │ - style.display = "none"; │ │ │ │ │ + for (var i = 0, len = this.controls.length; i < len; i++) { │ │ │ │ │ + this.addControlToMap(this.controls[i]); │ │ │ │ │ } │ │ │ │ │ │ │ │ │ │ - if (style.label != null && typeof style.label !== "string") { │ │ │ │ │ - style.label = String(style.label); │ │ │ │ │ + this.popups = []; │ │ │ │ │ + │ │ │ │ │ + this.unloadDestroy = OpenLayers.Function.bind(this.destroy, this); │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ + // always call map.destroy() │ │ │ │ │ + OpenLayers.Event.observe(window, 'unload', this.unloadDestroy); │ │ │ │ │ + │ │ │ │ │ + // add any initial layers │ │ │ │ │ + if (options && options.layers) { │ │ │ │ │ + /** │ │ │ │ │ + * If you have set options.center, the map center property will be │ │ │ │ │ + * set at this point. However, since setCenter has not been called, │ │ │ │ │ + * addLayers gets confused. So we delete the map center in this │ │ │ │ │ + * case. Because the check below uses options.center, it will │ │ │ │ │ + * be properly set below. │ │ │ │ │ + */ │ │ │ │ │ + delete this.center; │ │ │ │ │ + delete this.zoom; │ │ │ │ │ + this.addLayers(options.layers); │ │ │ │ │ + // set center (and optionally zoom) │ │ │ │ │ + if (options.center && !this.getCenter()) { │ │ │ │ │ + // zoom can be undefined here │ │ │ │ │ + this.setCenter(options.center, options.zoom); │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ │ │ │ │ │ - return style; │ │ │ │ │ + if (this.panMethod) { │ │ │ │ │ + this.panTween = new OpenLayers.Tween(this.panMethod); │ │ │ │ │ + } │ │ │ │ │ + if (this.zoomMethod && this.applyTransform.transform) { │ │ │ │ │ + this.zoomTween = new OpenLayers.Tween(this.zoomMethod); │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: applySymbolizer │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * rule - {} │ │ │ │ │ - * style - {Object} │ │ │ │ │ - * feature - {} │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: getViewport │ │ │ │ │ + * Get the DOMElement representing the view port. │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Object} A style with new symbolizer applied. │ │ │ │ │ + * {DOMElement} │ │ │ │ │ */ │ │ │ │ │ - applySymbolizer: function(rule, style, feature) { │ │ │ │ │ - var symbolizerPrefix = feature.geometry ? │ │ │ │ │ - this.getSymbolizerPrefix(feature.geometry) : │ │ │ │ │ - OpenLayers.Style.SYMBOLIZER_PREFIXES[0]; │ │ │ │ │ + getViewport: function() { │ │ │ │ │ + return this.viewPortDiv; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer; │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: render │ │ │ │ │ + * Render the map to a specified container. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * div - {String|DOMElement} The container that the map should be rendered │ │ │ │ │ + * to. If different than the current container, the map viewport │ │ │ │ │ + * will be moved from the current to the new container. │ │ │ │ │ + */ │ │ │ │ │ + render: function(div) { │ │ │ │ │ + this.div = OpenLayers.Util.getElement(div); │ │ │ │ │ + OpenLayers.Element.addClass(this.div, 'olMap'); │ │ │ │ │ + this.viewPortDiv.parentNode.removeChild(this.viewPortDiv); │ │ │ │ │ + this.div.appendChild(this.viewPortDiv); │ │ │ │ │ + this.updateSize(); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - 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 │ │ │ │ │ - }); │ │ │ │ │ + /** │ │ │ │ │ + * Method: unloadDestroy │ │ │ │ │ + * Function that is called to destroy the map on page unload. stored here │ │ │ │ │ + * so that if map is manually destroyed, we can unregister this. │ │ │ │ │ + */ │ │ │ │ │ + unloadDestroy: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: updateSizeDestroy │ │ │ │ │ + * When the map is destroyed, we need to stop listening to updateSize │ │ │ │ │ + * events: this method stores the function we need to unregister in │ │ │ │ │ + * non-IE browsers. │ │ │ │ │ + */ │ │ │ │ │ + updateSizeDestroy: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ + * Destroy this map. │ │ │ │ │ + * Note that if you are using an application which removes a container │ │ │ │ │ + * of the map from the DOM, you need to ensure that you destroy the │ │ │ │ │ + * map *before* this happens; otherwise, the page unload handler │ │ │ │ │ + * will fail because the DOM elements that map.destroy() wants │ │ │ │ │ + * to clean up will be gone. (See │ │ │ │ │ + * http://trac.osgeo.org/openlayers/ticket/2277 for more information). │ │ │ │ │ + * This will apply to GeoExt and also to other applications which │ │ │ │ │ + * modify the DOM of the container of the OpenLayers Map. │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + // if unloadDestroy is null, we've already been destroyed │ │ │ │ │ + if (!this.unloadDestroy) { │ │ │ │ │ + return false; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // make sure panning doesn't continue after destruction │ │ │ │ │ + if (this.panTween) { │ │ │ │ │ + this.panTween.stop(); │ │ │ │ │ + this.panTween = null; │ │ │ │ │ + } │ │ │ │ │ + // make sure zooming doesn't continue after destruction │ │ │ │ │ + if (this.zoomTween) { │ │ │ │ │ + this.zoomTween.stop(); │ │ │ │ │ + this.zoomTween = null; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // map has been destroyed. dont do it again! │ │ │ │ │ + OpenLayers.Event.stopObserving(window, 'unload', this.unloadDestroy); │ │ │ │ │ + this.unloadDestroy = null; │ │ │ │ │ + │ │ │ │ │ + if (this.updateSizeDestroy) { │ │ │ │ │ + OpenLayers.Event.stopObserving(window, 'resize', │ │ │ │ │ + this.updateSizeDestroy); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.paddingForPopups = null; │ │ │ │ │ + │ │ │ │ │ + if (this.controls != null) { │ │ │ │ │ + for (var i = this.controls.length - 1; i >= 0; --i) { │ │ │ │ │ + this.controls[i].destroy(); │ │ │ │ │ } │ │ │ │ │ - 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 │ │ │ │ │ - }); │ │ │ │ │ + this.controls = null; │ │ │ │ │ + } │ │ │ │ │ + if (this.layers != null) { │ │ │ │ │ + for (var i = this.layers.length - 1; i >= 0; --i) { │ │ │ │ │ + //pass 'false' to destroy so that map wont try to set a new │ │ │ │ │ + // baselayer after each baselayer is removed │ │ │ │ │ + this.layers[i].destroy(false); │ │ │ │ │ } │ │ │ │ │ + this.layers = null; │ │ │ │ │ + } │ │ │ │ │ + if (this.viewPortDiv && this.viewPortDiv.parentNode) { │ │ │ │ │ + this.viewPortDiv.parentNode.removeChild(this.viewPortDiv); │ │ │ │ │ } │ │ │ │ │ + this.viewPortDiv = null; │ │ │ │ │ │ │ │ │ │ - // merge the style with the current style │ │ │ │ │ - return this.createLiterals( │ │ │ │ │ - OpenLayers.Util.extend(style, symbolizer), feature); │ │ │ │ │ + if (this.tileManager) { │ │ │ │ │ + this.tileManager.removeMap(this); │ │ │ │ │ + this.tileManager = null; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (this.eventListeners) { │ │ │ │ │ + this.events.un(this.eventListeners); │ │ │ │ │ + this.eventListeners = null; │ │ │ │ │ + } │ │ │ │ │ + this.events.destroy(); │ │ │ │ │ + this.events = null; │ │ │ │ │ + │ │ │ │ │ + this.options = null; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: createLiterals │ │ │ │ │ - * creates literals for all style properties that have an entry in │ │ │ │ │ - * . │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: setOptions │ │ │ │ │ + * Change the map options │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * style - {Object} style to create literals for. Will be modified │ │ │ │ │ - * inline. │ │ │ │ │ - * feature - {Object} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} the modified style │ │ │ │ │ + * options - {Object} Hashtable of options to tag to the map │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ + setOptions: function(options) { │ │ │ │ │ + var updatePxExtent = this.minPx && │ │ │ │ │ + options.restrictedExtent != this.restrictedExtent; │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + // force recalculation of minPx and maxPx │ │ │ │ │ + updatePxExtent && this.moveTo(this.getCachedCenter(), this.zoom, { │ │ │ │ │ + forceZoomChange: true │ │ │ │ │ + }); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: getTileSize │ │ │ │ │ + * Get the tile size for the map │ │ │ │ │ + * │ │ │ │ │ * 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; │ │ │ │ │ + getTileSize: function() { │ │ │ │ │ + return this.tileSize; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ /** │ │ │ │ │ - * Method: addPropertyStyles │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: getBy │ │ │ │ │ + * Get a list of objects given a property and a match item. │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * propertyStyles - {Object} hash to add new property styles to. Will be │ │ │ │ │ - * modified inline │ │ │ │ │ - * symbolizer - {Object} search this symbolizer for property styles │ │ │ │ │ - * │ │ │ │ │ + * array - {String} A property on the map whose value is an array. │ │ │ │ │ + * property - {String} A property on each item of the given array. │ │ │ │ │ + * match - {String | Object} A string to match. Can also be a regular │ │ │ │ │ + * expression literal or object. In addition, it can be any object │ │ │ │ │ + * with a method named test. For reqular expressions or other, if │ │ │ │ │ + * match.test(map[array][i][property]) evaluates to true, the item will │ │ │ │ │ + * be included in the array returned. If no items are found, an empty │ │ │ │ │ + * array is returned. │ │ │ │ │ + * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Object} propertyStyles hash │ │ │ │ │ + * {Array} An array of items where the given property matches the given │ │ │ │ │ + * criteria. │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ + getBy: function(array, property, match) { │ │ │ │ │ + var test = (typeof match.test == "function"); │ │ │ │ │ + var found = OpenLayers.Array.filter(this[array], function(item) { │ │ │ │ │ + return item[property] == match || (test && match.test(item[property])); │ │ │ │ │ + }); │ │ │ │ │ + return found; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: addRules │ │ │ │ │ - * Adds rules to this style. │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: getLayersBy │ │ │ │ │ + * Get a list of layers with properties matching the given criteria. │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * rules - {Array()} │ │ │ │ │ + * property - {String} A layer property to be matched. │ │ │ │ │ + * match - {String | Object} A string to match. Can also be a regular │ │ │ │ │ + * expression literal or object. In addition, it can be any object │ │ │ │ │ + * with a method named test. For reqular expressions or other, if │ │ │ │ │ + * match.test(layer[property]) evaluates to true, the layer will be │ │ │ │ │ + * included in the array returned. If no layers are found, an empty │ │ │ │ │ + * array is returned. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Array()} A list of layers matching the given criteria. │ │ │ │ │ + * An empty array is returned if no matches are found. │ │ │ │ │ */ │ │ │ │ │ - addRules: function(rules) { │ │ │ │ │ - Array.prototype.push.apply(this.rules, rules); │ │ │ │ │ - this.propertyStyles = this.findPropertyStyles(); │ │ │ │ │ + getLayersBy: function(property, match) { │ │ │ │ │ + return this.getBy("layers", property, match); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: setDefaultStyle │ │ │ │ │ - * Sets the default style for this style object. │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: getLayersByName │ │ │ │ │ + * Get a list of layers with names matching the given name. │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * style - {Object} Hash of style properties │ │ │ │ │ + * match - {String | Object} A layer name. The name can also be a regular │ │ │ │ │ + * expression literal or object. In addition, it can be any object │ │ │ │ │ + * with a method named test. For reqular expressions or other, if │ │ │ │ │ + * name.test(layer.name) evaluates to true, the layer will be included │ │ │ │ │ + * in the list of layers returned. If no layers are found, an empty │ │ │ │ │ + * array is returned. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Array()} A list of layers matching the given name. │ │ │ │ │ + * An empty array is returned if no matches are found. │ │ │ │ │ */ │ │ │ │ │ - setDefaultStyle: function(style) { │ │ │ │ │ - this.defaultStyle = style; │ │ │ │ │ - this.propertyStyles = this.findPropertyStyles(); │ │ │ │ │ + getLayersByName: function(match) { │ │ │ │ │ + return this.getLayersBy("name", match); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getSymbolizerPrefix │ │ │ │ │ - * Returns the correct symbolizer prefix according to the │ │ │ │ │ - * geometry type of the passed geometry │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: getLayersByClass │ │ │ │ │ + * Get a list of layers of a given class (CLASS_NAME). │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * geometry - {} │ │ │ │ │ - * │ │ │ │ │ + * match - {String | Object} A layer class name. The match can also be a │ │ │ │ │ + * regular expression literal or object. In addition, it can be any │ │ │ │ │ + * object with a method named test. For reqular expressions or other, │ │ │ │ │ + * if type.test(layer.CLASS_NAME) evaluates to true, the layer will │ │ │ │ │ + * be included in the list of layers returned. If no layers are │ │ │ │ │ + * found, an empty array is returned. │ │ │ │ │ + * │ │ │ │ │ * Returns: │ │ │ │ │ - * {String} key of the according symbolizer │ │ │ │ │ + * {Array()} A list of layers matching the given class. │ │ │ │ │ + * An empty array is returned if no matches are found. │ │ │ │ │ */ │ │ │ │ │ - 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]; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ + getLayersByClass: function(match) { │ │ │ │ │ + return this.getLayersBy("CLASS_NAME", match); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: clone │ │ │ │ │ - * Clones this style. │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: getControlsBy │ │ │ │ │ + * Get a list of controls with properties matching the given criteria. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * property - {String} A control property to be matched. │ │ │ │ │ + * match - {String | Object} A string to match. Can also be a regular │ │ │ │ │ + * expression literal or object. In addition, it can be any object │ │ │ │ │ + * with a method named test. For reqular expressions or other, if │ │ │ │ │ + * match.test(layer[property]) evaluates to true, the layer will be │ │ │ │ │ + * included in the array returned. If no layers are found, an empty │ │ │ │ │ + * array is returned. │ │ │ │ │ + * │ │ │ │ │ * Returns: │ │ │ │ │ - * {} Clone of this style. │ │ │ │ │ + * {Array()} A list of controls matching the given │ │ │ │ │ + * criteria. An empty array is returned if no matches are found. │ │ │ │ │ */ │ │ │ │ │ - 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); │ │ │ │ │ + getControlsBy: function(property, match) { │ │ │ │ │ + return this.getBy("controls", property, match); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - 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 - {} optional feature to pass to │ │ │ │ │ - * 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/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"). │ │ │ │ │ + * APIMethod: getControlsByClass │ │ │ │ │ + * Get a list of controls of a given class (CLASS_NAME). │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * match - {String | Object} A control class name. The match can also be a │ │ │ │ │ + * regular expression literal or object. In addition, it can be any │ │ │ │ │ + * object with a method named test. For reqular expressions or other, │ │ │ │ │ + * if type.test(control.CLASS_NAME) evaluates to true, the control will │ │ │ │ │ + * be included in the list of controls returned. If no controls are │ │ │ │ │ + * found, an empty array is returned. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Array()} A list of controls matching the given class. │ │ │ │ │ + * An empty array is returned if no matches are found. │ │ │ │ │ */ │ │ │ │ │ - styles: null, │ │ │ │ │ + getControlsByClass: function(match) { │ │ │ │ │ + return this.getControlsBy("CLASS_NAME", match); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /********************************************************/ │ │ │ │ │ + /* */ │ │ │ │ │ + /* Layer Functions */ │ │ │ │ │ + /* */ │ │ │ │ │ + /* The following functions deal with adding and */ │ │ │ │ │ + /* removing Layers to and from the Map */ │ │ │ │ │ + /* */ │ │ │ │ │ + /********************************************************/ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * APIMethod: getLayer │ │ │ │ │ + * Get a layer based on its id │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * id - {String} A layer id │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} The Layer with the corresponding id from the map's │ │ │ │ │ + * layer collection, or null if not found. │ │ │ │ │ */ │ │ │ │ │ - extendDefault: true, │ │ │ │ │ + getLayer: function(id) { │ │ │ │ │ + var foundLayer = null; │ │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ │ + var layer = this.layers[i]; │ │ │ │ │ + if (layer.id == id) { │ │ │ │ │ + foundLayer = layer; │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return foundLayer; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.StyleMap │ │ │ │ │ + * Method: setLayerZIndex │ │ │ │ │ * │ │ │ │ │ * 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 - {} │ │ │ │ │ + * zIdx - {int} │ │ │ │ │ */ │ │ │ │ │ - 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); │ │ │ │ │ + setLayerZIndex: function(layer, zIdx) { │ │ │ │ │ + layer.setZIndex( │ │ │ │ │ + this.Z_INDEX_BASE[layer.isBaseLayer ? 'BaseLayer' : 'Overlay'] + │ │ │ │ │ + zIdx * 5); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: destroy │ │ │ │ │ + * Method: resetLayersZIndex │ │ │ │ │ + * Reset each layer's z-index based on layer's array index │ │ │ │ │ */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - for (var key in this.styles) { │ │ │ │ │ - this.styles[key].destroy(); │ │ │ │ │ + resetLayersZIndex: function() { │ │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ │ + var layer = this.layers[i]; │ │ │ │ │ + this.setLayerZIndex(layer, i); │ │ │ │ │ } │ │ │ │ │ - this.styles = null; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: createSymbolizer │ │ │ │ │ - * Creates the symbolizer for a feature for a render intent. │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: addLayer │ │ │ │ │ + * │ │ │ │ │ * 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). │ │ │ │ │ - * │ │ │ │ │ + * layer - {} │ │ │ │ │ + * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Object} symbolizer hash │ │ │ │ │ + * {Boolean} True if the layer has been added to the map. │ │ │ │ │ */ │ │ │ │ │ - createSymbolizer: function(feature, intent) { │ │ │ │ │ - if (!feature) { │ │ │ │ │ - feature = new OpenLayers.Feature.Vector(); │ │ │ │ │ + addLayer: function(layer) { │ │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ │ + if (this.layers[i] == layer) { │ │ │ │ │ + return false; │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ - if (!this.styles[intent]) { │ │ │ │ │ - intent = "default"; │ │ │ │ │ + if (this.events.triggerEvent("preaddlayer", { │ │ │ │ │ + layer: layer │ │ │ │ │ + }) === false) { │ │ │ │ │ + return false; │ │ │ │ │ } │ │ │ │ │ - feature.renderIntent = intent; │ │ │ │ │ - var defaultSymbolizer = {}; │ │ │ │ │ - if (this.extendDefault && intent != "default") { │ │ │ │ │ - defaultSymbolizer = this.styles["default"].createSymbolizer(feature); │ │ │ │ │ + if (this.allOverlays) { │ │ │ │ │ + layer.isBaseLayer = false; │ │ │ │ │ } │ │ │ │ │ - return OpenLayers.Util.extend(defaultSymbolizer, │ │ │ │ │ - this.styles[intent].createSymbolizer(feature)); │ │ │ │ │ + │ │ │ │ │ + layer.div.className = "olLayerDiv"; │ │ │ │ │ + layer.div.style.overflow = ""; │ │ │ │ │ + this.setLayerZIndex(layer, this.layers.length); │ │ │ │ │ + │ │ │ │ │ + if (layer.isFixed) { │ │ │ │ │ + this.viewPortDiv.appendChild(layer.div); │ │ │ │ │ + } else { │ │ │ │ │ + this.layerContainerDiv.appendChild(layer.div); │ │ │ │ │ + } │ │ │ │ │ + this.layers.push(layer); │ │ │ │ │ + layer.setMap(this); │ │ │ │ │ + │ │ │ │ │ + if (layer.isBaseLayer || (this.allOverlays && !this.baseLayer)) { │ │ │ │ │ + if (this.baseLayer == null) { │ │ │ │ │ + // set the first baselaye we add as the baselayer │ │ │ │ │ + this.setBaseLayer(layer); │ │ │ │ │ + } else { │ │ │ │ │ + layer.setVisibility(false); │ │ │ │ │ + } │ │ │ │ │ + } else { │ │ │ │ │ + layer.redraw(); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.events.triggerEvent("addlayer", { │ │ │ │ │ + layer: layer │ │ │ │ │ + }); │ │ │ │ │ + layer.events.triggerEvent("added", { │ │ │ │ │ + map: this, │ │ │ │ │ + layer: layer │ │ │ │ │ + }); │ │ │ │ │ + layer.afterAdd(); │ │ │ │ │ + │ │ │ │ │ + return true; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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 │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: addLayers │ │ │ │ │ + * │ │ │ │ │ * 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 │ │ │ │ │ + * layers - {Array()} │ │ │ │ │ */ │ │ │ │ │ - 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 │ │ │ │ │ - }) │ │ │ │ │ - })); │ │ │ │ │ + addLayers: function(layers) { │ │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ │ + this.addLayer(layers[i]); │ │ │ │ │ } │ │ │ │ │ - this.styles[renderIntent].addRules(rules); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.StyleMap" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Icon.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: removeLayer │ │ │ │ │ + * Removes a layer from the map by removing its visual element (the │ │ │ │ │ + * layer.div property), then removing it from the map's internal list │ │ │ │ │ + * of layers, setting the layer's map property to null. │ │ │ │ │ + * │ │ │ │ │ + * a "removelayer" event is triggered. │ │ │ │ │ + * │ │ │ │ │ + * very worthy of mention is that simply removing a layer from a map │ │ │ │ │ + * will not cause the removal of any popups which may have been created │ │ │ │ │ + * by the layer. this is due to the fact that it was decided at some │ │ │ │ │ + * point that popups would not belong to layers. thus there is no way │ │ │ │ │ + * for us to know here to which layer the popup belongs. │ │ │ │ │ + * │ │ │ │ │ + * A simple solution to this is simply to call destroy() on the layer. │ │ │ │ │ + * the default OpenLayers.Layer class's destroy() function │ │ │ │ │ + * automatically takes care to remove itself from whatever map it has │ │ │ │ │ + * been attached to. │ │ │ │ │ + * │ │ │ │ │ + * The correct solution is for the layer itself to register an │ │ │ │ │ + * event-handler on "removelayer" and when it is called, if it │ │ │ │ │ + * recognizes itself as the layer being removed, then it cycles through │ │ │ │ │ + * its own personal list of popups, removing them from the map. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * layer - {} │ │ │ │ │ + * setNewBaseLayer - {Boolean} Default is true │ │ │ │ │ + */ │ │ │ │ │ + removeLayer: function(layer, setNewBaseLayer) { │ │ │ │ │ + if (this.events.triggerEvent("preremovelayer", { │ │ │ │ │ + layer: layer │ │ │ │ │ + }) === false) { │ │ │ │ │ + return; │ │ │ │ │ + } │ │ │ │ │ + if (setNewBaseLayer == null) { │ │ │ │ │ + setNewBaseLayer = 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.isFixed) { │ │ │ │ │ + this.viewPortDiv.removeChild(layer.div); │ │ │ │ │ + } else { │ │ │ │ │ + this.layerContainerDiv.removeChild(layer.div); │ │ │ │ │ + } │ │ │ │ │ + OpenLayers.Util.removeItem(this.layers, layer); │ │ │ │ │ + layer.removeMap(this); │ │ │ │ │ + layer.map = null; │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - */ │ │ │ │ │ + // if we removed the base layer, need to set a new one │ │ │ │ │ + if (this.baseLayer == layer) { │ │ │ │ │ + this.baseLayer = null; │ │ │ │ │ + if (setNewBaseLayer) { │ │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ │ + var iLayer = this.layers[i]; │ │ │ │ │ + if (iLayer.isBaseLayer || this.allOverlays) { │ │ │ │ │ + this.setBaseLayer(iLayer); │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * 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({ │ │ │ │ │ + this.resetLayersZIndex(); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: url │ │ │ │ │ - * {String} image url │ │ │ │ │ - */ │ │ │ │ │ - url: null, │ │ │ │ │ + this.events.triggerEvent("removelayer", { │ │ │ │ │ + layer: layer │ │ │ │ │ + }); │ │ │ │ │ + layer.events.triggerEvent("removed", { │ │ │ │ │ + map: this, │ │ │ │ │ + layer: layer │ │ │ │ │ + }); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: size │ │ │ │ │ - * {|Object} An OpenLayers.Size or │ │ │ │ │ - * an object with a 'w' and 'h' properties. │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: getNumLayers │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Int} The number of layers attached to the map. │ │ │ │ │ */ │ │ │ │ │ - size: null, │ │ │ │ │ + getNumLayers: function() { │ │ │ │ │ + return this.layers.length; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * APIMethod: getLayerIndex │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * layer - {} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Integer} The current (zero-based) index of the given layer in the map's │ │ │ │ │ + * layer stack. Returns -1 if the layer isn't on the map. │ │ │ │ │ */ │ │ │ │ │ - offset: null, │ │ │ │ │ + getLayerIndex: function(layer) { │ │ │ │ │ + return OpenLayers.Util.indexOf(this.layers, layer); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: calculateOffset │ │ │ │ │ - * {Function} Function to calculate the offset (based on the size) │ │ │ │ │ + * APIMethod: setLayerIndex │ │ │ │ │ + * Move the given layer to the specified (zero-based) index in the layer │ │ │ │ │ + * list, changing its z-index in the map display. Use │ │ │ │ │ + * map.getLayerIndex() to find out the current index of a layer. Note │ │ │ │ │ + * that this cannot (or at least should not) be effectively used to │ │ │ │ │ + * raise base layers above overlays. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * layer - {} │ │ │ │ │ + * idx - {int} │ │ │ │ │ */ │ │ │ │ │ - calculateOffset: null, │ │ │ │ │ + setLayerIndex: function(layer, idx) { │ │ │ │ │ + var base = this.getLayerIndex(layer); │ │ │ │ │ + if (idx < 0) { │ │ │ │ │ + idx = 0; │ │ │ │ │ + } else if (idx > this.layers.length) { │ │ │ │ │ + idx = this.layers.length; │ │ │ │ │ + } │ │ │ │ │ + if (base != idx) { │ │ │ │ │ + this.layers.splice(base, 1); │ │ │ │ │ + this.layers.splice(idx, 0, layer); │ │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ │ + this.setLayerZIndex(this.layers[i], i); │ │ │ │ │ + } │ │ │ │ │ + this.events.triggerEvent("changelayer", { │ │ │ │ │ + layer: layer, │ │ │ │ │ + property: "order" │ │ │ │ │ + }); │ │ │ │ │ + if (this.allOverlays) { │ │ │ │ │ + if (idx === 0) { │ │ │ │ │ + this.setBaseLayer(layer); │ │ │ │ │ + } else if (this.baseLayer !== this.layers[0]) { │ │ │ │ │ + this.setBaseLayer(this.layers[0]); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: imageDiv │ │ │ │ │ - * {DOMElement} │ │ │ │ │ + * APIMethod: raiseLayer │ │ │ │ │ + * Change the index of the given layer by delta. If delta is positive, │ │ │ │ │ + * the layer is moved up the map's layer stack; if delta is negative, │ │ │ │ │ + * the layer is moved down. Again, note that this cannot (or at least │ │ │ │ │ + * should not) be effectively used to raise base layers above overlays. │ │ │ │ │ + * │ │ │ │ │ + * Paremeters: │ │ │ │ │ + * layer - {} │ │ │ │ │ + * delta - {int} │ │ │ │ │ */ │ │ │ │ │ - imageDiv: null, │ │ │ │ │ + raiseLayer: function(layer, delta) { │ │ │ │ │ + var idx = this.getLayerIndex(layer) + delta; │ │ │ │ │ + this.setLayerIndex(layer, idx); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: px │ │ │ │ │ - * {|Object} An OpenLayers.Pixel or an object │ │ │ │ │ - * with a 'x' and 'y' properties. │ │ │ │ │ + * APIMethod: setBaseLayer │ │ │ │ │ + * Allows user to specify one of the currently-loaded layers as the Map's │ │ │ │ │ + * new base layer. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * newBaseLayer - {} │ │ │ │ │ */ │ │ │ │ │ - px: null, │ │ │ │ │ + setBaseLayer: function(newBaseLayer) { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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; │ │ │ │ │ + if (newBaseLayer != this.baseLayer) { │ │ │ │ │ │ │ │ │ │ - var id = OpenLayers.Util.createUniqueID("OL_Icon_"); │ │ │ │ │ - this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id); │ │ │ │ │ - }, │ │ │ │ │ + // ensure newBaseLayer is already loaded │ │ │ │ │ + if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: destroy │ │ │ │ │ - * Nullify references and remove event listeners to prevent circular │ │ │ │ │ - * references and memory leaks │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - // erase any drawn elements │ │ │ │ │ - this.erase(); │ │ │ │ │ + // preserve center and scale when changing base layers │ │ │ │ │ + var center = this.getCachedCenter(); │ │ │ │ │ + var newResolution = OpenLayers.Util.getResolutionFromScale( │ │ │ │ │ + this.getScale(), newBaseLayer.units │ │ │ │ │ + ); │ │ │ │ │ │ │ │ │ │ - OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild); │ │ │ │ │ - this.imageDiv.innerHTML = ""; │ │ │ │ │ - this.imageDiv = null; │ │ │ │ │ + // make the old base layer invisible │ │ │ │ │ + if (this.baseLayer != null && !this.allOverlays) { │ │ │ │ │ + this.baseLayer.setVisibility(false); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // set new baselayer │ │ │ │ │ + this.baseLayer = newBaseLayer; │ │ │ │ │ + │ │ │ │ │ + if (!this.allOverlays || this.baseLayer.visibility) { │ │ │ │ │ + this.baseLayer.setVisibility(true); │ │ │ │ │ + // Layer may previously have been visible but not in range. │ │ │ │ │ + // In this case we need to redraw it to make it visible. │ │ │ │ │ + if (this.baseLayer.inRange === false) { │ │ │ │ │ + this.baseLayer.redraw(); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // recenter the map │ │ │ │ │ + if (center != null) { │ │ │ │ │ + // new zoom level derived from old scale │ │ │ │ │ + var newZoom = this.getZoomForResolution( │ │ │ │ │ + newResolution || this.resolution, true │ │ │ │ │ + ); │ │ │ │ │ + // zoom and force zoom change │ │ │ │ │ + this.setCenter(center, newZoom, false, true); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.events.triggerEvent("changebaselayer", { │ │ │ │ │ + layer: this.baseLayer │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: clone │ │ │ │ │ + │ │ │ │ │ + /********************************************************/ │ │ │ │ │ + /* */ │ │ │ │ │ + /* Control Functions */ │ │ │ │ │ + /* */ │ │ │ │ │ + /* The following functions deal with adding and */ │ │ │ │ │ + /* removing Controls to and from the Map */ │ │ │ │ │ + /* */ │ │ │ │ │ + /********************************************************/ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: addControl │ │ │ │ │ + * Add the passed over control to the map. Optionally │ │ │ │ │ + * position the control at the given pixel. │ │ │ │ │ * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} A fresh copy of the icon. │ │ │ │ │ + * Parameters: │ │ │ │ │ + * control - {} │ │ │ │ │ + * px - {} │ │ │ │ │ */ │ │ │ │ │ - clone: function() { │ │ │ │ │ - return new OpenLayers.Icon(this.url, │ │ │ │ │ - this.size, │ │ │ │ │ - this.offset, │ │ │ │ │ - this.calculateOffset); │ │ │ │ │ + addControl: function(control, px) { │ │ │ │ │ + this.controls.push(control); │ │ │ │ │ + this.addControlToMap(control, px); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: setSize │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: addControls │ │ │ │ │ + * Add all of the passed over controls to the map. │ │ │ │ │ + * You can pass over an optional second array │ │ │ │ │ + * with pixel-objects to position the controls. │ │ │ │ │ + * The indices of the two arrays should match and │ │ │ │ │ + * you can add null as pixel for those controls │ │ │ │ │ + * you want to be autopositioned. │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * size - {|Object} An OpenLayers.Size or │ │ │ │ │ - * an object with a 'w' and 'h' properties. │ │ │ │ │ + * controls - {Array()} │ │ │ │ │ + * pixels - {Array()} │ │ │ │ │ */ │ │ │ │ │ - setSize: function(size) { │ │ │ │ │ - if (size != null) { │ │ │ │ │ - this.size = size; │ │ │ │ │ + addControls: function(controls, pixels) { │ │ │ │ │ + var pxs = (arguments.length === 1) ? [] : pixels; │ │ │ │ │ + for (var i = 0, len = controls.length; i < len; i++) { │ │ │ │ │ + var ctrl = controls[i]; │ │ │ │ │ + var px = (pxs[i]) ? pxs[i] : null; │ │ │ │ │ + this.addControl(ctrl, px); │ │ │ │ │ } │ │ │ │ │ - this.draw(); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: setUrl │ │ │ │ │ + * Method: addControlToMap │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * url - {String} │ │ │ │ │ + * │ │ │ │ │ + * control - {} │ │ │ │ │ + * px - {} │ │ │ │ │ */ │ │ │ │ │ - setUrl: function(url) { │ │ │ │ │ - if (url != null) { │ │ │ │ │ - this.url = url; │ │ │ │ │ + addControlToMap: function(control, px) { │ │ │ │ │ + // If a control doesn't have a div at this point, it belongs in the │ │ │ │ │ + // viewport. │ │ │ │ │ + control.outsideViewport = (control.div != null); │ │ │ │ │ + │ │ │ │ │ + // If the map has a displayProjection, and the control doesn't, set │ │ │ │ │ + // the display projection. │ │ │ │ │ + if (this.displayProjection && !control.displayProjection) { │ │ │ │ │ + control.displayProjection = this.displayProjection; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + control.setMap(this); │ │ │ │ │ + var div = control.draw(px); │ │ │ │ │ + if (div) { │ │ │ │ │ + if (!control.outsideViewport) { │ │ │ │ │ + div.style.zIndex = this.Z_INDEX_BASE['Control'] + │ │ │ │ │ + this.controls.length; │ │ │ │ │ + this.viewPortDiv.appendChild(div); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + if (control.autoActivate) { │ │ │ │ │ + control.activate(); │ │ │ │ │ } │ │ │ │ │ - this.draw(); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: draw │ │ │ │ │ - * Move the div to the given pixel. │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: getControl │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * px - {|Object} An OpenLayers.Pixel or an │ │ │ │ │ - * object with a 'x' and 'y' properties. │ │ │ │ │ + * id - {String} ID of the control to return. │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {DOMElement} A new DOM Image of this icon set at the location passed-in │ │ │ │ │ + * {} The control from the map's list of controls │ │ │ │ │ + * which has a matching 'id'. If none found, │ │ │ │ │ + * returns null. │ │ │ │ │ */ │ │ │ │ │ - draw: function(px) { │ │ │ │ │ - OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, │ │ │ │ │ - null, │ │ │ │ │ - null, │ │ │ │ │ - this.size, │ │ │ │ │ - this.url, │ │ │ │ │ - "absolute"); │ │ │ │ │ - this.moveTo(px); │ │ │ │ │ - return this.imageDiv; │ │ │ │ │ + getControl: function(id) { │ │ │ │ │ + var returnControl = null; │ │ │ │ │ + for (var i = 0, len = this.controls.length; i < len; i++) { │ │ │ │ │ + var control = this.controls[i]; │ │ │ │ │ + if (control.id == id) { │ │ │ │ │ + returnControl = control; │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return returnControl; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: erase │ │ │ │ │ - * Erase the underlying image element. │ │ │ │ │ + * APIMethod: removeControl │ │ │ │ │ + * Remove a control from the map. Removes the control both from the map │ │ │ │ │ + * object's internal array of controls, as well as from the map's │ │ │ │ │ + * viewPort (assuming the control was not added outsideViewport) │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * control - {} The control to remove. │ │ │ │ │ */ │ │ │ │ │ - erase: function() { │ │ │ │ │ - if (this.imageDiv != null && this.imageDiv.parentNode != null) { │ │ │ │ │ - OpenLayers.Element.remove(this.imageDiv); │ │ │ │ │ + removeControl: function(control) { │ │ │ │ │ + //make sure control is non-null and actually part of our map │ │ │ │ │ + if ((control) && (control == this.getControl(control.id))) { │ │ │ │ │ + if (control.div && (control.div.parentNode == this.viewPortDiv)) { │ │ │ │ │ + this.viewPortDiv.removeChild(control.div); │ │ │ │ │ + } │ │ │ │ │ + OpenLayers.Util.removeItem(this.controls, control); │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ + /********************************************************/ │ │ │ │ │ + /* */ │ │ │ │ │ + /* Popup Functions */ │ │ │ │ │ + /* */ │ │ │ │ │ + /* The following functions deal with adding and */ │ │ │ │ │ + /* removing Popups to and from the Map */ │ │ │ │ │ + /* */ │ │ │ │ │ + /********************************************************/ │ │ │ │ │ + │ │ │ │ │ /** │ │ │ │ │ - * Method: setOpacity │ │ │ │ │ - * Change the icon's opacity │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: addPopup │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * opacity - {float} │ │ │ │ │ + * popup - {} │ │ │ │ │ + * exclusive - {Boolean} If true, closes all other popups first │ │ │ │ │ */ │ │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ │ - OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, │ │ │ │ │ - null, null, null, null, opacity); │ │ │ │ │ - │ │ │ │ │ - }, │ │ │ │ │ + addPopup: function(popup, exclusive) { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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 (exclusive) { │ │ │ │ │ + //remove all other popups from screen │ │ │ │ │ + for (var i = this.popups.length - 1; i >= 0; --i) { │ │ │ │ │ + this.removePopup(this.popups[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 │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ + popup.map = this; │ │ │ │ │ + this.popups.push(popup); │ │ │ │ │ + var popupDiv = popup.draw(); │ │ │ │ │ + if (popupDiv) { │ │ │ │ │ + popupDiv.style.zIndex = this.Z_INDEX_BASE['Popup'] + │ │ │ │ │ + this.popups.length; │ │ │ │ │ + this.layerContainerDiv.appendChild(popupDiv); │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: display │ │ │ │ │ - * Hide or show the icon │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: removePopup │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * display - {Boolean} │ │ │ │ │ + * popup - {} │ │ │ │ │ */ │ │ │ │ │ - display: function(display) { │ │ │ │ │ - this.imageDiv.style.display = (display) ? "" : "none"; │ │ │ │ │ + removePopup: function(popup) { │ │ │ │ │ + OpenLayers.Util.removeItem(this.popups, popup); │ │ │ │ │ + if (popup.div) { │ │ │ │ │ + try { │ │ │ │ │ + this.layerContainerDiv.removeChild(popup.div); │ │ │ │ │ + } catch (e) {} // Popups sometimes apparently get disconnected │ │ │ │ │ + // from the layerContainerDiv, and cause complaints. │ │ │ │ │ + } │ │ │ │ │ + popup.map = null; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ + /********************************************************/ │ │ │ │ │ + /* */ │ │ │ │ │ + /* Container Div Functions */ │ │ │ │ │ + /* */ │ │ │ │ │ + /* The following functions deal with the access to */ │ │ │ │ │ + /* and maintenance of the size of the container div */ │ │ │ │ │ + /* */ │ │ │ │ │ + /********************************************************/ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: isDrawn │ │ │ │ │ + * APIMethod: getSize │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Boolean} Whether or not the icon is drawn. │ │ │ │ │ + * {} An object that represents the │ │ │ │ │ + * size, in pixels, of the div into which OpenLayers │ │ │ │ │ + * has been loaded. │ │ │ │ │ + * Note - A clone() of this locally cached variable is │ │ │ │ │ + * returned, so as not to allow users to modify it. │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ + getSize: function() { │ │ │ │ │ + var size = null; │ │ │ │ │ + if (this.size != null) { │ │ │ │ │ + size = this.size.clone(); │ │ │ │ │ + } │ │ │ │ │ + return size; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - 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 │ │ │ │ │ - * 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. │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: updateSize │ │ │ │ │ + * This function should be called by any external code which dynamically │ │ │ │ │ + * changes the size of the map div (because mozilla wont let us catch │ │ │ │ │ + * the "onresize" for an element) │ │ │ │ │ */ │ │ │ │ │ - icon: null, │ │ │ │ │ + updateSize: function() { │ │ │ │ │ + // the div might have moved on the page, also │ │ │ │ │ + var newSize = this.getCurrentSize(); │ │ │ │ │ + if (newSize && !isNaN(newSize.h) && !isNaN(newSize.w)) { │ │ │ │ │ + this.events.clearMouseCache(); │ │ │ │ │ + var oldSize = this.getSize(); │ │ │ │ │ + if (oldSize == null) { │ │ │ │ │ + this.size = oldSize = newSize; │ │ │ │ │ + } │ │ │ │ │ + if (!newSize.equals(oldSize)) { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: lonlat │ │ │ │ │ - * {} location of object │ │ │ │ │ - */ │ │ │ │ │ - lonlat: null, │ │ │ │ │ + // store the new size │ │ │ │ │ + this.size = newSize; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: events │ │ │ │ │ - * {} the event handler. │ │ │ │ │ - */ │ │ │ │ │ - events: null, │ │ │ │ │ + //notify layers of mapresize │ │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ │ + this.layers[i].onMapResize(); │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: map │ │ │ │ │ - * {} the map this marker is attached to │ │ │ │ │ - */ │ │ │ │ │ - map: null, │ │ │ │ │ + var center = this.getCachedCenter(); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Marker │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * lonlat - {} the position of this marker │ │ │ │ │ - * icon - {} the icon for this marker │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(lonlat, icon) { │ │ │ │ │ - this.lonlat = lonlat; │ │ │ │ │ + if (this.baseLayer != null && center != null) { │ │ │ │ │ + var zoom = this.getZoom(); │ │ │ │ │ + this.zoom = null; │ │ │ │ │ + this.setCenter(center, zoom); │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - 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.events.triggerEvent("updatesize"); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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.) │ │ │ │ │ + * Method: getCurrentSize │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} A new object with the dimensions │ │ │ │ │ + * of the map div │ │ │ │ │ */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - // erase any drawn features │ │ │ │ │ - this.erase(); │ │ │ │ │ - │ │ │ │ │ - this.map = null; │ │ │ │ │ + getCurrentSize: function() { │ │ │ │ │ │ │ │ │ │ - this.events.destroy(); │ │ │ │ │ - this.events = null; │ │ │ │ │ + var size = new OpenLayers.Size(this.div.clientWidth, │ │ │ │ │ + this.div.clientHeight); │ │ │ │ │ │ │ │ │ │ - if (this.icon != null) { │ │ │ │ │ - this.icon.destroy(); │ │ │ │ │ - this.icon = null; │ │ │ │ │ + if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) { │ │ │ │ │ + size.w = this.div.offsetWidth; │ │ │ │ │ + size.h = this.div.offsetHeight; │ │ │ │ │ + } │ │ │ │ │ + if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) { │ │ │ │ │ + size.w = parseInt(this.div.style.width); │ │ │ │ │ + size.h = parseInt(this.div.style.height); │ │ │ │ │ } │ │ │ │ │ + return size; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: draw │ │ │ │ │ - * Calls draw on the icon, and returns that output. │ │ │ │ │ + * Method: calculateBounds │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * px - {} │ │ │ │ │ + * center - {} Default is this.getCenter() │ │ │ │ │ + * resolution - {float} Default is this.getResolution() │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {DOMElement} A new DOM Image with this marker's icon set at the │ │ │ │ │ - * location passed-in │ │ │ │ │ + * {} A bounds based on resolution, center, and │ │ │ │ │ + * current mapsize. │ │ │ │ │ */ │ │ │ │ │ - draw: function(px) { │ │ │ │ │ - return this.icon.draw(px); │ │ │ │ │ - }, │ │ │ │ │ + calculateBounds: function(center, resolution) { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: erase │ │ │ │ │ - * Erases any drawn elements for this marker. │ │ │ │ │ - */ │ │ │ │ │ - erase: function() { │ │ │ │ │ - if (this.icon != null) { │ │ │ │ │ - this.icon.erase(); │ │ │ │ │ + var extent = null; │ │ │ │ │ + │ │ │ │ │ + if (center == null) { │ │ │ │ │ + center = this.getCachedCenter(); │ │ │ │ │ + } │ │ │ │ │ + if (resolution == null) { │ │ │ │ │ + resolution = this.getResolution(); │ │ │ │ │ } │ │ │ │ │ - }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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); │ │ │ │ │ + if ((center != null) && (resolution != null)) { │ │ │ │ │ + var halfWDeg = (this.size.w * resolution) / 2; │ │ │ │ │ + var halfHDeg = (this.size.h * resolution) / 2; │ │ │ │ │ + │ │ │ │ │ + extent = new OpenLayers.Bounds(center.lon - halfWDeg, │ │ │ │ │ + center.lat - halfHDeg, │ │ │ │ │ + center.lon + halfWDeg, │ │ │ │ │ + center.lat + halfHDeg); │ │ │ │ │ } │ │ │ │ │ - this.lonlat = this.map.getLonLatFromLayerPx(px); │ │ │ │ │ + │ │ │ │ │ + return extent; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ + /********************************************************/ │ │ │ │ │ + /* */ │ │ │ │ │ + /* Zoom, Center, Pan Functions */ │ │ │ │ │ + /* */ │ │ │ │ │ + /* The following functions handle the validation, */ │ │ │ │ │ + /* getting and setting of the Zoom Level and Center */ │ │ │ │ │ + /* as well as the panning of the Map */ │ │ │ │ │ + /* */ │ │ │ │ │ + /********************************************************/ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: isDrawn │ │ │ │ │ + * APIMethod: getCenter │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Boolean} Whether or not the marker is drawn. │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - isDrawn: function() { │ │ │ │ │ - var isDrawn = (this.icon && this.icon.isDrawn()); │ │ │ │ │ - return isDrawn; │ │ │ │ │ + getCenter: function() { │ │ │ │ │ + var center = null; │ │ │ │ │ + var cachedCenter = this.getCachedCenter(); │ │ │ │ │ + if (cachedCenter) { │ │ │ │ │ + center = cachedCenter.clone(); │ │ │ │ │ + } │ │ │ │ │ + return center; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: onScreen │ │ │ │ │ + * Method: getCachedCenter │ │ │ │ │ * │ │ │ │ │ * 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); │ │ │ │ │ + getCachedCenter: function() { │ │ │ │ │ + if (!this.center && this.size) { │ │ │ │ │ + this.center = this.getLonLatFromViewPortPx({ │ │ │ │ │ + x: this.size.w / 2, │ │ │ │ │ + y: this.size.h / 2 │ │ │ │ │ + }); │ │ │ │ │ } │ │ │ │ │ - return onScreen; │ │ │ │ │ + return this.center; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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/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/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 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 │ │ │ │ │ - * {} An events object that handles all │ │ │ │ │ - * events on the {} object. │ │ │ │ │ - * │ │ │ │ │ - * All event listeners will receive an event object with three properties: │ │ │ │ │ - * request - {} 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 , , , , , or . │ │ │ │ │ - * 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 │ │ │ │ │ - * . │ │ │ │ │ - * 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 │ │ │ │ │ - * 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 . │ │ │ │ │ - * 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 and requests. │ │ │ │ │ - * Make sure to provide the appropriate "Content-Type" header for your │ │ │ │ │ - * data. For and 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 method, with the method property set │ │ │ │ │ - * to GET. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * config - {Object} Object with properties for configuring the request. │ │ │ │ │ - * See the 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 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 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 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 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 method, with the method property set │ │ │ │ │ - * to DELETE. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * config - {Object} Object with properties for configuring the request. │ │ │ │ │ - * See the 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 method, with the method property set │ │ │ │ │ - * to HEAD. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * config - {Object} Object with properties for configuring the request. │ │ │ │ │ - * See the 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 method, with the method property set │ │ │ │ │ - * to OPTIONS. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * config - {Object} Object with properties for configuring the request. │ │ │ │ │ - * See the 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/Format.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Format │ │ │ │ │ - * Base class for format reading/writing a variety of formats. Subclasses │ │ │ │ │ - * of OpenLayers.Format are expected to have read and write methods. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Format = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: options │ │ │ │ │ - * {Object} A reference to options passed to the constructor. │ │ │ │ │ - */ │ │ │ │ │ - options: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: externalProjection │ │ │ │ │ - * {} When passed a externalProjection and │ │ │ │ │ - * internalProjection, the format will reproject the geometries it │ │ │ │ │ - * reads or writes. The externalProjection is the projection used by │ │ │ │ │ - * the content which is passed into read or which comes out of write. │ │ │ │ │ - * In order to reproject, a projection transformation function for the │ │ │ │ │ - * specified projections must be available. This support may be │ │ │ │ │ - * provided via proj4js or via a custom transformation function. See │ │ │ │ │ - * {} for more information on │ │ │ │ │ - * custom transformations. │ │ │ │ │ - */ │ │ │ │ │ - externalProjection: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: internalProjection │ │ │ │ │ - * {} When passed a externalProjection and │ │ │ │ │ - * internalProjection, the format will reproject the geometries it │ │ │ │ │ - * reads or writes. The internalProjection is the projection used by │ │ │ │ │ - * the geometries which are returned by read or which are passed into │ │ │ │ │ - * write. In order to reproject, a projection transformation function │ │ │ │ │ - * for the specified projections must be available. This support may be │ │ │ │ │ - * provided via proj4js or via a custom transformation function. See │ │ │ │ │ - * {} for more information on │ │ │ │ │ - * custom transformations. │ │ │ │ │ - */ │ │ │ │ │ - internalProjection: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: data │ │ │ │ │ - * {Object} When is true, this is the parsed string sent to │ │ │ │ │ - * . │ │ │ │ │ - */ │ │ │ │ │ - data: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: keepData │ │ │ │ │ - * {Object} Maintain a reference () to the most recently read data. │ │ │ │ │ - * Default is false. │ │ │ │ │ - */ │ │ │ │ │ - keepData: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Format │ │ │ │ │ - * Instances of this class are not useful. See one of the subclasses. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} An optional object with properties to set on the │ │ │ │ │ - * format │ │ │ │ │ - * │ │ │ │ │ - * Valid options: │ │ │ │ │ - * keepData - {Boolean} If true, upon , the data property will be │ │ │ │ │ - * set to the parsed object (e.g. the json or xml object). │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * An instance of OpenLayers.Format │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(options) { │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ - this.options = options; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ - * Clean up. │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() {}, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: read │ │ │ │ │ - * Read data from a string, and return an object whose type depends on the │ │ │ │ │ - * subclass. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * data - {string} Data to read/parse. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * Depends on the subclass │ │ │ │ │ - */ │ │ │ │ │ - read: function(data) { │ │ │ │ │ - throw new Error('Read not implemented.'); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: write │ │ │ │ │ - * Accept an object, and return a string. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * object - {Object} Object to be serialized │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} A string representation of the object. │ │ │ │ │ - */ │ │ │ │ │ - write: function(object) { │ │ │ │ │ - throw new Error('Write not implemented.'); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Util/vendorPrefix.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/SingleFile.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -OpenLayers.Util = OpenLayers.Util || {}; │ │ │ │ │ -/** │ │ │ │ │ - * Namespace: OpenLayers.Util.vendorPrefix │ │ │ │ │ - * A collection of utility functions to detect vendor prefixed features │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Util.vendorPrefix = (function() { │ │ │ │ │ - "use strict"; │ │ │ │ │ - │ │ │ │ │ - var VENDOR_PREFIXES = ["", "O", "ms", "Moz", "Webkit"], │ │ │ │ │ - divStyle = document.createElement("div").style, │ │ │ │ │ - cssCache = {}, │ │ │ │ │ - jsCache = {}; │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Function: domToCss │ │ │ │ │ - * Converts a upper camel case DOM style property name to a CSS property │ │ │ │ │ - * i.e. transformOrigin -> transform-origin │ │ │ │ │ - * or WebkitTransformOrigin -> -webkit-transform-origin │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * prefixedDom - {String} The property to convert │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} The CSS property │ │ │ │ │ - */ │ │ │ │ │ - function domToCss(prefixedDom) { │ │ │ │ │ - if (!prefixedDom) { │ │ │ │ │ - return null; │ │ │ │ │ - } │ │ │ │ │ - return prefixedDom. │ │ │ │ │ - replace(/([A-Z])/g, function(c) { │ │ │ │ │ - return "-" + c.toLowerCase(); │ │ │ │ │ - }). │ │ │ │ │ - replace(/^ms-/, "-ms-"); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: css │ │ │ │ │ - * Detect which property is used for a CSS property │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * property - {String} The standard (unprefixed) CSS property name │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} The standard CSS property, prefixed property or null if not │ │ │ │ │ - * supported │ │ │ │ │ - */ │ │ │ │ │ - function css(property) { │ │ │ │ │ - if (cssCache[property] === undefined) { │ │ │ │ │ - var domProperty = property. │ │ │ │ │ - replace(/(-[\s\S])/g, function(c) { │ │ │ │ │ - return c.charAt(1).toUpperCase(); │ │ │ │ │ - }); │ │ │ │ │ - var prefixedDom = style(domProperty); │ │ │ │ │ - cssCache[property] = domToCss(prefixedDom); │ │ │ │ │ - } │ │ │ │ │ - return cssCache[property]; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: js │ │ │ │ │ - * Detect which property is used for a JS property/method │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * obj - {Object} The object to test on │ │ │ │ │ - * property - {String} The standard (unprefixed) JS property name │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} The standard JS property, prefixed property or null if not │ │ │ │ │ - * supported │ │ │ │ │ - */ │ │ │ │ │ - function js(obj, property) { │ │ │ │ │ - if (jsCache[property] === undefined) { │ │ │ │ │ - var tmpProp, │ │ │ │ │ - i = 0, │ │ │ │ │ - l = VENDOR_PREFIXES.length, │ │ │ │ │ - prefix, │ │ │ │ │ - isStyleObj = (typeof obj.cssText !== "undefined"); │ │ │ │ │ - │ │ │ │ │ - jsCache[property] = null; │ │ │ │ │ - for (; i < l; i++) { │ │ │ │ │ - prefix = VENDOR_PREFIXES[i]; │ │ │ │ │ - if (prefix) { │ │ │ │ │ - if (!isStyleObj) { │ │ │ │ │ - // js prefix should be lower-case, while style │ │ │ │ │ - // properties have upper case on first character │ │ │ │ │ - prefix = prefix.toLowerCase(); │ │ │ │ │ - } │ │ │ │ │ - tmpProp = prefix + property.charAt(0).toUpperCase() + property.slice(1); │ │ │ │ │ - } else { │ │ │ │ │ - tmpProp = property; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (obj[tmpProp] !== undefined) { │ │ │ │ │ - jsCache[property] = tmpProp; │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - return jsCache[property]; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: style │ │ │ │ │ - * Detect which property is used for a DOM style property │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * property - {String} The standard (unprefixed) style property name │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} The standard style property, prefixed property or null if not │ │ │ │ │ - * supported │ │ │ │ │ - */ │ │ │ │ │ - function style(property) { │ │ │ │ │ - return js(divStyle, property); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - return { │ │ │ │ │ - css: css, │ │ │ │ │ - js: js, │ │ │ │ │ - style: style, │ │ │ │ │ - │ │ │ │ │ - // used for testing │ │ │ │ │ - cssCache: cssCache, │ │ │ │ │ - jsCache: jsCache │ │ │ │ │ - }; │ │ │ │ │ -}()); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Animation.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/SingleFile.js │ │ │ │ │ - * @requires OpenLayers/Util/vendorPrefix.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Namespace: OpenLayers.Animation │ │ │ │ │ - * A collection of utility functions for executing methods that repaint a │ │ │ │ │ - * portion of the browser window. These methods take advantage of the │ │ │ │ │ - * browser's scheduled repaints where requestAnimationFrame is available. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Animation = (function(window) { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: isNative │ │ │ │ │ - * {Boolean} true if a native requestAnimationFrame function is available │ │ │ │ │ - */ │ │ │ │ │ - var requestAnimationFrame = OpenLayers.Util.vendorPrefix.js(window, "requestAnimationFrame"); │ │ │ │ │ - var isNative = !!(requestAnimationFrame); │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Function: requestFrame │ │ │ │ │ - * Schedule a function to be called at the next available animation frame. │ │ │ │ │ - * Uses the native method where available. Where requestAnimationFrame is │ │ │ │ │ - * not available, setTimeout will be called with a 16ms delay. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * callback - {Function} The function to be called at the next animation frame. │ │ │ │ │ - * element - {DOMElement} Optional element that visually bounds the animation. │ │ │ │ │ - */ │ │ │ │ │ - var requestFrame = (function() { │ │ │ │ │ - var request = window[requestAnimationFrame] || │ │ │ │ │ - function(callback, element) { │ │ │ │ │ - window.setTimeout(callback, 16); │ │ │ │ │ - }; │ │ │ │ │ - // bind to window to avoid illegal invocation of native function │ │ │ │ │ - return function(callback, element) { │ │ │ │ │ - request.apply(window, [callback, element]); │ │ │ │ │ - }; │ │ │ │ │ - })(); │ │ │ │ │ - │ │ │ │ │ - // private variables for animation loops │ │ │ │ │ - var counter = 0; │ │ │ │ │ - var loops = {}; │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Function: start │ │ │ │ │ - * Executes a method with 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/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 │ │ │ │ │ - * {} 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 │ │ │ │ │ - * {} 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. │ │ │ │ │ - */ │ │ │ │ │ - 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/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. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Namespace: OpenLayers.Projection │ │ │ │ │ - * Methods for coordinate transforms between coordinate systems. By default, │ │ │ │ │ - * OpenLayers ships with the ability to transform coordinates between │ │ │ │ │ - * geographic (EPSG:4326) and web or spherical mercator (EPSG:900913 et al.) │ │ │ │ │ - * coordinate reference systems. See the method for details │ │ │ │ │ - * on usage. │ │ │ │ │ - * │ │ │ │ │ - * Additional transforms may be added by using the │ │ │ │ │ - * library. If the proj4js library is included, the method │ │ │ │ │ - * will work between any two coordinate reference systems with proj4js │ │ │ │ │ - * definitions. │ │ │ │ │ - * │ │ │ │ │ - * If the proj4js library is not included, or if you wish to allow transforms │ │ │ │ │ - * between arbitrary coordinate reference systems, use the │ │ │ │ │ - * method to register a custom transform method. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Projection = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: proj │ │ │ │ │ - * {Object} Proj4js.Proj instance. │ │ │ │ │ - */ │ │ │ │ │ - proj: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: projCode │ │ │ │ │ - * {String} │ │ │ │ │ - */ │ │ │ │ │ - projCode: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: titleRegEx │ │ │ │ │ - * {RegExp} regular expression to strip the title from a proj4js definition │ │ │ │ │ - */ │ │ │ │ │ - titleRegEx: /\+title=[^\+]*/, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Projection │ │ │ │ │ - * This class offers several methods for interacting with a wrapped │ │ │ │ │ - * pro4js projection object. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * projCode - {String} A string identifying the Well Known Identifier for │ │ │ │ │ - * the projection. │ │ │ │ │ - * options - {Object} An optional object to set additional properties │ │ │ │ │ - * on the projection. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} A projection object. │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(projCode, options) { │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ - this.projCode = projCode; │ │ │ │ │ - if (typeof Proj4js == "object") { │ │ │ │ │ - this.proj = new Proj4js.Proj(projCode); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getCode │ │ │ │ │ - * Get the string SRS code. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} The SRS code. │ │ │ │ │ - */ │ │ │ │ │ - getCode: function() { │ │ │ │ │ - return this.proj ? this.proj.srsCode : this.projCode; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getUnits │ │ │ │ │ - * Get the units string for the projection -- returns null if │ │ │ │ │ - * proj4js is not available. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} The units abbreviation. │ │ │ │ │ - */ │ │ │ │ │ - getUnits: function() { │ │ │ │ │ - return this.proj ? this.proj.units : null; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: toString │ │ │ │ │ - * Convert projection to string (getCode wrapper). │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} The projection code. │ │ │ │ │ - */ │ │ │ │ │ - toString: function() { │ │ │ │ │ - return this.getCode(); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: equals │ │ │ │ │ - * Test equality of two projection instances. Determines equality based │ │ │ │ │ - * soley on the projection code. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The two projections are equivalent. │ │ │ │ │ - */ │ │ │ │ │ - equals: function(projection) { │ │ │ │ │ - var p = projection, │ │ │ │ │ - equals = false; │ │ │ │ │ - if (p) { │ │ │ │ │ - if (!(p instanceof OpenLayers.Projection)) { │ │ │ │ │ - p = new OpenLayers.Projection(p); │ │ │ │ │ - } │ │ │ │ │ - if ((typeof Proj4js == "object") && this.proj.defData && p.proj.defData) { │ │ │ │ │ - equals = this.proj.defData.replace(this.titleRegEx, "") == │ │ │ │ │ - p.proj.defData.replace(this.titleRegEx, ""); │ │ │ │ │ - } else if (p.getCode) { │ │ │ │ │ - var source = this.getCode(), │ │ │ │ │ - target = p.getCode(); │ │ │ │ │ - equals = source == target || │ │ │ │ │ - !!OpenLayers.Projection.transforms[source] && │ │ │ │ │ - OpenLayers.Projection.transforms[source][target] === │ │ │ │ │ - OpenLayers.Projection.nullTransform; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - return equals; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /* Method: destroy │ │ │ │ │ - * Destroy projection object. │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - delete this.proj; │ │ │ │ │ - delete this.projCode; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Projection" │ │ │ │ │ -}); │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Property: transforms │ │ │ │ │ - * {Object} Transforms is an object, with from properties, each of which may │ │ │ │ │ - * have a to property. This allows you to define projections without │ │ │ │ │ - * requiring support for proj4js to be included. │ │ │ │ │ - * │ │ │ │ │ - * This object has keys which correspond to a 'source' projection object. The │ │ │ │ │ - * keys should be strings, corresponding to the projection.getCode() value. │ │ │ │ │ - * Each source projection object should have a set of destination projection │ │ │ │ │ - * keys included in the object. │ │ │ │ │ - * │ │ │ │ │ - * Each value in the destination object should be a transformation function, │ │ │ │ │ - * where the function is expected to be passed an object with a .x and a .y │ │ │ │ │ - * property. The function should return the object, with the .x and .y │ │ │ │ │ - * transformed according to the transformation function. │ │ │ │ │ - * │ │ │ │ │ - * Note - Properties on this object should not be set directly. To add a │ │ │ │ │ - * transform method to this object, use the method. For an │ │ │ │ │ - * example of usage, see the OpenLayers.Layer.SphericalMercator file. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Projection.transforms = {}; │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * APIProperty: defaults │ │ │ │ │ - * {Object} Defaults for the SRS codes known to OpenLayers (currently │ │ │ │ │ - * EPSG:4326, CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, EPSG:900913, EPSG:3857, │ │ │ │ │ - * EPSG:102113 and EPSG:102100). Keys are the SRS code, values are units, │ │ │ │ │ - * maxExtent (the validity extent for the SRS) and yx (true if this SRS is │ │ │ │ │ - * known to have a reverse axis order). │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Projection.defaults = { │ │ │ │ │ - "EPSG:4326": { │ │ │ │ │ - units: "degrees", │ │ │ │ │ - maxExtent: [-180, -90, 180, 90], │ │ │ │ │ - yx: true │ │ │ │ │ - }, │ │ │ │ │ - "CRS:84": { │ │ │ │ │ - units: "degrees", │ │ │ │ │ - maxExtent: [-180, -90, 180, 90] │ │ │ │ │ - }, │ │ │ │ │ - "EPSG:900913": { │ │ │ │ │ - units: "m", │ │ │ │ │ - maxExtent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34] │ │ │ │ │ - } │ │ │ │ │ -}; │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * APIMethod: addTransform │ │ │ │ │ - * Set a custom transform method between two projections. Use this method in │ │ │ │ │ - * cases where the proj4js lib is not available or where custom projections │ │ │ │ │ - * need to be handled. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * from - {String} The code for the source projection │ │ │ │ │ - * to - {String} the code for the destination projection │ │ │ │ │ - * method - {Function} A function that takes a point as an argument and │ │ │ │ │ - * transforms that point from the source to the destination projection │ │ │ │ │ - * in place. The original point should be modified. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Projection.addTransform = function(from, to, method) { │ │ │ │ │ - if (method === OpenLayers.Projection.nullTransform) { │ │ │ │ │ - var defaults = OpenLayers.Projection.defaults[from]; │ │ │ │ │ - if (defaults && !OpenLayers.Projection.defaults[to]) { │ │ │ │ │ - OpenLayers.Projection.defaults[to] = defaults; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - if (!OpenLayers.Projection.transforms[from]) { │ │ │ │ │ - OpenLayers.Projection.transforms[from] = {}; │ │ │ │ │ - } │ │ │ │ │ - OpenLayers.Projection.transforms[from][to] = method; │ │ │ │ │ -}; │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * APIMethod: transform │ │ │ │ │ - * Transform a point coordinate from one projection to another. Note that │ │ │ │ │ - * the input point is transformed in place. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * point - { | Object} An object with x and y │ │ │ │ │ - * properties representing coordinates in those dimensions. │ │ │ │ │ - * source - {OpenLayers.Projection} Source map coordinate system │ │ │ │ │ - * dest - {OpenLayers.Projection} Destination map coordinate system │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * point - {object} A transformed coordinate. The original point is modified. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Projection.transform = function(point, source, dest) { │ │ │ │ │ - if (source && dest) { │ │ │ │ │ - if (!(source instanceof OpenLayers.Projection)) { │ │ │ │ │ - source = new OpenLayers.Projection(source); │ │ │ │ │ - } │ │ │ │ │ - if (!(dest instanceof OpenLayers.Projection)) { │ │ │ │ │ - dest = new OpenLayers.Projection(dest); │ │ │ │ │ - } │ │ │ │ │ - if (source.proj && dest.proj) { │ │ │ │ │ - point = Proj4js.transform(source.proj, dest.proj, point); │ │ │ │ │ - } else { │ │ │ │ │ - var sourceCode = source.getCode(); │ │ │ │ │ - var destCode = dest.getCode(); │ │ │ │ │ - var transforms = OpenLayers.Projection.transforms; │ │ │ │ │ - if (transforms[sourceCode] && transforms[sourceCode][destCode]) { │ │ │ │ │ - transforms[sourceCode][destCode](point); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - return point; │ │ │ │ │ -}; │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * APIFunction: nullTransform │ │ │ │ │ - * A null transformation - useful for defining projection aliases when │ │ │ │ │ - * proj4js is not available: │ │ │ │ │ - * │ │ │ │ │ - * (code) │ │ │ │ │ - * OpenLayers.Projection.addTransform("EPSG:3857", "EPSG:900913", │ │ │ │ │ - * OpenLayers.Projection.nullTransform); │ │ │ │ │ - * OpenLayers.Projection.addTransform("EPSG:900913", "EPSG:3857", │ │ │ │ │ - * OpenLayers.Projection.nullTransform); │ │ │ │ │ - * (end) │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Projection.nullTransform = function(point) { │ │ │ │ │ - return point; │ │ │ │ │ -}; │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Note: Transforms for web mercator <-> geographic │ │ │ │ │ - * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113 and EPSG:102100. │ │ │ │ │ - * OpenLayers originally started referring to EPSG:900913 as web mercator. │ │ │ │ │ - * The EPSG has declared EPSG:3857 to be web mercator. │ │ │ │ │ - * ArcGIS 10 recognizes the EPSG:3857, EPSG:102113, and EPSG:102100 as │ │ │ │ │ - * equivalent. See http://blogs.esri.com/Dev/blogs/arcgisserver/archive/2009/11/20/ArcGIS-Online-moving-to-Google-_2F00_-Bing-tiling-scheme_3A00_-What-does-this-mean-for-you_3F00_.aspx#12084. │ │ │ │ │ - * For geographic, OpenLayers recognizes EPSG:4326, CRS:84 and │ │ │ │ │ - * urn:ogc:def:crs:EPSG:6.6:4326. OpenLayers also knows about the reverse axis │ │ │ │ │ - * order for EPSG:4326. │ │ │ │ │ - */ │ │ │ │ │ -(function() { │ │ │ │ │ - │ │ │ │ │ - var pole = 20037508.34; │ │ │ │ │ - │ │ │ │ │ - function inverseMercator(xy) { │ │ │ │ │ - xy.x = 180 * xy.x / pole; │ │ │ │ │ - xy.y = 180 / Math.PI * (2 * Math.atan(Math.exp((xy.y / pole) * Math.PI)) - Math.PI / 2); │ │ │ │ │ - return xy; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - function forwardMercator(xy) { │ │ │ │ │ - xy.x = xy.x * pole / 180; │ │ │ │ │ - var y = Math.log(Math.tan((90 + xy.y) * Math.PI / 360)) / Math.PI * pole; │ │ │ │ │ - xy.y = Math.max(-20037508.34, Math.min(y, 20037508.34)); │ │ │ │ │ - return xy; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - function map(base, codes) { │ │ │ │ │ - var add = OpenLayers.Projection.addTransform; │ │ │ │ │ - var same = OpenLayers.Projection.nullTransform; │ │ │ │ │ - var i, len, code, other, j; │ │ │ │ │ - for (i = 0, len = codes.length; i < len; ++i) { │ │ │ │ │ - code = codes[i]; │ │ │ │ │ - add(base, code, forwardMercator); │ │ │ │ │ - add(code, base, inverseMercator); │ │ │ │ │ - for (j = i + 1; j < len; ++j) { │ │ │ │ │ - other = codes[j]; │ │ │ │ │ - add(code, other, same); │ │ │ │ │ - add(other, code, same); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // list of equivalent codes for web mercator │ │ │ │ │ - var mercator = ["EPSG:900913", "EPSG:3857", "EPSG:102113", "EPSG:102100"], │ │ │ │ │ - geographic = ["CRS:84", "urn:ogc:def:crs:EPSG:6.6:4326", "EPSG:4326"], │ │ │ │ │ - i; │ │ │ │ │ - for (i = mercator.length - 1; i >= 0; --i) { │ │ │ │ │ - map(mercator[i], geographic); │ │ │ │ │ - } │ │ │ │ │ - for (i = geographic.length - 1; i >= 0; --i) { │ │ │ │ │ - map(geographic[i], mercator); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ -})(); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Map.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ │ - * @requires OpenLayers/Util/vendorPrefix.js │ │ │ │ │ - * @requires OpenLayers/Events.js │ │ │ │ │ - * @requires OpenLayers/Tween.js │ │ │ │ │ - * @requires OpenLayers/Projection.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Map │ │ │ │ │ - * Instances of OpenLayers.Map are interactive maps embedded in a web page. │ │ │ │ │ - * Create a new map with the constructor. │ │ │ │ │ - * │ │ │ │ │ - * On their own maps do not provide much functionality. To extend a map │ │ │ │ │ - * it's necessary to add controls () and │ │ │ │ │ - * layers () to the map. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Map = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constant: Z_INDEX_BASE │ │ │ │ │ - * {Object} Base z-indexes for different classes of thing │ │ │ │ │ - */ │ │ │ │ │ - Z_INDEX_BASE: { │ │ │ │ │ - BaseLayer: 100, │ │ │ │ │ - Overlay: 325, │ │ │ │ │ - Feature: 725, │ │ │ │ │ - Popup: 750, │ │ │ │ │ - Control: 1000 │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: events │ │ │ │ │ - * {} │ │ │ │ │ - * │ │ │ │ │ - * Register a listener for a particular event with the following syntax: │ │ │ │ │ - * (code) │ │ │ │ │ - * map.events.register(type, obj, listener); │ │ │ │ │ - * (end) │ │ │ │ │ - * │ │ │ │ │ - * Listeners will be called with a reference to an event object. The │ │ │ │ │ - * properties of this event depends on exactly what happened. │ │ │ │ │ - * │ │ │ │ │ - * All event objects have at least the following properties: │ │ │ │ │ - * object - {Object} A reference to map.events.object. │ │ │ │ │ - * element - {DOMElement} A reference to map.events.element. │ │ │ │ │ - * │ │ │ │ │ - * Browser events have the following additional properties: │ │ │ │ │ - * xy - {} The pixel location of the event (relative │ │ │ │ │ - * to the the map viewport). │ │ │ │ │ - * │ │ │ │ │ - * Supported map event types: │ │ │ │ │ - * preaddlayer - triggered before a layer has been added. The event │ │ │ │ │ - * object will include a *layer* property that references the layer │ │ │ │ │ - * to be added. When a listener returns "false" the adding will be │ │ │ │ │ - * aborted. │ │ │ │ │ - * addlayer - triggered after a layer has been added. The event object │ │ │ │ │ - * will include a *layer* property that references the added layer. │ │ │ │ │ - * preremovelayer - triggered before a layer has been removed. The event │ │ │ │ │ - * object will include a *layer* property that references the layer │ │ │ │ │ - * to be removed. When a listener returns "false" the removal will be │ │ │ │ │ - * aborted. │ │ │ │ │ - * removelayer - triggered after a layer has been removed. The event │ │ │ │ │ - * object will include a *layer* property that references the removed │ │ │ │ │ - * layer. │ │ │ │ │ - * changelayer - triggered after a layer name change, order change, │ │ │ │ │ - * opacity change, params change, visibility change (actual visibility, │ │ │ │ │ - * not the layer's visibility property) or attribution change (due to │ │ │ │ │ - * extent change). Listeners will receive an event object with *layer* │ │ │ │ │ - * and *property* properties. The *layer* property will be a reference │ │ │ │ │ - * to the changed layer. The *property* property will be a key to the │ │ │ │ │ - * changed property (name, order, opacity, params, visibility or │ │ │ │ │ - * attribution). │ │ │ │ │ - * movestart - triggered after the start of a drag, pan, or zoom. The event │ │ │ │ │ - * object may include a *zoomChanged* property that tells whether the │ │ │ │ │ - * zoom has changed. │ │ │ │ │ - * move - triggered after each drag, pan, or zoom │ │ │ │ │ - * moveend - triggered after a drag, pan, or zoom completes │ │ │ │ │ - * zoomend - triggered after a zoom completes │ │ │ │ │ - * mouseover - triggered after mouseover the map │ │ │ │ │ - * mouseout - triggered after mouseout the map │ │ │ │ │ - * mousemove - triggered after mousemove the map │ │ │ │ │ - * changebaselayer - triggered after the base layer changes │ │ │ │ │ - * updatesize - triggered after the method was executed │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: id │ │ │ │ │ - * {String} Unique identifier for the map │ │ │ │ │ - */ │ │ │ │ │ - id: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: fractionalZoom │ │ │ │ │ - * {Boolean} For a base layer that supports it, allow the map resolution │ │ │ │ │ - * to be set to a value between one of the values in the resolutions │ │ │ │ │ - * array. Default is false. │ │ │ │ │ - * │ │ │ │ │ - * When fractionalZoom is set to true, it is possible to zoom to │ │ │ │ │ - * an arbitrary extent. This requires a base layer from a source │ │ │ │ │ - * that supports requests for arbitrary extents (i.e. not cached │ │ │ │ │ - * tiles on a regular lattice). This means that fractionalZoom │ │ │ │ │ - * will not work with commercial layers (Google, Yahoo, VE), layers │ │ │ │ │ - * using TileCache, or any other pre-cached data sources. │ │ │ │ │ - * │ │ │ │ │ - * If you are using fractionalZoom, then you should also use │ │ │ │ │ - * instead of layer.resolutions[zoom] as the │ │ │ │ │ - * former works for non-integer zoom levels. │ │ │ │ │ - */ │ │ │ │ │ - fractionalZoom: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: events │ │ │ │ │ - * {} An events object that handles all │ │ │ │ │ - * events on the map │ │ │ │ │ - */ │ │ │ │ │ - events: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: allOverlays │ │ │ │ │ - * {Boolean} Allow the map to function with "overlays" only. Defaults to │ │ │ │ │ - * false. If true, the lowest layer in the draw order will act as │ │ │ │ │ - * the base layer. In addition, if set to true, all layers will │ │ │ │ │ - * have isBaseLayer set to false when they are added to the map. │ │ │ │ │ - * │ │ │ │ │ - * Note: │ │ │ │ │ - * If you set map.allOverlays to true, then you *cannot* use │ │ │ │ │ - * map.setBaseLayer or layer.setIsBaseLayer. With allOverlays true, │ │ │ │ │ - * the lowest layer in the draw layer is the base layer. So, to change │ │ │ │ │ - * the base layer, use or to set the layer │ │ │ │ │ - * index to 0. │ │ │ │ │ - */ │ │ │ │ │ - allOverlays: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: div │ │ │ │ │ - * {DOMElement|String} The element that contains the map (or an id for │ │ │ │ │ - * that element). If the constructor is called │ │ │ │ │ - * with two arguments, this should be provided as the first argument. │ │ │ │ │ - * Alternatively, the map constructor can be called with the options │ │ │ │ │ - * object as the only argument. In this case (one argument), a │ │ │ │ │ - * div property may or may not be provided. If the div property │ │ │ │ │ - * is not provided, the map can be rendered to a container later │ │ │ │ │ - * using the method. │ │ │ │ │ - * │ │ │ │ │ - * Note: │ │ │ │ │ - * If you are calling after map construction, do not use │ │ │ │ │ - * auto. Instead, divide your by your │ │ │ │ │ - * maximum expected dimension. │ │ │ │ │ - */ │ │ │ │ │ - div: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: dragging │ │ │ │ │ - * {Boolean} The map is currently being dragged. │ │ │ │ │ - */ │ │ │ │ │ - dragging: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: size │ │ │ │ │ - * {} Size of the main div (this.div) │ │ │ │ │ - */ │ │ │ │ │ - size: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: viewPortDiv │ │ │ │ │ - * {HTMLDivElement} The element that represents the map viewport │ │ │ │ │ - */ │ │ │ │ │ - viewPortDiv: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: layerContainerOrigin │ │ │ │ │ - * {} The lonlat at which the later container was │ │ │ │ │ - * re-initialized (on-zoom) │ │ │ │ │ - */ │ │ │ │ │ - layerContainerOrigin: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: layerContainerDiv │ │ │ │ │ - * {HTMLDivElement} The element that contains the layers. │ │ │ │ │ - */ │ │ │ │ │ - layerContainerDiv: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: layers │ │ │ │ │ - * {Array()} Ordered list of layers in the map │ │ │ │ │ - */ │ │ │ │ │ - layers: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: controls │ │ │ │ │ - * {Array()} List of controls associated with the map. │ │ │ │ │ - * │ │ │ │ │ - * If not provided in the map options at construction, the map will │ │ │ │ │ - * by default be given the following controls if present in the build: │ │ │ │ │ - * - or │ │ │ │ │ - * - or │ │ │ │ │ - * - │ │ │ │ │ - * - │ │ │ │ │ - */ │ │ │ │ │ - controls: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: popups │ │ │ │ │ - * {Array()} List of popups associated with the map │ │ │ │ │ - */ │ │ │ │ │ - popups: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: baseLayer │ │ │ │ │ - * {} The currently selected base layer. This determines │ │ │ │ │ - * min/max zoom level, projection, etc. │ │ │ │ │ - */ │ │ │ │ │ - baseLayer: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: center │ │ │ │ │ - * {} The current center of the map │ │ │ │ │ - */ │ │ │ │ │ - center: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: resolution │ │ │ │ │ - * {Float} The resolution of the map. │ │ │ │ │ - */ │ │ │ │ │ - resolution: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: zoom │ │ │ │ │ - * {Integer} The current zoom level of the map │ │ │ │ │ - */ │ │ │ │ │ - zoom: 0, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: panRatio │ │ │ │ │ - * {Float} The ratio of the current extent within │ │ │ │ │ - * which panning will tween. │ │ │ │ │ - */ │ │ │ │ │ - panRatio: 1.5, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: options │ │ │ │ │ - * {Object} The options object passed to the class constructor. Read-only. │ │ │ │ │ - */ │ │ │ │ │ - options: null, │ │ │ │ │ - │ │ │ │ │ - // Options │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: tileSize │ │ │ │ │ - * {} Set in the map options to override the default tile │ │ │ │ │ - * size for this map. │ │ │ │ │ - */ │ │ │ │ │ - tileSize: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: projection │ │ │ │ │ - * {String} Set in the map options to specify the default projection │ │ │ │ │ - * for layers added to this map. When using a projection other than EPSG:4326 │ │ │ │ │ - * (CRS:84, Geographic) or EPSG:3857 (EPSG:900913, Web Mercator), │ │ │ │ │ - * also set maxExtent, maxResolution or resolutions. Default is "EPSG:4326". │ │ │ │ │ - * Note that the projection of the map is usually determined │ │ │ │ │ - * by that of the current baseLayer (see and ). │ │ │ │ │ - */ │ │ │ │ │ - projection: "EPSG:4326", │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: units │ │ │ │ │ - * {String} The map units. Possible values are 'degrees' (or 'dd'), 'm', │ │ │ │ │ - * 'ft', 'km', 'mi', 'inches'. Normally taken from the projection. │ │ │ │ │ - * Only required if both map and layers do not define a projection, │ │ │ │ │ - * or if they define a projection which does not define units │ │ │ │ │ - */ │ │ │ │ │ - units: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: resolutions │ │ │ │ │ - * {Array(Float)} A list of map resolutions (map units per pixel) in │ │ │ │ │ - * descending order. If this is not set in the layer constructor, it │ │ │ │ │ - * will be set based on other resolution related properties │ │ │ │ │ - * (maxExtent, maxResolution, maxScale, etc.). │ │ │ │ │ - */ │ │ │ │ │ - resolutions: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: maxResolution │ │ │ │ │ - * {Float} Required if you are not displaying the whole world on a tile │ │ │ │ │ - * with the size specified in . │ │ │ │ │ - */ │ │ │ │ │ - maxResolution: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: minResolution │ │ │ │ │ - * {Float} │ │ │ │ │ - */ │ │ │ │ │ - minResolution: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: maxScale │ │ │ │ │ - * {Float} │ │ │ │ │ - */ │ │ │ │ │ - maxScale: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: minScale │ │ │ │ │ - * {Float} │ │ │ │ │ - */ │ │ │ │ │ - minScale: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: maxExtent │ │ │ │ │ - * {|Array} If provided as an array, the array │ │ │ │ │ - * should consist of four values (left, bottom, right, top). │ │ │ │ │ - * The maximum extent for the map. │ │ │ │ │ - * Default depends on projection; if this is one of those defined in OpenLayers.Projection.defaults │ │ │ │ │ - * (EPSG:4326 or web mercator), maxExtent will be set to the value defined there; │ │ │ │ │ - * else, defaults to null. │ │ │ │ │ - * To restrict user panning and zooming of the map, use instead. │ │ │ │ │ - * The value for will change calculations for tile URLs. │ │ │ │ │ - */ │ │ │ │ │ - maxExtent: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: minExtent │ │ │ │ │ - * {|Array} If provided as an array, the array │ │ │ │ │ - * should consist of four values (left, bottom, right, top). │ │ │ │ │ - * The minimum extent for the map. Defaults to null. │ │ │ │ │ - */ │ │ │ │ │ - minExtent: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: restrictedExtent │ │ │ │ │ - * {|Array} If provided as an array, the array │ │ │ │ │ - * should consist of four values (left, bottom, right, top). │ │ │ │ │ - * Limit map navigation to this extent where possible. │ │ │ │ │ - * If a non-null restrictedExtent is set, panning will be restricted │ │ │ │ │ - * to the given bounds. In addition, zooming to a resolution that │ │ │ │ │ - * displays more than the restricted extent will center the map │ │ │ │ │ - * on the restricted extent. If you wish to limit the zoom level │ │ │ │ │ - * or resolution, use maxResolution. │ │ │ │ │ - */ │ │ │ │ │ - restrictedExtent: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: numZoomLevels │ │ │ │ │ - * {Integer} Number of zoom levels for the map. Defaults to 16. Set a │ │ │ │ │ - * different value in the map options if needed. │ │ │ │ │ - */ │ │ │ │ │ - numZoomLevels: 16, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: theme │ │ │ │ │ - * {String} Relative path to a CSS file from which to load theme styles. │ │ │ │ │ - * Specify null in the map options (e.g. {theme: null}) if you │ │ │ │ │ - * want to get cascading style declarations - by putting links to │ │ │ │ │ - * stylesheets or style declarations directly in your page. │ │ │ │ │ - */ │ │ │ │ │ - theme: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: displayProjection │ │ │ │ │ - * {} Requires proj4js support for projections other │ │ │ │ │ - * than EPSG:4326 or EPSG:900913/EPSG:3857. Projection used by │ │ │ │ │ - * several controls to display data to user. If this property is set, │ │ │ │ │ - * it will be set on any control which has a null displayProjection │ │ │ │ │ - * property at the time the control is added to the map. │ │ │ │ │ - */ │ │ │ │ │ - displayProjection: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: tileManager │ │ │ │ │ - * {|Object} By default, and if the build contains │ │ │ │ │ - * TileManager.js, the map will use the TileManager to queue image requests │ │ │ │ │ - * and to cache tile image elements. To create a map without a TileManager │ │ │ │ │ - * configure the map with tileManager: null. To create a TileManager with │ │ │ │ │ - * non-default options, supply the options instead or alternatively supply │ │ │ │ │ - * an instance of {}. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: fallThrough │ │ │ │ │ - * {Boolean} Should OpenLayers allow events on the map to fall through to │ │ │ │ │ - * other elements on the page, or should it swallow them? (#457) │ │ │ │ │ - * Default is to swallow. │ │ │ │ │ - */ │ │ │ │ │ - fallThrough: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: autoUpdateSize │ │ │ │ │ - * {Boolean} Should OpenLayers automatically update the size of the map │ │ │ │ │ - * when the resize event is fired. Default is true. │ │ │ │ │ - */ │ │ │ │ │ - autoUpdateSize: true, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: eventListeners │ │ │ │ │ - * {Object} If set as an option at construction, the eventListeners │ │ │ │ │ - * object will be registered with . Object │ │ │ │ │ - * structure must be a listeners object as shown in the example for │ │ │ │ │ - * the events.on method. │ │ │ │ │ - */ │ │ │ │ │ - eventListeners: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: panTween │ │ │ │ │ - * {} Animated panning tween object, see panTo() │ │ │ │ │ - */ │ │ │ │ │ - panTween: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: panMethod │ │ │ │ │ - * {Function} The Easing function to be used for tweening. Default is │ │ │ │ │ - * OpenLayers.Easing.Expo.easeOut. Setting this to 'null' turns off │ │ │ │ │ - * animated panning. │ │ │ │ │ - */ │ │ │ │ │ - panMethod: OpenLayers.Easing.Expo.easeOut, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: panDuration │ │ │ │ │ - * {Integer} The number of steps to be passed to the │ │ │ │ │ - * OpenLayers.Tween.start() method when the map is │ │ │ │ │ - * panned. │ │ │ │ │ - * Default is 50. │ │ │ │ │ - */ │ │ │ │ │ - panDuration: 50, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: zoomTween │ │ │ │ │ - * {} Animated zooming tween object, see zoomTo() │ │ │ │ │ - */ │ │ │ │ │ - zoomTween: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: zoomMethod │ │ │ │ │ - * {Function} The Easing function to be used for tweening. Default is │ │ │ │ │ - * OpenLayers.Easing.Quad.easeOut. Setting this to 'null' turns off │ │ │ │ │ - * animated zooming. │ │ │ │ │ - */ │ │ │ │ │ - zoomMethod: OpenLayers.Easing.Quad.easeOut, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: zoomDuration │ │ │ │ │ - * {Integer} The number of steps to be passed to the │ │ │ │ │ - * OpenLayers.Tween.start() method when the map is zoomed. │ │ │ │ │ - * Default is 20. │ │ │ │ │ - */ │ │ │ │ │ - zoomDuration: 20, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: paddingForPopups │ │ │ │ │ - * {} Outside margin of the popup. Used to prevent │ │ │ │ │ - * the popup from getting too close to the map border. │ │ │ │ │ - */ │ │ │ │ │ - paddingForPopups: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: layerContainerOriginPx │ │ │ │ │ - * {Object} Cached object representing the layer container origin (in pixels). │ │ │ │ │ - */ │ │ │ │ │ - layerContainerOriginPx: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: minPx │ │ │ │ │ - * {Object} An object with a 'x' and 'y' values that is the lower │ │ │ │ │ - * left of maxExtent in viewport pixel space. │ │ │ │ │ - * Used to verify in moveByPx that the new location we're moving to │ │ │ │ │ - * is valid. It is also used in the getLonLatFromViewPortPx function │ │ │ │ │ - * of Layer. │ │ │ │ │ - */ │ │ │ │ │ - minPx: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: maxPx │ │ │ │ │ - * {Object} An object with a 'x' and 'y' values that is the top │ │ │ │ │ - * right of maxExtent in viewport pixel space. │ │ │ │ │ - * Used to verify in moveByPx that the new location we're moving to │ │ │ │ │ - * is valid. │ │ │ │ │ - */ │ │ │ │ │ - maxPx: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Map │ │ │ │ │ - * Constructor for a new OpenLayers.Map instance. There are two possible │ │ │ │ │ - * ways to call the map constructor. See the examples below. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * div - {DOMElement|String} The element or id of an element in your page │ │ │ │ │ - * that will contain the map. May be omitted if the
option is │ │ │ │ │ - * provided or if you intend to call the method later. │ │ │ │ │ - * options - {Object} Optional object with properties to tag onto the map. │ │ │ │ │ - * │ │ │ │ │ - * Valid options (in addition to the listed API properties): │ │ │ │ │ - * center - {|Array} The default initial center of the map. │ │ │ │ │ - * If provided as array, the first value is the x coordinate, │ │ │ │ │ - * and the 2nd value is the y coordinate. │ │ │ │ │ - * Only specify if is provided. │ │ │ │ │ - * Note that if an ArgParser/Permalink control is present, │ │ │ │ │ - * and the querystring contains coordinates, center will be set │ │ │ │ │ - * by that, and this option will be ignored. │ │ │ │ │ - * zoom - {Number} The initial zoom level for the map. Only specify if │ │ │ │ │ - * is provided. │ │ │ │ │ - * Note that if an ArgParser/Permalink control is present, │ │ │ │ │ - * and the querystring contains a zoom level, zoom will be set │ │ │ │ │ - * by that, and this option will be ignored. │ │ │ │ │ - * extent - {|Array} The initial extent of the map. │ │ │ │ │ - * If provided as an array, the array should consist of │ │ │ │ │ - * four values (left, bottom, right, top). │ │ │ │ │ - * Only specify if
and are not provided. │ │ │ │ │ - * │ │ │ │ │ - * Examples: │ │ │ │ │ - * (code) │ │ │ │ │ - * // create a map with default options in an element with the id "map1" │ │ │ │ │ - * var map = new OpenLayers.Map("map1"); │ │ │ │ │ - * │ │ │ │ │ - * // create a map with non-default options in an element with id "map2" │ │ │ │ │ - * var options = { │ │ │ │ │ - * projection: "EPSG:3857", │ │ │ │ │ - * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000), │ │ │ │ │ - * center: new OpenLayers.LonLat(-12356463.476333, 5621521.4854095) │ │ │ │ │ - * }; │ │ │ │ │ - * var map = new OpenLayers.Map("map2", options); │ │ │ │ │ - * │ │ │ │ │ - * // map with non-default options - same as above but with a single argument, │ │ │ │ │ - * // a restricted extent, and using arrays for bounds and center │ │ │ │ │ - * var map = new OpenLayers.Map({ │ │ │ │ │ - * div: "map_id", │ │ │ │ │ - * projection: "EPSG:3857", │ │ │ │ │ - * maxExtent: [-18924313.432222, -15538711.094146, 18924313.432222, 15538711.094146], │ │ │ │ │ - * restrictedExtent: [-13358338.893333, -9608371.5085962, 13358338.893333, 9608371.5085962], │ │ │ │ │ - * center: [-12356463.476333, 5621521.4854095] │ │ │ │ │ - * }); │ │ │ │ │ - * │ │ │ │ │ - * // create a map without a reference to a container - call render later │ │ │ │ │ - * var map = new OpenLayers.Map({ │ │ │ │ │ - * projection: "EPSG:3857", │ │ │ │ │ - * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000) │ │ │ │ │ - * }); │ │ │ │ │ - * (end) │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(div, options) { │ │ │ │ │ - │ │ │ │ │ - // If only one argument is provided, check if it is an object. │ │ │ │ │ - if (arguments.length === 1 && typeof div === "object") { │ │ │ │ │ - options = div; │ │ │ │ │ - div = options && options.div; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // Simple-type defaults are set in class definition. │ │ │ │ │ - // Now set complex-type defaults │ │ │ │ │ - this.tileSize = new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH, │ │ │ │ │ - OpenLayers.Map.TILE_HEIGHT); │ │ │ │ │ - │ │ │ │ │ - this.paddingForPopups = new OpenLayers.Bounds(15, 15, 15, 15); │ │ │ │ │ - │ │ │ │ │ - this.theme = OpenLayers._getScriptLocation() + │ │ │ │ │ - 'theme/default/style.css'; │ │ │ │ │ - │ │ │ │ │ - // backup original options │ │ │ │ │ - this.options = OpenLayers.Util.extend({}, options); │ │ │ │ │ - │ │ │ │ │ - // now override default options │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ - │ │ │ │ │ - var projCode = this.projection instanceof OpenLayers.Projection ? │ │ │ │ │ - this.projection.projCode : this.projection; │ │ │ │ │ - OpenLayers.Util.applyDefaults(this, OpenLayers.Projection.defaults[projCode]); │ │ │ │ │ - │ │ │ │ │ - // allow extents and center to be arrays │ │ │ │ │ - if (this.maxExtent && !(this.maxExtent instanceof OpenLayers.Bounds)) { │ │ │ │ │ - this.maxExtent = new OpenLayers.Bounds(this.maxExtent); │ │ │ │ │ - } │ │ │ │ │ - if (this.minExtent && !(this.minExtent instanceof OpenLayers.Bounds)) { │ │ │ │ │ - this.minExtent = new OpenLayers.Bounds(this.minExtent); │ │ │ │ │ - } │ │ │ │ │ - if (this.restrictedExtent && !(this.restrictedExtent instanceof OpenLayers.Bounds)) { │ │ │ │ │ - this.restrictedExtent = new OpenLayers.Bounds(this.restrictedExtent); │ │ │ │ │ - } │ │ │ │ │ - if (this.center && !(this.center instanceof OpenLayers.LonLat)) { │ │ │ │ │ - this.center = new OpenLayers.LonLat(this.center); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // initialize layers array │ │ │ │ │ - this.layers = []; │ │ │ │ │ - │ │ │ │ │ - this.id = OpenLayers.Util.createUniqueID("OpenLayers.Map_"); │ │ │ │ │ - │ │ │ │ │ - this.div = OpenLayers.Util.getElement(div); │ │ │ │ │ - if (!this.div) { │ │ │ │ │ - this.div = document.createElement("div"); │ │ │ │ │ - this.div.style.height = "1px"; │ │ │ │ │ - this.div.style.width = "1px"; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - OpenLayers.Element.addClass(this.div, 'olMap'); │ │ │ │ │ - │ │ │ │ │ - // the viewPortDiv is the outermost div we modify │ │ │ │ │ - var id = this.id + "_OpenLayers_ViewPort"; │ │ │ │ │ - this.viewPortDiv = OpenLayers.Util.createDiv(id, null, null, null, │ │ │ │ │ - "relative", null, │ │ │ │ │ - "hidden"); │ │ │ │ │ - this.viewPortDiv.style.width = "100%"; │ │ │ │ │ - this.viewPortDiv.style.height = "100%"; │ │ │ │ │ - this.viewPortDiv.className = "olMapViewport"; │ │ │ │ │ - this.div.appendChild(this.viewPortDiv); │ │ │ │ │ - │ │ │ │ │ - this.events = new OpenLayers.Events( │ │ │ │ │ - this, this.viewPortDiv, null, this.fallThrough, { │ │ │ │ │ - includeXY: true │ │ │ │ │ - } │ │ │ │ │ - ); │ │ │ │ │ - │ │ │ │ │ - if (OpenLayers.TileManager && this.tileManager !== null) { │ │ │ │ │ - if (!(this.tileManager instanceof OpenLayers.TileManager)) { │ │ │ │ │ - this.tileManager = new OpenLayers.TileManager(this.tileManager); │ │ │ │ │ - } │ │ │ │ │ - this.tileManager.addMap(this); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // the layerContainerDiv is the one that holds all the layers │ │ │ │ │ - id = this.id + "_OpenLayers_Container"; │ │ │ │ │ - this.layerContainerDiv = OpenLayers.Util.createDiv(id); │ │ │ │ │ - this.layerContainerDiv.style.zIndex = this.Z_INDEX_BASE['Popup'] - 1; │ │ │ │ │ - this.layerContainerOriginPx = { │ │ │ │ │ - x: 0, │ │ │ │ │ - y: 0 │ │ │ │ │ - }; │ │ │ │ │ - this.applyTransform(); │ │ │ │ │ - │ │ │ │ │ - this.viewPortDiv.appendChild(this.layerContainerDiv); │ │ │ │ │ - │ │ │ │ │ - this.updateSize(); │ │ │ │ │ - if (this.eventListeners instanceof Object) { │ │ │ │ │ - this.events.on(this.eventListeners); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (this.autoUpdateSize === true) { │ │ │ │ │ - // updateSize on catching the window's resize │ │ │ │ │ - // Note that this is ok, as updateSize() does nothing if the │ │ │ │ │ - // map's size has not actually changed. │ │ │ │ │ - this.updateSizeDestroy = OpenLayers.Function.bind(this.updateSize, │ │ │ │ │ - this); │ │ │ │ │ - OpenLayers.Event.observe(window, 'resize', │ │ │ │ │ - this.updateSizeDestroy); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // only append link stylesheet if the theme property is set │ │ │ │ │ - if (this.theme) { │ │ │ │ │ - // check existing links for equivalent url │ │ │ │ │ - var addNode = true; │ │ │ │ │ - var nodes = document.getElementsByTagName('link'); │ │ │ │ │ - for (var i = 0, len = nodes.length; i < len; ++i) { │ │ │ │ │ - if (OpenLayers.Util.isEquivalentUrl(nodes.item(i).href, │ │ │ │ │ - this.theme)) { │ │ │ │ │ - addNode = false; │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - // only add a new node if one with an equivalent url hasn't already │ │ │ │ │ - // been added │ │ │ │ │ - if (addNode) { │ │ │ │ │ - var cssNode = document.createElement('link'); │ │ │ │ │ - cssNode.setAttribute('rel', 'stylesheet'); │ │ │ │ │ - cssNode.setAttribute('type', 'text/css'); │ │ │ │ │ - cssNode.setAttribute('href', this.theme); │ │ │ │ │ - document.getElementsByTagName('head')[0].appendChild(cssNode); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (this.controls == null) { // default controls │ │ │ │ │ - this.controls = []; │ │ │ │ │ - if (OpenLayers.Control != null) { // running full or lite? │ │ │ │ │ - // Navigation or TouchNavigation depending on what is in build │ │ │ │ │ - if (OpenLayers.Control.Navigation) { │ │ │ │ │ - this.controls.push(new OpenLayers.Control.Navigation()); │ │ │ │ │ - } else if (OpenLayers.Control.TouchNavigation) { │ │ │ │ │ - this.controls.push(new OpenLayers.Control.TouchNavigation()); │ │ │ │ │ - } │ │ │ │ │ - if (OpenLayers.Control.Zoom) { │ │ │ │ │ - this.controls.push(new OpenLayers.Control.Zoom()); │ │ │ │ │ - } else if (OpenLayers.Control.PanZoom) { │ │ │ │ │ - this.controls.push(new OpenLayers.Control.PanZoom()); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (OpenLayers.Control.ArgParser) { │ │ │ │ │ - this.controls.push(new OpenLayers.Control.ArgParser()); │ │ │ │ │ - } │ │ │ │ │ - if (OpenLayers.Control.Attribution) { │ │ │ │ │ - this.controls.push(new OpenLayers.Control.Attribution()); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - for (var i = 0, len = this.controls.length; i < len; i++) { │ │ │ │ │ - this.addControlToMap(this.controls[i]); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - this.popups = []; │ │ │ │ │ - │ │ │ │ │ - this.unloadDestroy = OpenLayers.Function.bind(this.destroy, this); │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ - // always call map.destroy() │ │ │ │ │ - OpenLayers.Event.observe(window, 'unload', this.unloadDestroy); │ │ │ │ │ - │ │ │ │ │ - // add any initial layers │ │ │ │ │ - if (options && options.layers) { │ │ │ │ │ - /** │ │ │ │ │ - * If you have set options.center, the map center property will be │ │ │ │ │ - * set at this point. However, since setCenter has not been called, │ │ │ │ │ - * addLayers gets confused. So we delete the map center in this │ │ │ │ │ - * case. Because the check below uses options.center, it will │ │ │ │ │ - * be properly set below. │ │ │ │ │ - */ │ │ │ │ │ - delete this.center; │ │ │ │ │ - delete this.zoom; │ │ │ │ │ - this.addLayers(options.layers); │ │ │ │ │ - // set center (and optionally zoom) │ │ │ │ │ - if (options.center && !this.getCenter()) { │ │ │ │ │ - // zoom can be undefined here │ │ │ │ │ - this.setCenter(options.center, options.zoom); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (this.panMethod) { │ │ │ │ │ - this.panTween = new OpenLayers.Tween(this.panMethod); │ │ │ │ │ - } │ │ │ │ │ - if (this.zoomMethod && this.applyTransform.transform) { │ │ │ │ │ - this.zoomTween = new OpenLayers.Tween(this.zoomMethod); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getViewport │ │ │ │ │ - * Get the DOMElement representing the view port. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {DOMElement} │ │ │ │ │ - */ │ │ │ │ │ - getViewport: function() { │ │ │ │ │ - return this.viewPortDiv; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: render │ │ │ │ │ - * Render the map to a specified container. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * div - {String|DOMElement} The container that the map should be rendered │ │ │ │ │ - * to. If different than the current container, the map viewport │ │ │ │ │ - * will be moved from the current to the new container. │ │ │ │ │ - */ │ │ │ │ │ - render: function(div) { │ │ │ │ │ - this.div = OpenLayers.Util.getElement(div); │ │ │ │ │ - OpenLayers.Element.addClass(this.div, 'olMap'); │ │ │ │ │ - this.viewPortDiv.parentNode.removeChild(this.viewPortDiv); │ │ │ │ │ - this.div.appendChild(this.viewPortDiv); │ │ │ │ │ - this.updateSize(); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: unloadDestroy │ │ │ │ │ - * Function that is called to destroy the map on page unload. stored here │ │ │ │ │ - * so that if map is manually destroyed, we can unregister this. │ │ │ │ │ - */ │ │ │ │ │ - unloadDestroy: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: updateSizeDestroy │ │ │ │ │ - * When the map is destroyed, we need to stop listening to updateSize │ │ │ │ │ - * events: this method stores the function we need to unregister in │ │ │ │ │ - * non-IE browsers. │ │ │ │ │ - */ │ │ │ │ │ - updateSizeDestroy: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ - * Destroy this map. │ │ │ │ │ - * Note that if you are using an application which removes a container │ │ │ │ │ - * of the map from the DOM, you need to ensure that you destroy the │ │ │ │ │ - * map *before* this happens; otherwise, the page unload handler │ │ │ │ │ - * will fail because the DOM elements that map.destroy() wants │ │ │ │ │ - * to clean up will be gone. (See │ │ │ │ │ - * http://trac.osgeo.org/openlayers/ticket/2277 for more information). │ │ │ │ │ - * This will apply to GeoExt and also to other applications which │ │ │ │ │ - * modify the DOM of the container of the OpenLayers Map. │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - // if unloadDestroy is null, we've already been destroyed │ │ │ │ │ - if (!this.unloadDestroy) { │ │ │ │ │ - return false; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // make sure panning doesn't continue after destruction │ │ │ │ │ - if (this.panTween) { │ │ │ │ │ - this.panTween.stop(); │ │ │ │ │ - this.panTween = null; │ │ │ │ │ - } │ │ │ │ │ - // make sure zooming doesn't continue after destruction │ │ │ │ │ - if (this.zoomTween) { │ │ │ │ │ - this.zoomTween.stop(); │ │ │ │ │ - this.zoomTween = null; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // map has been destroyed. dont do it again! │ │ │ │ │ - OpenLayers.Event.stopObserving(window, 'unload', this.unloadDestroy); │ │ │ │ │ - this.unloadDestroy = null; │ │ │ │ │ - │ │ │ │ │ - if (this.updateSizeDestroy) { │ │ │ │ │ - OpenLayers.Event.stopObserving(window, 'resize', │ │ │ │ │ - this.updateSizeDestroy); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - this.paddingForPopups = null; │ │ │ │ │ - │ │ │ │ │ - if (this.controls != null) { │ │ │ │ │ - for (var i = this.controls.length - 1; i >= 0; --i) { │ │ │ │ │ - this.controls[i].destroy(); │ │ │ │ │ - } │ │ │ │ │ - this.controls = null; │ │ │ │ │ - } │ │ │ │ │ - if (this.layers != null) { │ │ │ │ │ - for (var i = this.layers.length - 1; i >= 0; --i) { │ │ │ │ │ - //pass 'false' to destroy so that map wont try to set a new │ │ │ │ │ - // baselayer after each baselayer is removed │ │ │ │ │ - this.layers[i].destroy(false); │ │ │ │ │ - } │ │ │ │ │ - this.layers = null; │ │ │ │ │ - } │ │ │ │ │ - if (this.viewPortDiv && this.viewPortDiv.parentNode) { │ │ │ │ │ - this.viewPortDiv.parentNode.removeChild(this.viewPortDiv); │ │ │ │ │ - } │ │ │ │ │ - this.viewPortDiv = null; │ │ │ │ │ - │ │ │ │ │ - if (this.tileManager) { │ │ │ │ │ - this.tileManager.removeMap(this); │ │ │ │ │ - this.tileManager = null; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (this.eventListeners) { │ │ │ │ │ - this.events.un(this.eventListeners); │ │ │ │ │ - this.eventListeners = null; │ │ │ │ │ - } │ │ │ │ │ - this.events.destroy(); │ │ │ │ │ - this.events = null; │ │ │ │ │ - │ │ │ │ │ - this.options = null; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: setOptions │ │ │ │ │ - * Change the map options │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} Hashtable of options to tag to the map │ │ │ │ │ - */ │ │ │ │ │ - setOptions: function(options) { │ │ │ │ │ - var updatePxExtent = this.minPx && │ │ │ │ │ - options.restrictedExtent != this.restrictedExtent; │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ - // force recalculation of minPx and maxPx │ │ │ │ │ - updatePxExtent && this.moveTo(this.getCachedCenter(), this.zoom, { │ │ │ │ │ - forceZoomChange: true │ │ │ │ │ - }); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getTileSize │ │ │ │ │ - * Get the tile size for the map │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - getTileSize: function() { │ │ │ │ │ - return this.tileSize; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getBy │ │ │ │ │ - * Get a list of objects given a property and a match item. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * array - {String} A property on the map whose value is an array. │ │ │ │ │ - * property - {String} A property on each item of the given array. │ │ │ │ │ - * match - {String | Object} A string to match. Can also be a regular │ │ │ │ │ - * expression literal or object. In addition, it can be any object │ │ │ │ │ - * with a method named test. For reqular expressions or other, if │ │ │ │ │ - * match.test(map[array][i][property]) evaluates to true, the item will │ │ │ │ │ - * be included in the array returned. If no items are found, an empty │ │ │ │ │ - * array is returned. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Array} An array of items where the given property matches the given │ │ │ │ │ - * criteria. │ │ │ │ │ - */ │ │ │ │ │ - getBy: function(array, property, match) { │ │ │ │ │ - var test = (typeof match.test == "function"); │ │ │ │ │ - var found = OpenLayers.Array.filter(this[array], function(item) { │ │ │ │ │ - return item[property] == match || (test && match.test(item[property])); │ │ │ │ │ - }); │ │ │ │ │ - return found; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getLayersBy │ │ │ │ │ - * Get a list of layers with properties matching the given criteria. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * property - {String} A layer property to be matched. │ │ │ │ │ - * match - {String | Object} A string to match. Can also be a regular │ │ │ │ │ - * expression literal or object. In addition, it can be any object │ │ │ │ │ - * with a method named test. For reqular expressions or other, if │ │ │ │ │ - * match.test(layer[property]) evaluates to true, the layer will be │ │ │ │ │ - * included in the array returned. If no layers are found, an empty │ │ │ │ │ - * array is returned. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Array()} A list of layers matching the given criteria. │ │ │ │ │ - * An empty array is returned if no matches are found. │ │ │ │ │ - */ │ │ │ │ │ - getLayersBy: function(property, match) { │ │ │ │ │ - return this.getBy("layers", property, match); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getLayersByName │ │ │ │ │ - * Get a list of layers with names matching the given name. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * match - {String | Object} A layer name. The name can also be a regular │ │ │ │ │ - * expression literal or object. In addition, it can be any object │ │ │ │ │ - * with a method named test. For reqular expressions or other, if │ │ │ │ │ - * name.test(layer.name) evaluates to true, the layer will be included │ │ │ │ │ - * in the list of layers returned. If no layers are found, an empty │ │ │ │ │ - * array is returned. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Array()} A list of layers matching the given name. │ │ │ │ │ - * An empty array is returned if no matches are found. │ │ │ │ │ - */ │ │ │ │ │ - getLayersByName: function(match) { │ │ │ │ │ - return this.getLayersBy("name", match); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getLayersByClass │ │ │ │ │ - * Get a list of layers of a given class (CLASS_NAME). │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * match - {String | Object} A layer class name. The match can also be a │ │ │ │ │ - * regular expression literal or object. In addition, it can be any │ │ │ │ │ - * object with a method named test. For reqular expressions or other, │ │ │ │ │ - * if type.test(layer.CLASS_NAME) evaluates to true, the layer will │ │ │ │ │ - * be included in the list of layers returned. If no layers are │ │ │ │ │ - * found, an empty array is returned. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Array()} A list of layers matching the given class. │ │ │ │ │ - * An empty array is returned if no matches are found. │ │ │ │ │ - */ │ │ │ │ │ - getLayersByClass: function(match) { │ │ │ │ │ - return this.getLayersBy("CLASS_NAME", match); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getControlsBy │ │ │ │ │ - * Get a list of controls with properties matching the given criteria. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * property - {String} A control property to be matched. │ │ │ │ │ - * match - {String | Object} A string to match. Can also be a regular │ │ │ │ │ - * expression literal or object. In addition, it can be any object │ │ │ │ │ - * with a method named test. For reqular expressions or other, if │ │ │ │ │ - * match.test(layer[property]) evaluates to true, the layer will be │ │ │ │ │ - * included in the array returned. If no layers are found, an empty │ │ │ │ │ - * array is returned. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Array()} A list of controls matching the given │ │ │ │ │ - * criteria. An empty array is returned if no matches are found. │ │ │ │ │ - */ │ │ │ │ │ - getControlsBy: function(property, match) { │ │ │ │ │ - return this.getBy("controls", property, match); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getControlsByClass │ │ │ │ │ - * Get a list of controls of a given class (CLASS_NAME). │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * match - {String | Object} A control class name. The match can also be a │ │ │ │ │ - * regular expression literal or object. In addition, it can be any │ │ │ │ │ - * object with a method named test. For reqular expressions or other, │ │ │ │ │ - * if type.test(control.CLASS_NAME) evaluates to true, the control will │ │ │ │ │ - * be included in the list of controls returned. If no controls are │ │ │ │ │ - * found, an empty array is returned. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Array()} A list of controls matching the given class. │ │ │ │ │ - * An empty array is returned if no matches are found. │ │ │ │ │ - */ │ │ │ │ │ - getControlsByClass: function(match) { │ │ │ │ │ - return this.getControlsBy("CLASS_NAME", match); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /********************************************************/ │ │ │ │ │ - /* */ │ │ │ │ │ - /* Layer Functions */ │ │ │ │ │ - /* */ │ │ │ │ │ - /* The following functions deal with adding and */ │ │ │ │ │ - /* removing Layers to and from the Map */ │ │ │ │ │ - /* */ │ │ │ │ │ - /********************************************************/ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getLayer │ │ │ │ │ - * Get a layer based on its id │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * id - {String} A layer id │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} The Layer with the corresponding id from the map's │ │ │ │ │ - * layer collection, or null if not found. │ │ │ │ │ - */ │ │ │ │ │ - getLayer: function(id) { │ │ │ │ │ - var foundLayer = null; │ │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ │ - var layer = this.layers[i]; │ │ │ │ │ - if (layer.id == id) { │ │ │ │ │ - foundLayer = layer; │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - return foundLayer; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: setLayerZIndex │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * layer - {} │ │ │ │ │ - * zIdx - {int} │ │ │ │ │ - */ │ │ │ │ │ - setLayerZIndex: function(layer, zIdx) { │ │ │ │ │ - layer.setZIndex( │ │ │ │ │ - this.Z_INDEX_BASE[layer.isBaseLayer ? 'BaseLayer' : 'Overlay'] + │ │ │ │ │ - zIdx * 5); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: resetLayersZIndex │ │ │ │ │ - * Reset each layer's z-index based on layer's array index │ │ │ │ │ - */ │ │ │ │ │ - resetLayersZIndex: function() { │ │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ │ - var layer = this.layers[i]; │ │ │ │ │ - this.setLayerZIndex(layer, i); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: addLayer │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * layer - {} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} True if the layer has been added to the map. │ │ │ │ │ - */ │ │ │ │ │ - addLayer: function(layer) { │ │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ │ - if (this.layers[i] == layer) { │ │ │ │ │ - return false; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - if (this.events.triggerEvent("preaddlayer", { │ │ │ │ │ - layer: layer │ │ │ │ │ - }) === false) { │ │ │ │ │ - return false; │ │ │ │ │ - } │ │ │ │ │ - if (this.allOverlays) { │ │ │ │ │ - layer.isBaseLayer = false; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - layer.div.className = "olLayerDiv"; │ │ │ │ │ - layer.div.style.overflow = ""; │ │ │ │ │ - this.setLayerZIndex(layer, this.layers.length); │ │ │ │ │ - │ │ │ │ │ - if (layer.isFixed) { │ │ │ │ │ - this.viewPortDiv.appendChild(layer.div); │ │ │ │ │ - } else { │ │ │ │ │ - this.layerContainerDiv.appendChild(layer.div); │ │ │ │ │ - } │ │ │ │ │ - this.layers.push(layer); │ │ │ │ │ - layer.setMap(this); │ │ │ │ │ - │ │ │ │ │ - if (layer.isBaseLayer || (this.allOverlays && !this.baseLayer)) { │ │ │ │ │ - if (this.baseLayer == null) { │ │ │ │ │ - // set the first baselaye we add as the baselayer │ │ │ │ │ - this.setBaseLayer(layer); │ │ │ │ │ - } else { │ │ │ │ │ - layer.setVisibility(false); │ │ │ │ │ - } │ │ │ │ │ - } else { │ │ │ │ │ - layer.redraw(); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - this.events.triggerEvent("addlayer", { │ │ │ │ │ - layer: layer │ │ │ │ │ - }); │ │ │ │ │ - layer.events.triggerEvent("added", { │ │ │ │ │ - map: this, │ │ │ │ │ - layer: layer │ │ │ │ │ - }); │ │ │ │ │ - layer.afterAdd(); │ │ │ │ │ - │ │ │ │ │ - return true; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: addLayers │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * layers - {Array()} │ │ │ │ │ - */ │ │ │ │ │ - addLayers: function(layers) { │ │ │ │ │ - for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ │ - this.addLayer(layers[i]); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: removeLayer │ │ │ │ │ - * Removes a layer from the map by removing its visual element (the │ │ │ │ │ - * layer.div property), then removing it from the map's internal list │ │ │ │ │ - * of layers, setting the layer's map property to null. │ │ │ │ │ - * │ │ │ │ │ - * a "removelayer" event is triggered. │ │ │ │ │ - * │ │ │ │ │ - * very worthy of mention is that simply removing a layer from a map │ │ │ │ │ - * will not cause the removal of any popups which may have been created │ │ │ │ │ - * by the layer. this is due to the fact that it was decided at some │ │ │ │ │ - * point that popups would not belong to layers. thus there is no way │ │ │ │ │ - * for us to know here to which layer the popup belongs. │ │ │ │ │ - * │ │ │ │ │ - * A simple solution to this is simply to call destroy() on the layer. │ │ │ │ │ - * the default OpenLayers.Layer class's destroy() function │ │ │ │ │ - * automatically takes care to remove itself from whatever map it has │ │ │ │ │ - * been attached to. │ │ │ │ │ - * │ │ │ │ │ - * The correct solution is for the layer itself to register an │ │ │ │ │ - * event-handler on "removelayer" and when it is called, if it │ │ │ │ │ - * recognizes itself as the layer being removed, then it cycles through │ │ │ │ │ - * its own personal list of popups, removing them from the map. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * layer - {} │ │ │ │ │ - * setNewBaseLayer - {Boolean} Default is true │ │ │ │ │ - */ │ │ │ │ │ - removeLayer: function(layer, setNewBaseLayer) { │ │ │ │ │ - if (this.events.triggerEvent("preremovelayer", { │ │ │ │ │ - layer: layer │ │ │ │ │ - }) === false) { │ │ │ │ │ - return; │ │ │ │ │ - } │ │ │ │ │ - if (setNewBaseLayer == null) { │ │ │ │ │ - setNewBaseLayer = true; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (layer.isFixed) { │ │ │ │ │ - this.viewPortDiv.removeChild(layer.div); │ │ │ │ │ - } else { │ │ │ │ │ - this.layerContainerDiv.removeChild(layer.div); │ │ │ │ │ - } │ │ │ │ │ - OpenLayers.Util.removeItem(this.layers, layer); │ │ │ │ │ - layer.removeMap(this); │ │ │ │ │ - layer.map = null; │ │ │ │ │ - │ │ │ │ │ - // if we removed the base layer, need to set a new one │ │ │ │ │ - if (this.baseLayer == layer) { │ │ │ │ │ - this.baseLayer = null; │ │ │ │ │ - if (setNewBaseLayer) { │ │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ │ - var iLayer = this.layers[i]; │ │ │ │ │ - if (iLayer.isBaseLayer || this.allOverlays) { │ │ │ │ │ - this.setBaseLayer(iLayer); │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - this.resetLayersZIndex(); │ │ │ │ │ - │ │ │ │ │ - this.events.triggerEvent("removelayer", { │ │ │ │ │ - layer: layer │ │ │ │ │ - }); │ │ │ │ │ - layer.events.triggerEvent("removed", { │ │ │ │ │ - map: this, │ │ │ │ │ - layer: layer │ │ │ │ │ - }); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getNumLayers │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Int} The number of layers attached to the map. │ │ │ │ │ - */ │ │ │ │ │ - getNumLayers: function() { │ │ │ │ │ - return this.layers.length; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getLayerIndex │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * layer - {} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Integer} The current (zero-based) index of the given layer in the map's │ │ │ │ │ - * layer stack. Returns -1 if the layer isn't on the map. │ │ │ │ │ - */ │ │ │ │ │ - getLayerIndex: function(layer) { │ │ │ │ │ - return OpenLayers.Util.indexOf(this.layers, layer); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: setLayerIndex │ │ │ │ │ - * Move the given layer to the specified (zero-based) index in the layer │ │ │ │ │ - * list, changing its z-index in the map display. Use │ │ │ │ │ - * map.getLayerIndex() to find out the current index of a layer. Note │ │ │ │ │ - * that this cannot (or at least should not) be effectively used to │ │ │ │ │ - * raise base layers above overlays. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * layer - {} │ │ │ │ │ - * idx - {int} │ │ │ │ │ - */ │ │ │ │ │ - setLayerIndex: function(layer, idx) { │ │ │ │ │ - var base = this.getLayerIndex(layer); │ │ │ │ │ - if (idx < 0) { │ │ │ │ │ - idx = 0; │ │ │ │ │ - } else if (idx > this.layers.length) { │ │ │ │ │ - idx = this.layers.length; │ │ │ │ │ - } │ │ │ │ │ - if (base != idx) { │ │ │ │ │ - this.layers.splice(base, 1); │ │ │ │ │ - this.layers.splice(idx, 0, layer); │ │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ │ - this.setLayerZIndex(this.layers[i], i); │ │ │ │ │ - } │ │ │ │ │ - this.events.triggerEvent("changelayer", { │ │ │ │ │ - layer: layer, │ │ │ │ │ - property: "order" │ │ │ │ │ - }); │ │ │ │ │ - if (this.allOverlays) { │ │ │ │ │ - if (idx === 0) { │ │ │ │ │ - this.setBaseLayer(layer); │ │ │ │ │ - } else if (this.baseLayer !== this.layers[0]) { │ │ │ │ │ - this.setBaseLayer(this.layers[0]); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: raiseLayer │ │ │ │ │ - * Change the index of the given layer by delta. If delta is positive, │ │ │ │ │ - * the layer is moved up the map's layer stack; if delta is negative, │ │ │ │ │ - * the layer is moved down. Again, note that this cannot (or at least │ │ │ │ │ - * should not) be effectively used to raise base layers above overlays. │ │ │ │ │ - * │ │ │ │ │ - * Paremeters: │ │ │ │ │ - * layer - {} │ │ │ │ │ - * delta - {int} │ │ │ │ │ - */ │ │ │ │ │ - raiseLayer: function(layer, delta) { │ │ │ │ │ - var idx = this.getLayerIndex(layer) + delta; │ │ │ │ │ - this.setLayerIndex(layer, idx); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: setBaseLayer │ │ │ │ │ - * Allows user to specify one of the currently-loaded layers as the Map's │ │ │ │ │ - * new base layer. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * newBaseLayer - {} │ │ │ │ │ - */ │ │ │ │ │ - setBaseLayer: function(newBaseLayer) { │ │ │ │ │ - │ │ │ │ │ - if (newBaseLayer != this.baseLayer) { │ │ │ │ │ - │ │ │ │ │ - // ensure newBaseLayer is already loaded │ │ │ │ │ - if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) { │ │ │ │ │ - │ │ │ │ │ - // preserve center and scale when changing base layers │ │ │ │ │ - var center = this.getCachedCenter(); │ │ │ │ │ - var newResolution = OpenLayers.Util.getResolutionFromScale( │ │ │ │ │ - this.getScale(), newBaseLayer.units │ │ │ │ │ - ); │ │ │ │ │ - │ │ │ │ │ - // make the old base layer invisible │ │ │ │ │ - if (this.baseLayer != null && !this.allOverlays) { │ │ │ │ │ - this.baseLayer.setVisibility(false); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // set new baselayer │ │ │ │ │ - this.baseLayer = newBaseLayer; │ │ │ │ │ - │ │ │ │ │ - if (!this.allOverlays || this.baseLayer.visibility) { │ │ │ │ │ - this.baseLayer.setVisibility(true); │ │ │ │ │ - // Layer may previously have been visible but not in range. │ │ │ │ │ - // In this case we need to redraw it to make it visible. │ │ │ │ │ - if (this.baseLayer.inRange === false) { │ │ │ │ │ - this.baseLayer.redraw(); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // recenter the map │ │ │ │ │ - if (center != null) { │ │ │ │ │ - // new zoom level derived from old scale │ │ │ │ │ - var newZoom = this.getZoomForResolution( │ │ │ │ │ - newResolution || this.resolution, true │ │ │ │ │ - ); │ │ │ │ │ - // zoom and force zoom change │ │ │ │ │ - this.setCenter(center, newZoom, false, true); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - this.events.triggerEvent("changebaselayer", { │ │ │ │ │ - layer: this.baseLayer │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ - /********************************************************/ │ │ │ │ │ - /* */ │ │ │ │ │ - /* Control Functions */ │ │ │ │ │ - /* */ │ │ │ │ │ - /* The following functions deal with adding and */ │ │ │ │ │ - /* removing Controls to and from the Map */ │ │ │ │ │ - /* */ │ │ │ │ │ - /********************************************************/ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: addControl │ │ │ │ │ - * Add the passed over control to the map. Optionally │ │ │ │ │ - * position the control at the given pixel. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * control - {} │ │ │ │ │ - * px - {} │ │ │ │ │ - */ │ │ │ │ │ - addControl: function(control, px) { │ │ │ │ │ - this.controls.push(control); │ │ │ │ │ - this.addControlToMap(control, px); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: addControls │ │ │ │ │ - * Add all of the passed over controls to the map. │ │ │ │ │ - * You can pass over an optional second array │ │ │ │ │ - * with pixel-objects to position the controls. │ │ │ │ │ - * The indices of the two arrays should match and │ │ │ │ │ - * you can add null as pixel for those controls │ │ │ │ │ - * you want to be autopositioned. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * controls - {Array()} │ │ │ │ │ - * pixels - {Array()} │ │ │ │ │ - */ │ │ │ │ │ - addControls: function(controls, pixels) { │ │ │ │ │ - var pxs = (arguments.length === 1) ? [] : pixels; │ │ │ │ │ - for (var i = 0, len = controls.length; i < len; i++) { │ │ │ │ │ - var ctrl = controls[i]; │ │ │ │ │ - var px = (pxs[i]) ? pxs[i] : null; │ │ │ │ │ - this.addControl(ctrl, px); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: addControlToMap │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * │ │ │ │ │ - * control - {} │ │ │ │ │ - * px - {} │ │ │ │ │ - */ │ │ │ │ │ - addControlToMap: function(control, px) { │ │ │ │ │ - // If a control doesn't have a div at this point, it belongs in the │ │ │ │ │ - // viewport. │ │ │ │ │ - control.outsideViewport = (control.div != null); │ │ │ │ │ - │ │ │ │ │ - // If the map has a displayProjection, and the control doesn't, set │ │ │ │ │ - // the display projection. │ │ │ │ │ - if (this.displayProjection && !control.displayProjection) { │ │ │ │ │ - control.displayProjection = this.displayProjection; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - control.setMap(this); │ │ │ │ │ - var div = control.draw(px); │ │ │ │ │ - if (div) { │ │ │ │ │ - if (!control.outsideViewport) { │ │ │ │ │ - div.style.zIndex = this.Z_INDEX_BASE['Control'] + │ │ │ │ │ - this.controls.length; │ │ │ │ │ - this.viewPortDiv.appendChild(div); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - if (control.autoActivate) { │ │ │ │ │ - control.activate(); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getControl │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * id - {String} ID of the control to return. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} The control from the map's list of controls │ │ │ │ │ - * which has a matching 'id'. If none found, │ │ │ │ │ - * returns null. │ │ │ │ │ - */ │ │ │ │ │ - getControl: function(id) { │ │ │ │ │ - var returnControl = null; │ │ │ │ │ - for (var i = 0, len = this.controls.length; i < len; i++) { │ │ │ │ │ - var control = this.controls[i]; │ │ │ │ │ - if (control.id == id) { │ │ │ │ │ - returnControl = control; │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - return returnControl; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: removeControl │ │ │ │ │ - * Remove a control from the map. Removes the control both from the map │ │ │ │ │ - * object's internal array of controls, as well as from the map's │ │ │ │ │ - * viewPort (assuming the control was not added outsideViewport) │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * control - {} The control to remove. │ │ │ │ │ - */ │ │ │ │ │ - removeControl: function(control) { │ │ │ │ │ - //make sure control is non-null and actually part of our map │ │ │ │ │ - if ((control) && (control == this.getControl(control.id))) { │ │ │ │ │ - if (control.div && (control.div.parentNode == this.viewPortDiv)) { │ │ │ │ │ - this.viewPortDiv.removeChild(control.div); │ │ │ │ │ - } │ │ │ │ │ - OpenLayers.Util.removeItem(this.controls, control); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /********************************************************/ │ │ │ │ │ - /* */ │ │ │ │ │ - /* Popup Functions */ │ │ │ │ │ - /* */ │ │ │ │ │ - /* The following functions deal with adding and */ │ │ │ │ │ - /* removing Popups to and from the Map */ │ │ │ │ │ - /* */ │ │ │ │ │ - /********************************************************/ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: addPopup │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * popup - {} │ │ │ │ │ - * exclusive - {Boolean} If true, closes all other popups first │ │ │ │ │ - */ │ │ │ │ │ - addPopup: function(popup, exclusive) { │ │ │ │ │ - │ │ │ │ │ - if (exclusive) { │ │ │ │ │ - //remove all other popups from screen │ │ │ │ │ - for (var i = this.popups.length - 1; i >= 0; --i) { │ │ │ │ │ - this.removePopup(this.popups[i]); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - popup.map = this; │ │ │ │ │ - this.popups.push(popup); │ │ │ │ │ - var popupDiv = popup.draw(); │ │ │ │ │ - if (popupDiv) { │ │ │ │ │ - popupDiv.style.zIndex = this.Z_INDEX_BASE['Popup'] + │ │ │ │ │ - this.popups.length; │ │ │ │ │ - this.layerContainerDiv.appendChild(popupDiv); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: removePopup │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * popup - {} │ │ │ │ │ - */ │ │ │ │ │ - removePopup: function(popup) { │ │ │ │ │ - OpenLayers.Util.removeItem(this.popups, popup); │ │ │ │ │ - if (popup.div) { │ │ │ │ │ - try { │ │ │ │ │ - this.layerContainerDiv.removeChild(popup.div); │ │ │ │ │ - } catch (e) {} // Popups sometimes apparently get disconnected │ │ │ │ │ - // from the layerContainerDiv, and cause complaints. │ │ │ │ │ - } │ │ │ │ │ - popup.map = null; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /********************************************************/ │ │ │ │ │ - /* */ │ │ │ │ │ - /* Container Div Functions */ │ │ │ │ │ - /* */ │ │ │ │ │ - /* The following functions deal with the access to */ │ │ │ │ │ - /* and maintenance of the size of the container div */ │ │ │ │ │ - /* */ │ │ │ │ │ - /********************************************************/ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getSize │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} An object that represents the │ │ │ │ │ - * size, in pixels, of the div into which OpenLayers │ │ │ │ │ - * has been loaded. │ │ │ │ │ - * Note - A clone() of this locally cached variable is │ │ │ │ │ - * returned, so as not to allow users to modify it. │ │ │ │ │ - */ │ │ │ │ │ - getSize: function() { │ │ │ │ │ - var size = null; │ │ │ │ │ - if (this.size != null) { │ │ │ │ │ - size = this.size.clone(); │ │ │ │ │ - } │ │ │ │ │ - return size; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: updateSize │ │ │ │ │ - * This function should be called by any external code which dynamically │ │ │ │ │ - * changes the size of the map div (because mozilla wont let us catch │ │ │ │ │ - * the "onresize" for an element) │ │ │ │ │ - */ │ │ │ │ │ - updateSize: function() { │ │ │ │ │ - // the div might have moved on the page, also │ │ │ │ │ - var newSize = this.getCurrentSize(); │ │ │ │ │ - if (newSize && !isNaN(newSize.h) && !isNaN(newSize.w)) { │ │ │ │ │ - this.events.clearMouseCache(); │ │ │ │ │ - var oldSize = this.getSize(); │ │ │ │ │ - if (oldSize == null) { │ │ │ │ │ - this.size = oldSize = newSize; │ │ │ │ │ - } │ │ │ │ │ - if (!newSize.equals(oldSize)) { │ │ │ │ │ - │ │ │ │ │ - // store the new size │ │ │ │ │ - this.size = newSize; │ │ │ │ │ - │ │ │ │ │ - //notify layers of mapresize │ │ │ │ │ - for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ │ - this.layers[i].onMapResize(); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - var center = this.getCachedCenter(); │ │ │ │ │ - │ │ │ │ │ - if (this.baseLayer != null && center != null) { │ │ │ │ │ - var zoom = this.getZoom(); │ │ │ │ │ - this.zoom = null; │ │ │ │ │ - this.setCenter(center, zoom); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - this.events.triggerEvent("updatesize"); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: getCurrentSize │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} A new object with the dimensions │ │ │ │ │ - * of the map div │ │ │ │ │ - */ │ │ │ │ │ - getCurrentSize: function() { │ │ │ │ │ - │ │ │ │ │ - var size = new OpenLayers.Size(this.div.clientWidth, │ │ │ │ │ - this.div.clientHeight); │ │ │ │ │ - │ │ │ │ │ - if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) { │ │ │ │ │ - size.w = this.div.offsetWidth; │ │ │ │ │ - size.h = this.div.offsetHeight; │ │ │ │ │ - } │ │ │ │ │ - if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) { │ │ │ │ │ - size.w = parseInt(this.div.style.width); │ │ │ │ │ - size.h = parseInt(this.div.style.height); │ │ │ │ │ - } │ │ │ │ │ - return size; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: calculateBounds │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * center - {} Default is this.getCenter() │ │ │ │ │ - * resolution - {float} Default is this.getResolution() │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} A bounds based on resolution, center, and │ │ │ │ │ - * current mapsize. │ │ │ │ │ - */ │ │ │ │ │ - calculateBounds: function(center, resolution) { │ │ │ │ │ - │ │ │ │ │ - var extent = null; │ │ │ │ │ - │ │ │ │ │ - if (center == null) { │ │ │ │ │ - center = this.getCachedCenter(); │ │ │ │ │ - } │ │ │ │ │ - if (resolution == null) { │ │ │ │ │ - resolution = this.getResolution(); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if ((center != null) && (resolution != null)) { │ │ │ │ │ - var halfWDeg = (this.size.w * resolution) / 2; │ │ │ │ │ - var halfHDeg = (this.size.h * resolution) / 2; │ │ │ │ │ - │ │ │ │ │ - extent = new OpenLayers.Bounds(center.lon - halfWDeg, │ │ │ │ │ - center.lat - halfHDeg, │ │ │ │ │ - center.lon + halfWDeg, │ │ │ │ │ - center.lat + halfHDeg); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - return extent; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ - /********************************************************/ │ │ │ │ │ - /* */ │ │ │ │ │ - /* Zoom, Center, Pan Functions */ │ │ │ │ │ - /* */ │ │ │ │ │ - /* The following functions handle the validation, */ │ │ │ │ │ - /* getting and setting of the Zoom Level and Center */ │ │ │ │ │ - /* as well as the panning of the Map */ │ │ │ │ │ - /* */ │ │ │ │ │ - /********************************************************/ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getCenter │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - getCenter: function() { │ │ │ │ │ - var center = null; │ │ │ │ │ - var cachedCenter = this.getCachedCenter(); │ │ │ │ │ - if (cachedCenter) { │ │ │ │ │ - center = cachedCenter.clone(); │ │ │ │ │ - } │ │ │ │ │ - return center; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: getCachedCenter │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - getCachedCenter: function() { │ │ │ │ │ - if (!this.center && this.size) { │ │ │ │ │ - this.center = this.getLonLatFromViewPortPx({ │ │ │ │ │ - x: this.size.w / 2, │ │ │ │ │ - y: this.size.h / 2 │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ - return this.center; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getZoom │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Integer} │ │ │ │ │ + * APIMethod: getZoom │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Integer} │ │ │ │ │ */ │ │ │ │ │ getZoom: function() { │ │ │ │ │ return this.zoom; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ * APIMethod: pan │ │ │ │ │ @@ -13114,1631 +9457,1815 @@ │ │ │ │ │ OpenLayers.Map.TILE_WIDTH = 256; │ │ │ │ │ /** │ │ │ │ │ * Constant: TILE_HEIGHT │ │ │ │ │ * {Integer} 256 Default tile height (unless otherwise specified) │ │ │ │ │ */ │ │ │ │ │ OpenLayers.Map.TILE_HEIGHT = 256; │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Layer.js │ │ │ │ │ + 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 │ │ │ │ │ - * @requires OpenLayers/Map.js │ │ │ │ │ - * @requires OpenLayers/Projection.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Layer │ │ │ │ │ + * 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.Layer = OpenLayers.Class({ │ │ │ │ │ +OpenLayers.Renderer = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: id │ │ │ │ │ - * {String} │ │ │ │ │ + /** │ │ │ │ │ + * Property: container │ │ │ │ │ + * {DOMElement} │ │ │ │ │ */ │ │ │ │ │ - id: null, │ │ │ │ │ + container: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: name │ │ │ │ │ - * {String} │ │ │ │ │ + /** │ │ │ │ │ + * Property: root │ │ │ │ │ + * {DOMElement} │ │ │ │ │ */ │ │ │ │ │ - name: null, │ │ │ │ │ + root: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: div │ │ │ │ │ - * {DOMElement} │ │ │ │ │ + * Property: extent │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - div: null, │ │ │ │ │ + extent: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: opacity │ │ │ │ │ - * {Float} The layer's opacity. Float number between 0.0 and 1.0. Default │ │ │ │ │ - * is 1. │ │ │ │ │ + * 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. │ │ │ │ │ */ │ │ │ │ │ - opacity: 1, │ │ │ │ │ + locked: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: size │ │ │ │ │ + * {} │ │ │ │ │ + */ │ │ │ │ │ + size: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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: resolution │ │ │ │ │ + * {Float} cache of current map resolution │ │ │ │ │ */ │ │ │ │ │ - alwaysInRange: null, │ │ │ │ │ + resolution: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constant: RESOLUTION_PROPERTIES │ │ │ │ │ - * {Array} The properties that are used for calculating resolutions │ │ │ │ │ - * information. │ │ │ │ │ + * Property: map │ │ │ │ │ + * {} Reference to the map -- this is set in Vector's setMap() │ │ │ │ │ */ │ │ │ │ │ - RESOLUTION_PROPERTIES: [ │ │ │ │ │ - 'scales', 'resolutions', │ │ │ │ │ - 'maxScale', 'minScale', │ │ │ │ │ - 'maxResolution', 'minResolution', │ │ │ │ │ - 'numZoomLevels', 'maxZoomLevel' │ │ │ │ │ - ], │ │ │ │ │ + map: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: 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 ). 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: featureDx │ │ │ │ │ + * {Number} Feature offset in x direction. Will be calculated for and │ │ │ │ │ + * applied to the current feature while rendering (see │ │ │ │ │ + * ). │ │ │ │ │ */ │ │ │ │ │ - events: null, │ │ │ │ │ + featureDx: 0, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: map │ │ │ │ │ - * {} This variable is set when the layer is added to │ │ │ │ │ - * the map, via the accessor function setMap(). │ │ │ │ │ + * Constructor: OpenLayers.Renderer │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * containerID - {} │ │ │ │ │ + * options - {Object} options for this renderer. See sublcasses for │ │ │ │ │ + * supported options. │ │ │ │ │ */ │ │ │ │ │ - map: null, │ │ │ │ │ + initialize: function(containerID, options) { │ │ │ │ │ + this.container = OpenLayers.Util.getElement(containerID); │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ │ - * {Boolean} Whether or not the layer is a base layer. This should be set │ │ │ │ │ - * individually by all subclasses. Default is false │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ */ │ │ │ │ │ - isBaseLayer: false, │ │ │ │ │ + destroy: function() { │ │ │ │ │ + this.container = null; │ │ │ │ │ + this.extent = null; │ │ │ │ │ + this.size = null; │ │ │ │ │ + this.resolution = null; │ │ │ │ │ + this.map = null; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * APIMethod: supported │ │ │ │ │ + * This should be overridden by specific subclasses │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Whether or not the browser supports the renderer class │ │ │ │ │ */ │ │ │ │ │ - displayInLayerSwitcher: true, │ │ │ │ │ + supported: function() { │ │ │ │ │ + return false; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: visibility │ │ │ │ │ - * {Boolean} The layer should be displayed in the map. Default is 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 - {} │ │ │ │ │ + * 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. │ │ │ │ │ */ │ │ │ │ │ - visibility: true, │ │ │ │ │ + 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; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: attribution │ │ │ │ │ - * {String} Attribution string, displayed when an │ │ │ │ │ - * has been added to the map. │ │ │ │ │ + * 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 - {} │ │ │ │ │ */ │ │ │ │ │ - attribution: null, │ │ │ │ │ + setSize: function(size) { │ │ │ │ │ + this.size = size.clone(); │ │ │ │ │ + this.resolution = null; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: inRange │ │ │ │ │ - * {Boolean} The current map resolution is within the layer's min/max │ │ │ │ │ - * range. This is set in whenever the zoom │ │ │ │ │ - * changes. │ │ │ │ │ + * Method: getResolution │ │ │ │ │ + * Uses cached copy of resolution if available to minimize computing │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} The current map's resolution │ │ │ │ │ */ │ │ │ │ │ - inRange: false, │ │ │ │ │ + getResolution: function() { │ │ │ │ │ + this.resolution = this.resolution || this.map.getResolution(); │ │ │ │ │ + return this.resolution; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Propery: imageSize │ │ │ │ │ - * {} For layers with a gutter, the image is larger than │ │ │ │ │ - * the tile by twice the gutter in each dimension. │ │ │ │ │ + * 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 │ │ │ │ │ */ │ │ │ │ │ - imageSize: null, │ │ │ │ │ + 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) { │ │ │ │ │ │ │ │ │ │ - // OPTIONS │ │ │ │ │ + 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; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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. │ │ │ │ │ + /** │ │ │ │ │ + * 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 │ │ │ │ │ */ │ │ │ │ │ - options: null, │ │ │ │ │ + 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; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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. │ │ │ │ │ + /** │ │ │ │ │ + * 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 - {} │ │ │ │ │ */ │ │ │ │ │ - eventListeners: null, │ │ │ │ │ + drawGeometry: function(geometry, style, featureId) {}, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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: drawText │ │ │ │ │ + * Function for drawing text labels. │ │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * featureId - {String} │ │ │ │ │ + * style - │ │ │ │ │ + * location - {} │ │ │ │ │ */ │ │ │ │ │ - gutter: 0, │ │ │ │ │ + drawText: function(featureId, style, location) {}, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: projection │ │ │ │ │ - * {} or {} 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 object; │ │ │ │ │ - * if a string is passed, will be converted to an object when │ │ │ │ │ - * the layer is added to the map. │ │ │ │ │ + * Method: removeText │ │ │ │ │ + * Function for removing text labels. │ │ │ │ │ + * This method is only called by the renderer itself. │ │ │ │ │ * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * featureId - {String} │ │ │ │ │ */ │ │ │ │ │ - projection: null, │ │ │ │ │ + removeText: function(featureId) {}, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * Method: clear │ │ │ │ │ + * Clear all vectors from the renderer. │ │ │ │ │ + * virtual function. │ │ │ │ │ */ │ │ │ │ │ - units: null, │ │ │ │ │ + clear: function() {}, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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 instead wherever possible. │ │ │ │ │ + * 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. │ │ │ │ │ */ │ │ │ │ │ - scales: null, │ │ │ │ │ + getFeatureIdFromEvent: function(evt) {}, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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.). │ │ │ │ │ + * Method: eraseFeatures │ │ │ │ │ + * This is called by the layer to erase features │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * features - {Array()} │ │ │ │ │ */ │ │ │ │ │ - resolutions: null, │ │ │ │ │ + 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); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: maxExtent │ │ │ │ │ - * {|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. │ │ │ │ │ + * Method: eraseGeometry │ │ │ │ │ + * Remove a geometry from the renderer (by id). │ │ │ │ │ + * virtual function. │ │ │ │ │ * │ │ │ │ │ - * The center of these bounds will not stray outside │ │ │ │ │ - * of the viewport extent during panning. In addition, if │ │ │ │ │ - * is set to false, data will not be │ │ │ │ │ - * requested that falls completely outside of these bounds. │ │ │ │ │ + * Parameters: │ │ │ │ │ + * geometry - {} │ │ │ │ │ + * featureId - {String} │ │ │ │ │ */ │ │ │ │ │ - maxExtent: null, │ │ │ │ │ + eraseGeometry: function(geometry, featureId) {}, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: minExtent │ │ │ │ │ - * {|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. │ │ │ │ │ + * 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 │ │ │ │ │ */ │ │ │ │ │ - minExtent: null, │ │ │ │ │ + moveRoot: function(renderer) {}, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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 │ │ │ │ │ - * and displaying the whole world. │ │ │ │ │ + * 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. │ │ │ │ │ */ │ │ │ │ │ - maxResolution: null, │ │ │ │ │ + getRenderLayerId: function() { │ │ │ │ │ + return this.container.id; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: minResolution │ │ │ │ │ - * {Float} │ │ │ │ │ + * Method: applyDefaultSymbolizer │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * symbolizer - {Object} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Object} │ │ │ │ │ */ │ │ │ │ │ - minResolution: null, │ │ │ │ │ + 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; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: numZoomLevels │ │ │ │ │ - * {Integer} │ │ │ │ │ + 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/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 │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - numZoomLevels: null, │ │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: minScale │ │ │ │ │ - * {Float} │ │ │ │ │ + /** │ │ │ │ │ + * Property: id │ │ │ │ │ + * {String} │ │ │ │ │ */ │ │ │ │ │ - minScale: null, │ │ │ │ │ + id: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: maxScale │ │ │ │ │ - * {Float} │ │ │ │ │ + /** │ │ │ │ │ + * Property: lonlat │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - maxScale: null, │ │ │ │ │ + lonlat: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: displayOutsideMaxExtent │ │ │ │ │ - * {Boolean} Request map tiles that are completely outside of the max │ │ │ │ │ - * extent for this layer. Defaults to false. │ │ │ │ │ + /** │ │ │ │ │ + * Property: data │ │ │ │ │ + * {Object} │ │ │ │ │ */ │ │ │ │ │ - displayOutsideMaxExtent: false, │ │ │ │ │ + data: 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. │ │ │ │ │ + /** │ │ │ │ │ + * Property: marker │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - wrapDateLine: false, │ │ │ │ │ + marker: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: metadata │ │ │ │ │ - * {Object} This object can be used to store additional information on a │ │ │ │ │ - * layer object. │ │ │ │ │ + * APIProperty: popupClass │ │ │ │ │ + * {} The class which will be used to instantiate │ │ │ │ │ + * a new Popup. Default is . │ │ │ │ │ */ │ │ │ │ │ - metadata: null, │ │ │ │ │ + popupClass: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Layer │ │ │ │ │ + /** │ │ │ │ │ + * Property: popup │ │ │ │ │ + * {} │ │ │ │ │ + */ │ │ │ │ │ + popup: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Feature │ │ │ │ │ + * Constructor for features. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * name - {String} The layer name │ │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ │ + * layer - {} │ │ │ │ │ + * lonlat - {} │ │ │ │ │ + * data - {Object} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - 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 + "_"); │ │ │ │ │ + initialize: function(layer, lonlat, data) { │ │ │ │ │ + this.layer = layer; │ │ │ │ │ + this.lonlat = lonlat; │ │ │ │ │ + this.data = (data != null) ? data : {}; │ │ │ │ │ + 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"; │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroy │ │ │ │ │ + * nullify references to prevent circular references and memory leaks │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ │ │ │ │ │ - this.events = new OpenLayers.Events(this, this.div); │ │ │ │ │ - if (this.eventListeners instanceof Object) { │ │ │ │ │ - this.events.on(this.eventListeners); │ │ │ │ │ + //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: 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. │ │ │ │ │ + * Method: onScreen │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Whether or not the feature is currently visible on screen │ │ │ │ │ + * (based on its 'lonlat' property) │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ + onScreen: function() { │ │ │ │ │ │ │ │ │ │ - if (this.events) { │ │ │ │ │ - if (this.eventListeners) { │ │ │ │ │ - this.events.un(this.eventListeners); │ │ │ │ │ - } │ │ │ │ │ - this.events.destroy(); │ │ │ │ │ + var onScreen = false; │ │ │ │ │ + if ((this.layer != null) && (this.layer.map != null)) { │ │ │ │ │ + var screenBounds = this.layer.map.getExtent(); │ │ │ │ │ + onScreen = screenBounds.containsLonLat(this.lonlat); │ │ │ │ │ } │ │ │ │ │ - this.eventListeners = null; │ │ │ │ │ - this.events = null; │ │ │ │ │ + return onScreen; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ /** │ │ │ │ │ - * Method: clone │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * obj - {} The layer to be cloned │ │ │ │ │ + * Method: createMarker │ │ │ │ │ + * Based on the data associated with the Feature, create and return a marker object. │ │ │ │ │ * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} An exact clone of this │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} 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 │ │ │ │ │ + * │ │ │ │ │ */ │ │ │ │ │ - clone: function(obj) { │ │ │ │ │ + createMarker: function() { │ │ │ │ │ │ │ │ │ │ - if (obj == null) { │ │ │ │ │ - obj = new OpenLayers.Layer(this.name, this.getOptions()); │ │ │ │ │ + if (this.lonlat != null) { │ │ │ │ │ + this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon); │ │ │ │ │ } │ │ │ │ │ + return this.marker; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // 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: 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: 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: 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: │ │ │ │ │ - * {Object} the of the layer, representing the current state. │ │ │ │ │ + * {} 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 . │ │ │ │ │ + * │ │ │ │ │ */ │ │ │ │ │ - getOptions: function() { │ │ │ │ │ - var options = {}; │ │ │ │ │ - for (var o in this.options) { │ │ │ │ │ - options[o] = this[o]; │ │ │ │ │ + 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 options; │ │ │ │ │ + return this.popup; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: setName │ │ │ │ │ - * Sets the new layer name for this layer. Can trigger a changelayer event │ │ │ │ │ - * on the map. │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroyPopup │ │ │ │ │ + * Destroys the popup created via createPopup. │ │ │ │ │ * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * newName - {String} The new name. │ │ │ │ │ + * As with the marker, if user overrides the createPopup() function, s/he │ │ │ │ │ + * should also be able to override the destruction │ │ │ │ │ */ │ │ │ │ │ - setName: function(newName) { │ │ │ │ │ - if (newName != this.name) { │ │ │ │ │ - this.name = newName; │ │ │ │ │ - if (this.map != null) { │ │ │ │ │ - this.map.events.triggerEvent("changelayer", { │ │ │ │ │ - layer: this, │ │ │ │ │ - property: "name" │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ + destroyPopup: function() { │ │ │ │ │ + if (this.popup) { │ │ │ │ │ + this.popup.feature = null; │ │ │ │ │ + this.popup.destroy(); │ │ │ │ │ + this.popup = null; │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: addOptions │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * newOptions - {Object} │ │ │ │ │ - * reinitialize - {Boolean} If set to true, and if resolution options of the │ │ │ │ │ - * current baseLayer were changed, the map will be recentered to make │ │ │ │ │ - * sure that it is displayed with a valid resolution, and a │ │ │ │ │ - * changebaselayer event will be triggered. │ │ │ │ │ - */ │ │ │ │ │ - addOptions: function(newOptions, reinitialize) { │ │ │ │ │ + CLASS_NAME: "OpenLayers.Feature" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Feature/Vector.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - if (this.options == null) { │ │ │ │ │ - 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 (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); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ +// TRASH THIS │ │ │ │ │ +OpenLayers.State = { │ │ │ │ │ + /** states */ │ │ │ │ │ + UNKNOWN: 'Unknown', │ │ │ │ │ + INSERT: 'Insert', │ │ │ │ │ + UPDATE: 'Update', │ │ │ │ │ + DELETE: 'Delete' │ │ │ │ │ +}; │ │ │ │ │ │ │ │ │ │ - // update our copy for clone │ │ │ │ │ - OpenLayers.Util.extend(this.options, newOptions); │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Feature.js │ │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - // add new options to this │ │ │ │ │ - OpenLayers.Util.extend(this, newOptions); │ │ │ │ │ +/** │ │ │ │ │ + * 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 │ │ │ │ │ + * objects. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, { │ │ │ │ │ │ │ │ │ │ - // 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(); │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Property: fid │ │ │ │ │ + * {String} │ │ │ │ │ + */ │ │ │ │ │ + fid: null, │ │ │ │ │ │ │ │ │ │ - // 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) { │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: geometry │ │ │ │ │ + * {} │ │ │ │ │ + */ │ │ │ │ │ + geometry: null, │ │ │ │ │ │ │ │ │ │ - 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; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: attributes │ │ │ │ │ + * {Object} This object holds arbitrary, serializable properties that │ │ │ │ │ + * describe the feature. │ │ │ │ │ + */ │ │ │ │ │ + attributes: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: onMapResize │ │ │ │ │ - * This function can be implemented by subclasses │ │ │ │ │ + * Property: bounds │ │ │ │ │ + * {} The box bounding that feature's geometry, that │ │ │ │ │ + * property can be set by an object when │ │ │ │ │ + * deserializing the feature, so in most cases it represents an │ │ │ │ │ + * information set by the server. │ │ │ │ │ */ │ │ │ │ │ - onMapResize: function() { │ │ │ │ │ - //this function can be implemented by subclasses │ │ │ │ │ - }, │ │ │ │ │ + bounds: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: redraw │ │ │ │ │ - * Redraws the layer. Returns true if the layer was redrawn, false if not. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The layer was redrawn. │ │ │ │ │ + /** │ │ │ │ │ + * Property: state │ │ │ │ │ + * {String} │ │ │ │ │ */ │ │ │ │ │ - redraw: function() { │ │ │ │ │ - var redrawn = false; │ │ │ │ │ - if (this.map) { │ │ │ │ │ + state: null, │ │ │ │ │ │ │ │ │ │ - // min/max Range may have changed │ │ │ │ │ - this.inRange = this.calculateInRange(); │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: style │ │ │ │ │ + * {Object} │ │ │ │ │ + */ │ │ │ │ │ + style: null, │ │ │ │ │ │ │ │ │ │ - // map's center might not yet be set │ │ │ │ │ - var extent = this.getExtent(); │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: url │ │ │ │ │ + * {String} If this property is set it will be taken into account by │ │ │ │ │ + * {} when upadting or deleting the feature. │ │ │ │ │ + */ │ │ │ │ │ + url: null, │ │ │ │ │ │ │ │ │ │ - if (extent && this.inRange && this.visibility) { │ │ │ │ │ - var zoomChanged = true; │ │ │ │ │ - this.moveTo(extent, zoomChanged, false); │ │ │ │ │ - this.events.triggerEvent("moveend", { │ │ │ │ │ - "zoomChanged": zoomChanged │ │ │ │ │ - }); │ │ │ │ │ - redrawn = true; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - return redrawn; │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * Property: renderIntent │ │ │ │ │ + * {String} rendering intent currently being used │ │ │ │ │ + */ │ │ │ │ │ + renderIntent: "default", │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: moveTo │ │ │ │ │ + * 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 , and written by │ │ │ │ │ + * , 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 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: │ │ │ │ │ - * bounds - {} │ │ │ │ │ - * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to │ │ │ │ │ - * do some init work in that case. │ │ │ │ │ - * dragging - {Boolean} │ │ │ │ │ + * geometry - {} The geometry that this feature │ │ │ │ │ + * represents. │ │ │ │ │ + * attributes - {Object} An optional object that will be mapped to the │ │ │ │ │ + * property. │ │ │ │ │ + * style - {Object} An optional style object. │ │ │ │ │ */ │ │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ │ - var display = this.visibility; │ │ │ │ │ - if (!this.isBaseLayer) { │ │ │ │ │ - display = display && this.inRange; │ │ │ │ │ + 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.display(display); │ │ │ │ │ + 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: moveByPx │ │ │ │ │ - * Move the layer based on pixel vector. To be implemented by subclasses. │ │ │ │ │ + * Method: clone │ │ │ │ │ + * Create a clone of this vector feature. Does not set any non-standard │ │ │ │ │ + * properties. │ │ │ │ │ * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * dx - {Number} The x coord of the displacement vector. │ │ │ │ │ - * dy - {Number} The y coord of the displacement vector. │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} An exact clone of this vector feature. │ │ │ │ │ */ │ │ │ │ │ - moveByPx: function(dx, dy) {}, │ │ │ │ │ + clone: function() { │ │ │ │ │ + return new OpenLayers.Feature.Vector( │ │ │ │ │ + this.geometry ? this.geometry.clone() : null, │ │ │ │ │ + this.attributes, │ │ │ │ │ + this.style); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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: 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: │ │ │ │ │ - * map - {} │ │ │ │ │ + * 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). │ │ │ │ │ */ │ │ │ │ │ - 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"; │ │ │ │ │ + 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); │ │ │ │ │ } │ │ │ │ │ - │ │ │ │ │ - // deal with gutters │ │ │ │ │ - this.setTileSize(); │ │ │ │ │ } │ │ │ │ │ + return onScreen; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * 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. │ │ │ │ │ * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * map - {} │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The feature is currently displayed. │ │ │ │ │ */ │ │ │ │ │ - removeMap: function(map) { │ │ │ │ │ - //to be overridden by subclasses │ │ │ │ │ + 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: getImageSize │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * 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) │ │ │ │ │ + * Method: createMarker │ │ │ │ │ + * HACK - we need to decide if all vector features should be able to │ │ │ │ │ + * create markers │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {} The size that the image should be, taking into │ │ │ │ │ - * account gutters. │ │ │ │ │ + * {} For now just returns null │ │ │ │ │ */ │ │ │ │ │ - getImageSize: function(bounds) { │ │ │ │ │ - return (this.imageSize || this.tileSize); │ │ │ │ │ + createMarker: function() { │ │ │ │ │ + return null; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: setTileSize │ │ │ │ │ - * Set the tile size based on the map size. This also sets layer.imageSize │ │ │ │ │ - * or use by Tile.Image. │ │ │ │ │ + * Method: destroyMarker │ │ │ │ │ + * HACK - we need to decide if all vector features should be able to │ │ │ │ │ + * delete markers │ │ │ │ │ * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * size - {} │ │ │ │ │ + * If user overrides the createMarker() function, s/he should be able │ │ │ │ │ + * to also specify an alternative function for destroying it │ │ │ │ │ */ │ │ │ │ │ - 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)); │ │ │ │ │ - } │ │ │ │ │ + destroyMarker: function() { │ │ │ │ │ + // pass │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: getVisibility │ │ │ │ │ + * Method: createPopup │ │ │ │ │ + * HACK - we need to decide if all vector features should be able to │ │ │ │ │ + * create popups │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Boolean} The layer should be displayed (if in range). │ │ │ │ │ + * {} For now just returns null │ │ │ │ │ */ │ │ │ │ │ - getVisibility: function() { │ │ │ │ │ - return this.visibility; │ │ │ │ │ + createPopup: function() { │ │ │ │ │ + return null; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: setVisibility │ │ │ │ │ - * Set the visibility flag for the layer and hide/show & redraw │ │ │ │ │ - * accordingly. Fire event unless otherwise specified │ │ │ │ │ + /** │ │ │ │ │ + * Method: atPoint │ │ │ │ │ + * Determins whether the feature intersects with the specified location. │ │ │ │ │ * │ │ │ │ │ - * 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: │ │ │ │ │ + * 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 │ │ │ │ │ * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * visibility - {Boolean} Whether or not to display the layer (if in range) │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Whether or not the feature is at the specified location │ │ │ │ │ */ │ │ │ │ │ - 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"); │ │ │ │ │ + atPoint: function(lonlat, toleranceLon, toleranceLat) { │ │ │ │ │ + var atPoint = false; │ │ │ │ │ + if (this.geometry) { │ │ │ │ │ + atPoint = this.geometry.atPoint(lonlat, toleranceLon, │ │ │ │ │ + toleranceLat); │ │ │ │ │ } │ │ │ │ │ + return atPoint; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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} │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroyPopup │ │ │ │ │ + * HACK - we need to decide if all vector features should be able to │ │ │ │ │ + * delete popups │ │ │ │ │ */ │ │ │ │ │ - display: function(display) { │ │ │ │ │ - if (display != (this.div.style.display != "none")) { │ │ │ │ │ - this.div.style.display = (display && this.calculateInRange()) ? "block" : "none"; │ │ │ │ │ - } │ │ │ │ │ + destroyPopup: function() { │ │ │ │ │ + // pass │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * Method: move │ │ │ │ │ + * Moves the feature and redraws it at its new location │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * location - { or } the │ │ │ │ │ + * location to which to move the feature. │ │ │ │ │ */ │ │ │ │ │ - calculateInRange: function() { │ │ │ │ │ - var inRange = false; │ │ │ │ │ + move: function(location) { │ │ │ │ │ │ │ │ │ │ - if (this.alwaysInRange) { │ │ │ │ │ - inRange = true; │ │ │ │ │ + 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 { │ │ │ │ │ - if (this.map) { │ │ │ │ │ - var resolution = this.map.getResolution(); │ │ │ │ │ - inRange = ((resolution >= this.minResolution) && │ │ │ │ │ - (resolution <= this.maxResolution)); │ │ │ │ │ - } │ │ │ │ │ + pixel = location; │ │ │ │ │ } │ │ │ │ │ - return inRange; │ │ │ │ │ + │ │ │ │ │ + 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; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: setIsBaseLayer │ │ │ │ │ - * │ │ │ │ │ + /** │ │ │ │ │ + * Method: toState │ │ │ │ │ + * Sets the new state │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * isBaseLayer - {Boolean} │ │ │ │ │ + * state - {String} │ │ │ │ │ */ │ │ │ │ │ - setIsBaseLayer: function(isBaseLayer) { │ │ │ │ │ - if (isBaseLayer != this.isBaseLayer) { │ │ │ │ │ - this.isBaseLayer = isBaseLayer; │ │ │ │ │ - if (this.map != null) { │ │ │ │ │ - this.map.events.triggerEvent("changebaselayer", { │ │ │ │ │ - layer: this │ │ │ │ │ - }); │ │ │ │ │ + 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; │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /********************************************************/ │ │ │ │ │ - /* */ │ │ │ │ │ - /* Baselayer Functions */ │ │ │ │ │ - /* */ │ │ │ │ │ - /********************************************************/ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Feature.Vector" │ │ │ │ │ +}); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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! │ │ │ │ │ +/** │ │ │ │ │ + * 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 │ │ │ │ │ │ │ │ │ │ - var i, len, p; │ │ │ │ │ - var props = {}, │ │ │ │ │ - alwaysInRange = true; │ │ │ │ │ + }, │ │ │ │ │ + '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 │ │ │ │ │ │ │ │ │ │ - // 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; │ │ │ │ │ - } │ │ │ │ │ + }, │ │ │ │ │ + 'delete': { │ │ │ │ │ + display: "none" │ │ │ │ │ + } │ │ │ │ │ +}; │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Style.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - // if we don't have resolutions then attempt to derive them from scales │ │ │ │ │ - if (props.resolutions == null) { │ │ │ │ │ - props.resolutions = this.resolutionsFromScales(props.scales); │ │ │ │ │ - } │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of 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 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); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ │ + * @requires OpenLayers/Feature/Vector.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - // ok, we new need to set properties in the instance │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Style │ │ │ │ │ + * This class represents a UserStyle obtained │ │ │ │ │ + * from a SLD, containing styling rules. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Style = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ - // 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); │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Property: id │ │ │ │ │ + * {String} A unique id for this session. │ │ │ │ │ + */ │ │ │ │ │ + id: null, │ │ │ │ │ │ │ │ │ │ - // 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); │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: name │ │ │ │ │ + * {String} │ │ │ │ │ + */ │ │ │ │ │ + name: null, │ │ │ │ │ │ │ │ │ │ - if (props.resolutions) { │ │ │ │ │ + /** │ │ │ │ │ + * Property: title │ │ │ │ │ + * {String} Title of this style (set if included in SLD) │ │ │ │ │ + */ │ │ │ │ │ + title: null, │ │ │ │ │ │ │ │ │ │ - //sort resolutions array descendingly │ │ │ │ │ - props.resolutions.sort(function(a, b) { │ │ │ │ │ - return (b - a); │ │ │ │ │ - }); │ │ │ │ │ + /** │ │ │ │ │ + * Property: description │ │ │ │ │ + * {String} Description of this style (set if abstract is included in SLD) │ │ │ │ │ + */ │ │ │ │ │ + description: null, │ │ │ │ │ │ │ │ │ │ - // if we still don't have a maxResolution get it from the │ │ │ │ │ - // resolutions array │ │ │ │ │ - if (!maxResolution) { │ │ │ │ │ - maxResolution = props.resolutions[0]; │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: layerName │ │ │ │ │ + * {} name of the layer that this style belongs to, usually │ │ │ │ │ + * according to the NamedLayer attribute of an SLD document. │ │ │ │ │ + */ │ │ │ │ │ + layerName: null, │ │ │ │ │ │ │ │ │ │ - // 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]; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: isDefault │ │ │ │ │ + * {Boolean} │ │ │ │ │ + */ │ │ │ │ │ + isDefault: false, │ │ │ │ │ │ │ │ │ │ - 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); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * Property: rules │ │ │ │ │ + * {Array()} │ │ │ │ │ + */ │ │ │ │ │ + rules: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: resolutionsFromScales │ │ │ │ │ - * Derive resolutions from scales. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * scales - {Array(Number)} Scales │ │ │ │ │ - * │ │ │ │ │ - * Returns │ │ │ │ │ - * {Array(Number)} Resolutions │ │ │ │ │ + * 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 │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ - }, │ │ │ │ │ + context: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: calculateResolutions │ │ │ │ │ - * Calculate resolutions based on the provided properties. │ │ │ │ │ + * 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 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 will extend the symbolizer │ │ │ │ │ + * of every rule. Properties of the 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: │ │ │ │ │ - * props - {Object} Properties │ │ │ │ │ + * 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()} List of rules to be added to the │ │ │ │ │ + * style. │ │ │ │ │ + * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Array({Number})} Array of resolutions. │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - calculateResolutions: function(props) { │ │ │ │ │ - │ │ │ │ │ - var viewSize, wRes, hRes; │ │ │ │ │ + initialize: function(style, options) { │ │ │ │ │ │ │ │ │ │ - // 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); │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + this.rules = []; │ │ │ │ │ + if (options && options.rules) { │ │ │ │ │ + this.addRules(options.rules); │ │ │ │ │ } │ │ │ │ │ │ │ │ │ │ - // 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); │ │ │ │ │ - } │ │ │ │ │ + // use the default style from OpenLayers.Feature.Vector if no style │ │ │ │ │ + // was given in the constructor │ │ │ │ │ + this.setDefaultStyle(style || │ │ │ │ │ + OpenLayers.Feature.Vector.style["default"]); │ │ │ │ │ │ │ │ │ │ - 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 │ │ │ │ │ - ); │ │ │ │ │ - } │ │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // 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; │ │ │ │ │ + /** │ │ │ │ │ + * 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; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // are we able to calculate resolutions? │ │ │ │ │ - if (typeof numZoomLevels !== "number" || numZoomLevels <= 0 || │ │ │ │ │ - (typeof maxResolution !== "number" && │ │ │ │ │ - typeof minResolution !== "number")) { │ │ │ │ │ - return; │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Method: createSymbolizer │ │ │ │ │ + * creates a style by applying all feature-dependent rules to the base │ │ │ │ │ + * style. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * 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); │ │ │ │ │ │ │ │ │ │ - // now we have numZoomLevels and at least one of maxResolution │ │ │ │ │ - // or minResolution, we can populate the resolutions array │ │ │ │ │ + var rules = this.rules; │ │ │ │ │ │ │ │ │ │ - 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 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); │ │ │ │ │ │ │ │ │ │ - var i; │ │ │ │ │ - if (typeof maxResolution === "number") { │ │ │ │ │ - for (i = 0; i < numZoomLevels; i++) { │ │ │ │ │ - resolutions[i] = maxResolution / Math.pow(base, i); │ │ │ │ │ + if (applies) { │ │ │ │ │ + if (rule instanceof OpenLayers.Rule && rule.elseFilter) { │ │ │ │ │ + elseRules.push(rule); │ │ │ │ │ + } else { │ │ │ │ │ + appliedRules = true; │ │ │ │ │ + this.applySymbolizer(rule, style, feature); │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ - } else { │ │ │ │ │ - for (i = 0; i < numZoomLevels; i++) { │ │ │ │ │ - resolutions[numZoomLevels - 1 - i] = │ │ │ │ │ - minResolution * Math.pow(base, i); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // 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); │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ │ │ │ │ │ - return resolutions; │ │ │ │ │ - }, │ │ │ │ │ + // don't display if there were rules but none applied │ │ │ │ │ + if (rules.length > 0 && appliedRules == false) { │ │ │ │ │ + style.display = "none"; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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); │ │ │ │ │ - }, │ │ │ │ │ + if (style.label != null && typeof style.label !== "string") { │ │ │ │ │ + style.label = String(style.label); │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getExtent │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} 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 - {} │ │ │ │ │ - * 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 - {} │ │ │ │ │ + * style - {Object} │ │ │ │ │ + * feature - {} │ │ │ │ │ * │ │ │ │ │ * 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: │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - 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 │ │ │ │ │ + * . │ │ │ │ │ * │ │ │ │ │ * 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 - {|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: │ │ │ │ │ - * {} An OpenLayers.LonLat which is the passed-in │ │ │ │ │ - * view port , 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 - {|Object} An OpenLayers.LonLat or │ │ │ │ │ - * an object with a 'lon' │ │ │ │ │ - * and 'lat' properties. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} An which is the passed-in │ │ │ │ │ - * lonlat translated into view port pixels. │ │ │ │ │ + * rules - {Array()} │ │ │ │ │ */ │ │ │ │ │ - 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 - {} │ │ │ │ │ * │ │ │ │ │ - * 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 - {} │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} 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 - {} optional feature to pass to │ │ │ │ │ + * 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/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/Layer.js │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Style.js │ │ │ │ │ + * @requires OpenLayers/Feature/Vector.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Layer.HTTPRequest │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * Class: OpenLayers.StyleMap │ │ │ │ │ */ │ │ │ │ │ -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, │ │ │ │ │ +OpenLayers.StyleMap = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: params │ │ │ │ │ - * {Object} Hashtable of key/value parameters │ │ │ │ │ + /** │ │ │ │ │ + * Property: styles │ │ │ │ │ + * {Object} Hash of {}, keyed by names of well known │ │ │ │ │ + * rendering intents (e.g. "default", "temporary", "select", "delete"). │ │ │ │ │ */ │ │ │ │ │ - params: null, │ │ │ │ │ + styles: 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: 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. │ │ │ │ │ */ │ │ │ │ │ - reproject: false, │ │ │ │ │ + extendDefault: true, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Layer.HTTPRequest │ │ │ │ │ + * Constructor: OpenLayers.StyleMap │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * name - {String} │ │ │ │ │ - * url - {Array(String) or String} │ │ │ │ │ - * params - {Object} │ │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ │ + * 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(name, url, params, options) { │ │ │ │ │ - OpenLayers.Layer.prototype.initialize.apply(this, [name, options]); │ │ │ │ │ - this.url = url; │ │ │ │ │ - if (!this.params) { │ │ │ │ │ - this.params = OpenLayers.Util.extend({}, params); │ │ │ │ │ + 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); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ + * Method: destroy │ │ │ │ │ */ │ │ │ │ │ destroy: function() { │ │ │ │ │ - this.url = null; │ │ │ │ │ - this.params = null; │ │ │ │ │ - OpenLayers.Layer.prototype.destroy.apply(this, arguments); │ │ │ │ │ + for (var key in this.styles) { │ │ │ │ │ + this.styles[key].destroy(); │ │ │ │ │ + } │ │ │ │ │ + this.styles = null; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: clone │ │ │ │ │ + * Method: createSymbolizer │ │ │ │ │ + * Creates the symbolizer for a feature for a render intent. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * obj - {Object} │ │ │ │ │ + * 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: │ │ │ │ │ - * {} An exact clone of this │ │ │ │ │ - * │ │ │ │ │ + * {Object} symbolizer hash │ │ │ │ │ */ │ │ │ │ │ - clone: function(obj) { │ │ │ │ │ - │ │ │ │ │ - if (obj == null) { │ │ │ │ │ - obj = new OpenLayers.Layer.HTTPRequest(this.name, │ │ │ │ │ - this.url, │ │ │ │ │ - this.params, │ │ │ │ │ - this.getOptions()); │ │ │ │ │ + createSymbolizer: function(feature, intent) { │ │ │ │ │ + if (!feature) { │ │ │ │ │ + feature = new OpenLayers.Feature.Vector(); │ │ │ │ │ } │ │ │ │ │ - │ │ │ │ │ - //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" │ │ │ │ │ - }); │ │ │ │ │ + if (!this.styles[intent]) { │ │ │ │ │ + intent = "default"; │ │ │ │ │ } │ │ │ │ │ - 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, []); │ │ │ │ │ + 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: 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" │ │ │ │ │ + * 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 │ │ │ │ │ * │ │ │ │ │ - * 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} │ │ │ │ │ + * 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 │ │ │ │ │ */ │ │ │ │ │ - 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]; │ │ │ │ │ - } │ │ │ │ │ + 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 │ │ │ │ │ + }) │ │ │ │ │ + })); │ │ │ │ │ } │ │ │ │ │ - paramsString = OpenLayers.Util.getParameterString(allParams); │ │ │ │ │ - │ │ │ │ │ - return OpenLayers.Util.urlAppend(url, paramsString); │ │ │ │ │ + this.styles[renderIntent].addRules(rules); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.HTTPRequest" │ │ │ │ │ + CLASS_NAME: "OpenLayers.StyleMap" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ 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. │ │ │ │ │ @@ -15032,3940 +11559,785 @@ │ │ │ │ │ clear: function(draw) { │ │ │ │ │ // to be extended by subclasses │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Tile" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Tile/Image.js │ │ │ │ │ + OpenLayers/Format.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Tile.js │ │ │ │ │ - * @requires OpenLayers/Animation.js │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ * @requires OpenLayers/Util.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Tile.Image │ │ │ │ │ - * Instances of OpenLayers.Tile.Image are used to manage the image tiles │ │ │ │ │ - * used by various layers. Create a new image tile with the │ │ │ │ │ - * constructor. │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * Class: OpenLayers.Format │ │ │ │ │ + * Base class for format reading/writing a variety of formats. Subclasses │ │ │ │ │ + * of OpenLayers.Format are expected to have read and write methods. │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: events │ │ │ │ │ - * {} An events object that handles all │ │ │ │ │ - * events on the tile. │ │ │ │ │ - * │ │ │ │ │ - * Register a listener for a particular event with the following syntax: │ │ │ │ │ - * (code) │ │ │ │ │ - * tile.events.register(type, obj, listener); │ │ │ │ │ - * (end) │ │ │ │ │ - * │ │ │ │ │ - * Supported event types (in addition to the events): │ │ │ │ │ - * beforeload - Triggered before an image is prepared for loading, when the │ │ │ │ │ - * url for the image is known already. Listeners may call on │ │ │ │ │ - * the tile instance. If they do so, that image will be used and no new │ │ │ │ │ - * one will be created. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: url │ │ │ │ │ - * {String} The URL of the image being requested. No default. Filled in by │ │ │ │ │ - * layer.getURL() function. May be modified by loadstart listeners. │ │ │ │ │ - */ │ │ │ │ │ - url: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: imgDiv │ │ │ │ │ - * {HTMLImageElement} The image for this tile. │ │ │ │ │ - */ │ │ │ │ │ - imgDiv: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: frame │ │ │ │ │ - * {DOMElement} The image element is appended to the frame. Any gutter on │ │ │ │ │ - * the image will be hidden behind the frame. If no gutter is set, │ │ │ │ │ - * this will be null. │ │ │ │ │ - */ │ │ │ │ │ - frame: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: imageReloadAttempts │ │ │ │ │ - * {Integer} Attempts to load the image. │ │ │ │ │ - */ │ │ │ │ │ - imageReloadAttempts: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: layerAlphaHack │ │ │ │ │ - * {Boolean} True if the png alpha hack needs to be applied on the layer's div. │ │ │ │ │ - */ │ │ │ │ │ - layerAlphaHack: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: asyncRequestId │ │ │ │ │ - * {Integer} ID of an request to see if request is still valid. This is a │ │ │ │ │ - * number which increments by 1 for each asynchronous request. │ │ │ │ │ - */ │ │ │ │ │ - asyncRequestId: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: maxGetUrlLength │ │ │ │ │ - * {Number} If set, requests that would result in GET urls with more │ │ │ │ │ - * characters than the number provided will be made using form-encoded │ │ │ │ │ - * HTTP POST. It is good practice to avoid urls that are longer than 2048 │ │ │ │ │ - * characters. │ │ │ │ │ - * │ │ │ │ │ - * Caution: │ │ │ │ │ - * Older versions of Gecko based browsers (e.g. Firefox < 3.5) and most │ │ │ │ │ - * Opera versions do not fully support this option. On all browsers, │ │ │ │ │ - * transition effects are not supported if POST requests are used. │ │ │ │ │ - */ │ │ │ │ │ - maxGetUrlLength: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: canvasContext │ │ │ │ │ - * {CanvasRenderingContext2D} A canvas context associated with │ │ │ │ │ - * the tile image. │ │ │ │ │ - */ │ │ │ │ │ - canvasContext: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: crossOriginKeyword │ │ │ │ │ - * The value of the crossorigin keyword to use when loading images. This is │ │ │ │ │ - * only relevant when using for tiles from remote │ │ │ │ │ - * origins and should be set to either 'anonymous' or 'use-credentials' │ │ │ │ │ - * for servers that send Access-Control-Allow-Origin headers with their │ │ │ │ │ - * tiles. │ │ │ │ │ - */ │ │ │ │ │ - crossOriginKeyword: null, │ │ │ │ │ - │ │ │ │ │ - /** TBD 3.0 - reorder the parameters to the init function to remove │ │ │ │ │ - * URL. the getUrl() function on the layer gets called on │ │ │ │ │ - * each draw(), so no need to specify it here. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Tile.Image │ │ │ │ │ - * Constructor for a new instance. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * layer - {} layer that the tile will go in. │ │ │ │ │ - * position - {} │ │ │ │ │ - * bounds - {} │ │ │ │ │ - * url - {} Deprecated. Remove me in 3.0. │ │ │ │ │ - * size - {} │ │ │ │ │ - * options - {Object} │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(layer, position, bounds, url, size, options) { │ │ │ │ │ - OpenLayers.Tile.prototype.initialize.apply(this, arguments); │ │ │ │ │ - │ │ │ │ │ - this.url = url; //deprecated remove me │ │ │ │ │ - │ │ │ │ │ - this.layerAlphaHack = this.layer.alpha && OpenLayers.Util.alphaHack(); │ │ │ │ │ - │ │ │ │ │ - if (this.maxGetUrlLength != null || this.layer.gutter || this.layerAlphaHack) { │ │ │ │ │ - // only create frame if it's needed │ │ │ │ │ - this.frame = document.createElement("div"); │ │ │ │ │ - this.frame.style.position = "absolute"; │ │ │ │ │ - this.frame.style.overflow = "hidden"; │ │ │ │ │ - } │ │ │ │ │ - if (this.maxGetUrlLength != null) { │ │ │ │ │ - OpenLayers.Util.extend(this, OpenLayers.Tile.Image.IFrame); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ - * nullify references to prevent circular references and memory leaks │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - if (this.imgDiv) { │ │ │ │ │ - this.clear(); │ │ │ │ │ - this.imgDiv = null; │ │ │ │ │ - this.frame = null; │ │ │ │ │ - } │ │ │ │ │ - // don't handle async requests any more │ │ │ │ │ - this.asyncRequestId = null; │ │ │ │ │ - OpenLayers.Tile.prototype.destroy.apply(this, arguments); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: draw │ │ │ │ │ - * Check that a tile should be drawn, and draw it. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} Was a tile drawn? Or null if a beforedraw listener returned │ │ │ │ │ - * false. │ │ │ │ │ - */ │ │ │ │ │ - draw: function() { │ │ │ │ │ - var shouldDraw = OpenLayers.Tile.prototype.draw.apply(this, arguments); │ │ │ │ │ - if (shouldDraw) { │ │ │ │ │ - // The layer's reproject option is deprecated. │ │ │ │ │ - if (this.layer != this.layer.map.baseLayer && this.layer.reproject) { │ │ │ │ │ - // getBoundsFromBaseLayer is defined in deprecated.js. │ │ │ │ │ - this.bounds = this.getBoundsFromBaseLayer(this.position); │ │ │ │ │ - } │ │ │ │ │ - if (this.isLoading) { │ │ │ │ │ - //if we're already loading, send 'reload' instead of 'loadstart'. │ │ │ │ │ - this._loadEvent = "reload"; │ │ │ │ │ - } else { │ │ │ │ │ - this.isLoading = true; │ │ │ │ │ - this._loadEvent = "loadstart"; │ │ │ │ │ - } │ │ │ │ │ - this.renderTile(); │ │ │ │ │ - this.positionTile(); │ │ │ │ │ - } else if (shouldDraw === false) { │ │ │ │ │ - this.unload(); │ │ │ │ │ - } │ │ │ │ │ - return shouldDraw; │ │ │ │ │ - }, │ │ │ │ │ +OpenLayers.Format = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: renderTile │ │ │ │ │ - * Internal function to actually initialize the image tile, │ │ │ │ │ - * position it correctly, and set its url. │ │ │ │ │ + * Property: options │ │ │ │ │ + * {Object} A reference to options passed to the constructor. │ │ │ │ │ */ │ │ │ │ │ - renderTile: function() { │ │ │ │ │ - if (this.layer.async) { │ │ │ │ │ - // Asynchronous image requests call the asynchronous getURL method │ │ │ │ │ - // on the layer to fetch an image that covers 'this.bounds'. │ │ │ │ │ - var id = this.asyncRequestId = (this.asyncRequestId || 0) + 1; │ │ │ │ │ - this.layer.getURLasync(this.bounds, function(url) { │ │ │ │ │ - if (id == this.asyncRequestId) { │ │ │ │ │ - this.url = url; │ │ │ │ │ - this.initImage(); │ │ │ │ │ - } │ │ │ │ │ - }, this); │ │ │ │ │ - } else { │ │ │ │ │ - // synchronous image requests get the url immediately. │ │ │ │ │ - this.url = this.layer.getURL(this.bounds); │ │ │ │ │ - this.initImage(); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ + options: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: positionTile │ │ │ │ │ - * Using the properties currenty set on the layer, position the tile correctly. │ │ │ │ │ - * This method is used both by the async and non-async versions of the Tile.Image │ │ │ │ │ - * code. │ │ │ │ │ - */ │ │ │ │ │ - positionTile: function() { │ │ │ │ │ - var style = this.getTile().style, │ │ │ │ │ - size = this.frame ? this.size : │ │ │ │ │ - this.layer.getImageSize(this.bounds), │ │ │ │ │ - ratio = 1; │ │ │ │ │ - if (this.layer instanceof OpenLayers.Layer.Grid) { │ │ │ │ │ - ratio = this.layer.getServerResolution() / this.layer.map.getResolution(); │ │ │ │ │ - } │ │ │ │ │ - style.left = this.position.x + "px"; │ │ │ │ │ - style.top = this.position.y + "px"; │ │ │ │ │ - style.width = Math.round(ratio * size.w) + "px"; │ │ │ │ │ - style.height = Math.round(ratio * size.h) + "px"; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: clear │ │ │ │ │ - * Remove the tile from the DOM, clear it of any image related data so that │ │ │ │ │ - * it can be reused in a new location. │ │ │ │ │ + * APIProperty: externalProjection │ │ │ │ │ + * {} When passed a externalProjection and │ │ │ │ │ + * internalProjection, the format will reproject the geometries it │ │ │ │ │ + * reads or writes. The externalProjection is the projection used by │ │ │ │ │ + * the content which is passed into read or which comes out of write. │ │ │ │ │ + * In order to reproject, a projection transformation function for the │ │ │ │ │ + * specified projections must be available. This support may be │ │ │ │ │ + * provided via proj4js or via a custom transformation function. See │ │ │ │ │ + * {} for more information on │ │ │ │ │ + * custom transformations. │ │ │ │ │ */ │ │ │ │ │ - clear: function() { │ │ │ │ │ - OpenLayers.Tile.prototype.clear.apply(this, arguments); │ │ │ │ │ - var img = this.imgDiv; │ │ │ │ │ - if (img) { │ │ │ │ │ - var tile = this.getTile(); │ │ │ │ │ - if (tile.parentNode === this.layer.div) { │ │ │ │ │ - this.layer.div.removeChild(tile); │ │ │ │ │ - } │ │ │ │ │ - this.setImgSrc(); │ │ │ │ │ - if (this.layerAlphaHack === true) { │ │ │ │ │ - img.style.filter = ""; │ │ │ │ │ - } │ │ │ │ │ - OpenLayers.Element.removeClass(img, "olImageLoadError"); │ │ │ │ │ - } │ │ │ │ │ - this.canvasContext = null; │ │ │ │ │ - }, │ │ │ │ │ + externalProjection: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getImage │ │ │ │ │ - * Returns or creates and returns the tile image. │ │ │ │ │ + * APIProperty: internalProjection │ │ │ │ │ + * {} When passed a externalProjection and │ │ │ │ │ + * internalProjection, the format will reproject the geometries it │ │ │ │ │ + * reads or writes. The internalProjection is the projection used by │ │ │ │ │ + * the geometries which are returned by read or which are passed into │ │ │ │ │ + * write. In order to reproject, a projection transformation function │ │ │ │ │ + * for the specified projections must be available. This support may be │ │ │ │ │ + * provided via proj4js or via a custom transformation function. See │ │ │ │ │ + * {} for more information on │ │ │ │ │ + * custom transformations. │ │ │ │ │ */ │ │ │ │ │ - getImage: function() { │ │ │ │ │ - if (!this.imgDiv) { │ │ │ │ │ - this.imgDiv = OpenLayers.Tile.Image.IMAGE.cloneNode(false); │ │ │ │ │ - │ │ │ │ │ - var style = this.imgDiv.style; │ │ │ │ │ - if (this.frame) { │ │ │ │ │ - var left = 0, │ │ │ │ │ - top = 0; │ │ │ │ │ - if (this.layer.gutter) { │ │ │ │ │ - left = this.layer.gutter / this.layer.tileSize.w * 100; │ │ │ │ │ - top = this.layer.gutter / this.layer.tileSize.h * 100; │ │ │ │ │ - } │ │ │ │ │ - style.left = -left + "%"; │ │ │ │ │ - style.top = -top + "%"; │ │ │ │ │ - style.width = (2 * left + 100) + "%"; │ │ │ │ │ - style.height = (2 * top + 100) + "%"; │ │ │ │ │ - } │ │ │ │ │ - style.visibility = "hidden"; │ │ │ │ │ - style.opacity = 0; │ │ │ │ │ - if (this.layer.opacity < 1) { │ │ │ │ │ - style.filter = 'alpha(opacity=' + │ │ │ │ │ - (this.layer.opacity * 100) + │ │ │ │ │ - ')'; │ │ │ │ │ - } │ │ │ │ │ - style.position = "absolute"; │ │ │ │ │ - if (this.layerAlphaHack) { │ │ │ │ │ - // move the image out of sight │ │ │ │ │ - style.paddingTop = style.height; │ │ │ │ │ - style.height = "0"; │ │ │ │ │ - style.width = "100%"; │ │ │ │ │ - } │ │ │ │ │ - if (this.frame) { │ │ │ │ │ - this.frame.appendChild(this.imgDiv); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - return this.imgDiv; │ │ │ │ │ - }, │ │ │ │ │ + internalProjection: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: setImage │ │ │ │ │ - * Sets the image element for this tile. This method should only be called │ │ │ │ │ - * from beforeload listeners. │ │ │ │ │ - * │ │ │ │ │ - * Parameters │ │ │ │ │ - * img - {HTMLImageElement} The image to use for this tile. │ │ │ │ │ + * APIProperty: data │ │ │ │ │ + * {Object} When is true, this is the parsed string sent to │ │ │ │ │ + * . │ │ │ │ │ */ │ │ │ │ │ - setImage: function(img) { │ │ │ │ │ - this.imgDiv = img; │ │ │ │ │ - }, │ │ │ │ │ + data: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: initImage │ │ │ │ │ - * Creates the content for the frame on the tile. │ │ │ │ │ + * APIProperty: keepData │ │ │ │ │ + * {Object} Maintain a reference () to the most recently read data. │ │ │ │ │ + * Default is false. │ │ │ │ │ */ │ │ │ │ │ - initImage: function() { │ │ │ │ │ - if (!this.url && !this.imgDiv) { │ │ │ │ │ - // fast path out - if there is no tile url and no previous image │ │ │ │ │ - this.isLoading = false; │ │ │ │ │ - return; │ │ │ │ │ - } │ │ │ │ │ - this.events.triggerEvent('beforeload'); │ │ │ │ │ - this.layer.div.appendChild(this.getTile()); │ │ │ │ │ - this.events.triggerEvent(this._loadEvent); │ │ │ │ │ - var img = this.getImage(); │ │ │ │ │ - var src = img.getAttribute('src') || ''; │ │ │ │ │ - if (this.url && OpenLayers.Util.isEquivalentUrl(src, this.url)) { │ │ │ │ │ - this._loadTimeout = window.setTimeout( │ │ │ │ │ - OpenLayers.Function.bind(this.onImageLoad, this), 0 │ │ │ │ │ - ); │ │ │ │ │ - } else { │ │ │ │ │ - this.stopLoading(); │ │ │ │ │ - if (this.crossOriginKeyword) { │ │ │ │ │ - img.removeAttribute("crossorigin"); │ │ │ │ │ - } │ │ │ │ │ - OpenLayers.Event.observe(img, "load", │ │ │ │ │ - OpenLayers.Function.bind(this.onImageLoad, this) │ │ │ │ │ - ); │ │ │ │ │ - OpenLayers.Event.observe(img, "error", │ │ │ │ │ - OpenLayers.Function.bind(this.onImageError, this) │ │ │ │ │ - ); │ │ │ │ │ - this.imageReloadAttempts = 0; │ │ │ │ │ - this.setImgSrc(this.url); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ + keepData: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: setImgSrc │ │ │ │ │ - * Sets the source for the tile image │ │ │ │ │ + * Constructor: OpenLayers.Format │ │ │ │ │ + * Instances of this class are not useful. See one of the subclasses. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * url - {String} or undefined to hide the image │ │ │ │ │ - */ │ │ │ │ │ - setImgSrc: function(url) { │ │ │ │ │ - var img = this.imgDiv; │ │ │ │ │ - if (url) { │ │ │ │ │ - img.style.visibility = 'hidden'; │ │ │ │ │ - img.style.opacity = 0; │ │ │ │ │ - // don't set crossOrigin if the url is a data URL │ │ │ │ │ - if (this.crossOriginKeyword) { │ │ │ │ │ - if (url.substr(0, 5) !== 'data:') { │ │ │ │ │ - img.setAttribute("crossorigin", this.crossOriginKeyword); │ │ │ │ │ - } else { │ │ │ │ │ - img.removeAttribute("crossorigin"); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - img.src = url; │ │ │ │ │ - } else { │ │ │ │ │ - // Remove reference to the image, and leave it to the browser's │ │ │ │ │ - // caching and garbage collection. │ │ │ │ │ - this.stopLoading(); │ │ │ │ │ - this.imgDiv = null; │ │ │ │ │ - if (img.parentNode) { │ │ │ │ │ - img.parentNode.removeChild(img); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: getTile │ │ │ │ │ - * Get the tile's markup. │ │ │ │ │ + * options - {Object} An optional object with properties to set on the │ │ │ │ │ + * format │ │ │ │ │ * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {DOMElement} The tile's markup │ │ │ │ │ - */ │ │ │ │ │ - getTile: function() { │ │ │ │ │ - return this.frame ? this.frame : this.getImage(); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: createBackBuffer │ │ │ │ │ - * Create a backbuffer for this tile. A backbuffer isn't exactly a clone │ │ │ │ │ - * of the tile's markup, because we want to avoid the reloading of the │ │ │ │ │ - * image. So we clone the frame, and steal the image from the tile. │ │ │ │ │ + * Valid options: │ │ │ │ │ + * keepData - {Boolean} If true, upon , the data property will be │ │ │ │ │ + * set to the parsed object (e.g. the json or xml object). │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {DOMElement} The markup, or undefined if the tile has no image │ │ │ │ │ - * or if it's currently loading. │ │ │ │ │ - */ │ │ │ │ │ - createBackBuffer: function() { │ │ │ │ │ - if (!this.imgDiv || this.isLoading) { │ │ │ │ │ - return; │ │ │ │ │ - } │ │ │ │ │ - var backBuffer; │ │ │ │ │ - if (this.frame) { │ │ │ │ │ - backBuffer = this.frame.cloneNode(false); │ │ │ │ │ - backBuffer.appendChild(this.imgDiv); │ │ │ │ │ - } else { │ │ │ │ │ - backBuffer = this.imgDiv; │ │ │ │ │ - } │ │ │ │ │ - this.imgDiv = null; │ │ │ │ │ - return backBuffer; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: onImageLoad │ │ │ │ │ - * Handler for the image onload event │ │ │ │ │ + * An instance of OpenLayers.Format │ │ │ │ │ */ │ │ │ │ │ - onImageLoad: function() { │ │ │ │ │ - var img = this.imgDiv; │ │ │ │ │ - this.stopLoading(); │ │ │ │ │ - img.style.visibility = 'inherit'; │ │ │ │ │ - img.style.opacity = this.layer.opacity; │ │ │ │ │ - this.isLoading = false; │ │ │ │ │ - this.canvasContext = null; │ │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ │ - │ │ │ │ │ - if (this.layerAlphaHack === true) { │ │ │ │ │ - img.style.filter = │ │ │ │ │ - "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + │ │ │ │ │ - img.src + "', sizingMethod='scale')"; │ │ │ │ │ - } │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + this.options = options; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: onImageError │ │ │ │ │ - * Handler for the image onerror event │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ + * Clean up. │ │ │ │ │ */ │ │ │ │ │ - onImageError: function() { │ │ │ │ │ - var img = this.imgDiv; │ │ │ │ │ - if (img.src != null) { │ │ │ │ │ - this.imageReloadAttempts++; │ │ │ │ │ - if (this.imageReloadAttempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) { │ │ │ │ │ - this.setImgSrc(this.layer.getURL(this.bounds)); │ │ │ │ │ - } else { │ │ │ │ │ - OpenLayers.Element.addClass(img, "olImageLoadError"); │ │ │ │ │ - this.events.triggerEvent("loaderror"); │ │ │ │ │ - this.onImageLoad(); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ + destroy: function() {}, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: stopLoading │ │ │ │ │ - * Stops a loading sequence so won't be executed. │ │ │ │ │ + * Method: read │ │ │ │ │ + * Read data from a string, and return an object whose type depends on the │ │ │ │ │ + * subclass. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * data - {string} Data to read/parse. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * Depends on the subclass │ │ │ │ │ */ │ │ │ │ │ - stopLoading: function() { │ │ │ │ │ - OpenLayers.Event.stopObservingElement(this.imgDiv); │ │ │ │ │ - window.clearTimeout(this._loadTimeout); │ │ │ │ │ - delete this._loadTimeout; │ │ │ │ │ + read: function(data) { │ │ │ │ │ + throw new Error('Read not implemented.'); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: getCanvasContext │ │ │ │ │ - * Returns a canvas context associated with the tile image (with │ │ │ │ │ - * the image drawn on it). │ │ │ │ │ - * Returns undefined if the browser does not support canvas, if │ │ │ │ │ - * the tile has no image or if it's currently loading. │ │ │ │ │ + * Method: write │ │ │ │ │ + * Accept an object, and return a string. │ │ │ │ │ * │ │ │ │ │ - * The function returns a canvas context instance but the │ │ │ │ │ - * underlying canvas is still available in the 'canvas' property: │ │ │ │ │ - * (code) │ │ │ │ │ - * var context = tile.getCanvasContext(); │ │ │ │ │ - * if (context) { │ │ │ │ │ - * var data = context.canvas.toDataURL('image/jpeg'); │ │ │ │ │ - * } │ │ │ │ │ - * (end) │ │ │ │ │ + * Parameters: │ │ │ │ │ + * object - {Object} Object to be serialized │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Boolean} │ │ │ │ │ + * {String} A string representation of the object. │ │ │ │ │ */ │ │ │ │ │ - getCanvasContext: function() { │ │ │ │ │ - if (OpenLayers.CANVAS_SUPPORTED && this.imgDiv && !this.isLoading) { │ │ │ │ │ - if (!this.canvasContext) { │ │ │ │ │ - var canvas = document.createElement("canvas"); │ │ │ │ │ - canvas.width = this.size.w; │ │ │ │ │ - canvas.height = this.size.h; │ │ │ │ │ - this.canvasContext = canvas.getContext("2d"); │ │ │ │ │ - this.canvasContext.drawImage(this.imgDiv, 0, 0); │ │ │ │ │ - } │ │ │ │ │ - return this.canvasContext; │ │ │ │ │ - } │ │ │ │ │ + write: function(object) { │ │ │ │ │ + throw new Error('Write not implemented.'); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Tile.Image" │ │ │ │ │ - │ │ │ │ │ + CLASS_NAME: "OpenLayers.Format" │ │ │ │ │ }); │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Tile.Image.IMAGE │ │ │ │ │ - * {HTMLImageElement} The image for a tile. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Tile.Image.IMAGE = (function() { │ │ │ │ │ - var img = new Image(); │ │ │ │ │ - img.className = "olTileImage"; │ │ │ │ │ - // avoid image gallery menu in IE6 │ │ │ │ │ - img.galleryImg = "no"; │ │ │ │ │ - return img; │ │ │ │ │ -}()); │ │ │ │ │ - │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Layer/Grid.js │ │ │ │ │ + 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. */ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Layer/HTTPRequest.js │ │ │ │ │ - * @requires OpenLayers/Tile/Image.js │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Layer.Grid │ │ │ │ │ - * Base class for layers that use a lattice of tiles. Create a new grid │ │ │ │ │ - * layer with the constructor. │ │ │ │ │ + * Class: OpenLayers.Popup │ │ │ │ │ + * A popup is a small div that can opened and closed on the map. │ │ │ │ │ + * Typically opened in response to clicking on a marker. │ │ │ │ │ + * See . Popup's don't require their own │ │ │ │ │ + * layer and are added the the map using the │ │ │ │ │ + * method. │ │ │ │ │ * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * Example: │ │ │ │ │ + * (code) │ │ │ │ │ + * popup = new OpenLayers.Popup("chicken", │ │ │ │ │ + * new OpenLayers.LonLat(5,40), │ │ │ │ │ + * new OpenLayers.Size(200,200), │ │ │ │ │ + * "example popup", │ │ │ │ │ + * true); │ │ │ │ │ + * │ │ │ │ │ + * map.addPopup(popup); │ │ │ │ │ + * (end) │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { │ │ │ │ │ +OpenLayers.Popup = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: tileSize │ │ │ │ │ - * {} │ │ │ │ │ + /** │ │ │ │ │ + * Property: events │ │ │ │ │ + * {} custom event manager │ │ │ │ │ */ │ │ │ │ │ - tileSize: null, │ │ │ │ │ + events: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: tileOriginCorner │ │ │ │ │ - * {String} If the property is not provided, the tile origin │ │ │ │ │ - * will be derived from the layer's . The corner of the │ │ │ │ │ - * used is determined by this property. Acceptable values │ │ │ │ │ - * are "tl" (top left), "tr" (top right), "bl" (bottom left), and "br" │ │ │ │ │ - * (bottom right). Default is "bl". │ │ │ │ │ + /** Property: id │ │ │ │ │ + * {String} the unique identifier assigned to this popup. │ │ │ │ │ */ │ │ │ │ │ - tileOriginCorner: "bl", │ │ │ │ │ + id: "", │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: tileOrigin │ │ │ │ │ - * {} Optional origin for aligning the grid of tiles. │ │ │ │ │ - * If provided, requests for tiles at all resolutions will be aligned │ │ │ │ │ - * with this location (no tiles shall overlap this location). If │ │ │ │ │ - * not provided, the grid of tiles will be aligned with the layer's │ │ │ │ │ - * . Default is ``null``. │ │ │ │ │ + /** │ │ │ │ │ + * Property: lonlat │ │ │ │ │ + * {} the position of this popup on the map │ │ │ │ │ */ │ │ │ │ │ - tileOrigin: null, │ │ │ │ │ + lonlat: null, │ │ │ │ │ │ │ │ │ │ - /** APIProperty: tileOptions │ │ │ │ │ - * {Object} optional configuration options for instances │ │ │ │ │ - * created by this Layer, if supported by the tile class. │ │ │ │ │ + /** │ │ │ │ │ + * Property: div │ │ │ │ │ + * {DOMElement} the div that contains this popup. │ │ │ │ │ */ │ │ │ │ │ - tileOptions: null, │ │ │ │ │ + div: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: tileClass │ │ │ │ │ - * {} The tile class to use for this layer. │ │ │ │ │ - * Defaults is OpenLayers.Tile.Image. │ │ │ │ │ + /** │ │ │ │ │ + * Property: contentSize │ │ │ │ │ + * {} the width and height of the content. │ │ │ │ │ */ │ │ │ │ │ - tileClass: OpenLayers.Tile.Image, │ │ │ │ │ + contentSize: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: grid │ │ │ │ │ - * {Array(Array())} This is an array of rows, each row is │ │ │ │ │ - * an array of tiles. │ │ │ │ │ + /** │ │ │ │ │ + * Property: size │ │ │ │ │ + * {} the width and height of the popup. │ │ │ │ │ */ │ │ │ │ │ - grid: null, │ │ │ │ │ + size: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: singleTile │ │ │ │ │ - * {Boolean} Moves the layer into single-tile mode, meaning that one tile │ │ │ │ │ - * will be loaded. The tile's size will be determined by the 'ratio' │ │ │ │ │ - * property. When the tile is dragged such that it does not cover the │ │ │ │ │ - * entire viewport, it is reloaded. │ │ │ │ │ + /** │ │ │ │ │ + * Property: contentHTML │ │ │ │ │ + * {String} An HTML string for this popup to display. │ │ │ │ │ */ │ │ │ │ │ - singleTile: false, │ │ │ │ │ + contentHTML: null, │ │ │ │ │ │ │ │ │ │ - /** APIProperty: ratio │ │ │ │ │ - * {Float} Used only when in single-tile mode, this specifies the │ │ │ │ │ - * ratio of the size of the single tile to the size of the map. │ │ │ │ │ - * Default value is 1.5. │ │ │ │ │ + /** │ │ │ │ │ + * Property: backgroundColor │ │ │ │ │ + * {String} the background color used by the popup. │ │ │ │ │ */ │ │ │ │ │ - ratio: 1.5, │ │ │ │ │ + backgroundColor: "", │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: buffer │ │ │ │ │ - * {Integer} Used only when in gridded mode, this specifies the number of │ │ │ │ │ - * extra rows and colums of tiles on each side which will │ │ │ │ │ - * surround the minimum grid tiles to cover the map. │ │ │ │ │ - * For very slow loading layers, a larger value may increase │ │ │ │ │ - * performance somewhat when dragging, but will increase bandwidth │ │ │ │ │ - * use significantly. │ │ │ │ │ + /** │ │ │ │ │ + * Property: opacity │ │ │ │ │ + * {float} the opacity of this popup (between 0.0 and 1.0) │ │ │ │ │ */ │ │ │ │ │ - buffer: 0, │ │ │ │ │ + opacity: "", │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: transitionEffect │ │ │ │ │ - * {String} The transition effect to use when the map is zoomed. │ │ │ │ │ - * Two posible values: │ │ │ │ │ - * │ │ │ │ │ - * "resize" - Existing tiles are resized on zoom to provide a visual │ │ │ │ │ - * effect of the zoom having taken place immediately. As the │ │ │ │ │ - * new tiles become available, they are drawn on top of the │ │ │ │ │ - * resized tiles (this is the default setting). │ │ │ │ │ - * "map-resize" - Existing tiles are resized on zoom and placed below the │ │ │ │ │ - * base layer. New tiles for the base layer will cover existing tiles. │ │ │ │ │ - * This setting is recommended when having an overlay duplicated during │ │ │ │ │ - * the transition is undesirable (e.g. street labels or big transparent │ │ │ │ │ - * fills). │ │ │ │ │ - * null - No transition effect. │ │ │ │ │ - * │ │ │ │ │ - * Using "resize" on non-opaque layers can cause undesired visual │ │ │ │ │ - * effects. Set transitionEffect to null in this case. │ │ │ │ │ + /** │ │ │ │ │ + * Property: border │ │ │ │ │ + * {String} the border size of the popup. (eg 2px) │ │ │ │ │ */ │ │ │ │ │ - transitionEffect: "resize", │ │ │ │ │ + border: "", │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: numLoadingTiles │ │ │ │ │ - * {Integer} How many tiles are still loading? │ │ │ │ │ + /** │ │ │ │ │ + * Property: contentDiv │ │ │ │ │ + * {DOMElement} a reference to the element that holds the content of │ │ │ │ │ + * the div. │ │ │ │ │ */ │ │ │ │ │ - numLoadingTiles: 0, │ │ │ │ │ + contentDiv: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: serverResolutions │ │ │ │ │ - * {Array(Number}} This property is documented in subclasses as │ │ │ │ │ - * an API property. │ │ │ │ │ + /** │ │ │ │ │ + * Property: groupDiv │ │ │ │ │ + * {DOMElement} First and only child of 'div'. The group Div contains the │ │ │ │ │ + * 'contentDiv' and the 'closeDiv'. │ │ │ │ │ */ │ │ │ │ │ - serverResolutions: null, │ │ │ │ │ + groupDiv: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: loading │ │ │ │ │ - * {Boolean} Indicates if tiles are being loaded. │ │ │ │ │ + /** │ │ │ │ │ + * Property: closeDiv │ │ │ │ │ + * {DOMElement} the optional closer image │ │ │ │ │ */ │ │ │ │ │ - loading: false, │ │ │ │ │ + closeDiv: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: backBuffer │ │ │ │ │ - * {DOMElement} The back buffer. │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: autoSize │ │ │ │ │ + * {Boolean} Resize the popup to auto-fit the contents. │ │ │ │ │ + * Default is false. │ │ │ │ │ */ │ │ │ │ │ - backBuffer: null, │ │ │ │ │ + autoSize: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: gridResolution │ │ │ │ │ - * {Number} The resolution of the current grid. Used for backbuffer and │ │ │ │ │ - * client zoom. This property is updated every time the grid is │ │ │ │ │ - * initialized. │ │ │ │ │ + * APIProperty: minSize │ │ │ │ │ + * {} Minimum size allowed for the popup's contents. │ │ │ │ │ */ │ │ │ │ │ - gridResolution: null, │ │ │ │ │ + minSize: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: backBufferResolution │ │ │ │ │ - * {Number} The resolution of the current back buffer. This property is │ │ │ │ │ - * updated each time a back buffer is created. │ │ │ │ │ + * APIProperty: maxSize │ │ │ │ │ + * {} Maximum size allowed for the popup's contents. │ │ │ │ │ */ │ │ │ │ │ - backBufferResolution: null, │ │ │ │ │ + maxSize: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: backBufferLonLat │ │ │ │ │ - * {Object} The top-left corner of the current back buffer. Includes lon │ │ │ │ │ - * and lat properties. This object is updated each time a back buffer │ │ │ │ │ - * is created. │ │ │ │ │ + /** │ │ │ │ │ + * Property: displayClass │ │ │ │ │ + * {String} The CSS class of the popup. │ │ │ │ │ */ │ │ │ │ │ - backBufferLonLat: null, │ │ │ │ │ + displayClass: "olPopup", │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: backBufferTimerId │ │ │ │ │ - * {Number} The id of the back buffer timer. This timer is used to │ │ │ │ │ - * delay the removal of the back buffer, thereby preventing │ │ │ │ │ - * flash effects caused by tile animation. │ │ │ │ │ + /** │ │ │ │ │ + * Property: contentDisplayClass │ │ │ │ │ + * {String} The CSS class of the popup content div. │ │ │ │ │ */ │ │ │ │ │ - backBufferTimerId: null, │ │ │ │ │ + contentDisplayClass: "olPopupContent", │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: removeBackBufferDelay │ │ │ │ │ - * {Number} Delay for removing the backbuffer when all tiles have finished │ │ │ │ │ - * loading. Can be set to 0 when no css opacity transitions for the │ │ │ │ │ - * olTileImage class are used. Default is 0 for layers, │ │ │ │ │ - * 2500 for tiled layers. See for more information on │ │ │ │ │ - * tile animation. │ │ │ │ │ + /** │ │ │ │ │ + * Property: padding │ │ │ │ │ + * {int or } An extra opportunity to specify internal │ │ │ │ │ + * padding of the content div inside the popup. This was originally │ │ │ │ │ + * confused with the css padding as specified in style.css's │ │ │ │ │ + * 'olPopupContent' class. We would like to get rid of this altogether, │ │ │ │ │ + * except that it does come in handy for the framed and anchoredbubble │ │ │ │ │ + * popups, who need to maintain yet another barrier between their │ │ │ │ │ + * content and the outer border of the popup itself. │ │ │ │ │ + * │ │ │ │ │ + * Note that in order to not break API, we must continue to support │ │ │ │ │ + * this property being set as an integer. Really, though, we'd like to │ │ │ │ │ + * have this specified as a Bounds object so that user can specify │ │ │ │ │ + * distinct left, top, right, bottom paddings. With the 3.0 release │ │ │ │ │ + * we can make this only a bounds. │ │ │ │ │ */ │ │ │ │ │ - removeBackBufferDelay: null, │ │ │ │ │ + padding: 0, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: className │ │ │ │ │ - * {String} Name of the class added to the layer div. If not set in the │ │ │ │ │ - * options passed to the constructor then className defaults to │ │ │ │ │ - * "olLayerGridSingleTile" for single tile layers (see ), │ │ │ │ │ - * and "olLayerGrid" for non single tile layers. │ │ │ │ │ - * │ │ │ │ │ - * Note: │ │ │ │ │ - * │ │ │ │ │ - * The displaying of tiles is not animated by default for single tile │ │ │ │ │ - * layers - OpenLayers' default theme (style.css) includes this: │ │ │ │ │ - * (code) │ │ │ │ │ - * .olLayerGrid .olTileImage { │ │ │ │ │ - * -webkit-transition: opacity 0.2s linear; │ │ │ │ │ - * -moz-transition: opacity 0.2s linear; │ │ │ │ │ - * -o-transition: opacity 0.2s linear; │ │ │ │ │ - * transition: opacity 0.2s linear; │ │ │ │ │ - * } │ │ │ │ │ - * (end) │ │ │ │ │ - * To animate tile displaying for any grid layer the following │ │ │ │ │ - * CSS rule can be used: │ │ │ │ │ - * (code) │ │ │ │ │ - * .olTileImage { │ │ │ │ │ - * -webkit-transition: opacity 0.2s linear; │ │ │ │ │ - * -moz-transition: opacity 0.2s linear; │ │ │ │ │ - * -o-transition: opacity 0.2s linear; │ │ │ │ │ - * transition: opacity 0.2s linear; │ │ │ │ │ - * } │ │ │ │ │ - * (end) │ │ │ │ │ - * In that case, to avoid flash effects, │ │ │ │ │ - * should not be zero. │ │ │ │ │ + /** │ │ │ │ │ + * Property: disableFirefoxOverflowHack │ │ │ │ │ + * {Boolean} The hack for overflow in Firefox causes all elements │ │ │ │ │ + * to be re-drawn, which causes Flash elements to be │ │ │ │ │ + * re-initialized, which is troublesome. │ │ │ │ │ + * With this property the hack can be disabled. │ │ │ │ │ */ │ │ │ │ │ - className: null, │ │ │ │ │ + disableFirefoxOverflowHack: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Register a listener for a particular event with the following syntax: │ │ │ │ │ - * (code) │ │ │ │ │ - * layer.events.register(type, obj, listener); │ │ │ │ │ - * (end) │ │ │ │ │ - * │ │ │ │ │ - * Listeners will be called with a reference to an event object. The │ │ │ │ │ - * properties of this event depends on exactly what happened. │ │ │ │ │ - * │ │ │ │ │ - * All event objects have at least the following properties: │ │ │ │ │ - * object - {Object} A reference to layer.events.object. │ │ │ │ │ - * element - {DOMElement} A reference to layer.events.element. │ │ │ │ │ - * │ │ │ │ │ - * Supported event types: │ │ │ │ │ - * addtile - Triggered when a tile is added to this layer. Listeners receive │ │ │ │ │ - * an object as first argument, which has a tile property that │ │ │ │ │ - * references the tile that has been added. │ │ │ │ │ - * tileloadstart - Triggered when a tile starts loading. Listeners receive │ │ │ │ │ - * an object as first argument, which has a tile property that │ │ │ │ │ - * references the tile that starts loading. │ │ │ │ │ - * tileloaded - Triggered when each new tile is │ │ │ │ │ - * loaded, as a means of progress update to listeners. │ │ │ │ │ - * listeners can access 'numLoadingTiles' if they wish to keep │ │ │ │ │ - * track of the loading progress. Listeners are called with an object │ │ │ │ │ - * with a 'tile' property as first argument, making the loaded tile │ │ │ │ │ - * available to the listener, and an 'aborted' property, which will be │ │ │ │ │ - * true when loading was aborted and no tile data is available. │ │ │ │ │ - * tileerror - Triggered before the tileloaded event (i.e. when the tile is │ │ │ │ │ - * still hidden) if a tile failed to load. Listeners receive an object │ │ │ │ │ - * as first argument, which has a tile property that references the │ │ │ │ │ - * tile that could not be loaded. │ │ │ │ │ - * retile - Triggered when the layer recreates its tile grid. │ │ │ │ │ + * Method: fixPadding │ │ │ │ │ + * To be removed in 3.0, this function merely helps us to deal with the │ │ │ │ │ + * case where the user may have set an integer value for padding, │ │ │ │ │ + * instead of an object. │ │ │ │ │ */ │ │ │ │ │ + fixPadding: function() { │ │ │ │ │ + if (typeof this.padding == "number") { │ │ │ │ │ + this.padding = new OpenLayers.Bounds( │ │ │ │ │ + this.padding, this.padding, this.padding, this.padding │ │ │ │ │ + ); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: gridLayout │ │ │ │ │ - * {Object} Object containing properties tilelon, tilelat, startcol, │ │ │ │ │ - * startrow │ │ │ │ │ + * APIProperty: panMapIfOutOfView │ │ │ │ │ + * {Boolean} When drawn, pan map such that the entire popup is visible in │ │ │ │ │ + * the current viewport (if necessary). │ │ │ │ │ + * Default is false. │ │ │ │ │ */ │ │ │ │ │ - gridLayout: null, │ │ │ │ │ + panMapIfOutOfView: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: rowSign │ │ │ │ │ - * {Number} 1 for grids starting at the top, -1 for grids starting at the │ │ │ │ │ - * bottom. This is used for several grid index and offset calculations. │ │ │ │ │ + * APIProperty: keepInMap │ │ │ │ │ + * {Boolean} If panMapIfOutOfView is false, and this property is true, │ │ │ │ │ + * contrain the popup such that it always fits in the available map │ │ │ │ │ + * space. By default, this is not set on the base class. If you are │ │ │ │ │ + * creating popups that are near map edges and not allowing pannning, │ │ │ │ │ + * and especially if you have a popup which has a │ │ │ │ │ + * fixedRelativePosition, setting this to false may be a smart thing to │ │ │ │ │ + * do. Subclasses may want to override this setting. │ │ │ │ │ + * │ │ │ │ │ + * Default is false. │ │ │ │ │ */ │ │ │ │ │ - rowSign: null, │ │ │ │ │ + keepInMap: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: transitionendEvents │ │ │ │ │ - * {Array} Event names for transitionend │ │ │ │ │ + * APIProperty: closeOnMove │ │ │ │ │ + * {Boolean} When map pans, close the popup. │ │ │ │ │ + * Default is false. │ │ │ │ │ */ │ │ │ │ │ - transitionendEvents: [ │ │ │ │ │ - 'transitionend', 'webkitTransitionEnd', 'otransitionend', │ │ │ │ │ - 'oTransitionEnd' │ │ │ │ │ - ], │ │ │ │ │ + closeOnMove: false, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Layer.Grid │ │ │ │ │ - * Create a new grid layer │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * name - {String} │ │ │ │ │ - * url - {String} │ │ │ │ │ - * params - {Object} │ │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ │ + /** │ │ │ │ │ + * Property: map │ │ │ │ │ + * {} this gets set in Map.js when the popup is added to the map │ │ │ │ │ */ │ │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ │ - OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this, │ │ │ │ │ - arguments); │ │ │ │ │ - this.grid = []; │ │ │ │ │ - this._removeBackBuffer = OpenLayers.Function.bind(this.removeBackBuffer, this); │ │ │ │ │ - │ │ │ │ │ - this.initProperties(); │ │ │ │ │ - │ │ │ │ │ - this.rowSign = this.tileOriginCorner.substr(0, 1) === "t" ? 1 : -1; │ │ │ │ │ - }, │ │ │ │ │ + map: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: initProperties │ │ │ │ │ - * Set any properties that depend on the value of singleTile. │ │ │ │ │ - * Currently sets removeBackBufferDelay and className │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Popup │ │ │ │ │ + * Create a popup. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * id - {String} a unqiue identifier for this popup. If null is passed │ │ │ │ │ + * an identifier will be automatically generated. │ │ │ │ │ + * lonlat - {} The position on the map the popup will │ │ │ │ │ + * be shown. │ │ │ │ │ + * contentSize - {} The size of the content. │ │ │ │ │ + * contentHTML - {String} An HTML string to display inside the │ │ │ │ │ + * popup. │ │ │ │ │ + * closeBox - {Boolean} Whether to display a close box inside │ │ │ │ │ + * the popup. │ │ │ │ │ + * closeBoxCallback - {Function} Function to be called on closeBox click. │ │ │ │ │ */ │ │ │ │ │ - initProperties: function() { │ │ │ │ │ - if (this.options.removeBackBufferDelay === undefined) { │ │ │ │ │ - this.removeBackBufferDelay = this.singleTile ? 0 : 2500; │ │ │ │ │ + initialize: function(id, lonlat, contentSize, contentHTML, closeBox, closeBoxCallback) { │ │ │ │ │ + if (id == null) { │ │ │ │ │ + id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ } │ │ │ │ │ │ │ │ │ │ - if (this.options.className === undefined) { │ │ │ │ │ - this.className = this.singleTile ? 'olLayerGridSingleTile' : │ │ │ │ │ - 'olLayerGrid'; │ │ │ │ │ + this.id = id; │ │ │ │ │ + this.lonlat = lonlat; │ │ │ │ │ + │ │ │ │ │ + this.contentSize = (contentSize != null) ? contentSize : │ │ │ │ │ + new OpenLayers.Size( │ │ │ │ │ + OpenLayers.Popup.WIDTH, │ │ │ │ │ + OpenLayers.Popup.HEIGHT); │ │ │ │ │ + if (contentHTML != null) { │ │ │ │ │ + this.contentHTML = contentHTML; │ │ │ │ │ } │ │ │ │ │ - }, │ │ │ │ │ + this.backgroundColor = OpenLayers.Popup.COLOR; │ │ │ │ │ + this.opacity = OpenLayers.Popup.OPACITY; │ │ │ │ │ + this.border = OpenLayers.Popup.BORDER; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: setMap │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * map - {} The map. │ │ │ │ │ - */ │ │ │ │ │ - setMap: function(map) { │ │ │ │ │ - OpenLayers.Layer.HTTPRequest.prototype.setMap.call(this, map); │ │ │ │ │ - OpenLayers.Element.addClass(this.div, this.className); │ │ │ │ │ - }, │ │ │ │ │ + this.div = OpenLayers.Util.createDiv(this.id, null, null, │ │ │ │ │ + null, null, null, "hidden"); │ │ │ │ │ + this.div.className = this.displayClass; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: removeMap │ │ │ │ │ - * Called when the layer is removed from the map. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * map - {} The map. │ │ │ │ │ - */ │ │ │ │ │ - removeMap: function(map) { │ │ │ │ │ - this.removeBackBuffer(); │ │ │ │ │ + var groupDivId = this.id + "_GroupDiv"; │ │ │ │ │ + this.groupDiv = OpenLayers.Util.createDiv(groupDivId, null, null, │ │ │ │ │ + null, "relative", null, │ │ │ │ │ + "hidden"); │ │ │ │ │ + │ │ │ │ │ + var id = this.div.id + "_contentDiv"; │ │ │ │ │ + this.contentDiv = OpenLayers.Util.createDiv(id, null, this.contentSize.clone(), │ │ │ │ │ + null, "relative"); │ │ │ │ │ + this.contentDiv.className = this.contentDisplayClass; │ │ │ │ │ + this.groupDiv.appendChild(this.contentDiv); │ │ │ │ │ + this.div.appendChild(this.groupDiv); │ │ │ │ │ + │ │ │ │ │ + if (closeBox) { │ │ │ │ │ + this.addCloseBox(closeBoxCallback); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.registerEvents(); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ - * Deconstruct the layer and clear the grid. │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroy │ │ │ │ │ + * nullify references to prevent circular references and memory leaks │ │ │ │ │ */ │ │ │ │ │ destroy: function() { │ │ │ │ │ - this.removeBackBuffer(); │ │ │ │ │ - this.clearGrid(); │ │ │ │ │ │ │ │ │ │ - this.grid = null; │ │ │ │ │ - this.tileSize = null; │ │ │ │ │ - OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments); │ │ │ │ │ + this.id = null; │ │ │ │ │ + this.lonlat = null; │ │ │ │ │ + this.size = null; │ │ │ │ │ + this.contentHTML = null; │ │ │ │ │ + │ │ │ │ │ + this.backgroundColor = null; │ │ │ │ │ + this.opacity = null; │ │ │ │ │ + this.border = null; │ │ │ │ │ + │ │ │ │ │ + if (this.closeOnMove && this.map) { │ │ │ │ │ + this.map.events.unregister("movestart", this, this.hide); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.events.destroy(); │ │ │ │ │ + this.events = null; │ │ │ │ │ + │ │ │ │ │ + if (this.closeDiv) { │ │ │ │ │ + OpenLayers.Event.stopObservingElement(this.closeDiv); │ │ │ │ │ + this.groupDiv.removeChild(this.closeDiv); │ │ │ │ │ + } │ │ │ │ │ + this.closeDiv = null; │ │ │ │ │ + │ │ │ │ │ + this.div.removeChild(this.groupDiv); │ │ │ │ │ + this.groupDiv = null; │ │ │ │ │ + │ │ │ │ │ + if (this.map != null) { │ │ │ │ │ + this.map.removePopup(this); │ │ │ │ │ + } │ │ │ │ │ + this.map = null; │ │ │ │ │ + this.div = null; │ │ │ │ │ + │ │ │ │ │ + this.autoSize = null; │ │ │ │ │ + this.minSize = null; │ │ │ │ │ + this.maxSize = null; │ │ │ │ │ + this.padding = null; │ │ │ │ │ + this.panMapIfOutOfView = null; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: mergeNewParams │ │ │ │ │ - * Refetches tiles with new params merged, keeping a backbuffer. Each │ │ │ │ │ - * loading new tile will have a css class of '.olTileReplacing'. If a │ │ │ │ │ - * stylesheet applies a 'display: none' style to that class, any fade-in │ │ │ │ │ - * transition will not apply, and backbuffers for each tile will be removed │ │ │ │ │ - * as soon as the tile is loaded. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * newParams - {Object} │ │ │ │ │ + /** │ │ │ │ │ + * Method: draw │ │ │ │ │ + * Constructs the elements that make up the popup. │ │ │ │ │ * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * px - {} the position the popup in pixels. │ │ │ │ │ + * │ │ │ │ │ * Returns: │ │ │ │ │ - * redrawn: {Boolean} whether the layer was actually redrawn. │ │ │ │ │ + * {DOMElement} Reference to a div that contains the drawn popup │ │ │ │ │ */ │ │ │ │ │ + draw: function(px) { │ │ │ │ │ + if (px == null) { │ │ │ │ │ + if ((this.lonlat != null) && (this.map != null)) { │ │ │ │ │ + px = this.map.getLayerPxFromLonLat(this.lonlat); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: clearGrid │ │ │ │ │ - * Go through and remove all tiles from the grid, calling │ │ │ │ │ - * destroy() on each of them to kill circular references │ │ │ │ │ - */ │ │ │ │ │ - clearGrid: function() { │ │ │ │ │ - if (this.grid) { │ │ │ │ │ - for (var iRow = 0, len = this.grid.length; iRow < len; iRow++) { │ │ │ │ │ - var row = this.grid[iRow]; │ │ │ │ │ - for (var iCol = 0, clen = row.length; iCol < clen; iCol++) { │ │ │ │ │ - var tile = row[iCol]; │ │ │ │ │ - this.destroyTile(tile); │ │ │ │ │ + // this assumes that this.map already exists, which is okay because │ │ │ │ │ + // this.draw is only called once the popup has been added to the map. │ │ │ │ │ + if (this.closeOnMove) { │ │ │ │ │ + this.map.events.register("movestart", this, this.hide); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + //listen to movestart, moveend to disable overflow (FF bug) │ │ │ │ │ + if (!this.disableFirefoxOverflowHack && OpenLayers.BROWSER_NAME == 'firefox') { │ │ │ │ │ + this.map.events.register("movestart", this, function() { │ │ │ │ │ + var style = document.defaultView.getComputedStyle( │ │ │ │ │ + this.contentDiv, null │ │ │ │ │ + ); │ │ │ │ │ + var currentOverflow = style.getPropertyValue("overflow"); │ │ │ │ │ + if (currentOverflow != "hidden") { │ │ │ │ │ + this.contentDiv._oldOverflow = currentOverflow; │ │ │ │ │ + this.contentDiv.style.overflow = "hidden"; │ │ │ │ │ + } │ │ │ │ │ + }); │ │ │ │ │ + this.map.events.register("moveend", this, function() { │ │ │ │ │ + var oldOverflow = this.contentDiv._oldOverflow; │ │ │ │ │ + if (oldOverflow) { │ │ │ │ │ + this.contentDiv.style.overflow = oldOverflow; │ │ │ │ │ + this.contentDiv._oldOverflow = null; │ │ │ │ │ } │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.moveTo(px); │ │ │ │ │ + if (!this.autoSize && !this.size) { │ │ │ │ │ + this.setSize(this.contentSize); │ │ │ │ │ + } │ │ │ │ │ + this.setBackgroundColor(); │ │ │ │ │ + this.setOpacity(); │ │ │ │ │ + this.setBorder(); │ │ │ │ │ + this.setContentHTML(); │ │ │ │ │ + │ │ │ │ │ + if (this.panMapIfOutOfView) { │ │ │ │ │ + this.panIntoView(); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + return this.div; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: updatePosition │ │ │ │ │ + * if the popup has a lonlat and its map members set, │ │ │ │ │ + * then have it move itself to its proper position │ │ │ │ │ + */ │ │ │ │ │ + updatePosition: function() { │ │ │ │ │ + if ((this.lonlat) && (this.map)) { │ │ │ │ │ + var px = this.map.getLayerPxFromLonLat(this.lonlat); │ │ │ │ │ + if (px) { │ │ │ │ │ + this.moveTo(px); │ │ │ │ │ } │ │ │ │ │ - this.grid = []; │ │ │ │ │ - this.gridResolution = null; │ │ │ │ │ - this.gridLayout = null; │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: addOptions │ │ │ │ │ + * Method: moveTo │ │ │ │ │ * │ │ │ │ │ * 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. │ │ │ │ │ + * px - {} the top and left position of the popup div. │ │ │ │ │ */ │ │ │ │ │ - addOptions: function(newOptions, reinitialize) { │ │ │ │ │ - var singleTileChanged = newOptions.singleTile !== undefined && │ │ │ │ │ - newOptions.singleTile !== this.singleTile; │ │ │ │ │ - OpenLayers.Layer.HTTPRequest.prototype.addOptions.apply(this, arguments); │ │ │ │ │ - if (this.map && singleTileChanged) { │ │ │ │ │ - this.initProperties(); │ │ │ │ │ - this.clearGrid(); │ │ │ │ │ - this.tileSize = this.options.tileSize; │ │ │ │ │ - this.setTileSize(); │ │ │ │ │ - this.moveTo(null, true); │ │ │ │ │ + moveTo: function(px) { │ │ │ │ │ + if ((px != null) && (this.div != null)) { │ │ │ │ │ + this.div.style.left = px.x + "px"; │ │ │ │ │ + this.div.style.top = px.y + "px"; │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: clone │ │ │ │ │ - * Create a clone of this layer │ │ │ │ │ + * Method: visible │ │ │ │ │ * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * obj - {Object} Is this ever used? │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} An exact clone of this OpenLayers.Layer.Grid │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Boolean indicating whether or not the popup is visible │ │ │ │ │ */ │ │ │ │ │ - clone: function(obj) { │ │ │ │ │ + visible: function() { │ │ │ │ │ + return OpenLayers.Element.visible(this.div); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (obj == null) { │ │ │ │ │ - obj = new OpenLayers.Layer.Grid(this.name, │ │ │ │ │ - this.url, │ │ │ │ │ - this.params, │ │ │ │ │ - this.getOptions()); │ │ │ │ │ + /** │ │ │ │ │ + * Method: toggle │ │ │ │ │ + * Toggles visibility of the popup. │ │ │ │ │ + */ │ │ │ │ │ + toggle: function() { │ │ │ │ │ + if (this.visible()) { │ │ │ │ │ + this.hide(); │ │ │ │ │ + } else { │ │ │ │ │ + this.show(); │ │ │ │ │ } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - //get all additions from superclasses │ │ │ │ │ - obj = OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this, [obj]); │ │ │ │ │ + /** │ │ │ │ │ + * Method: show │ │ │ │ │ + * Makes the popup visible. │ │ │ │ │ + */ │ │ │ │ │ + show: function() { │ │ │ │ │ + this.div.style.display = ''; │ │ │ │ │ │ │ │ │ │ - // copy/set any non-init, non-simple values here │ │ │ │ │ - if (this.tileSize != null) { │ │ │ │ │ - obj.tileSize = this.tileSize.clone(); │ │ │ │ │ + if (this.panMapIfOutOfView) { │ │ │ │ │ + this.panIntoView(); │ │ │ │ │ } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // we do not want to copy reference to grid, so we make a new array │ │ │ │ │ - obj.grid = []; │ │ │ │ │ - obj.gridResolution = null; │ │ │ │ │ - // same for backbuffer │ │ │ │ │ - obj.backBuffer = null; │ │ │ │ │ - obj.backBufferTimerId = null; │ │ │ │ │ - obj.loading = false; │ │ │ │ │ - obj.numLoadingTiles = 0; │ │ │ │ │ - │ │ │ │ │ - return obj; │ │ │ │ │ + /** │ │ │ │ │ + * Method: hide │ │ │ │ │ + * Makes the popup invisible. │ │ │ │ │ + */ │ │ │ │ │ + hide: function() { │ │ │ │ │ + this.div.style.display = 'none'; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: moveTo │ │ │ │ │ - * This function is called whenever the map is moved. All the moving │ │ │ │ │ - * of actual 'tiles' is done by the map, but moveTo's role is to accept │ │ │ │ │ - * a bounds and make sure the data that that bounds requires is pre-loaded. │ │ │ │ │ + * Method: setSize │ │ │ │ │ + * Used to adjust the size of the popup. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * bounds - {} │ │ │ │ │ - * zoomChanged - {Boolean} │ │ │ │ │ - * dragging - {Boolean} │ │ │ │ │ + * contentSize - {} the new size for the popup's │ │ │ │ │ + * contents div (in pixels). │ │ │ │ │ */ │ │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ │ + setSize: function(contentSize) { │ │ │ │ │ + this.size = contentSize.clone(); │ │ │ │ │ │ │ │ │ │ - OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this, arguments); │ │ │ │ │ + // if our contentDiv has a css 'padding' set on it by a stylesheet, we │ │ │ │ │ + // must add that to the desired "size". │ │ │ │ │ + var contentDivPadding = this.getContentDivPadding(); │ │ │ │ │ + var wPadding = contentDivPadding.left + contentDivPadding.right; │ │ │ │ │ + var hPadding = contentDivPadding.top + contentDivPadding.bottom; │ │ │ │ │ │ │ │ │ │ - bounds = bounds || this.map.getExtent(); │ │ │ │ │ + // take into account the popup's 'padding' property │ │ │ │ │ + this.fixPadding(); │ │ │ │ │ + wPadding += this.padding.left + this.padding.right; │ │ │ │ │ + hPadding += this.padding.top + this.padding.bottom; │ │ │ │ │ │ │ │ │ │ - if (bounds != null) { │ │ │ │ │ + // make extra space for the close div │ │ │ │ │ + if (this.closeDiv) { │ │ │ │ │ + var closeDivWidth = parseInt(this.closeDiv.style.width); │ │ │ │ │ + wPadding += closeDivWidth + contentDivPadding.right; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - // if grid is empty or zoom has changed, we *must* re-tile │ │ │ │ │ - var forceReTile = !this.grid.length || zoomChanged; │ │ │ │ │ + //increase size of the main popup div to take into account the │ │ │ │ │ + // users's desired padding and close div. │ │ │ │ │ + this.size.w += wPadding; │ │ │ │ │ + this.size.h += hPadding; │ │ │ │ │ │ │ │ │ │ - // total bounds of the tiles │ │ │ │ │ - var tilesBounds = this.getTilesBounds(); │ │ │ │ │ + //now if our browser is IE, we need to actually make the contents │ │ │ │ │ + // div itself bigger to take its own padding into effect. this makes │ │ │ │ │ + // me want to shoot someone, but so it goes. │ │ │ │ │ + if (OpenLayers.BROWSER_NAME == "msie") { │ │ │ │ │ + this.contentSize.w += │ │ │ │ │ + contentDivPadding.left + contentDivPadding.right; │ │ │ │ │ + this.contentSize.h += │ │ │ │ │ + contentDivPadding.bottom + contentDivPadding.top; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - // the new map resolution │ │ │ │ │ - var resolution = this.map.getResolution(); │ │ │ │ │ + if (this.div != null) { │ │ │ │ │ + this.div.style.width = this.size.w + "px"; │ │ │ │ │ + this.div.style.height = this.size.h + "px"; │ │ │ │ │ + } │ │ │ │ │ + if (this.contentDiv != null) { │ │ │ │ │ + this.contentDiv.style.width = contentSize.w + "px"; │ │ │ │ │ + this.contentDiv.style.height = contentSize.h + "px"; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // the server-supported resolution for the new map resolution │ │ │ │ │ - var serverResolution = this.getServerResolution(resolution); │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: updateSize │ │ │ │ │ + * Auto size the popup so that it precisely fits its contents (as │ │ │ │ │ + * determined by this.contentDiv.innerHTML). Popup size will, of │ │ │ │ │ + * course, be limited by the available space on the current map │ │ │ │ │ + */ │ │ │ │ │ + updateSize: function() { │ │ │ │ │ │ │ │ │ │ - if (this.singleTile) { │ │ │ │ │ + // determine actual render dimensions of the contents by putting its │ │ │ │ │ + // contents into a fake contentDiv (for the CSS) and then measuring it │ │ │ │ │ + var preparedHTML = "
" + │ │ │ │ │ + this.contentDiv.innerHTML + │ │ │ │ │ + "
"; │ │ │ │ │ │ │ │ │ │ - // We want to redraw whenever even the slightest part of the │ │ │ │ │ - // current bounds is not contained by our tile. │ │ │ │ │ - // (thus, we do not specify partial -- its default is false) │ │ │ │ │ + var containerElement = (this.map) ? this.map.div : document.body; │ │ │ │ │ + var realSize = OpenLayers.Util.getRenderedDimensions( │ │ │ │ │ + preparedHTML, null, { │ │ │ │ │ + displayClass: this.displayClass, │ │ │ │ │ + containerElement: containerElement │ │ │ │ │ + } │ │ │ │ │ + ); │ │ │ │ │ │ │ │ │ │ - if (forceReTile || │ │ │ │ │ - (!dragging && !tilesBounds.containsBounds(bounds))) { │ │ │ │ │ + // is the "real" size of the div is safe to display in our map? │ │ │ │ │ + var safeSize = this.getSafeContentSize(realSize); │ │ │ │ │ │ │ │ │ │ - // In single tile mode with no transition effect, we insert │ │ │ │ │ - // a non-scaled backbuffer when the layer is moved. But if │ │ │ │ │ - // a zoom occurs right after a move, i.e. before the new │ │ │ │ │ - // image is received, we need to remove the backbuffer, or │ │ │ │ │ - // an ill-positioned image will be visible during the zoom │ │ │ │ │ - // transition. │ │ │ │ │ + var newSize = null; │ │ │ │ │ + if (safeSize.equals(realSize)) { │ │ │ │ │ + //real size of content is small enough to fit on the map, │ │ │ │ │ + // so we use real size. │ │ │ │ │ + newSize = realSize; │ │ │ │ │ │ │ │ │ │ - if (zoomChanged && this.transitionEffect !== 'resize') { │ │ │ │ │ - this.removeBackBuffer(); │ │ │ │ │ - } │ │ │ │ │ + } else { │ │ │ │ │ │ │ │ │ │ - if (!zoomChanged || this.transitionEffect === 'resize') { │ │ │ │ │ - this.applyBackBuffer(resolution); │ │ │ │ │ - } │ │ │ │ │ + // make a new 'size' object with the clipped dimensions │ │ │ │ │ + // set or null if not clipped. │ │ │ │ │ + var fixedSize = { │ │ │ │ │ + w: (safeSize.w < realSize.w) ? safeSize.w : null, │ │ │ │ │ + h: (safeSize.h < realSize.h) ? safeSize.h : null │ │ │ │ │ + }; │ │ │ │ │ │ │ │ │ │ - this.initSingleTile(bounds); │ │ │ │ │ - } │ │ │ │ │ + if (fixedSize.w && fixedSize.h) { │ │ │ │ │ + //content is too big in both directions, so we will use │ │ │ │ │ + // max popup size (safeSize), knowing well that it will │ │ │ │ │ + // overflow both ways. │ │ │ │ │ + newSize = safeSize; │ │ │ │ │ } else { │ │ │ │ │ + //content is clipped in only one direction, so we need to │ │ │ │ │ + // run getRenderedDimensions() again with a fixed dimension │ │ │ │ │ + var clippedSize = OpenLayers.Util.getRenderedDimensions( │ │ │ │ │ + preparedHTML, fixedSize, { │ │ │ │ │ + displayClass: this.contentDisplayClass, │ │ │ │ │ + containerElement: containerElement │ │ │ │ │ + } │ │ │ │ │ + ); │ │ │ │ │ │ │ │ │ │ - // if the bounds have changed such that they are not even │ │ │ │ │ - // *partially* contained by our tiles (e.g. when user has │ │ │ │ │ - // programmatically panned to the other side of the earth on │ │ │ │ │ - // zoom level 18), then moveGriddedTiles could potentially have │ │ │ │ │ - // to run through thousands of cycles, so we want to reTile │ │ │ │ │ - // instead (thus, partial true). │ │ │ │ │ - forceReTile = forceReTile || │ │ │ │ │ - !tilesBounds.intersectsBounds(bounds, { │ │ │ │ │ - worldBounds: this.map.baseLayer.wrapDateLine && │ │ │ │ │ - this.map.getMaxExtent() │ │ │ │ │ - }); │ │ │ │ │ - │ │ │ │ │ - if (forceReTile) { │ │ │ │ │ - if (zoomChanged && (this.transitionEffect === 'resize' || │ │ │ │ │ - this.gridResolution === resolution)) { │ │ │ │ │ - this.applyBackBuffer(resolution); │ │ │ │ │ + //if the clipped size is still the same as the safeSize, │ │ │ │ │ + // that means that our content must be fixed in the │ │ │ │ │ + // offending direction. If overflow is 'auto', this means │ │ │ │ │ + // we are going to have a scrollbar for sure, so we must │ │ │ │ │ + // adjust for that. │ │ │ │ │ + // │ │ │ │ │ + var currentOverflow = OpenLayers.Element.getStyle( │ │ │ │ │ + this.contentDiv, "overflow" │ │ │ │ │ + ); │ │ │ │ │ + if ((currentOverflow != "hidden") && │ │ │ │ │ + (clippedSize.equals(safeSize))) { │ │ │ │ │ + var scrollBar = OpenLayers.Util.getScrollbarWidth(); │ │ │ │ │ + if (fixedSize.w) { │ │ │ │ │ + clippedSize.h += scrollBar; │ │ │ │ │ + } else { │ │ │ │ │ + clippedSize.w += scrollBar; │ │ │ │ │ } │ │ │ │ │ - this.initGriddedTiles(bounds); │ │ │ │ │ - } else { │ │ │ │ │ - this.moveGriddedTiles(); │ │ │ │ │ } │ │ │ │ │ + │ │ │ │ │ + newSize = this.getSafeContentSize(clippedSize); │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ + this.setSize(newSize); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getTileData │ │ │ │ │ - * Given a map location, retrieve a tile and the pixel offset within that │ │ │ │ │ - * tile corresponding to the location. If there is not an existing │ │ │ │ │ - * tile in the grid that covers the given location, null will be │ │ │ │ │ - * returned. │ │ │ │ │ + * Method: setBackgroundColor │ │ │ │ │ + * Sets the background color of the popup. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * loc - {} map location │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} Object with the following properties: tile ({}), │ │ │ │ │ - * i ({Number} x-pixel offset from top left), and j ({Integer} y-pixel │ │ │ │ │ - * offset from top left). │ │ │ │ │ + * color - {String} the background color. eg "#FFBBBB" │ │ │ │ │ */ │ │ │ │ │ - getTileData: function(loc) { │ │ │ │ │ - var data = null, │ │ │ │ │ - x = loc.lon, │ │ │ │ │ - y = loc.lat, │ │ │ │ │ - numRows = this.grid.length; │ │ │ │ │ + setBackgroundColor: function(color) { │ │ │ │ │ + if (color != undefined) { │ │ │ │ │ + this.backgroundColor = color; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - if (this.map && numRows) { │ │ │ │ │ - var res = this.map.getResolution(), │ │ │ │ │ - tileWidth = this.tileSize.w, │ │ │ │ │ - tileHeight = this.tileSize.h, │ │ │ │ │ - bounds = this.grid[0][0].bounds, │ │ │ │ │ - left = bounds.left, │ │ │ │ │ - top = bounds.top; │ │ │ │ │ + if (this.div != null) { │ │ │ │ │ + this.div.style.backgroundColor = this.backgroundColor; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (x < left) { │ │ │ │ │ - // deal with multiple worlds │ │ │ │ │ - if (this.map.baseLayer.wrapDateLine) { │ │ │ │ │ - var worldWidth = this.map.getMaxExtent().getWidth(); │ │ │ │ │ - var worldsAway = Math.ceil((left - x) / worldWidth); │ │ │ │ │ - x += worldWidth * worldsAway; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - // tile distance to location (fractional number of tiles); │ │ │ │ │ - var dtx = (x - left) / (res * tileWidth); │ │ │ │ │ - var dty = (top - y) / (res * tileHeight); │ │ │ │ │ - // index of tile in grid │ │ │ │ │ - var col = Math.floor(dtx); │ │ │ │ │ - var row = Math.floor(dty); │ │ │ │ │ - if (row >= 0 && row < numRows) { │ │ │ │ │ - var tile = this.grid[row][col]; │ │ │ │ │ - if (tile) { │ │ │ │ │ - data = { │ │ │ │ │ - tile: tile, │ │ │ │ │ - // pixel index within tile │ │ │ │ │ - i: Math.floor((dtx - col) * tileWidth), │ │ │ │ │ - j: Math.floor((dty - row) * tileHeight) │ │ │ │ │ - }; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Method: setOpacity │ │ │ │ │ + * Sets the opacity of the popup. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid). │ │ │ │ │ + */ │ │ │ │ │ + setOpacity: function(opacity) { │ │ │ │ │ + if (opacity != undefined) { │ │ │ │ │ + this.opacity = opacity; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (this.div != null) { │ │ │ │ │ + // for Mozilla and Safari │ │ │ │ │ + this.div.style.opacity = this.opacity; │ │ │ │ │ + │ │ │ │ │ + // for IE │ │ │ │ │ + this.div.style.filter = 'alpha(opacity=' + this.opacity * 100 + ')'; │ │ │ │ │ } │ │ │ │ │ - return data; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: destroyTile │ │ │ │ │ + * Method: setBorder │ │ │ │ │ + * Sets the border style of the popup. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * tile - {} │ │ │ │ │ + * border - {String} The border style value. eg 2px │ │ │ │ │ */ │ │ │ │ │ - destroyTile: function(tile) { │ │ │ │ │ - this.removeTileMonitoringHooks(tile); │ │ │ │ │ - tile.destroy(); │ │ │ │ │ + setBorder: function(border) { │ │ │ │ │ + if (border != undefined) { │ │ │ │ │ + this.border = border; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (this.div != null) { │ │ │ │ │ + this.div.style.border = this.border; │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getServerResolution │ │ │ │ │ - * Return the closest server-supported resolution. │ │ │ │ │ + * Method: setContentHTML │ │ │ │ │ + * Allows the user to set the HTML content of the popup. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * resolution - {Number} The base resolution. If undefined the │ │ │ │ │ - * map resolution is used. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Number} The closest server resolution value. │ │ │ │ │ - */ │ │ │ │ │ - getServerResolution: function(resolution) { │ │ │ │ │ - var distance = Number.POSITIVE_INFINITY; │ │ │ │ │ - resolution = resolution || this.map.getResolution(); │ │ │ │ │ - if (this.serverResolutions && │ │ │ │ │ - OpenLayers.Util.indexOf(this.serverResolutions, resolution) === -1) { │ │ │ │ │ - var i, newDistance, newResolution, serverResolution; │ │ │ │ │ - for (i = this.serverResolutions.length - 1; i >= 0; i--) { │ │ │ │ │ - newResolution = this.serverResolutions[i]; │ │ │ │ │ - newDistance = Math.abs(newResolution - resolution); │ │ │ │ │ - if (newDistance > distance) { │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - distance = newDistance; │ │ │ │ │ - serverResolution = newResolution; │ │ │ │ │ - } │ │ │ │ │ - resolution = serverResolution; │ │ │ │ │ - } │ │ │ │ │ - return resolution; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: getServerZoom │ │ │ │ │ - * Return the zoom value corresponding to the best matching server │ │ │ │ │ - * resolution, taking into account and . │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Number} The closest server supported zoom. This is not the map zoom │ │ │ │ │ - * level, but an index of the server's resolutions array. │ │ │ │ │ - */ │ │ │ │ │ - getServerZoom: function() { │ │ │ │ │ - var resolution = this.getServerResolution(); │ │ │ │ │ - return this.serverResolutions ? │ │ │ │ │ - OpenLayers.Util.indexOf(this.serverResolutions, resolution) : │ │ │ │ │ - this.map.getZoomForResolution(resolution) + (this.zoomOffset || 0); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: applyBackBuffer │ │ │ │ │ - * Create, insert, scale and position a back buffer for the layer. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * resolution - {Number} The resolution to transition to. │ │ │ │ │ - */ │ │ │ │ │ - applyBackBuffer: function(resolution) { │ │ │ │ │ - if (this.backBufferTimerId !== null) { │ │ │ │ │ - this.removeBackBuffer(); │ │ │ │ │ - } │ │ │ │ │ - var backBuffer = this.backBuffer; │ │ │ │ │ - if (!backBuffer) { │ │ │ │ │ - backBuffer = this.createBackBuffer(); │ │ │ │ │ - if (!backBuffer) { │ │ │ │ │ - return; │ │ │ │ │ - } │ │ │ │ │ - if (resolution === this.gridResolution) { │ │ │ │ │ - this.div.insertBefore(backBuffer, this.div.firstChild); │ │ │ │ │ - } else { │ │ │ │ │ - this.map.baseLayer.div.parentNode.insertBefore(backBuffer, this.map.baseLayer.div); │ │ │ │ │ - } │ │ │ │ │ - this.backBuffer = backBuffer; │ │ │ │ │ - │ │ │ │ │ - // set some information in the instance for subsequent │ │ │ │ │ - // calls to applyBackBuffer where the same back buffer │ │ │ │ │ - // is reused │ │ │ │ │ - var topLeftTileBounds = this.grid[0][0].bounds; │ │ │ │ │ - this.backBufferLonLat = { │ │ │ │ │ - lon: topLeftTileBounds.left, │ │ │ │ │ - lat: topLeftTileBounds.top │ │ │ │ │ - }; │ │ │ │ │ - this.backBufferResolution = this.gridResolution; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - var ratio = this.backBufferResolution / resolution; │ │ │ │ │ - │ │ │ │ │ - // scale the tiles inside the back buffer │ │ │ │ │ - var tiles = backBuffer.childNodes, │ │ │ │ │ - tile; │ │ │ │ │ - for (var i = tiles.length - 1; i >= 0; --i) { │ │ │ │ │ - tile = tiles[i]; │ │ │ │ │ - tile.style.top = ((ratio * tile._i * tile._h) | 0) + 'px'; │ │ │ │ │ - tile.style.left = ((ratio * tile._j * tile._w) | 0) + 'px'; │ │ │ │ │ - tile.style.width = Math.round(ratio * tile._w) + 'px'; │ │ │ │ │ - tile.style.height = Math.round(ratio * tile._h) + 'px'; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // and position it (based on the grid's top-left corner) │ │ │ │ │ - var position = this.getViewPortPxFromLonLat( │ │ │ │ │ - this.backBufferLonLat, resolution); │ │ │ │ │ - var leftOffset = this.map.layerContainerOriginPx.x; │ │ │ │ │ - var topOffset = this.map.layerContainerOriginPx.y; │ │ │ │ │ - backBuffer.style.left = Math.round(position.x - leftOffset) + 'px'; │ │ │ │ │ - backBuffer.style.top = Math.round(position.y - topOffset) + 'px'; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: createBackBuffer │ │ │ │ │ - * Create a back buffer. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {DOMElement} The DOM element for the back buffer, undefined if the │ │ │ │ │ - * grid isn't initialized yet. │ │ │ │ │ - */ │ │ │ │ │ - createBackBuffer: function() { │ │ │ │ │ - var backBuffer; │ │ │ │ │ - if (this.grid.length > 0) { │ │ │ │ │ - backBuffer = document.createElement('div'); │ │ │ │ │ - backBuffer.id = this.div.id + '_bb'; │ │ │ │ │ - backBuffer.className = 'olBackBuffer'; │ │ │ │ │ - backBuffer.style.position = 'absolute'; │ │ │ │ │ - var map = this.map; │ │ │ │ │ - backBuffer.style.zIndex = this.transitionEffect === 'resize' ? │ │ │ │ │ - this.getZIndex() - 1 : │ │ │ │ │ - // 'map-resize': │ │ │ │ │ - map.Z_INDEX_BASE.BaseLayer - │ │ │ │ │ - (map.getNumLayers() - map.getLayerIndex(this)); │ │ │ │ │ - for (var i = 0, lenI = this.grid.length; i < lenI; i++) { │ │ │ │ │ - for (var j = 0, lenJ = this.grid[i].length; j < lenJ; j++) { │ │ │ │ │ - var tile = this.grid[i][j], │ │ │ │ │ - markup = this.grid[i][j].createBackBuffer(); │ │ │ │ │ - if (markup) { │ │ │ │ │ - markup._i = i; │ │ │ │ │ - markup._j = j; │ │ │ │ │ - markup._w = tile.size.w; │ │ │ │ │ - markup._h = tile.size.h; │ │ │ │ │ - markup.id = tile.id + '_bb'; │ │ │ │ │ - backBuffer.appendChild(markup); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - return backBuffer; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: removeBackBuffer │ │ │ │ │ - * Remove back buffer from DOM. │ │ │ │ │ - */ │ │ │ │ │ - removeBackBuffer: function() { │ │ │ │ │ - if (this._transitionElement) { │ │ │ │ │ - for (var i = this.transitionendEvents.length - 1; i >= 0; --i) { │ │ │ │ │ - OpenLayers.Event.stopObserving(this._transitionElement, │ │ │ │ │ - this.transitionendEvents[i], this._removeBackBuffer); │ │ │ │ │ - } │ │ │ │ │ - delete this._transitionElement; │ │ │ │ │ - } │ │ │ │ │ - if (this.backBuffer) { │ │ │ │ │ - if (this.backBuffer.parentNode) { │ │ │ │ │ - this.backBuffer.parentNode.removeChild(this.backBuffer); │ │ │ │ │ - } │ │ │ │ │ - this.backBuffer = null; │ │ │ │ │ - this.backBufferResolution = null; │ │ │ │ │ - if (this.backBufferTimerId !== null) { │ │ │ │ │ - window.clearTimeout(this.backBufferTimerId); │ │ │ │ │ - this.backBufferTimerId = null; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: moveByPx │ │ │ │ │ - * Move the layer based on pixel vector. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * dx - {Number} │ │ │ │ │ - * dy - {Number} │ │ │ │ │ - */ │ │ │ │ │ - moveByPx: function(dx, dy) { │ │ │ │ │ - if (!this.singleTile) { │ │ │ │ │ - this.moveGriddedTiles(); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: setTileSize │ │ │ │ │ - * Check if we are in singleTile mode and if so, set the size as a ratio │ │ │ │ │ - * of the map size (as specified by the layer's 'ratio' property). │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * size - {} │ │ │ │ │ - */ │ │ │ │ │ - setTileSize: function(size) { │ │ │ │ │ - if (this.singleTile) { │ │ │ │ │ - size = this.map.getSize(); │ │ │ │ │ - size.h = parseInt(size.h * this.ratio, 10); │ │ │ │ │ - size.w = parseInt(size.w * this.ratio, 10); │ │ │ │ │ - } │ │ │ │ │ - OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this, [size]); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getTilesBounds │ │ │ │ │ - * Return the bounds of the tile grid. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} A Bounds object representing the bounds of all the │ │ │ │ │ - * currently loaded tiles (including those partially or not at all seen │ │ │ │ │ - * onscreen). │ │ │ │ │ - */ │ │ │ │ │ - getTilesBounds: function() { │ │ │ │ │ - var bounds = null; │ │ │ │ │ - │ │ │ │ │ - var length = this.grid.length; │ │ │ │ │ - if (length) { │ │ │ │ │ - var bottomLeftTileBounds = this.grid[length - 1][0].bounds, │ │ │ │ │ - width = this.grid[0].length * bottomLeftTileBounds.getWidth(), │ │ │ │ │ - height = this.grid.length * bottomLeftTileBounds.getHeight(); │ │ │ │ │ - │ │ │ │ │ - bounds = new OpenLayers.Bounds(bottomLeftTileBounds.left, │ │ │ │ │ - bottomLeftTileBounds.bottom, │ │ │ │ │ - bottomLeftTileBounds.left + width, │ │ │ │ │ - bottomLeftTileBounds.bottom + height); │ │ │ │ │ - } │ │ │ │ │ - return bounds; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: initSingleTile │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * bounds - {} │ │ │ │ │ - */ │ │ │ │ │ - initSingleTile: function(bounds) { │ │ │ │ │ - this.events.triggerEvent("retile"); │ │ │ │ │ - │ │ │ │ │ - //determine new tile bounds │ │ │ │ │ - var center = bounds.getCenterLonLat(); │ │ │ │ │ - var tileWidth = bounds.getWidth() * this.ratio; │ │ │ │ │ - var tileHeight = bounds.getHeight() * this.ratio; │ │ │ │ │ - │ │ │ │ │ - var tileBounds = │ │ │ │ │ - new OpenLayers.Bounds(center.lon - (tileWidth / 2), │ │ │ │ │ - center.lat - (tileHeight / 2), │ │ │ │ │ - center.lon + (tileWidth / 2), │ │ │ │ │ - center.lat + (tileHeight / 2)); │ │ │ │ │ - │ │ │ │ │ - var px = this.map.getLayerPxFromLonLat({ │ │ │ │ │ - lon: tileBounds.left, │ │ │ │ │ - lat: tileBounds.top │ │ │ │ │ - }); │ │ │ │ │ - │ │ │ │ │ - if (!this.grid.length) { │ │ │ │ │ - this.grid[0] = []; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - var tile = this.grid[0][0]; │ │ │ │ │ - if (!tile) { │ │ │ │ │ - tile = this.addTile(tileBounds, px); │ │ │ │ │ - │ │ │ │ │ - this.addTileMonitoringHooks(tile); │ │ │ │ │ - tile.draw(); │ │ │ │ │ - this.grid[0][0] = tile; │ │ │ │ │ - } else { │ │ │ │ │ - tile.moveTo(tileBounds, px); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - //remove all but our single tile │ │ │ │ │ - this.removeExcessTiles(1, 1); │ │ │ │ │ - │ │ │ │ │ - // store the resolution of the grid │ │ │ │ │ - this.gridResolution = this.getServerResolution(); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: calculateGridLayout │ │ │ │ │ - * Generate parameters for the grid layout. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * bounds - {|Object} OpenLayers.Bounds or an │ │ │ │ │ - * object with a 'left' and 'top' properties. │ │ │ │ │ - * origin - {|Object} OpenLayers.LonLat or an │ │ │ │ │ - * object with a 'lon' and 'lat' properties. │ │ │ │ │ - * resolution - {Number} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} Object containing properties tilelon, tilelat, startcol, │ │ │ │ │ - * startrow │ │ │ │ │ - */ │ │ │ │ │ - calculateGridLayout: function(bounds, origin, resolution) { │ │ │ │ │ - var tilelon = resolution * this.tileSize.w; │ │ │ │ │ - var tilelat = resolution * this.tileSize.h; │ │ │ │ │ - │ │ │ │ │ - var offsetlon = bounds.left - origin.lon; │ │ │ │ │ - var tilecol = Math.floor(offsetlon / tilelon) - this.buffer; │ │ │ │ │ - │ │ │ │ │ - var rowSign = this.rowSign; │ │ │ │ │ - │ │ │ │ │ - var offsetlat = rowSign * (origin.lat - bounds.top + tilelat); │ │ │ │ │ - var tilerow = Math[~rowSign ? 'floor' : 'ceil'](offsetlat / tilelat) - this.buffer * rowSign; │ │ │ │ │ - │ │ │ │ │ - return { │ │ │ │ │ - tilelon: tilelon, │ │ │ │ │ - tilelat: tilelat, │ │ │ │ │ - startcol: tilecol, │ │ │ │ │ - startrow: tilerow │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: getTileOrigin │ │ │ │ │ - * Determine the origin for aligning the grid of tiles. If a │ │ │ │ │ - * property is supplied, that will be returned. Otherwise, the origin │ │ │ │ │ - * will be derived from the layer's property. In this case, │ │ │ │ │ - * the tile origin will be the corner of the given by the │ │ │ │ │ - * property. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} The tile origin. │ │ │ │ │ - */ │ │ │ │ │ - getTileOrigin: function() { │ │ │ │ │ - var origin = this.tileOrigin; │ │ │ │ │ - if (!origin) { │ │ │ │ │ - var extent = this.getMaxExtent(); │ │ │ │ │ - var edges = ({ │ │ │ │ │ - "tl": ["left", "top"], │ │ │ │ │ - "tr": ["right", "top"], │ │ │ │ │ - "bl": ["left", "bottom"], │ │ │ │ │ - "br": ["right", "bottom"] │ │ │ │ │ - })[this.tileOriginCorner]; │ │ │ │ │ - origin = new OpenLayers.LonLat(extent[edges[0]], extent[edges[1]]); │ │ │ │ │ - } │ │ │ │ │ - return origin; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: getTileBoundsForGridIndex │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * row - {Number} The row of the grid │ │ │ │ │ - * col - {Number} The column of the grid │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} The bounds for the tile at (row, col) │ │ │ │ │ - */ │ │ │ │ │ - getTileBoundsForGridIndex: function(row, col) { │ │ │ │ │ - var origin = this.getTileOrigin(); │ │ │ │ │ - var tileLayout = this.gridLayout; │ │ │ │ │ - var tilelon = tileLayout.tilelon; │ │ │ │ │ - var tilelat = tileLayout.tilelat; │ │ │ │ │ - var startcol = tileLayout.startcol; │ │ │ │ │ - var startrow = tileLayout.startrow; │ │ │ │ │ - var rowSign = this.rowSign; │ │ │ │ │ - return new OpenLayers.Bounds( │ │ │ │ │ - origin.lon + (startcol + col) * tilelon, │ │ │ │ │ - origin.lat - (startrow + row * rowSign) * tilelat * rowSign, │ │ │ │ │ - origin.lon + (startcol + col + 1) * tilelon, │ │ │ │ │ - origin.lat - (startrow + (row - 1) * rowSign) * tilelat * rowSign │ │ │ │ │ - ); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: initGriddedTiles │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * bounds - {} │ │ │ │ │ - */ │ │ │ │ │ - initGriddedTiles: function(bounds) { │ │ │ │ │ - this.events.triggerEvent("retile"); │ │ │ │ │ - │ │ │ │ │ - // work out mininum number of rows and columns; this is the number of │ │ │ │ │ - // tiles required to cover the viewport plus at least one for panning │ │ │ │ │ - │ │ │ │ │ - var viewSize = this.map.getSize(); │ │ │ │ │ - │ │ │ │ │ - var origin = this.getTileOrigin(); │ │ │ │ │ - var resolution = this.map.getResolution(), │ │ │ │ │ - serverResolution = this.getServerResolution(), │ │ │ │ │ - ratio = resolution / serverResolution, │ │ │ │ │ - tileSize = { │ │ │ │ │ - w: this.tileSize.w / ratio, │ │ │ │ │ - h: this.tileSize.h / ratio │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - var minRows = Math.ceil(viewSize.h / tileSize.h) + │ │ │ │ │ - 2 * this.buffer + 1; │ │ │ │ │ - var minCols = Math.ceil(viewSize.w / tileSize.w) + │ │ │ │ │ - 2 * this.buffer + 1; │ │ │ │ │ - │ │ │ │ │ - var tileLayout = this.calculateGridLayout(bounds, origin, serverResolution); │ │ │ │ │ - this.gridLayout = tileLayout; │ │ │ │ │ - │ │ │ │ │ - var tilelon = tileLayout.tilelon; │ │ │ │ │ - var tilelat = tileLayout.tilelat; │ │ │ │ │ - │ │ │ │ │ - var layerContainerDivLeft = this.map.layerContainerOriginPx.x; │ │ │ │ │ - var layerContainerDivTop = this.map.layerContainerOriginPx.y; │ │ │ │ │ - │ │ │ │ │ - var tileBounds = this.getTileBoundsForGridIndex(0, 0); │ │ │ │ │ - var startPx = this.map.getViewPortPxFromLonLat( │ │ │ │ │ - new OpenLayers.LonLat(tileBounds.left, tileBounds.top) │ │ │ │ │ - ); │ │ │ │ │ - startPx.x = Math.round(startPx.x) - layerContainerDivLeft; │ │ │ │ │ - startPx.y = Math.round(startPx.y) - layerContainerDivTop; │ │ │ │ │ - │ │ │ │ │ - var tileData = [], │ │ │ │ │ - center = this.map.getCenter(); │ │ │ │ │ - │ │ │ │ │ - var rowidx = 0; │ │ │ │ │ - do { │ │ │ │ │ - var row = this.grid[rowidx]; │ │ │ │ │ - if (!row) { │ │ │ │ │ - row = []; │ │ │ │ │ - this.grid.push(row); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - var colidx = 0; │ │ │ │ │ - do { │ │ │ │ │ - tileBounds = this.getTileBoundsForGridIndex(rowidx, colidx); │ │ │ │ │ - var px = startPx.clone(); │ │ │ │ │ - px.x = px.x + colidx * Math.round(tileSize.w); │ │ │ │ │ - px.y = px.y + rowidx * Math.round(tileSize.h); │ │ │ │ │ - var tile = row[colidx]; │ │ │ │ │ - if (!tile) { │ │ │ │ │ - tile = this.addTile(tileBounds, px); │ │ │ │ │ - this.addTileMonitoringHooks(tile); │ │ │ │ │ - row.push(tile); │ │ │ │ │ - } else { │ │ │ │ │ - tile.moveTo(tileBounds, px, false); │ │ │ │ │ - } │ │ │ │ │ - var tileCenter = tileBounds.getCenterLonLat(); │ │ │ │ │ - tileData.push({ │ │ │ │ │ - tile: tile, │ │ │ │ │ - distance: Math.pow(tileCenter.lon - center.lon, 2) + │ │ │ │ │ - Math.pow(tileCenter.lat - center.lat, 2) │ │ │ │ │ - }); │ │ │ │ │ - │ │ │ │ │ - colidx += 1; │ │ │ │ │ - } while ((tileBounds.right <= bounds.right + tilelon * this.buffer) || │ │ │ │ │ - colidx < minCols); │ │ │ │ │ - │ │ │ │ │ - rowidx += 1; │ │ │ │ │ - } while ((tileBounds.bottom >= bounds.bottom - tilelat * this.buffer) || │ │ │ │ │ - rowidx < minRows); │ │ │ │ │ - │ │ │ │ │ - //shave off exceess rows and colums │ │ │ │ │ - this.removeExcessTiles(rowidx, colidx); │ │ │ │ │ - │ │ │ │ │ - var resolution = this.getServerResolution(); │ │ │ │ │ - // store the resolution of the grid │ │ │ │ │ - this.gridResolution = resolution; │ │ │ │ │ - │ │ │ │ │ - //now actually draw the tiles │ │ │ │ │ - tileData.sort(function(a, b) { │ │ │ │ │ - return a.distance - b.distance; │ │ │ │ │ - }); │ │ │ │ │ - for (var i = 0, ii = tileData.length; i < ii; ++i) { │ │ │ │ │ - tileData[i].tile.draw(); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: getMaxExtent │ │ │ │ │ - * Get this layer's maximum extent. (Implemented as a getter for │ │ │ │ │ - * potential specific implementations in sub-classes.) │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - getMaxExtent: function() { │ │ │ │ │ - return this.maxExtent; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: addTile │ │ │ │ │ - * Create a tile, initialize it, and add it to the layer div. │ │ │ │ │ - * │ │ │ │ │ - * Parameters │ │ │ │ │ - * bounds - {} │ │ │ │ │ - * position - {} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} The added OpenLayers.Tile │ │ │ │ │ - */ │ │ │ │ │ - addTile: function(bounds, position) { │ │ │ │ │ - var tile = new this.tileClass( │ │ │ │ │ - this, position, bounds, null, this.tileSize, this.tileOptions │ │ │ │ │ - ); │ │ │ │ │ - this.events.triggerEvent("addtile", { │ │ │ │ │ - tile: tile │ │ │ │ │ - }); │ │ │ │ │ - return tile; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: addTileMonitoringHooks │ │ │ │ │ - * This function takes a tile as input and adds the appropriate hooks to │ │ │ │ │ - * the tile so that the layer can keep track of the loading tiles. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * tile - {} │ │ │ │ │ - */ │ │ │ │ │ - addTileMonitoringHooks: function(tile) { │ │ │ │ │ - │ │ │ │ │ - var replacingCls = 'olTileReplacing'; │ │ │ │ │ - │ │ │ │ │ - tile.onLoadStart = function() { │ │ │ │ │ - //if that was first tile then trigger a 'loadstart' on the layer │ │ │ │ │ - if (this.loading === false) { │ │ │ │ │ - this.loading = true; │ │ │ │ │ - this.events.triggerEvent("loadstart"); │ │ │ │ │ - } │ │ │ │ │ - this.events.triggerEvent("tileloadstart", { │ │ │ │ │ - tile: tile │ │ │ │ │ - }); │ │ │ │ │ - this.numLoadingTiles++; │ │ │ │ │ - if (!this.singleTile && this.backBuffer && this.gridResolution === this.backBufferResolution) { │ │ │ │ │ - OpenLayers.Element.addClass(tile.getTile(), replacingCls); │ │ │ │ │ - } │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - tile.onLoadEnd = function(evt) { │ │ │ │ │ - this.numLoadingTiles--; │ │ │ │ │ - var aborted = evt.type === 'unload'; │ │ │ │ │ - this.events.triggerEvent("tileloaded", { │ │ │ │ │ - tile: tile, │ │ │ │ │ - aborted: aborted │ │ │ │ │ - }); │ │ │ │ │ - if (!this.singleTile && !aborted && this.backBuffer && this.gridResolution === this.backBufferResolution) { │ │ │ │ │ - var tileDiv = tile.getTile(); │ │ │ │ │ - if (OpenLayers.Element.getStyle(tileDiv, 'display') === 'none') { │ │ │ │ │ - var bufferTile = document.getElementById(tile.id + '_bb'); │ │ │ │ │ - if (bufferTile) { │ │ │ │ │ - bufferTile.parentNode.removeChild(bufferTile); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - OpenLayers.Element.removeClass(tileDiv, replacingCls); │ │ │ │ │ - } │ │ │ │ │ - //if that was the last tile, then trigger a 'loadend' on the layer │ │ │ │ │ - if (this.numLoadingTiles === 0) { │ │ │ │ │ - if (this.backBuffer) { │ │ │ │ │ - if (this.backBuffer.childNodes.length === 0) { │ │ │ │ │ - // no tiles transitioning, remove immediately │ │ │ │ │ - this.removeBackBuffer(); │ │ │ │ │ - } else { │ │ │ │ │ - // wait until transition has ended or delay has passed │ │ │ │ │ - this._transitionElement = aborted ? │ │ │ │ │ - this.div.lastChild : tile.imgDiv; │ │ │ │ │ - var transitionendEvents = this.transitionendEvents; │ │ │ │ │ - for (var i = transitionendEvents.length - 1; i >= 0; --i) { │ │ │ │ │ - OpenLayers.Event.observe(this._transitionElement, │ │ │ │ │ - transitionendEvents[i], │ │ │ │ │ - this._removeBackBuffer); │ │ │ │ │ - } │ │ │ │ │ - // the removal of the back buffer is delayed to prevent │ │ │ │ │ - // flash effects due to the animation of tile displaying │ │ │ │ │ - this.backBufferTimerId = window.setTimeout( │ │ │ │ │ - this._removeBackBuffer, this.removeBackBufferDelay │ │ │ │ │ - ); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - this.loading = false; │ │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ │ - } │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - tile.onLoadError = function() { │ │ │ │ │ - this.events.triggerEvent("tileerror", { │ │ │ │ │ - tile: tile │ │ │ │ │ - }); │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - tile.events.on({ │ │ │ │ │ - "loadstart": tile.onLoadStart, │ │ │ │ │ - "loadend": tile.onLoadEnd, │ │ │ │ │ - "unload": tile.onLoadEnd, │ │ │ │ │ - "loaderror": tile.onLoadError, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: removeTileMonitoringHooks │ │ │ │ │ - * This function takes a tile as input and removes the tile hooks │ │ │ │ │ - * that were added in addTileMonitoringHooks() │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * tile - {} │ │ │ │ │ - */ │ │ │ │ │ - removeTileMonitoringHooks: function(tile) { │ │ │ │ │ - tile.unload(); │ │ │ │ │ - tile.events.un({ │ │ │ │ │ - "loadstart": tile.onLoadStart, │ │ │ │ │ - "loadend": tile.onLoadEnd, │ │ │ │ │ - "unload": tile.onLoadEnd, │ │ │ │ │ - "loaderror": tile.onLoadError, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: moveGriddedTiles │ │ │ │ │ - */ │ │ │ │ │ - moveGriddedTiles: function() { │ │ │ │ │ - var buffer = this.buffer + 1; │ │ │ │ │ - while (true) { │ │ │ │ │ - var tlTile = this.grid[0][0]; │ │ │ │ │ - var tlViewPort = { │ │ │ │ │ - x: tlTile.position.x + │ │ │ │ │ - this.map.layerContainerOriginPx.x, │ │ │ │ │ - y: tlTile.position.y + │ │ │ │ │ - this.map.layerContainerOriginPx.y │ │ │ │ │ - }; │ │ │ │ │ - var ratio = this.getServerResolution() / this.map.getResolution(); │ │ │ │ │ - var tileSize = { │ │ │ │ │ - w: Math.round(this.tileSize.w * ratio), │ │ │ │ │ - h: Math.round(this.tileSize.h * ratio) │ │ │ │ │ - }; │ │ │ │ │ - if (tlViewPort.x > -tileSize.w * (buffer - 1)) { │ │ │ │ │ - this.shiftColumn(true, tileSize); │ │ │ │ │ - } else if (tlViewPort.x < -tileSize.w * buffer) { │ │ │ │ │ - this.shiftColumn(false, tileSize); │ │ │ │ │ - } else if (tlViewPort.y > -tileSize.h * (buffer - 1)) { │ │ │ │ │ - this.shiftRow(true, tileSize); │ │ │ │ │ - } else if (tlViewPort.y < -tileSize.h * buffer) { │ │ │ │ │ - this.shiftRow(false, tileSize); │ │ │ │ │ - } else { │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: shiftRow │ │ │ │ │ - * Shifty grid work │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * prepend - {Boolean} if true, prepend to beginning. │ │ │ │ │ - * if false, then append to end │ │ │ │ │ - * tileSize - {Object} rendered tile size; object with w and h properties │ │ │ │ │ - */ │ │ │ │ │ - shiftRow: function(prepend, tileSize) { │ │ │ │ │ - var grid = this.grid; │ │ │ │ │ - var rowIndex = prepend ? 0 : (grid.length - 1); │ │ │ │ │ - var sign = prepend ? -1 : 1; │ │ │ │ │ - var rowSign = this.rowSign; │ │ │ │ │ - var tileLayout = this.gridLayout; │ │ │ │ │ - tileLayout.startrow += sign * rowSign; │ │ │ │ │ - │ │ │ │ │ - var modelRow = grid[rowIndex]; │ │ │ │ │ - var row = grid[prepend ? 'pop' : 'shift'](); │ │ │ │ │ - for (var i = 0, len = row.length; i < len; i++) { │ │ │ │ │ - var tile = row[i]; │ │ │ │ │ - var position = modelRow[i].position.clone(); │ │ │ │ │ - position.y += tileSize.h * sign; │ │ │ │ │ - tile.moveTo(this.getTileBoundsForGridIndex(rowIndex, i), position); │ │ │ │ │ - } │ │ │ │ │ - grid[prepend ? 'unshift' : 'push'](row); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: shiftColumn │ │ │ │ │ - * Shift grid work in the other dimension │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * prepend - {Boolean} if true, prepend to beginning. │ │ │ │ │ - * if false, then append to end │ │ │ │ │ - * tileSize - {Object} rendered tile size; object with w and h properties │ │ │ │ │ - */ │ │ │ │ │ - shiftColumn: function(prepend, tileSize) { │ │ │ │ │ - var grid = this.grid; │ │ │ │ │ - var colIndex = prepend ? 0 : (grid[0].length - 1); │ │ │ │ │ - var sign = prepend ? -1 : 1; │ │ │ │ │ - var tileLayout = this.gridLayout; │ │ │ │ │ - tileLayout.startcol += sign; │ │ │ │ │ - │ │ │ │ │ - for (var i = 0, len = grid.length; i < len; i++) { │ │ │ │ │ - var row = grid[i]; │ │ │ │ │ - var position = row[colIndex].position.clone(); │ │ │ │ │ - var tile = row[prepend ? 'pop' : 'shift'](); │ │ │ │ │ - position.x += tileSize.w * sign; │ │ │ │ │ - tile.moveTo(this.getTileBoundsForGridIndex(i, colIndex), position); │ │ │ │ │ - row[prepend ? 'unshift' : 'push'](tile); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: removeExcessTiles │ │ │ │ │ - * When the size of the map or the buffer changes, we may need to │ │ │ │ │ - * remove some excess rows and columns. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * rows - {Integer} Maximum number of rows we want our grid to have. │ │ │ │ │ - * columns - {Integer} Maximum number of columns we want our grid to have. │ │ │ │ │ - */ │ │ │ │ │ - removeExcessTiles: function(rows, columns) { │ │ │ │ │ - var i, l; │ │ │ │ │ - │ │ │ │ │ - // remove extra rows │ │ │ │ │ - while (this.grid.length > rows) { │ │ │ │ │ - var row = this.grid.pop(); │ │ │ │ │ - for (i = 0, l = row.length; i < l; i++) { │ │ │ │ │ - var tile = row[i]; │ │ │ │ │ - this.destroyTile(tile); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // remove extra columns │ │ │ │ │ - for (i = 0, l = this.grid.length; i < l; i++) { │ │ │ │ │ - while (this.grid[i].length > columns) { │ │ │ │ │ - var row = this.grid[i]; │ │ │ │ │ - var tile = row.pop(); │ │ │ │ │ - this.destroyTile(tile); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: onMapResize │ │ │ │ │ - * For singleTile layers, this will set a new tile size according to the │ │ │ │ │ - * dimensions of the map pane. │ │ │ │ │ - */ │ │ │ │ │ - onMapResize: function() { │ │ │ │ │ - if (this.singleTile) { │ │ │ │ │ - this.clearGrid(); │ │ │ │ │ - this.setTileSize(); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getTileBounds │ │ │ │ │ - * Returns The tile bounds for a layer given a pixel location. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * viewPortPx - {} The location in the viewport. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} Bounds of the tile at the given pixel location. │ │ │ │ │ - */ │ │ │ │ │ - getTileBounds: function(viewPortPx) { │ │ │ │ │ - var maxExtent = this.maxExtent; │ │ │ │ │ - var resolution = this.getResolution(); │ │ │ │ │ - var tileMapWidth = resolution * this.tileSize.w; │ │ │ │ │ - var tileMapHeight = resolution * this.tileSize.h; │ │ │ │ │ - var mapPoint = this.getLonLatFromViewPortPx(viewPortPx); │ │ │ │ │ - var tileLeft = maxExtent.left + (tileMapWidth * │ │ │ │ │ - Math.floor((mapPoint.lon - │ │ │ │ │ - maxExtent.left) / │ │ │ │ │ - tileMapWidth)); │ │ │ │ │ - var tileBottom = maxExtent.bottom + (tileMapHeight * │ │ │ │ │ - Math.floor((mapPoint.lat - │ │ │ │ │ - maxExtent.bottom) / │ │ │ │ │ - tileMapHeight)); │ │ │ │ │ - return new OpenLayers.Bounds(tileLeft, tileBottom, │ │ │ │ │ - tileLeft + tileMapWidth, │ │ │ │ │ - tileBottom + tileMapHeight); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Grid" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/TileManager.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ │ - * @requires OpenLayers/BaseTypes.js │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Element.js │ │ │ │ │ - * @requires OpenLayers/Layer/Grid.js │ │ │ │ │ - * @requires OpenLayers/Tile/Image.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.TileManager │ │ │ │ │ - * Provides queueing of image requests and caching of image elements. │ │ │ │ │ - * │ │ │ │ │ - * Queueing avoids unnecessary image requests while changing zoom levels │ │ │ │ │ - * quickly, and helps improve dragging performance on mobile devices that show │ │ │ │ │ - * a lag in dragging when loading of new images starts. and │ │ │ │ │ - * are the configuration options to control this behavior. │ │ │ │ │ - * │ │ │ │ │ - * Caching avoids setting the src on image elements for images that have already │ │ │ │ │ - * been used. Several maps can share a TileManager instance, in which case each │ │ │ │ │ - * map gets its own tile queue, but all maps share the same tile cache. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.TileManager = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: cacheSize │ │ │ │ │ - * {Number} Number of image elements to keep referenced in this instance's │ │ │ │ │ - * cache for fast reuse. Default is 256. │ │ │ │ │ - */ │ │ │ │ │ - cacheSize: 256, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: tilesPerFrame │ │ │ │ │ - * {Number} Number of queued tiles to load per frame (see ). │ │ │ │ │ - * Default is 2. │ │ │ │ │ - */ │ │ │ │ │ - tilesPerFrame: 2, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: frameDelay │ │ │ │ │ - * {Number} Delay between tile loading frames (see ) in │ │ │ │ │ - * milliseconds. Default is 16. │ │ │ │ │ - */ │ │ │ │ │ - frameDelay: 16, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: moveDelay │ │ │ │ │ - * {Number} Delay in milliseconds after a map's move event before loading │ │ │ │ │ - * tiles. Default is 100. │ │ │ │ │ - */ │ │ │ │ │ - moveDelay: 100, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: zoomDelay │ │ │ │ │ - * {Number} Delay in milliseconds after a map's zoomend event before loading │ │ │ │ │ - * tiles. Default is 200. │ │ │ │ │ - */ │ │ │ │ │ - zoomDelay: 200, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: maps │ │ │ │ │ - * {Array()} The maps to manage tiles on. │ │ │ │ │ - */ │ │ │ │ │ - maps: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: tileQueueId │ │ │ │ │ - * {Object} The ids of the loop, keyed by map id. │ │ │ │ │ - */ │ │ │ │ │ - tileQueueId: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: tileQueue │ │ │ │ │ - * {Object(Array())} Tiles queued for drawing, keyed by │ │ │ │ │ - * map id. │ │ │ │ │ - */ │ │ │ │ │ - tileQueue: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: tileCache │ │ │ │ │ - * {Object} Cached image elements, keyed by URL. │ │ │ │ │ - */ │ │ │ │ │ - tileCache: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: tileCacheIndex │ │ │ │ │ - * {Array(String)} URLs of cached tiles. First entry is the least recently │ │ │ │ │ - * used. │ │ │ │ │ - */ │ │ │ │ │ - tileCacheIndex: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.TileManager │ │ │ │ │ - * Constructor for a new instance. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} Configuration for this instance. │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(options) { │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ - this.maps = []; │ │ │ │ │ - this.tileQueueId = {}; │ │ │ │ │ - this.tileQueue = {}; │ │ │ │ │ - this.tileCache = {}; │ │ │ │ │ - this.tileCacheIndex = []; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: addMap │ │ │ │ │ - * Binds this instance to a map │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * map - {} │ │ │ │ │ - */ │ │ │ │ │ - addMap: function(map) { │ │ │ │ │ - if (this._destroyed || !OpenLayers.Layer.Grid) { │ │ │ │ │ - return; │ │ │ │ │ - } │ │ │ │ │ - this.maps.push(map); │ │ │ │ │ - this.tileQueue[map.id] = []; │ │ │ │ │ - for (var i = 0, ii = map.layers.length; i < ii; ++i) { │ │ │ │ │ - this.addLayer({ │ │ │ │ │ - layer: map.layers[i] │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ - map.events.on({ │ │ │ │ │ - move: this.move, │ │ │ │ │ - zoomend: this.zoomEnd, │ │ │ │ │ - changelayer: this.changeLayer, │ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ │ - preremovelayer: this.removeLayer, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: removeMap │ │ │ │ │ - * Unbinds this instance from a map │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * map - {} │ │ │ │ │ - */ │ │ │ │ │ - removeMap: function(map) { │ │ │ │ │ - if (this._destroyed || !OpenLayers.Layer.Grid) { │ │ │ │ │ - return; │ │ │ │ │ - } │ │ │ │ │ - window.clearTimeout(this.tileQueueId[map.id]); │ │ │ │ │ - if (map.layers) { │ │ │ │ │ - for (var i = 0, ii = map.layers.length; i < ii; ++i) { │ │ │ │ │ - this.removeLayer({ │ │ │ │ │ - layer: map.layers[i] │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - if (map.events) { │ │ │ │ │ - map.events.un({ │ │ │ │ │ - move: this.move, │ │ │ │ │ - zoomend: this.zoomEnd, │ │ │ │ │ - changelayer: this.changeLayer, │ │ │ │ │ - addlayer: this.addLayer, │ │ │ │ │ - preremovelayer: this.removeLayer, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ - delete this.tileQueue[map.id]; │ │ │ │ │ - delete this.tileQueueId[map.id]; │ │ │ │ │ - OpenLayers.Util.removeItem(this.maps, map); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: move │ │ │ │ │ - * Handles the map's move event │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Object} Listener argument │ │ │ │ │ - */ │ │ │ │ │ - move: function(evt) { │ │ │ │ │ - this.updateTimeout(evt.object, this.moveDelay, true); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: zoomEnd │ │ │ │ │ - * Handles the map's zoomEnd event │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Object} Listener argument │ │ │ │ │ - */ │ │ │ │ │ - zoomEnd: function(evt) { │ │ │ │ │ - this.updateTimeout(evt.object, this.zoomDelay); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: changeLayer │ │ │ │ │ - * Handles the map's changeLayer event │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Object} Listener argument │ │ │ │ │ - */ │ │ │ │ │ - changeLayer: function(evt) { │ │ │ │ │ - if (evt.property === 'visibility' || evt.property === 'params') { │ │ │ │ │ - this.updateTimeout(evt.object, 0); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: addLayer │ │ │ │ │ - * Handles the map's addlayer event │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Object} The listener argument │ │ │ │ │ - */ │ │ │ │ │ - addLayer: function(evt) { │ │ │ │ │ - var layer = evt.layer; │ │ │ │ │ - if (layer instanceof OpenLayers.Layer.Grid) { │ │ │ │ │ - layer.events.on({ │ │ │ │ │ - addtile: this.addTile, │ │ │ │ │ - retile: this.clearTileQueue, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ - var i, j, tile; │ │ │ │ │ - for (i = layer.grid.length - 1; i >= 0; --i) { │ │ │ │ │ - for (j = layer.grid[i].length - 1; j >= 0; --j) { │ │ │ │ │ - tile = layer.grid[i][j]; │ │ │ │ │ - this.addTile({ │ │ │ │ │ - tile: tile │ │ │ │ │ - }); │ │ │ │ │ - if (tile.url && !tile.imgDiv) { │ │ │ │ │ - this.manageTileCache({ │ │ │ │ │ - object: tile │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: removeLayer │ │ │ │ │ - * Handles the map's preremovelayer event │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Object} The listener argument │ │ │ │ │ - */ │ │ │ │ │ - removeLayer: function(evt) { │ │ │ │ │ - var layer = evt.layer; │ │ │ │ │ - if (layer instanceof OpenLayers.Layer.Grid) { │ │ │ │ │ - this.clearTileQueue({ │ │ │ │ │ - object: layer │ │ │ │ │ - }); │ │ │ │ │ - if (layer.events) { │ │ │ │ │ - layer.events.un({ │ │ │ │ │ - addtile: this.addTile, │ │ │ │ │ - retile: this.clearTileQueue, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ - if (layer.grid) { │ │ │ │ │ - var i, j, tile; │ │ │ │ │ - for (i = layer.grid.length - 1; i >= 0; --i) { │ │ │ │ │ - for (j = layer.grid[i].length - 1; j >= 0; --j) { │ │ │ │ │ - tile = layer.grid[i][j]; │ │ │ │ │ - this.unloadTile({ │ │ │ │ │ - object: tile │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: updateTimeout │ │ │ │ │ - * Applies the or to the loop, │ │ │ │ │ - * and schedules more queue processing after if there are still │ │ │ │ │ - * tiles in the queue. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * map - {} The map to update the timeout for │ │ │ │ │ - * delay - {Number} The delay to apply │ │ │ │ │ - * nice - {Boolean} If true, the timeout function will only be created if │ │ │ │ │ - * the tilequeue is not empty. This is used by the move handler to │ │ │ │ │ - * avoid impacts on dragging performance. For other events, the tile │ │ │ │ │ - * queue may not be populated yet, so we need to set the timer │ │ │ │ │ - * regardless of the queue size. │ │ │ │ │ - */ │ │ │ │ │ - updateTimeout: function(map, delay, nice) { │ │ │ │ │ - window.clearTimeout(this.tileQueueId[map.id]); │ │ │ │ │ - var tileQueue = this.tileQueue[map.id]; │ │ │ │ │ - if (!nice || tileQueue.length) { │ │ │ │ │ - this.tileQueueId[map.id] = window.setTimeout( │ │ │ │ │ - OpenLayers.Function.bind(function() { │ │ │ │ │ - this.drawTilesFromQueue(map); │ │ │ │ │ - if (tileQueue.length) { │ │ │ │ │ - this.updateTimeout(map, this.frameDelay); │ │ │ │ │ - } │ │ │ │ │ - }, this), delay │ │ │ │ │ - ); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: addTile │ │ │ │ │ - * Listener for the layer's addtile event │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Object} The listener argument │ │ │ │ │ - */ │ │ │ │ │ - addTile: function(evt) { │ │ │ │ │ - if (evt.tile instanceof OpenLayers.Tile.Image) { │ │ │ │ │ - evt.tile.events.on({ │ │ │ │ │ - beforedraw: this.queueTileDraw, │ │ │ │ │ - beforeload: this.manageTileCache, │ │ │ │ │ - loadend: this.addToCache, │ │ │ │ │ - unload: this.unloadTile, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ - } else { │ │ │ │ │ - // Layer has the wrong tile type, so don't handle it any longer │ │ │ │ │ - this.removeLayer({ │ │ │ │ │ - layer: evt.tile.layer │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: unloadTile │ │ │ │ │ - * Listener for the tile's unload event │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Object} The listener argument │ │ │ │ │ - */ │ │ │ │ │ - unloadTile: function(evt) { │ │ │ │ │ - var tile = evt.object; │ │ │ │ │ - tile.events.un({ │ │ │ │ │ - beforedraw: this.queueTileDraw, │ │ │ │ │ - beforeload: this.manageTileCache, │ │ │ │ │ - loadend: this.addToCache, │ │ │ │ │ - unload: this.unloadTile, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ - OpenLayers.Util.removeItem(this.tileQueue[tile.layer.map.id], tile); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: queueTileDraw │ │ │ │ │ - * Adds a tile to the queue that will draw it. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Object} Listener argument of the tile's beforedraw event │ │ │ │ │ - */ │ │ │ │ │ - queueTileDraw: function(evt) { │ │ │ │ │ - var tile = evt.object; │ │ │ │ │ - var queued = false; │ │ │ │ │ - var layer = tile.layer; │ │ │ │ │ - var url = layer.getURL(tile.bounds); │ │ │ │ │ - var img = this.tileCache[url]; │ │ │ │ │ - if (img && img.className !== 'olTileImage') { │ │ │ │ │ - // cached image no longer valid, e.g. because we're olTileReplacing │ │ │ │ │ - delete this.tileCache[url]; │ │ │ │ │ - OpenLayers.Util.removeItem(this.tileCacheIndex, url); │ │ │ │ │ - img = null; │ │ │ │ │ - } │ │ │ │ │ - // queue only if image with same url not cached already │ │ │ │ │ - if (layer.url && (layer.async || !img)) { │ │ │ │ │ - // add to queue only if not in queue already │ │ │ │ │ - var tileQueue = this.tileQueue[layer.map.id]; │ │ │ │ │ - if (!~OpenLayers.Util.indexOf(tileQueue, tile)) { │ │ │ │ │ - tileQueue.push(tile); │ │ │ │ │ - } │ │ │ │ │ - queued = true; │ │ │ │ │ - } │ │ │ │ │ - return !queued; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: drawTilesFromQueue │ │ │ │ │ - * Draws tiles from the tileQueue, and unqueues the tiles │ │ │ │ │ - */ │ │ │ │ │ - drawTilesFromQueue: function(map) { │ │ │ │ │ - var tileQueue = this.tileQueue[map.id]; │ │ │ │ │ - var limit = this.tilesPerFrame; │ │ │ │ │ - var animating = map.zoomTween && map.zoomTween.playing; │ │ │ │ │ - while (!animating && tileQueue.length && limit) { │ │ │ │ │ - tileQueue.shift().draw(true); │ │ │ │ │ - --limit; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: manageTileCache │ │ │ │ │ - * Adds, updates, removes and fetches cache entries. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Object} Listener argument of the tile's beforeload event │ │ │ │ │ - */ │ │ │ │ │ - manageTileCache: function(evt) { │ │ │ │ │ - var tile = evt.object; │ │ │ │ │ - var img = this.tileCache[tile.url]; │ │ │ │ │ - if (img) { │ │ │ │ │ - // if image is on its layer's backbuffer, remove it from backbuffer │ │ │ │ │ - if (img.parentNode && │ │ │ │ │ - OpenLayers.Element.hasClass(img.parentNode, 'olBackBuffer')) { │ │ │ │ │ - img.parentNode.removeChild(img); │ │ │ │ │ - img.id = null; │ │ │ │ │ - } │ │ │ │ │ - // only use image from cache if it is not on a layer already │ │ │ │ │ - if (!img.parentNode) { │ │ │ │ │ - img.style.visibility = 'hidden'; │ │ │ │ │ - img.style.opacity = 0; │ │ │ │ │ - tile.setImage(img); │ │ │ │ │ - // LRU - move tile to the end of the array to mark it as the most │ │ │ │ │ - // recently used │ │ │ │ │ - OpenLayers.Util.removeItem(this.tileCacheIndex, tile.url); │ │ │ │ │ - this.tileCacheIndex.push(tile.url); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: addToCache │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Object} Listener argument for the tile's loadend event │ │ │ │ │ - */ │ │ │ │ │ - addToCache: function(evt) { │ │ │ │ │ - var tile = evt.object; │ │ │ │ │ - if (!this.tileCache[tile.url]) { │ │ │ │ │ - if (!OpenLayers.Element.hasClass(tile.imgDiv, 'olImageLoadError')) { │ │ │ │ │ - if (this.tileCacheIndex.length >= this.cacheSize) { │ │ │ │ │ - delete this.tileCache[this.tileCacheIndex[0]]; │ │ │ │ │ - this.tileCacheIndex.shift(); │ │ │ │ │ - } │ │ │ │ │ - this.tileCache[tile.url] = tile.imgDiv; │ │ │ │ │ - this.tileCacheIndex.push(tile.url); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: clearTileQueue │ │ │ │ │ - * Clears the tile queue from tiles of a specific layer │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Object} Listener argument of the layer's retile event │ │ │ │ │ - */ │ │ │ │ │ - clearTileQueue: function(evt) { │ │ │ │ │ - var layer = evt.object; │ │ │ │ │ - var tileQueue = this.tileQueue[layer.map.id]; │ │ │ │ │ - for (var i = tileQueue.length - 1; i >= 0; --i) { │ │ │ │ │ - if (tileQueue[i].layer === layer) { │ │ │ │ │ - tileQueue.splice(i, 1); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: destroy │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - for (var i = this.maps.length - 1; i >= 0; --i) { │ │ │ │ │ - this.removeMap(this.maps[i]); │ │ │ │ │ - } │ │ │ │ │ - this.maps = null; │ │ │ │ │ - this.tileQueue = null; │ │ │ │ │ - this.tileQueueId = null; │ │ │ │ │ - this.tileCache = null; │ │ │ │ │ - this.tileCacheIndex = null; │ │ │ │ │ - this._destroyed = true; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - 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 │ │ │ │ │ - * {} 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: │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - 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 - {} 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 - {} 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: │ │ │ │ │ - * {} 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/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/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); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - 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. │ │ │ │ │ - * │ │ │ │ │ - * 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. │ │ │ │ │ - */ │ │ │ │ │ - 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({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * 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. │ │ │ │ │ - * │ │ │ │ │ - * 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/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/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. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Popup │ │ │ │ │ - * A popup is a small div that can opened and closed on the map. │ │ │ │ │ - * Typically opened in response to clicking on a marker. │ │ │ │ │ - * See . Popup's don't require their own │ │ │ │ │ - * layer and are added the the map using the │ │ │ │ │ - * method. │ │ │ │ │ - * │ │ │ │ │ - * Example: │ │ │ │ │ - * (code) │ │ │ │ │ - * popup = new OpenLayers.Popup("chicken", │ │ │ │ │ - * new OpenLayers.LonLat(5,40), │ │ │ │ │ - * new OpenLayers.Size(200,200), │ │ │ │ │ - * "example popup", │ │ │ │ │ - * true); │ │ │ │ │ - * │ │ │ │ │ - * map.addPopup(popup); │ │ │ │ │ - * (end) │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Popup = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: events │ │ │ │ │ - * {} custom event manager │ │ │ │ │ - */ │ │ │ │ │ - events: null, │ │ │ │ │ - │ │ │ │ │ - /** Property: id │ │ │ │ │ - * {String} the unique identifier assigned to this popup. │ │ │ │ │ - */ │ │ │ │ │ - id: "", │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: lonlat │ │ │ │ │ - * {} the position of this popup on the map │ │ │ │ │ - */ │ │ │ │ │ - lonlat: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: div │ │ │ │ │ - * {DOMElement} the div that contains this popup. │ │ │ │ │ - */ │ │ │ │ │ - div: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: contentSize │ │ │ │ │ - * {} the width and height of the content. │ │ │ │ │ - */ │ │ │ │ │ - contentSize: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: size │ │ │ │ │ - * {} the width and height of the popup. │ │ │ │ │ - */ │ │ │ │ │ - size: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: contentHTML │ │ │ │ │ - * {String} An HTML string for this popup to display. │ │ │ │ │ - */ │ │ │ │ │ - contentHTML: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: backgroundColor │ │ │ │ │ - * {String} the background color used by the popup. │ │ │ │ │ - */ │ │ │ │ │ - backgroundColor: "", │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: opacity │ │ │ │ │ - * {float} the opacity of this popup (between 0.0 and 1.0) │ │ │ │ │ - */ │ │ │ │ │ - opacity: "", │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: border │ │ │ │ │ - * {String} the border size of the popup. (eg 2px) │ │ │ │ │ - */ │ │ │ │ │ - border: "", │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: contentDiv │ │ │ │ │ - * {DOMElement} a reference to the element that holds the content of │ │ │ │ │ - * the div. │ │ │ │ │ - */ │ │ │ │ │ - contentDiv: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: groupDiv │ │ │ │ │ - * {DOMElement} First and only child of 'div'. The group Div contains the │ │ │ │ │ - * 'contentDiv' and the 'closeDiv'. │ │ │ │ │ - */ │ │ │ │ │ - groupDiv: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: closeDiv │ │ │ │ │ - * {DOMElement} the optional closer image │ │ │ │ │ - */ │ │ │ │ │ - closeDiv: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: autoSize │ │ │ │ │ - * {Boolean} Resize the popup to auto-fit the contents. │ │ │ │ │ - * Default is false. │ │ │ │ │ - */ │ │ │ │ │ - autoSize: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: minSize │ │ │ │ │ - * {} Minimum size allowed for the popup's contents. │ │ │ │ │ - */ │ │ │ │ │ - minSize: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: maxSize │ │ │ │ │ - * {} Maximum size allowed for the popup's contents. │ │ │ │ │ - */ │ │ │ │ │ - maxSize: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: displayClass │ │ │ │ │ - * {String} The CSS class of the popup. │ │ │ │ │ - */ │ │ │ │ │ - displayClass: "olPopup", │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: contentDisplayClass │ │ │ │ │ - * {String} The CSS class of the popup content div. │ │ │ │ │ - */ │ │ │ │ │ - contentDisplayClass: "olPopupContent", │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: padding │ │ │ │ │ - * {int or } An extra opportunity to specify internal │ │ │ │ │ - * padding of the content div inside the popup. This was originally │ │ │ │ │ - * confused with the css padding as specified in style.css's │ │ │ │ │ - * 'olPopupContent' class. We would like to get rid of this altogether, │ │ │ │ │ - * except that it does come in handy for the framed and anchoredbubble │ │ │ │ │ - * popups, who need to maintain yet another barrier between their │ │ │ │ │ - * content and the outer border of the popup itself. │ │ │ │ │ - * │ │ │ │ │ - * Note that in order to not break API, we must continue to support │ │ │ │ │ - * this property being set as an integer. Really, though, we'd like to │ │ │ │ │ - * have this specified as a Bounds object so that user can specify │ │ │ │ │ - * distinct left, top, right, bottom paddings. With the 3.0 release │ │ │ │ │ - * we can make this only a bounds. │ │ │ │ │ - */ │ │ │ │ │ - padding: 0, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: disableFirefoxOverflowHack │ │ │ │ │ - * {Boolean} The hack for overflow in Firefox causes all elements │ │ │ │ │ - * to be re-drawn, which causes Flash elements to be │ │ │ │ │ - * re-initialized, which is troublesome. │ │ │ │ │ - * With this property the hack can be disabled. │ │ │ │ │ - */ │ │ │ │ │ - disableFirefoxOverflowHack: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: fixPadding │ │ │ │ │ - * To be removed in 3.0, this function merely helps us to deal with the │ │ │ │ │ - * case where the user may have set an integer value for padding, │ │ │ │ │ - * instead of an object. │ │ │ │ │ - */ │ │ │ │ │ - fixPadding: function() { │ │ │ │ │ - if (typeof this.padding == "number") { │ │ │ │ │ - this.padding = new OpenLayers.Bounds( │ │ │ │ │ - this.padding, this.padding, this.padding, this.padding │ │ │ │ │ - ); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: panMapIfOutOfView │ │ │ │ │ - * {Boolean} When drawn, pan map such that the entire popup is visible in │ │ │ │ │ - * the current viewport (if necessary). │ │ │ │ │ - * Default is false. │ │ │ │ │ - */ │ │ │ │ │ - panMapIfOutOfView: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: keepInMap │ │ │ │ │ - * {Boolean} If panMapIfOutOfView is false, and this property is true, │ │ │ │ │ - * contrain the popup such that it always fits in the available map │ │ │ │ │ - * space. By default, this is not set on the base class. If you are │ │ │ │ │ - * creating popups that are near map edges and not allowing pannning, │ │ │ │ │ - * and especially if you have a popup which has a │ │ │ │ │ - * fixedRelativePosition, setting this to false may be a smart thing to │ │ │ │ │ - * do. Subclasses may want to override this setting. │ │ │ │ │ - * │ │ │ │ │ - * Default is false. │ │ │ │ │ - */ │ │ │ │ │ - keepInMap: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: closeOnMove │ │ │ │ │ - * {Boolean} When map pans, close the popup. │ │ │ │ │ - * Default is false. │ │ │ │ │ - */ │ │ │ │ │ - closeOnMove: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: map │ │ │ │ │ - * {} this gets set in Map.js when the popup is added to the map │ │ │ │ │ - */ │ │ │ │ │ - map: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Popup │ │ │ │ │ - * Create a popup. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * id - {String} a unqiue identifier for this popup. If null is passed │ │ │ │ │ - * an identifier will be automatically generated. │ │ │ │ │ - * lonlat - {} The position on the map the popup will │ │ │ │ │ - * be shown. │ │ │ │ │ - * contentSize - {} The size of the content. │ │ │ │ │ - * contentHTML - {String} An HTML string to display inside the │ │ │ │ │ - * popup. │ │ │ │ │ - * closeBox - {Boolean} Whether to display a close box inside │ │ │ │ │ - * the popup. │ │ │ │ │ - * closeBoxCallback - {Function} Function to be called on closeBox click. │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(id, lonlat, contentSize, contentHTML, closeBox, closeBoxCallback) { │ │ │ │ │ - if (id == null) { │ │ │ │ │ - id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - this.id = id; │ │ │ │ │ - this.lonlat = lonlat; │ │ │ │ │ - │ │ │ │ │ - this.contentSize = (contentSize != null) ? contentSize : │ │ │ │ │ - new OpenLayers.Size( │ │ │ │ │ - OpenLayers.Popup.WIDTH, │ │ │ │ │ - OpenLayers.Popup.HEIGHT); │ │ │ │ │ - if (contentHTML != null) { │ │ │ │ │ - this.contentHTML = contentHTML; │ │ │ │ │ - } │ │ │ │ │ - this.backgroundColor = OpenLayers.Popup.COLOR; │ │ │ │ │ - this.opacity = OpenLayers.Popup.OPACITY; │ │ │ │ │ - this.border = OpenLayers.Popup.BORDER; │ │ │ │ │ - │ │ │ │ │ - this.div = OpenLayers.Util.createDiv(this.id, null, null, │ │ │ │ │ - null, null, null, "hidden"); │ │ │ │ │ - this.div.className = this.displayClass; │ │ │ │ │ - │ │ │ │ │ - var groupDivId = this.id + "_GroupDiv"; │ │ │ │ │ - this.groupDiv = OpenLayers.Util.createDiv(groupDivId, null, null, │ │ │ │ │ - null, "relative", null, │ │ │ │ │ - "hidden"); │ │ │ │ │ - │ │ │ │ │ - var id = this.div.id + "_contentDiv"; │ │ │ │ │ - this.contentDiv = OpenLayers.Util.createDiv(id, null, this.contentSize.clone(), │ │ │ │ │ - null, "relative"); │ │ │ │ │ - this.contentDiv.className = this.contentDisplayClass; │ │ │ │ │ - this.groupDiv.appendChild(this.contentDiv); │ │ │ │ │ - this.div.appendChild(this.groupDiv); │ │ │ │ │ - │ │ │ │ │ - if (closeBox) { │ │ │ │ │ - this.addCloseBox(closeBoxCallback); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - this.registerEvents(); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: destroy │ │ │ │ │ - * nullify references to prevent circular references and memory leaks │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - │ │ │ │ │ - this.id = null; │ │ │ │ │ - this.lonlat = null; │ │ │ │ │ - this.size = null; │ │ │ │ │ - this.contentHTML = null; │ │ │ │ │ - │ │ │ │ │ - this.backgroundColor = null; │ │ │ │ │ - this.opacity = null; │ │ │ │ │ - this.border = null; │ │ │ │ │ - │ │ │ │ │ - if (this.closeOnMove && this.map) { │ │ │ │ │ - this.map.events.unregister("movestart", this, this.hide); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - this.events.destroy(); │ │ │ │ │ - this.events = null; │ │ │ │ │ - │ │ │ │ │ - if (this.closeDiv) { │ │ │ │ │ - OpenLayers.Event.stopObservingElement(this.closeDiv); │ │ │ │ │ - this.groupDiv.removeChild(this.closeDiv); │ │ │ │ │ - } │ │ │ │ │ - this.closeDiv = null; │ │ │ │ │ - │ │ │ │ │ - this.div.removeChild(this.groupDiv); │ │ │ │ │ - this.groupDiv = null; │ │ │ │ │ - │ │ │ │ │ - if (this.map != null) { │ │ │ │ │ - this.map.removePopup(this); │ │ │ │ │ - } │ │ │ │ │ - this.map = null; │ │ │ │ │ - this.div = null; │ │ │ │ │ - │ │ │ │ │ - this.autoSize = null; │ │ │ │ │ - this.minSize = null; │ │ │ │ │ - this.maxSize = null; │ │ │ │ │ - this.padding = null; │ │ │ │ │ - this.panMapIfOutOfView = null; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: draw │ │ │ │ │ - * Constructs the elements that make up the popup. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * px - {} the position the popup in pixels. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {DOMElement} Reference to a div that contains the drawn popup │ │ │ │ │ - */ │ │ │ │ │ - draw: function(px) { │ │ │ │ │ - if (px == null) { │ │ │ │ │ - if ((this.lonlat != null) && (this.map != null)) { │ │ │ │ │ - px = this.map.getLayerPxFromLonLat(this.lonlat); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // this assumes that this.map already exists, which is okay because │ │ │ │ │ - // this.draw is only called once the popup has been added to the map. │ │ │ │ │ - if (this.closeOnMove) { │ │ │ │ │ - this.map.events.register("movestart", this, this.hide); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - //listen to movestart, moveend to disable overflow (FF bug) │ │ │ │ │ - if (!this.disableFirefoxOverflowHack && OpenLayers.BROWSER_NAME == 'firefox') { │ │ │ │ │ - this.map.events.register("movestart", this, function() { │ │ │ │ │ - var style = document.defaultView.getComputedStyle( │ │ │ │ │ - this.contentDiv, null │ │ │ │ │ - ); │ │ │ │ │ - var currentOverflow = style.getPropertyValue("overflow"); │ │ │ │ │ - if (currentOverflow != "hidden") { │ │ │ │ │ - this.contentDiv._oldOverflow = currentOverflow; │ │ │ │ │ - this.contentDiv.style.overflow = "hidden"; │ │ │ │ │ - } │ │ │ │ │ - }); │ │ │ │ │ - this.map.events.register("moveend", this, function() { │ │ │ │ │ - var oldOverflow = this.contentDiv._oldOverflow; │ │ │ │ │ - if (oldOverflow) { │ │ │ │ │ - this.contentDiv.style.overflow = oldOverflow; │ │ │ │ │ - this.contentDiv._oldOverflow = null; │ │ │ │ │ - } │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - this.moveTo(px); │ │ │ │ │ - if (!this.autoSize && !this.size) { │ │ │ │ │ - this.setSize(this.contentSize); │ │ │ │ │ - } │ │ │ │ │ - this.setBackgroundColor(); │ │ │ │ │ - this.setOpacity(); │ │ │ │ │ - this.setBorder(); │ │ │ │ │ - this.setContentHTML(); │ │ │ │ │ - │ │ │ │ │ - if (this.panMapIfOutOfView) { │ │ │ │ │ - this.panIntoView(); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - return this.div; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: updatePosition │ │ │ │ │ - * if the popup has a lonlat and its map members set, │ │ │ │ │ - * then have it move itself to its proper position │ │ │ │ │ - */ │ │ │ │ │ - updatePosition: function() { │ │ │ │ │ - if ((this.lonlat) && (this.map)) { │ │ │ │ │ - var px = this.map.getLayerPxFromLonLat(this.lonlat); │ │ │ │ │ - if (px) { │ │ │ │ │ - this.moveTo(px); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: moveTo │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * px - {} the top and left position of the popup div. │ │ │ │ │ - */ │ │ │ │ │ - moveTo: function(px) { │ │ │ │ │ - if ((px != null) && (this.div != null)) { │ │ │ │ │ - this.div.style.left = px.x + "px"; │ │ │ │ │ - this.div.style.top = px.y + "px"; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: visible │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} Boolean indicating whether or not the popup is visible │ │ │ │ │ - */ │ │ │ │ │ - visible: function() { │ │ │ │ │ - return OpenLayers.Element.visible(this.div); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: toggle │ │ │ │ │ - * Toggles visibility of the popup. │ │ │ │ │ - */ │ │ │ │ │ - toggle: function() { │ │ │ │ │ - if (this.visible()) { │ │ │ │ │ - this.hide(); │ │ │ │ │ - } else { │ │ │ │ │ - this.show(); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: show │ │ │ │ │ - * Makes the popup visible. │ │ │ │ │ - */ │ │ │ │ │ - show: function() { │ │ │ │ │ - this.div.style.display = ''; │ │ │ │ │ - │ │ │ │ │ - if (this.panMapIfOutOfView) { │ │ │ │ │ - this.panIntoView(); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: hide │ │ │ │ │ - * Makes the popup invisible. │ │ │ │ │ - */ │ │ │ │ │ - hide: function() { │ │ │ │ │ - this.div.style.display = 'none'; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: setSize │ │ │ │ │ - * Used to adjust the size of the popup. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * contentSize - {} the new size for the popup's │ │ │ │ │ - * contents div (in pixels). │ │ │ │ │ - */ │ │ │ │ │ - setSize: function(contentSize) { │ │ │ │ │ - this.size = contentSize.clone(); │ │ │ │ │ - │ │ │ │ │ - // if our contentDiv has a css 'padding' set on it by a stylesheet, we │ │ │ │ │ - // must add that to the desired "size". │ │ │ │ │ - var contentDivPadding = this.getContentDivPadding(); │ │ │ │ │ - var wPadding = contentDivPadding.left + contentDivPadding.right; │ │ │ │ │ - var hPadding = contentDivPadding.top + contentDivPadding.bottom; │ │ │ │ │ - │ │ │ │ │ - // take into account the popup's 'padding' property │ │ │ │ │ - this.fixPadding(); │ │ │ │ │ - wPadding += this.padding.left + this.padding.right; │ │ │ │ │ - hPadding += this.padding.top + this.padding.bottom; │ │ │ │ │ - │ │ │ │ │ - // make extra space for the close div │ │ │ │ │ - if (this.closeDiv) { │ │ │ │ │ - var closeDivWidth = parseInt(this.closeDiv.style.width); │ │ │ │ │ - wPadding += closeDivWidth + contentDivPadding.right; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - //increase size of the main popup div to take into account the │ │ │ │ │ - // users's desired padding and close div. │ │ │ │ │ - this.size.w += wPadding; │ │ │ │ │ - this.size.h += hPadding; │ │ │ │ │ - │ │ │ │ │ - //now if our browser is IE, we need to actually make the contents │ │ │ │ │ - // div itself bigger to take its own padding into effect. this makes │ │ │ │ │ - // me want to shoot someone, but so it goes. │ │ │ │ │ - if (OpenLayers.BROWSER_NAME == "msie") { │ │ │ │ │ - this.contentSize.w += │ │ │ │ │ - contentDivPadding.left + contentDivPadding.right; │ │ │ │ │ - this.contentSize.h += │ │ │ │ │ - contentDivPadding.bottom + contentDivPadding.top; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (this.div != null) { │ │ │ │ │ - this.div.style.width = this.size.w + "px"; │ │ │ │ │ - this.div.style.height = this.size.h + "px"; │ │ │ │ │ - } │ │ │ │ │ - if (this.contentDiv != null) { │ │ │ │ │ - this.contentDiv.style.width = contentSize.w + "px"; │ │ │ │ │ - this.contentDiv.style.height = contentSize.h + "px"; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: updateSize │ │ │ │ │ - * Auto size the popup so that it precisely fits its contents (as │ │ │ │ │ - * determined by this.contentDiv.innerHTML). Popup size will, of │ │ │ │ │ - * course, be limited by the available space on the current map │ │ │ │ │ - */ │ │ │ │ │ - updateSize: function() { │ │ │ │ │ - │ │ │ │ │ - // determine actual render dimensions of the contents by putting its │ │ │ │ │ - // contents into a fake contentDiv (for the CSS) and then measuring it │ │ │ │ │ - var preparedHTML = "
" + │ │ │ │ │ - this.contentDiv.innerHTML + │ │ │ │ │ - "
"; │ │ │ │ │ - │ │ │ │ │ - var containerElement = (this.map) ? this.map.div : document.body; │ │ │ │ │ - var realSize = OpenLayers.Util.getRenderedDimensions( │ │ │ │ │ - preparedHTML, null, { │ │ │ │ │ - displayClass: this.displayClass, │ │ │ │ │ - containerElement: containerElement │ │ │ │ │ - } │ │ │ │ │ - ); │ │ │ │ │ - │ │ │ │ │ - // is the "real" size of the div is safe to display in our map? │ │ │ │ │ - var safeSize = this.getSafeContentSize(realSize); │ │ │ │ │ - │ │ │ │ │ - var newSize = null; │ │ │ │ │ - if (safeSize.equals(realSize)) { │ │ │ │ │ - //real size of content is small enough to fit on the map, │ │ │ │ │ - // so we use real size. │ │ │ │ │ - newSize = realSize; │ │ │ │ │ - │ │ │ │ │ - } else { │ │ │ │ │ - │ │ │ │ │ - // make a new 'size' object with the clipped dimensions │ │ │ │ │ - // set or null if not clipped. │ │ │ │ │ - var fixedSize = { │ │ │ │ │ - w: (safeSize.w < realSize.w) ? safeSize.w : null, │ │ │ │ │ - h: (safeSize.h < realSize.h) ? safeSize.h : null │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - if (fixedSize.w && fixedSize.h) { │ │ │ │ │ - //content is too big in both directions, so we will use │ │ │ │ │ - // max popup size (safeSize), knowing well that it will │ │ │ │ │ - // overflow both ways. │ │ │ │ │ - newSize = safeSize; │ │ │ │ │ - } else { │ │ │ │ │ - //content is clipped in only one direction, so we need to │ │ │ │ │ - // run getRenderedDimensions() again with a fixed dimension │ │ │ │ │ - var clippedSize = OpenLayers.Util.getRenderedDimensions( │ │ │ │ │ - preparedHTML, fixedSize, { │ │ │ │ │ - displayClass: this.contentDisplayClass, │ │ │ │ │ - containerElement: containerElement │ │ │ │ │ - } │ │ │ │ │ - ); │ │ │ │ │ - │ │ │ │ │ - //if the clipped size is still the same as the safeSize, │ │ │ │ │ - // that means that our content must be fixed in the │ │ │ │ │ - // offending direction. If overflow is 'auto', this means │ │ │ │ │ - // we are going to have a scrollbar for sure, so we must │ │ │ │ │ - // adjust for that. │ │ │ │ │ - // │ │ │ │ │ - var currentOverflow = OpenLayers.Element.getStyle( │ │ │ │ │ - this.contentDiv, "overflow" │ │ │ │ │ - ); │ │ │ │ │ - if ((currentOverflow != "hidden") && │ │ │ │ │ - (clippedSize.equals(safeSize))) { │ │ │ │ │ - var scrollBar = OpenLayers.Util.getScrollbarWidth(); │ │ │ │ │ - if (fixedSize.w) { │ │ │ │ │ - clippedSize.h += scrollBar; │ │ │ │ │ - } else { │ │ │ │ │ - clippedSize.w += scrollBar; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - newSize = this.getSafeContentSize(clippedSize); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - this.setSize(newSize); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: setBackgroundColor │ │ │ │ │ - * Sets the background color of the popup. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * color - {String} the background color. eg "#FFBBBB" │ │ │ │ │ - */ │ │ │ │ │ - setBackgroundColor: function(color) { │ │ │ │ │ - if (color != undefined) { │ │ │ │ │ - this.backgroundColor = color; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (this.div != null) { │ │ │ │ │ - this.div.style.backgroundColor = this.backgroundColor; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: setOpacity │ │ │ │ │ - * Sets the opacity of the popup. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid). │ │ │ │ │ - */ │ │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ │ - if (opacity != undefined) { │ │ │ │ │ - this.opacity = opacity; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (this.div != null) { │ │ │ │ │ - // for Mozilla and Safari │ │ │ │ │ - this.div.style.opacity = this.opacity; │ │ │ │ │ - │ │ │ │ │ - // for IE │ │ │ │ │ - this.div.style.filter = 'alpha(opacity=' + this.opacity * 100 + ')'; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: setBorder │ │ │ │ │ - * Sets the border style of the popup. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * border - {String} The border style value. eg 2px │ │ │ │ │ - */ │ │ │ │ │ - setBorder: function(border) { │ │ │ │ │ - if (border != undefined) { │ │ │ │ │ - this.border = border; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (this.div != null) { │ │ │ │ │ - this.div.style.border = this.border; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: setContentHTML │ │ │ │ │ - * Allows the user to set the HTML content of the popup. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * contentHTML - {String} HTML for the div. │ │ │ │ │ + * contentHTML - {String} HTML for the div. │ │ │ │ │ */ │ │ │ │ │ setContentHTML: function(contentHTML) { │ │ │ │ │ │ │ │ │ │ if (contentHTML != null) { │ │ │ │ │ this.contentHTML = contentHTML; │ │ │ │ │ } │ │ │ │ │ │ │ │ │ │ @@ -19386,830 +12758,103 @@ │ │ │ │ │ │ │ │ │ │ OpenLayers.Popup.WIDTH = 200; │ │ │ │ │ OpenLayers.Popup.HEIGHT = 200; │ │ │ │ │ OpenLayers.Popup.COLOR = "white"; │ │ │ │ │ OpenLayers.Popup.OPACITY = 1; │ │ │ │ │ OpenLayers.Popup.BORDER = "0px"; │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Renderer.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. */ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ /** │ │ │ │ │ * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ │ + * @requires OpenLayers/Style.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. │ │ │ │ │ - * │ │ │ │ │ + * Class: OpenLayers.Filter │ │ │ │ │ + * This class represents an OGC Filter. │ │ │ │ │ */ │ │ │ │ │ -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; │ │ │ │ │ - }, │ │ │ │ │ +OpenLayers.Filter = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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(). │ │ │ │ │ + * Constructor: OpenLayers.Filter │ │ │ │ │ + * This class represents a generic filter. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * feature - {} │ │ │ │ │ - * style - {} │ │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ + * instance. │ │ │ │ │ * │ │ │ │ │ * 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; │ │ │ │ │ - } │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ + * Remove reference to anything added. │ │ │ │ │ */ │ │ │ │ │ - getRenderLayerId: function() { │ │ │ │ │ - return this.container.id; │ │ │ │ │ - }, │ │ │ │ │ + destroy: function() {}, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: applyDefaultSymbolizer │ │ │ │ │ + * APIMethod: evaluate │ │ │ │ │ + * Evaluates this filter in a specific context. Instances or subclasses │ │ │ │ │ + * are supposed to override this method. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * symbolizer - {Object} │ │ │ │ │ + * context - {Object} Context to use in evaluating the filter. If a vector │ │ │ │ │ + * feature is provided, the feature.attributes will be used as context. │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Object} │ │ │ │ │ + * {Boolean} The filter applies. │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ + evaluate: function(context) { │ │ │ │ │ + return true; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - 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/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. │ │ │ │ │ + * APIMethod: clone │ │ │ │ │ + * Clones this filter. Should be implemented by subclasses. │ │ │ │ │ * │ │ │ │ │ - * 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 │ │ │ │ │ + * {} Clone of this filter. │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ + clone: function() { │ │ │ │ │ + return null; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: moveTo │ │ │ │ │ - * Sets the left and top style attributes to the passed in pixel │ │ │ │ │ - * coordinates. │ │ │ │ │ + * APIMethod: toString │ │ │ │ │ * │ │ │ │ │ - * 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. │ │ │ │ │ + * {String} Include in your build to get a CQL │ │ │ │ │ + * representation of the filter returned. Otherwise "[Object object]" │ │ │ │ │ + * will be returned. │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ + 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 false; │ │ │ │ │ + return string; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control" │ │ │ │ │ + CLASS_NAME: "OpenLayers.Filter" │ │ │ │ │ }); │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Control.TYPE_BUTTON │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Control.TYPE_BUTTON = 1; │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Control.TYPE_TOGGLE │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Control.TYPE_TOGGLE = 2; │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Control.TYPE_TOOL │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Control.TYPE_TOOL = 3; │ │ │ │ │ /* ====================================================================== │ │ │ │ │ OpenLayers/Geometry.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ @@ -26951,104 +19596,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. */ │ │ │ │ │ @@ -31847,332 +24402,1255 @@ │ │ │ │ │ "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Format.WPSExecute" │ │ │ │ │ │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/WPSProcess.js │ │ │ │ │ + OpenLayers/Request/XMLHttpRequest.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published 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 │ │ │ │ │ - */ │ │ │ │ │ +// 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/Geometry.js │ │ │ │ │ - * @requires OpenLayers/Feature/Vector.js │ │ │ │ │ - * @requires OpenLayers/Format/WKT.js │ │ │ │ │ - * @requires OpenLayers/Format/GeoJSON.js │ │ │ │ │ - * @requires OpenLayers/Format/WPSExecute.js │ │ │ │ │ * @requires OpenLayers/Request.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.WPSProcess │ │ │ │ │ - * Representation of a WPS process. Usually instances of │ │ │ │ │ - * are created by calling 'getProcess' on an │ │ │ │ │ - * instance. │ │ │ │ │ - * │ │ │ │ │ - * Currently supports processes that have geometries │ │ │ │ │ - * or features as output, using WKT or GeoJSON as output format. It also │ │ │ │ │ - * supports chaining of processes by using the method to create a │ │ │ │ │ - * handle that is used as process input instead of a static value. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.WPSProcess = OpenLayers.Class({ │ │ │ │ │ +(function() { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: client │ │ │ │ │ - * {} The client that manages this process. │ │ │ │ │ - */ │ │ │ │ │ - client: null, │ │ │ │ │ + // Save reference to earlier defined object implementation (if any) │ │ │ │ │ + var oXMLHttpRequest = window.XMLHttpRequest; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: server │ │ │ │ │ - * {String} Local client identifier for this process's server. │ │ │ │ │ - */ │ │ │ │ │ - server: 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: identifier │ │ │ │ │ - * {String} Process identifier known to the server. │ │ │ │ │ - */ │ │ │ │ │ - identifier: null, │ │ │ │ │ + // Enables "XMLHttpRequest()" call next to "new XMLHttpReques()" │ │ │ │ │ + function fXMLHttpRequest() { │ │ │ │ │ + this._object = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP"); │ │ │ │ │ + this._listeners = []; │ │ │ │ │ + }; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: description │ │ │ │ │ - * {Object} DescribeProcess response for this process. │ │ │ │ │ - */ │ │ │ │ │ - description: null, │ │ │ │ │ + // Constructor │ │ │ │ │ + function cXMLHttpRequest() { │ │ │ │ │ + return new fXMLHttpRequest; │ │ │ │ │ + }; │ │ │ │ │ + cXMLHttpRequest.prototype = fXMLHttpRequest.prototype; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: localWPS │ │ │ │ │ - * {String} Service endpoint for locally chained WPS processes. Default is │ │ │ │ │ - * 'http://geoserver/wps'. │ │ │ │ │ - */ │ │ │ │ │ - localWPS: 'http://geoserver/wps', │ │ │ │ │ + // BUGFIX: Firefox with Firebug installed would break pages if not executed │ │ │ │ │ + if (bGecko && oXMLHttpRequest.wrapped) │ │ │ │ │ + cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: formats │ │ │ │ │ - * {Object} OpenLayers.Format instances keyed by mimetype. │ │ │ │ │ - */ │ │ │ │ │ - formats: null, │ │ │ │ │ + // Constants │ │ │ │ │ + cXMLHttpRequest.UNSENT = 0; │ │ │ │ │ + cXMLHttpRequest.OPENED = 1; │ │ │ │ │ + cXMLHttpRequest.HEADERS_RECEIVED = 2; │ │ │ │ │ + cXMLHttpRequest.LOADING = 3; │ │ │ │ │ + cXMLHttpRequest.DONE = 4; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: chained │ │ │ │ │ - * {Integer} Number of chained processes for pending execute requests that │ │ │ │ │ - * don't have a full configuration yet. │ │ │ │ │ - */ │ │ │ │ │ - chained: 0, │ │ │ │ │ + // Public Properties │ │ │ │ │ + cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ │ + cXMLHttpRequest.prototype.responseText = ''; │ │ │ │ │ + cXMLHttpRequest.prototype.responseXML = null; │ │ │ │ │ + cXMLHttpRequest.prototype.status = 0; │ │ │ │ │ + cXMLHttpRequest.prototype.statusText = ''; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: executeCallbacks │ │ │ │ │ - * {Array} Callbacks waiting to be executed until all chained processes │ │ │ │ │ - * are configured; │ │ │ │ │ - */ │ │ │ │ │ - executeCallbacks: null, │ │ │ │ │ + // Priority proposal │ │ │ │ │ + cXMLHttpRequest.prototype.priority = "NORMAL"; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.WPSProcess │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} Object whose properties will be set on the instance. │ │ │ │ │ - * │ │ │ │ │ - * Avaliable options: │ │ │ │ │ - * client - {} Mandatory. Client that manages this │ │ │ │ │ - * process. │ │ │ │ │ - * server - {String} Mandatory. Local client identifier of this process's │ │ │ │ │ - * server. │ │ │ │ │ - * identifier - {String} Mandatory. Process identifier known to the server. │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(options) { │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ - this.executeCallbacks = []; │ │ │ │ │ - this.formats = { │ │ │ │ │ - 'application/wkt': new OpenLayers.Format.WKT(), │ │ │ │ │ - 'application/json': new OpenLayers.Format.GeoJSON() │ │ │ │ │ - }; │ │ │ │ │ - }, │ │ │ │ │ + // Instance-level Events Handlers │ │ │ │ │ + cXMLHttpRequest.prototype.onreadystatechange = null; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: describe │ │ │ │ │ - * Makes the client issue a DescribeProcess request asynchronously. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} Configuration for the method call │ │ │ │ │ - * │ │ │ │ │ - * Available options: │ │ │ │ │ - * callback - {Function} Callback to execute when the description is │ │ │ │ │ - * available. Will be called with the parsed description as argument. │ │ │ │ │ - * Optional. │ │ │ │ │ - * scope - {Object} The scope in which the callback will be executed. │ │ │ │ │ - * Default is the global object. │ │ │ │ │ - */ │ │ │ │ │ - describe: function(options) { │ │ │ │ │ - options = options || {}; │ │ │ │ │ - if (!this.description) { │ │ │ │ │ - this.client.describeProcess(this.server, this.identifier, function(description) { │ │ │ │ │ - if (!this.description) { │ │ │ │ │ - this.parseDescription(description); │ │ │ │ │ - } │ │ │ │ │ - if (options.callback) { │ │ │ │ │ - options.callback.call(options.scope, this.description); │ │ │ │ │ + // 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(); │ │ │ │ │ } │ │ │ │ │ - }, this); │ │ │ │ │ - } else if (options.callback) { │ │ │ │ │ - var description = this.description; │ │ │ │ │ - window.setTimeout(function() { │ │ │ │ │ - options.callback.call(options.scope, description); │ │ │ │ │ - }, 0); │ │ │ │ │ + }; │ │ │ │ │ + window.attachEvent("onunload", fOnUnload); │ │ │ │ │ } │ │ │ │ │ - }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: configure │ │ │ │ │ - * Configure the process, but do not execute it. Use this for processes │ │ │ │ │ - * that are chained as input of a different process by means of the │ │ │ │ │ - * method. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} this process. │ │ │ │ │ - * │ │ │ │ │ - * Available options: │ │ │ │ │ - * 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. │ │ │ │ │ - * callback - {Function} Callback to call when the configuration is │ │ │ │ │ - * complete. Optional. │ │ │ │ │ - * scope - {Object} Optional scope for the callback. │ │ │ │ │ - */ │ │ │ │ │ - configure: function(options) { │ │ │ │ │ - this.describe({ │ │ │ │ │ - callback: function() { │ │ │ │ │ - var description = this.description, │ │ │ │ │ - inputs = options.inputs, │ │ │ │ │ - input, i, ii; │ │ │ │ │ - for (i = 0, ii = description.dataInputs.length; i < ii; ++i) { │ │ │ │ │ - input = description.dataInputs[i]; │ │ │ │ │ - this.setInputData(input, inputs[input.identifier]); │ │ │ │ │ - } │ │ │ │ │ - if (options.callback) { │ │ │ │ │ - options.callback.call(options.scope); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ - return this; │ │ │ │ │ - }, │ │ │ │ │ + // Add method sniffer │ │ │ │ │ + if (cXMLHttpRequest.onopen) │ │ │ │ │ + cXMLHttpRequest.onopen.apply(this, arguments); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: execute │ │ │ │ │ - * Configures and executes the process │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} │ │ │ │ │ - * │ │ │ │ │ - * Available options: │ │ │ │ │ - * 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 the output to request and parse. │ │ │ │ │ - * Optional. If not provided, the first output will be requested. │ │ │ │ │ - * 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 │ │ │ │ │ - * (or 'result' if output was not configured). For processes that │ │ │ │ │ - * generate spatial output, the value will be an array of │ │ │ │ │ - * instances. │ │ │ │ │ - * scope - {Object} Optional scope for the success callback. │ │ │ │ │ - */ │ │ │ │ │ - execute: function(options) { │ │ │ │ │ - this.configure({ │ │ │ │ │ - inputs: options.inputs, │ │ │ │ │ - callback: function() { │ │ │ │ │ - var me = this; │ │ │ │ │ - //TODO For now we only deal with a single output │ │ │ │ │ - var outputIndex = this.getOutputIndex( │ │ │ │ │ - me.description.processOutputs, options.output │ │ │ │ │ - ); │ │ │ │ │ - me.setResponseForm({ │ │ │ │ │ - outputIndex: outputIndex │ │ │ │ │ - }); │ │ │ │ │ - (function callback() { │ │ │ │ │ - OpenLayers.Util.removeItem(me.executeCallbacks, callback); │ │ │ │ │ - if (me.chained !== 0) { │ │ │ │ │ - // need to wait until chained processes have a │ │ │ │ │ - // description and configuration - see chainProcess │ │ │ │ │ - me.executeCallbacks.push(callback); │ │ │ │ │ - return; │ │ │ │ │ - } │ │ │ │ │ - // all chained processes are added as references now, so │ │ │ │ │ - // let's proceed. │ │ │ │ │ - OpenLayers.Request.POST({ │ │ │ │ │ - url: me.client.servers[me.server].url, │ │ │ │ │ - data: new OpenLayers.Format.WPSExecute().write(me.description), │ │ │ │ │ - success: function(response) { │ │ │ │ │ - var output = me.description.processOutputs[outputIndex]; │ │ │ │ │ - var mimeType = me.findMimeType( │ │ │ │ │ - output.complexOutput.supported.formats │ │ │ │ │ - ); │ │ │ │ │ - //TODO For now we assume a spatial output │ │ │ │ │ - var features = me.formats[mimeType].read(response.responseText); │ │ │ │ │ - if (features instanceof OpenLayers.Feature.Vector) { │ │ │ │ │ - features = [features]; │ │ │ │ │ - } │ │ │ │ │ - if (options.success) { │ │ │ │ │ - var outputs = {}; │ │ │ │ │ - outputs[options.output || 'result'] = features; │ │ │ │ │ - options.success.call(options.scope, outputs); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - scope: me │ │ │ │ │ - }); │ │ │ │ │ - })(); │ │ │ │ │ - }, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ - }, │ │ │ │ │ + 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); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: output │ │ │ │ │ - * Chain an output of a configured process (see ) as input to │ │ │ │ │ - * another process. │ │ │ │ │ - * │ │ │ │ │ - * (code) │ │ │ │ │ - * intersect = client.getProcess('opengeo', 'JTS:intersection'); │ │ │ │ │ - * intersect.configure({ │ │ │ │ │ - * // ... │ │ │ │ │ - * }); │ │ │ │ │ - * buffer = client.getProcess('opengeo', 'JTS:buffer'); │ │ │ │ │ - * buffer.execute({ │ │ │ │ │ - * inputs: { │ │ │ │ │ - * geom: intersect.output('result'), // <-- here we're chaining │ │ │ │ │ - * distance: 1 │ │ │ │ │ - * }, │ │ │ │ │ - * // ... │ │ │ │ │ - * }); │ │ │ │ │ - * (end) │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * identifier - {String} Identifier of the output that we're chaining. If │ │ │ │ │ - * not provided, the first output will be used. │ │ │ │ │ - */ │ │ │ │ │ - output: function(identifier) { │ │ │ │ │ - return new OpenLayers.WPSProcess.ChainLink({ │ │ │ │ │ - process: this, │ │ │ │ │ - output: identifier │ │ │ │ │ - }); │ │ │ │ │ - }, │ │ │ │ │ + this.readyState = cXMLHttpRequest.OPENED; │ │ │ │ │ + fReadyStateChange(this); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: parseDescription │ │ │ │ │ - * Parses the DescribeProcess response │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * description - {Object} │ │ │ │ │ - */ │ │ │ │ │ - parseDescription: function(description) { │ │ │ │ │ - var server = this.client.servers[this.server]; │ │ │ │ │ - this.description = new OpenLayers.Format.WPSDescribeProcess() │ │ │ │ │ - .read(server.processDescription[this.identifier]) │ │ │ │ │ - .processDescriptions[this.identifier]; │ │ │ │ │ - }, │ │ │ │ │ + this._object.onreadystatechange = function() { │ │ │ │ │ + if (bGecko && !bAsync) │ │ │ │ │ + return; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: setInputData │ │ │ │ │ - * Sets the data for a single input │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * input - {Object} An entry from the dataInputs array of the process │ │ │ │ │ - * description. │ │ │ │ │ - * data - {Mixed} For spatial data inputs, this is usually an │ │ │ │ │ - * , an or an array of │ │ │ │ │ - * geometries or features. │ │ │ │ │ - */ │ │ │ │ │ - setInputData: function(input, data) { │ │ │ │ │ - // clear any previous data │ │ │ │ │ - delete input.data; │ │ │ │ │ - delete input.reference; │ │ │ │ │ - if (data instanceof OpenLayers.WPSProcess.ChainLink) { │ │ │ │ │ - ++this.chained; │ │ │ │ │ - input.reference = { │ │ │ │ │ - method: 'POST', │ │ │ │ │ - href: data.process.server === this.server ? │ │ │ │ │ - this.localWPS : this.client.servers[data.process.server].url │ │ │ │ │ - }; │ │ │ │ │ + // 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/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 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 │ │ │ │ │ + * {} An events object that handles all │ │ │ │ │ + * events on the {} object. │ │ │ │ │ + * │ │ │ │ │ + * All event listeners will receive an event object with three properties: │ │ │ │ │ + * request - {} 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 , , , , , or . │ │ │ │ │ + * 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 │ │ │ │ │ + * . │ │ │ │ │ + * 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 │ │ │ │ │ + * 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 . │ │ │ │ │ + * 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 and requests. │ │ │ │ │ + * Make sure to provide the appropriate "Content-Type" header for your │ │ │ │ │ + * data. For and 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 method, with the method property set │ │ │ │ │ + * to GET. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} Object with properties for configuring the request. │ │ │ │ │ + * See the 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 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 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 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 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 method, with the method property set │ │ │ │ │ + * to DELETE. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} Object with properties for configuring the request. │ │ │ │ │ + * See the 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 method, with the method property set │ │ │ │ │ + * to HEAD. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} Object with properties for configuring the request. │ │ │ │ │ + * See the 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 method, with the method property set │ │ │ │ │ + * to OPTIONS. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} Object with properties for configuring the request. │ │ │ │ │ + * See the 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/WPSProcess.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published 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/Geometry.js │ │ │ │ │ + * @requires OpenLayers/Feature/Vector.js │ │ │ │ │ + * @requires OpenLayers/Format/WKT.js │ │ │ │ │ + * @requires OpenLayers/Format/GeoJSON.js │ │ │ │ │ + * @requires OpenLayers/Format/WPSExecute.js │ │ │ │ │ + * @requires OpenLayers/Request.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.WPSProcess │ │ │ │ │ + * Representation of a WPS process. Usually instances of │ │ │ │ │ + * are created by calling 'getProcess' on an │ │ │ │ │ + * instance. │ │ │ │ │ + * │ │ │ │ │ + * Currently supports processes that have geometries │ │ │ │ │ + * or features as output, using WKT or GeoJSON as output format. It also │ │ │ │ │ + * supports chaining of processes by using the method to create a │ │ │ │ │ + * handle that is used as process input instead of a static value. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.WPSProcess = OpenLayers.Class({ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: client │ │ │ │ │ + * {} The client that manages this process. │ │ │ │ │ + */ │ │ │ │ │ + client: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: server │ │ │ │ │ + * {String} Local client identifier for this process's server. │ │ │ │ │ + */ │ │ │ │ │ + server: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: identifier │ │ │ │ │ + * {String} Process identifier known to the server. │ │ │ │ │ + */ │ │ │ │ │ + identifier: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: description │ │ │ │ │ + * {Object} DescribeProcess response for this process. │ │ │ │ │ + */ │ │ │ │ │ + description: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: localWPS │ │ │ │ │ + * {String} Service endpoint for locally chained WPS processes. Default is │ │ │ │ │ + * 'http://geoserver/wps'. │ │ │ │ │ + */ │ │ │ │ │ + localWPS: 'http://geoserver/wps', │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: formats │ │ │ │ │ + * {Object} OpenLayers.Format instances keyed by mimetype. │ │ │ │ │ + */ │ │ │ │ │ + formats: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: chained │ │ │ │ │ + * {Integer} Number of chained processes for pending execute requests that │ │ │ │ │ + * don't have a full configuration yet. │ │ │ │ │ + */ │ │ │ │ │ + chained: 0, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: executeCallbacks │ │ │ │ │ + * {Array} Callbacks waiting to be executed until all chained processes │ │ │ │ │ + * are configured; │ │ │ │ │ + */ │ │ │ │ │ + executeCallbacks: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.WPSProcess │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} Object whose properties will be set on the instance. │ │ │ │ │ + * │ │ │ │ │ + * Avaliable options: │ │ │ │ │ + * client - {} Mandatory. Client that manages this │ │ │ │ │ + * process. │ │ │ │ │ + * server - {String} Mandatory. Local client identifier of this process's │ │ │ │ │ + * server. │ │ │ │ │ + * identifier - {String} Mandatory. Process identifier known to the server. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + this.executeCallbacks = []; │ │ │ │ │ + this.formats = { │ │ │ │ │ + 'application/wkt': new OpenLayers.Format.WKT(), │ │ │ │ │ + 'application/json': new OpenLayers.Format.GeoJSON() │ │ │ │ │ + }; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: describe │ │ │ │ │ + * Makes the client issue a DescribeProcess request asynchronously. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} Configuration for the method call │ │ │ │ │ + * │ │ │ │ │ + * Available options: │ │ │ │ │ + * callback - {Function} Callback to execute when the description is │ │ │ │ │ + * available. Will be called with the parsed description as argument. │ │ │ │ │ + * Optional. │ │ │ │ │ + * scope - {Object} The scope in which the callback will be executed. │ │ │ │ │ + * Default is the global object. │ │ │ │ │ + */ │ │ │ │ │ + describe: function(options) { │ │ │ │ │ + options = options || {}; │ │ │ │ │ + if (!this.description) { │ │ │ │ │ + this.client.describeProcess(this.server, this.identifier, function(description) { │ │ │ │ │ + if (!this.description) { │ │ │ │ │ + this.parseDescription(description); │ │ │ │ │ + } │ │ │ │ │ + if (options.callback) { │ │ │ │ │ + options.callback.call(options.scope, this.description); │ │ │ │ │ + } │ │ │ │ │ + }, this); │ │ │ │ │ + } else if (options.callback) { │ │ │ │ │ + var description = this.description; │ │ │ │ │ + window.setTimeout(function() { │ │ │ │ │ + options.callback.call(options.scope, description); │ │ │ │ │ + }, 0); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: configure │ │ │ │ │ + * Configure the process, but do not execute it. Use this for processes │ │ │ │ │ + * that are chained as input of a different process by means of the │ │ │ │ │ + * method. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} this process. │ │ │ │ │ + * │ │ │ │ │ + * Available options: │ │ │ │ │ + * 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. │ │ │ │ │ + * callback - {Function} Callback to call when the configuration is │ │ │ │ │ + * complete. Optional. │ │ │ │ │ + * scope - {Object} Optional scope for the callback. │ │ │ │ │ + */ │ │ │ │ │ + configure: function(options) { │ │ │ │ │ + this.describe({ │ │ │ │ │ + callback: function() { │ │ │ │ │ + var description = this.description, │ │ │ │ │ + inputs = options.inputs, │ │ │ │ │ + input, i, ii; │ │ │ │ │ + for (i = 0, ii = description.dataInputs.length; i < ii; ++i) { │ │ │ │ │ + input = description.dataInputs[i]; │ │ │ │ │ + this.setInputData(input, inputs[input.identifier]); │ │ │ │ │ + } │ │ │ │ │ + if (options.callback) { │ │ │ │ │ + options.callback.call(options.scope); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + return this; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: execute │ │ │ │ │ + * Configures and executes the process │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} │ │ │ │ │ + * │ │ │ │ │ + * Available options: │ │ │ │ │ + * 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 the output to request and parse. │ │ │ │ │ + * Optional. If not provided, the first output will be requested. │ │ │ │ │ + * 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 │ │ │ │ │ + * (or 'result' if output was not configured). For processes that │ │ │ │ │ + * generate spatial output, the value will be an array of │ │ │ │ │ + * instances. │ │ │ │ │ + * scope - {Object} Optional scope for the success callback. │ │ │ │ │ + */ │ │ │ │ │ + execute: function(options) { │ │ │ │ │ + this.configure({ │ │ │ │ │ + inputs: options.inputs, │ │ │ │ │ + callback: function() { │ │ │ │ │ + var me = this; │ │ │ │ │ + //TODO For now we only deal with a single output │ │ │ │ │ + var outputIndex = this.getOutputIndex( │ │ │ │ │ + me.description.processOutputs, options.output │ │ │ │ │ + ); │ │ │ │ │ + me.setResponseForm({ │ │ │ │ │ + outputIndex: outputIndex │ │ │ │ │ + }); │ │ │ │ │ + (function callback() { │ │ │ │ │ + OpenLayers.Util.removeItem(me.executeCallbacks, callback); │ │ │ │ │ + if (me.chained !== 0) { │ │ │ │ │ + // need to wait until chained processes have a │ │ │ │ │ + // description and configuration - see chainProcess │ │ │ │ │ + me.executeCallbacks.push(callback); │ │ │ │ │ + return; │ │ │ │ │ + } │ │ │ │ │ + // all chained processes are added as references now, so │ │ │ │ │ + // let's proceed. │ │ │ │ │ + OpenLayers.Request.POST({ │ │ │ │ │ + url: me.client.servers[me.server].url, │ │ │ │ │ + data: new OpenLayers.Format.WPSExecute().write(me.description), │ │ │ │ │ + success: function(response) { │ │ │ │ │ + var output = me.description.processOutputs[outputIndex]; │ │ │ │ │ + var mimeType = me.findMimeType( │ │ │ │ │ + output.complexOutput.supported.formats │ │ │ │ │ + ); │ │ │ │ │ + //TODO For now we assume a spatial output │ │ │ │ │ + var features = me.formats[mimeType].read(response.responseText); │ │ │ │ │ + if (features instanceof OpenLayers.Feature.Vector) { │ │ │ │ │ + features = [features]; │ │ │ │ │ + } │ │ │ │ │ + if (options.success) { │ │ │ │ │ + var outputs = {}; │ │ │ │ │ + outputs[options.output || 'result'] = features; │ │ │ │ │ + options.success.call(options.scope, outputs); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + scope: me │ │ │ │ │ + }); │ │ │ │ │ + })(); │ │ │ │ │ + }, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: output │ │ │ │ │ + * Chain an output of a configured process (see ) as input to │ │ │ │ │ + * another process. │ │ │ │ │ + * │ │ │ │ │ + * (code) │ │ │ │ │ + * intersect = client.getProcess('opengeo', 'JTS:intersection'); │ │ │ │ │ + * intersect.configure({ │ │ │ │ │ + * // ... │ │ │ │ │ + * }); │ │ │ │ │ + * buffer = client.getProcess('opengeo', 'JTS:buffer'); │ │ │ │ │ + * buffer.execute({ │ │ │ │ │ + * inputs: { │ │ │ │ │ + * geom: intersect.output('result'), // <-- here we're chaining │ │ │ │ │ + * distance: 1 │ │ │ │ │ + * }, │ │ │ │ │ + * // ... │ │ │ │ │ + * }); │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * identifier - {String} Identifier of the output that we're chaining. If │ │ │ │ │ + * not provided, the first output will be used. │ │ │ │ │ + */ │ │ │ │ │ + output: function(identifier) { │ │ │ │ │ + return new OpenLayers.WPSProcess.ChainLink({ │ │ │ │ │ + process: this, │ │ │ │ │ + output: identifier │ │ │ │ │ + }); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: parseDescription │ │ │ │ │ + * Parses the DescribeProcess response │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * description - {Object} │ │ │ │ │ + */ │ │ │ │ │ + parseDescription: function(description) { │ │ │ │ │ + var server = this.client.servers[this.server]; │ │ │ │ │ + this.description = new OpenLayers.Format.WPSDescribeProcess() │ │ │ │ │ + .read(server.processDescription[this.identifier]) │ │ │ │ │ + .processDescriptions[this.identifier]; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: setInputData │ │ │ │ │ + * Sets the data for a single input │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * input - {Object} An entry from the dataInputs array of the process │ │ │ │ │ + * description. │ │ │ │ │ + * data - {Mixed} For spatial data inputs, this is usually an │ │ │ │ │ + * , an or an array of │ │ │ │ │ + * geometries or features. │ │ │ │ │ + */ │ │ │ │ │ + setInputData: function(input, data) { │ │ │ │ │ + // clear any previous data │ │ │ │ │ + delete input.data; │ │ │ │ │ + delete input.reference; │ │ │ │ │ + if (data instanceof OpenLayers.WPSProcess.ChainLink) { │ │ │ │ │ + ++this.chained; │ │ │ │ │ + input.reference = { │ │ │ │ │ + method: 'POST', │ │ │ │ │ + href: data.process.server === this.server ? │ │ │ │ │ + this.localWPS : this.client.servers[data.process.server].url │ │ │ │ │ + }; │ │ │ │ │ data.process.describe({ │ │ │ │ │ callback: function() { │ │ │ │ │ --this.chained; │ │ │ │ │ this.chainProcess(input, data); │ │ │ │ │ }, │ │ │ │ │ scope: this │ │ │ │ │ }); │ │ │ │ │ @@ -32354,428 +25832,640 @@ │ │ │ │ │ OpenLayers.Util.extend(this, options); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.WPSProcess.ChainLink" │ │ │ │ │ │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Format/WPSDescribeProcess.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/Format/XML.js │ │ │ │ │ - * @requires OpenLayers/Format/OWSCommon/v1_1_0.js │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Format.WPSDescribeProcess │ │ │ │ │ - * Read WPS DescribeProcess responses. │ │ │ │ │ + * Class: OpenLayers.Icon │ │ │ │ │ + * │ │ │ │ │ + * The icon represents a graphical icon on the screen. Typically used in │ │ │ │ │ + * conjunction with a to represent markers on a screen. │ │ │ │ │ * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * 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.Format.WPSDescribeProcess = OpenLayers.Class( │ │ │ │ │ - OpenLayers.Format.XML, { │ │ │ │ │ +OpenLayers.Icon = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constant: VERSION │ │ │ │ │ - * {String} 1.0.0 │ │ │ │ │ - */ │ │ │ │ │ - VERSION: "1.0.0", │ │ │ │ │ + /** │ │ │ │ │ + * Property: url │ │ │ │ │ + * {String} image url │ │ │ │ │ + */ │ │ │ │ │ + url: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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: size │ │ │ │ │ + * {|Object} An OpenLayers.Size or │ │ │ │ │ + * an object with a 'w' and 'h' properties. │ │ │ │ │ + */ │ │ │ │ │ + size: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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: 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: defaultPrefix │ │ │ │ │ - */ │ │ │ │ │ - defaultPrefix: "wps", │ │ │ │ │ + /** │ │ │ │ │ + * Property: calculateOffset │ │ │ │ │ + * {Function} Function to calculate the offset (based on the size) │ │ │ │ │ + */ │ │ │ │ │ + calculateOffset: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: regExes │ │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ │ - */ │ │ │ │ │ - regExes: { │ │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * Property: imageDiv │ │ │ │ │ + * {DOMElement} │ │ │ │ │ + */ │ │ │ │ │ + imageDiv: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Format.WPSDescribeProcess │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ │ - * this instance. │ │ │ │ │ - */ │ │ │ │ │ + /** │ │ │ │ │ + * Property: px │ │ │ │ │ + * {|Object} An OpenLayers.Pixel or an object │ │ │ │ │ + * with a 'x' and 'y' properties. │ │ │ │ │ + */ │ │ │ │ │ + px: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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; │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * 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; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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); │ │ │ │ │ + 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); │ │ │ │ │ } │ │ │ │ │ - }, │ │ │ │ │ - "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ │ - }, │ │ │ │ │ + OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, { │ │ │ │ │ + x: this.px.x + this.offset.x, │ │ │ │ │ + y: this.px.y + this.offset.y │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WPSDescribeProcess" │ │ │ │ │ + /** │ │ │ │ │ + * 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/WPSClient.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/SingleFile.js │ │ │ │ │ - */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ * @requires OpenLayers/Events.js │ │ │ │ │ - * @requires OpenLayers/WPSProcess.js │ │ │ │ │ - * @requires OpenLayers/Format/WPSDescribeProcess.js │ │ │ │ │ - * @requires OpenLayers/Request.js │ │ │ │ │ + * @requires OpenLayers/Icon.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. │ │ │ │ │ + * 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.WPSClient = OpenLayers.Class({ │ │ │ │ │ +OpenLayers.Marker = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: servers │ │ │ │ │ - * {Object} Service metadata, keyed by a local identifier. │ │ │ │ │ + /** │ │ │ │ │ + * 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 │ │ │ │ │ * │ │ │ │ │ - * 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. │ │ │ │ │ + * Parameters: │ │ │ │ │ + * lonlat - {} the position of this marker │ │ │ │ │ + * icon - {} the icon for this marker │ │ │ │ │ */ │ │ │ │ │ - servers: 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); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: version │ │ │ │ │ - * {String} The default WPS version to use if none is configured. Default │ │ │ │ │ - * is '1.0.0'. │ │ │ │ │ + * 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.) │ │ │ │ │ */ │ │ │ │ │ - version: '1.0.0', │ │ │ │ │ + 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(); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: lazy │ │ │ │ │ - * {Boolean} Should the DescribeProcess be deferred until a process is │ │ │ │ │ - * fully configured? Default is false. │ │ │ │ │ + * 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. │ │ │ │ │ */ │ │ │ │ │ - lazy: false, │ │ │ │ │ + moveTo: function(px) { │ │ │ │ │ + if ((px != null) && (this.icon != null)) { │ │ │ │ │ + this.icon.moveTo(px); │ │ │ │ │ + } │ │ │ │ │ + this.lonlat = this.map.getLonLatFromLayerPx(px); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: events │ │ │ │ │ - * {} │ │ │ │ │ + * APIMethod: isDrawn │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Whether or not the marker is drawn. │ │ │ │ │ + */ │ │ │ │ │ + isDrawn: function() { │ │ │ │ │ + var isDrawn = (this.icon && this.icon.isDrawn()); │ │ │ │ │ + return isDrawn; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: onScreen │ │ │ │ │ * │ │ │ │ │ - * 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. │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Whether or not the marker is currently visible on screen. │ │ │ │ │ */ │ │ │ │ │ - events: null, │ │ │ │ │ + onScreen: function() { │ │ │ │ │ + │ │ │ │ │ + var onScreen = false; │ │ │ │ │ + if (this.map) { │ │ │ │ │ + var screenBounds = this.map.getExtent(); │ │ │ │ │ + onScreen = screenBounds.containsLonLat(this.lonlat); │ │ │ │ │ + } │ │ │ │ │ + return onScreen; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.WPSClient │ │ │ │ │ + * Method: inflate │ │ │ │ │ + * Englarges the markers icon by the specified ratio. │ │ │ │ │ * │ │ │ │ │ * 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. │ │ │ │ │ + * inflate - {float} the ratio to enlarge the marker by (passing 2 │ │ │ │ │ + * will double the size). │ │ │ │ │ */ │ │ │ │ │ - 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]; │ │ │ │ │ + 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); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: execute │ │ │ │ │ - * Shortcut to execute a process with a single function call. This is │ │ │ │ │ - * equivalent to using and then calling execute on the │ │ │ │ │ - * process. │ │ │ │ │ + * 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/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 │ │ │ │ │ + * {} 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} 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. │ │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ + * instance. │ │ │ │ │ */ │ │ │ │ │ - execute: function(options) { │ │ │ │ │ - var process = this.getProcess(options.server, options.process); │ │ │ │ │ - process.execute({ │ │ │ │ │ - inputs: options.inputs, │ │ │ │ │ - success: options.success, │ │ │ │ │ - scope: options.scope │ │ │ │ │ - }); │ │ │ │ │ + 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: getProcess │ │ │ │ │ - * Creates an . │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ + * Clean up the strategy. │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + this.deactivate(); │ │ │ │ │ + this.layer = null; │ │ │ │ │ + this.options = null; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: setLayer │ │ │ │ │ + * Called to set the property. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * serverID - {String} Local identifier from the servers that this instance │ │ │ │ │ - * was constructed with. │ │ │ │ │ - * processID - {String} Process identifier known to the server. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} │ │ │ │ │ + * layer - {} │ │ │ │ │ */ │ │ │ │ │ - getProcess: function(serverID, processID) { │ │ │ │ │ - var process = new OpenLayers.WPSProcess({ │ │ │ │ │ - client: this, │ │ │ │ │ - server: serverID, │ │ │ │ │ - identifier: processID │ │ │ │ │ - }); │ │ │ │ │ - if (!this.lazy) { │ │ │ │ │ - process.describe(); │ │ │ │ │ - } │ │ │ │ │ - return process; │ │ │ │ │ + setLayer: function(layer) { │ │ │ │ │ + this.layer = layer; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: describeProcess │ │ │ │ │ + * Method: activate │ │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ │ * │ │ │ │ │ - * 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 │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} True if the strategy was successfully activated or false if │ │ │ │ │ + * the strategy was already active. │ │ │ │ │ */ │ │ │ │ │ - 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); │ │ │ │ │ + activate: function() { │ │ │ │ │ + if (!this.active) { │ │ │ │ │ + this.active = true; │ │ │ │ │ + return true; │ │ │ │ │ } │ │ │ │ │ + return false; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: destroy │ │ │ │ │ + * 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. │ │ │ │ │ */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - this.events.destroy(); │ │ │ │ │ - this.events = null; │ │ │ │ │ - this.servers = null; │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + if (this.active) { │ │ │ │ │ + this.active = false; │ │ │ │ │ + return true; │ │ │ │ │ + } │ │ │ │ │ + return false; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: 'OpenLayers.WPSClient' │ │ │ │ │ - │ │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ 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. │ │ │ │ │ @@ -32958,4851 +26648,6323 @@ │ │ │ │ │ OpenLayers.Function.bind(timerCallback, this) │ │ │ │ │ ); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Kinetic" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Strategy/Save.js │ │ │ │ │ + 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/Strategy.js │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Map.js │ │ │ │ │ + * @requires OpenLayers/Projection.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Strategy.Save │ │ │ │ │ - * A strategy that commits newly created or modified features. By default │ │ │ │ │ - * the strategy waits for a call to before persisting changes. By │ │ │ │ │ - * configuring the strategy with the option, changes can be saved │ │ │ │ │ - * automatically. │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * Class: OpenLayers.Layer │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Strategy.Save = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ +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 │ │ │ │ │ - * {} 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); │ │ │ │ │ + * layer.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 │ │ │ │ │ - * │ │ │ │ │ + * 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 ). 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 │ │ │ │ │ + * {} 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, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: events │ │ │ │ │ - * {} Events instance for triggering this protocol │ │ │ │ │ - * events. │ │ │ │ │ + * APIProperty: displayInLayerSwitcher │ │ │ │ │ + * {Boolean} Display the layer's name in the layer switcher. Default is │ │ │ │ │ + * true. │ │ │ │ │ */ │ │ │ │ │ - events: null, │ │ │ │ │ + displayInLayerSwitcher: 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). │ │ │ │ │ + * APIProperty: visibility │ │ │ │ │ + * {Boolean} The layer should be displayed in the map. Default is true. │ │ │ │ │ */ │ │ │ │ │ - auto: false, │ │ │ │ │ + visibility: true, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: timer │ │ │ │ │ - * {Number} The id of the timer. │ │ │ │ │ + * APIProperty: attribution │ │ │ │ │ + * {String} Attribution string, displayed when an │ │ │ │ │ + * has been added to the map. │ │ │ │ │ */ │ │ │ │ │ - timer: null, │ │ │ │ │ + attribution: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: inRange │ │ │ │ │ + * {Boolean} The current map resolution is within the layer's min/max │ │ │ │ │ + * range. This is set in whenever the zoom │ │ │ │ │ + * changes. │ │ │ │ │ + */ │ │ │ │ │ + inRange: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Strategy.Save │ │ │ │ │ - * Create a new Save strategy. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ - * instance. │ │ │ │ │ + * Propery: imageSize │ │ │ │ │ + * {} For layers with a gutter, the image is larger than │ │ │ │ │ + * the tile by twice the gutter in each dimension. │ │ │ │ │ */ │ │ │ │ │ - initialize: function(options) { │ │ │ │ │ - OpenLayers.Strategy.prototype.initialize.apply(this, [options]); │ │ │ │ │ - this.events = new OpenLayers.Events(this); │ │ │ │ │ - }, │ │ │ │ │ + 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, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: activate │ │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The strategy was successfully activated. │ │ │ │ │ + * 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. │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ - }, │ │ │ │ │ + eventListeners: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: deactivate │ │ │ │ │ - * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ │ - * tear-down. │ │ │ │ │ + * 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 │ │ │ │ │ + * {} or {} 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 object; │ │ │ │ │ + * if a string is passed, will be converted to an object when │ │ │ │ │ + * the layer is added to the map. │ │ │ │ │ * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The strategy was successfully deactivated. │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ - }, │ │ │ │ │ + projection: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * 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. │ │ │ │ │ */ │ │ │ │ │ - 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]); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ + units: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * 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 instead wherever possible. │ │ │ │ │ */ │ │ │ │ │ - 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 │ │ │ │ │ - }); │ │ │ │ │ - }, │ │ │ │ │ + scales: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: onCommit │ │ │ │ │ - * Called after protocol commit. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * response - {} A response object. │ │ │ │ │ + * 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.). │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ + resolutions: null, │ │ │ │ │ │ │ │ │ │ - if (destroys.length > 0) { │ │ │ │ │ - this.layer.destroyFeatures(destroys); │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: maxExtent │ │ │ │ │ + * {|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 │ │ │ │ │ + * is set to false, data will not be │ │ │ │ │ + * requested that falls completely outside of these bounds. │ │ │ │ │ + */ │ │ │ │ │ + maxExtent: null, │ │ │ │ │ │ │ │ │ │ - this.events.triggerEvent("success", evt); │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: minExtent │ │ │ │ │ + * {|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, │ │ │ │ │ │ │ │ │ │ - } else { │ │ │ │ │ - this.events.triggerEvent("fail", evt); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * 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 │ │ │ │ │ + * and displaying the whole world. │ │ │ │ │ + */ │ │ │ │ │ + maxResolution: null, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Save" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Strategy/Refresh.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: minResolution │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + minResolution: 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. */ │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: numZoomLevels │ │ │ │ │ + * {Integer} │ │ │ │ │ + */ │ │ │ │ │ + numZoomLevels: null, │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Strategy.js │ │ │ │ │ - */ │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: minScale │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + minScale: null, │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Strategy.Refresh │ │ │ │ │ - * A strategy that refreshes the layer. By default the strategy waits for a │ │ │ │ │ - * call to before refreshing. By configuring the strategy with │ │ │ │ │ - * the option, refreshing can take place automatically. │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Strategy.Refresh = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: maxScale │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + maxScale: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: force │ │ │ │ │ - * {Boolean} Force a refresh on the layer. Default is false. │ │ │ │ │ + * APIProperty: displayOutsideMaxExtent │ │ │ │ │ + * {Boolean} Request map tiles that are completely outside of the max │ │ │ │ │ + * extent for this layer. Defaults to false. │ │ │ │ │ */ │ │ │ │ │ - force: false, │ │ │ │ │ + displayOutsideMaxExtent: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: interval │ │ │ │ │ - * {Number} Auto-refresh. Default is 0. If > 0, layer will be refreshed │ │ │ │ │ - * every N milliseconds. │ │ │ │ │ + * 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. │ │ │ │ │ */ │ │ │ │ │ - interval: 0, │ │ │ │ │ + wrapDateLine: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: timer │ │ │ │ │ - * {Number} The id of the timer. │ │ │ │ │ + * Property: metadata │ │ │ │ │ + * {Object} This object can be used to store additional information on a │ │ │ │ │ + * layer object. │ │ │ │ │ */ │ │ │ │ │ - timer: null, │ │ │ │ │ + metadata: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Strategy.Refresh │ │ │ │ │ - * Create a new Refresh strategy. │ │ │ │ │ + * Constructor: OpenLayers.Layer │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ - * instance. │ │ │ │ │ + * 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); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: activate │ │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} True if the strategy was successfully activated. │ │ │ │ │ + * 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. │ │ │ │ │ */ │ │ │ │ │ - activate: function() { │ │ │ │ │ - var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ │ - if (activated) { │ │ │ │ │ - if (this.layer.visibility === true) { │ │ │ │ │ - this.start(); │ │ │ │ │ + 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.layer.events.on({ │ │ │ │ │ - "visibilitychanged": this.reset, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ + this.events.destroy(); │ │ │ │ │ } │ │ │ │ │ - return activated; │ │ │ │ │ + this.eventListeners = null; │ │ │ │ │ + this.events = null; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: deactivate │ │ │ │ │ - * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ │ - * tear-down. │ │ │ │ │ - * │ │ │ │ │ + * Method: clone │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * obj - {} The layer to be cloned │ │ │ │ │ + * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Boolean} True if the strategy was successfully deactivated. │ │ │ │ │ + * {} An exact clone of this │ │ │ │ │ */ │ │ │ │ │ - deactivate: function() { │ │ │ │ │ - var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ │ - if (deactivated) { │ │ │ │ │ - this.stop(); │ │ │ │ │ - this.layer.events.un({ │ │ │ │ │ - "visibilitychanged": this.reset, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ + clone: function(obj) { │ │ │ │ │ + │ │ │ │ │ + if (obj == null) { │ │ │ │ │ + obj = new OpenLayers.Layer(this.name, this.getOptions()); │ │ │ │ │ } │ │ │ │ │ - return deactivated; │ │ │ │ │ + │ │ │ │ │ + // 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: reset │ │ │ │ │ - * Start or cancel the refresh interval depending on the visibility of │ │ │ │ │ - * the layer. │ │ │ │ │ + * 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 of the layer, representing the current state. │ │ │ │ │ */ │ │ │ │ │ - reset: function() { │ │ │ │ │ - if (this.layer.visibility === true) { │ │ │ │ │ - this.start(); │ │ │ │ │ - } else { │ │ │ │ │ - this.stop(); │ │ │ │ │ + getOptions: function() { │ │ │ │ │ + var options = {}; │ │ │ │ │ + for (var o in this.options) { │ │ │ │ │ + options[o] = this[o]; │ │ │ │ │ } │ │ │ │ │ + return options; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: start │ │ │ │ │ - * Start the refresh interval. │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: setName │ │ │ │ │ + * Sets the new layer name for this layer. Can trigger a changelayer event │ │ │ │ │ + * on the map. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * newName - {String} The new name. │ │ │ │ │ */ │ │ │ │ │ - start: function() { │ │ │ │ │ - if (this.interval && typeof this.interval === "number" && │ │ │ │ │ - this.interval > 0) { │ │ │ │ │ - │ │ │ │ │ - this.timer = window.setInterval( │ │ │ │ │ - OpenLayers.Function.bind(this.refresh, this), │ │ │ │ │ - this.interval); │ │ │ │ │ + setName: function(newName) { │ │ │ │ │ + if (newName != this.name) { │ │ │ │ │ + this.name = newName; │ │ │ │ │ + if (this.map != null) { │ │ │ │ │ + this.map.events.triggerEvent("changelayer", { │ │ │ │ │ + layer: this, │ │ │ │ │ + property: "name" │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: refresh │ │ │ │ │ - * Tell the strategy to refresh which will refresh the layer. │ │ │ │ │ + * 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. │ │ │ │ │ */ │ │ │ │ │ - refresh: function() { │ │ │ │ │ - if (this.layer && this.layer.refresh && │ │ │ │ │ - typeof this.layer.refresh == "function") { │ │ │ │ │ + addOptions: function(newOptions, reinitialize) { │ │ │ │ │ │ │ │ │ │ - this.layer.refresh({ │ │ │ │ │ - force: this.force │ │ │ │ │ - }); │ │ │ │ │ + if (this.options == null) { │ │ │ │ │ + this.options = {}; │ │ │ │ │ } │ │ │ │ │ - }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: stop │ │ │ │ │ - * Cancels the refresh interval. │ │ │ │ │ - */ │ │ │ │ │ - stop: function() { │ │ │ │ │ - if (this.timer !== null) { │ │ │ │ │ - window.clearInterval(this.timer); │ │ │ │ │ - this.timer = null; │ │ │ │ │ + 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); │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ - }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Refresh" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Strategy/Paging.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ + // update our copy for clone │ │ │ │ │ + OpenLayers.Util.extend(this.options, newOptions); │ │ │ │ │ │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of 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 new options to this │ │ │ │ │ + OpenLayers.Util.extend(this, newOptions); │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Strategy.js │ │ │ │ │ - */ │ │ │ │ │ + // 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(); │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Strategy.Paging │ │ │ │ │ - * Strategy for vector feature paging │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ + // 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) { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: features │ │ │ │ │ - * {Array()} Cached features. │ │ │ │ │ - */ │ │ │ │ │ - features: null, │ │ │ │ │ + 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; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: length │ │ │ │ │ - * {Integer} Number of features per page. Default is 10. │ │ │ │ │ + * APIMethod: onMapResize │ │ │ │ │ + * This function can be implemented by subclasses │ │ │ │ │ */ │ │ │ │ │ - length: 10, │ │ │ │ │ + onMapResize: function() { │ │ │ │ │ + //this function can be implemented by subclasses │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: num │ │ │ │ │ - * {Integer} The currently displayed page number. │ │ │ │ │ + * APIMethod: redraw │ │ │ │ │ + * Redraws the layer. Returns true if the layer was redrawn, false if not. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The layer was redrawn. │ │ │ │ │ */ │ │ │ │ │ - num: 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; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: paging │ │ │ │ │ - * {Boolean} The strategy is currently changing pages. │ │ │ │ │ + * Method: moveTo │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * bounds - {} │ │ │ │ │ + * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to │ │ │ │ │ + * do some init work in that case. │ │ │ │ │ + * dragging - {Boolean} │ │ │ │ │ */ │ │ │ │ │ - paging: false, │ │ │ │ │ + moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ │ + var display = this.visibility; │ │ │ │ │ + if (!this.isBaseLayer) { │ │ │ │ │ + display = display && this.inRange; │ │ │ │ │ + } │ │ │ │ │ + this.display(display); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Strategy.Paging │ │ │ │ │ - * Create a new paging strategy. │ │ │ │ │ + * Method: moveByPx │ │ │ │ │ + * Move the layer based on pixel vector. To be implemented by subclasses. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ - * instance. │ │ │ │ │ + * dx - {Number} The x coord of the displacement vector. │ │ │ │ │ + * dy - {Number} The y coord of the displacement vector. │ │ │ │ │ */ │ │ │ │ │ + moveByPx: function(dx, dy) {}, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: activate │ │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ │ + * 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. │ │ │ │ │ * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The strategy was successfully activated. │ │ │ │ │ + * Here we take care to bring over any of the necessary default │ │ │ │ │ + * properties from the map. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * 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) { │ │ │ │ │ + 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(); │ │ │ │ │ } │ │ │ │ │ - return activated; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: deactivate │ │ │ │ │ - * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ │ - * tear-down. │ │ │ │ │ + * 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. │ │ │ │ │ * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The strategy was successfully deactivated. │ │ │ │ │ + * Parameters: │ │ │ │ │ + * map - {} │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ + removeMap: function(map) { │ │ │ │ │ + //to be overridden by subclasses │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: cacheFeatures │ │ │ │ │ - * Cache features before they are added to the layer. │ │ │ │ │ + * APIMethod: getImageSize │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * event - {Object} The event that this was listening for. This will come │ │ │ │ │ - * with a batch of features to be paged. │ │ │ │ │ + * 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: │ │ │ │ │ + * {} The size that the image should be, taking into │ │ │ │ │ + * account gutters. │ │ │ │ │ */ │ │ │ │ │ - cacheFeatures: function(event) { │ │ │ │ │ - if (!this.paging) { │ │ │ │ │ - this.clearCache(); │ │ │ │ │ - this.features = event.features; │ │ │ │ │ - this.pageNext(event); │ │ │ │ │ - } │ │ │ │ │ + getImageSize: function(bounds) { │ │ │ │ │ + return (this.imageSize || this.tileSize); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: clearCache │ │ │ │ │ - * Clear out the cached features. This destroys features, assuming │ │ │ │ │ - * nothing else has a reference. │ │ │ │ │ + * APIMethod: setTileSize │ │ │ │ │ + * Set the tile size based on the map size. This also sets layer.imageSize │ │ │ │ │ + * or use by Tile.Image. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * size - {} │ │ │ │ │ */ │ │ │ │ │ - clearCache: function() { │ │ │ │ │ - if (this.features) { │ │ │ │ │ - for (var i = 0; i < this.features.length; ++i) { │ │ │ │ │ - this.features[i].destroy(); │ │ │ │ │ - } │ │ │ │ │ + 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)); │ │ │ │ │ } │ │ │ │ │ - this.features = null; │ │ │ │ │ - this.num = null; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: pageCount │ │ │ │ │ - * Get the total count of pages given the current cache of features. │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: getVisibility │ │ │ │ │ + * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Integer} The page count. │ │ │ │ │ + * {Boolean} The layer should be displayed (if in range). │ │ │ │ │ */ │ │ │ │ │ - pageCount: function() { │ │ │ │ │ - var numFeatures = this.features ? this.features.length : 0; │ │ │ │ │ - return Math.ceil(numFeatures / this.length); │ │ │ │ │ + getVisibility: function() { │ │ │ │ │ + return this.visibility; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: pageNum │ │ │ │ │ - * Get the zero based page number. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Integer} The current page number being displayed. │ │ │ │ │ + /** │ │ │ │ │ + * 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) │ │ │ │ │ */ │ │ │ │ │ - pageNum: function() { │ │ │ │ │ - return this.num; │ │ │ │ │ + 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: pageLength │ │ │ │ │ - * Gets or sets page length. │ │ │ │ │ - * │ │ │ │ │ + /** │ │ │ │ │ + * 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: │ │ │ │ │ - * newLength - {Integer} Optional length to be set. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Integer} The length of a page (number of features per page). │ │ │ │ │ + * display - {Boolean} │ │ │ │ │ */ │ │ │ │ │ - pageLength: function(newLength) { │ │ │ │ │ - if (newLength && newLength > 0) { │ │ │ │ │ - this.length = newLength; │ │ │ │ │ + display: function(display) { │ │ │ │ │ + if (display != (this.div.style.display != "none")) { │ │ │ │ │ + this.div.style.display = (display && this.calculateInRange()) ? "block" : "none"; │ │ │ │ │ } │ │ │ │ │ - return this.length; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: pageNext │ │ │ │ │ - * Display the next page of features. │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: calculateInRange │ │ │ │ │ + * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Boolean} A new page was displayed. │ │ │ │ │ + * {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. │ │ │ │ │ */ │ │ │ │ │ - pageNext: function(event) { │ │ │ │ │ - var changed = false; │ │ │ │ │ - if (this.features) { │ │ │ │ │ - if (this.num === null) { │ │ │ │ │ - this.num = -1; │ │ │ │ │ + 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)); │ │ │ │ │ } │ │ │ │ │ - var start = (this.num + 1) * this.length; │ │ │ │ │ - changed = this.page(start, event); │ │ │ │ │ } │ │ │ │ │ - return changed; │ │ │ │ │ + return inRange; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: pagePrevious │ │ │ │ │ - * Display the previous page of features. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} A new page was displayed. │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: setIsBaseLayer │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * isBaseLayer - {Boolean} │ │ │ │ │ */ │ │ │ │ │ - pagePrevious: function() { │ │ │ │ │ - var changed = false; │ │ │ │ │ - if (this.features) { │ │ │ │ │ - if (this.num === null) { │ │ │ │ │ - this.num = this.pageCount(); │ │ │ │ │ + setIsBaseLayer: function(isBaseLayer) { │ │ │ │ │ + if (isBaseLayer != this.isBaseLayer) { │ │ │ │ │ + this.isBaseLayer = isBaseLayer; │ │ │ │ │ + if (this.map != null) { │ │ │ │ │ + this.map.events.triggerEvent("changebaselayer", { │ │ │ │ │ + layer: this │ │ │ │ │ + }); │ │ │ │ │ } │ │ │ │ │ - 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. │ │ │ │ │ + /********************************************************/ │ │ │ │ │ + /* */ │ │ │ │ │ + /* 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 │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ - } │ │ │ │ │ + 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; │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ - return changed; │ │ │ │ │ - }, │ │ │ │ │ + if (this.options.alwaysInRange == null) { │ │ │ │ │ + this.alwaysInRange = alwaysInRange; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Paging" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Strategy/Fixed.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ + // if we don't have resolutions then attempt to derive them from scales │ │ │ │ │ + if (props.resolutions == null) { │ │ │ │ │ + props.resolutions = this.resolutionsFromScales(props.scales); │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of 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 we still don't have resolutions then attempt to calculate them │ │ │ │ │ + if (props.resolutions == null) { │ │ │ │ │ + props.resolutions = this.calculateResolutions(props); │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Strategy.js │ │ │ │ │ - */ │ │ │ │ │ + // 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); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Strategy.Fixed │ │ │ │ │ - * A simple strategy that requests features once and never requests new data. │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ + // ok, we new need to set properties in the instance │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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, │ │ │ │ │ + // 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); │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Strategy.Fixed │ │ │ │ │ - * Create a new Fixed strategy. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ - * instance. │ │ │ │ │ - */ │ │ │ │ │ + // 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); │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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 (props.resolutions) { │ │ │ │ │ + │ │ │ │ │ + //sort resolutions array descendingly │ │ │ │ │ + props.resolutions.sort(function(a, b) { │ │ │ │ │ + return (b - a); │ │ │ │ │ }); │ │ │ │ │ - if (this.layer.visibility == true || this.preload) { │ │ │ │ │ - this.load(); │ │ │ │ │ - } else { │ │ │ │ │ - this.layer.events.on({ │ │ │ │ │ - "visibilitychanged": this.load, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ + │ │ │ │ │ + // 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]; │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ - return activated; │ │ │ │ │ - }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: deactivate │ │ │ │ │ - * Deactivate the strategy. Undo what is done in . │ │ │ │ │ - * │ │ │ │ │ - * 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 │ │ │ │ │ - }); │ │ │ │ │ + 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); │ │ │ │ │ } │ │ │ │ │ - return deactivated; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: load │ │ │ │ │ - * Tells protocol to load data and unhooks the visibilitychanged event │ │ │ │ │ + * Method: resolutionsFromScales │ │ │ │ │ + * Derive resolutions from scales. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * options - {Object} options to pass to protocol read. │ │ │ │ │ + * scales - {Array(Number)} Scales │ │ │ │ │ + * │ │ │ │ │ + * Returns │ │ │ │ │ + * {Array(Number)} Resolutions │ │ │ │ │ */ │ │ │ │ │ - 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 │ │ │ │ │ - }); │ │ │ │ │ + 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: 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: calculateResolutions │ │ │ │ │ + * Calculate resolutions based on the provided properties. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * resp - {} The response object passed │ │ │ │ │ - * by the protocol. │ │ │ │ │ + * props - {Object} Properties │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Array({Number})} Array of resolutions. │ │ │ │ │ */ │ │ │ │ │ - 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); │ │ │ │ │ + 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); │ │ │ │ │ } │ │ │ │ │ - layer.events.triggerEvent("loadend", { │ │ │ │ │ - response: resp │ │ │ │ │ - }); │ │ │ │ │ - }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.Fixed" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Strategy/Cluster.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ + // 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); │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of 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 (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 │ │ │ │ │ + ); │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Strategy.js │ │ │ │ │ - */ │ │ │ │ │ + // 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; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Strategy.Cluster │ │ │ │ │ - * Strategy for vector feature clustering. │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ + // are we able to calculate resolutions? │ │ │ │ │ + if (typeof numZoomLevels !== "number" || numZoomLevels <= 0 || │ │ │ │ │ + (typeof maxResolution !== "number" && │ │ │ │ │ + typeof minResolution !== "number")) { │ │ │ │ │ + return; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: distance │ │ │ │ │ - * {Integer} Pixel distance between features that should be considered a │ │ │ │ │ - * single cluster. Default is 20 pixels. │ │ │ │ │ - */ │ │ │ │ │ - distance: 20, │ │ │ │ │ + // now we have numZoomLevels and at least one of maxResolution │ │ │ │ │ + // or minResolution, we can populate the resolutions array │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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, │ │ │ │ │ + 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)) │ │ │ │ │ + ); │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: features │ │ │ │ │ - * {Array()} Cached features. │ │ │ │ │ - */ │ │ │ │ │ - features: null, │ │ │ │ │ + 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); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: clusters │ │ │ │ │ - * {Array()} Calculated clusters. │ │ │ │ │ - */ │ │ │ │ │ - clusters: null, │ │ │ │ │ + return resolutions; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: clustering │ │ │ │ │ - * {Boolean} The strategy is currently clustering features. │ │ │ │ │ + * APIMethod: getResolution │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} The currently selected resolution of the map, taken from the │ │ │ │ │ + * resolutions array, indexed by current zoom level. │ │ │ │ │ */ │ │ │ │ │ - clustering: false, │ │ │ │ │ + getResolution: function() { │ │ │ │ │ + var zoom = this.map.getZoom(); │ │ │ │ │ + return this.getResolutionForZoom(zoom); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: resolution │ │ │ │ │ - * {Float} The resolution (map units per pixel) of the current cluster set. │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: getExtent │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} A Bounds object which represents the lon/lat │ │ │ │ │ + * bounds of the current viewPort. │ │ │ │ │ */ │ │ │ │ │ - resolution: null, │ │ │ │ │ + getExtent: function() { │ │ │ │ │ + // just use stock map calculateBounds function -- passing no arguments │ │ │ │ │ + // means it will user map's current center & resolution │ │ │ │ │ + // │ │ │ │ │ + return this.map.calculateBounds(); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Strategy.Cluster │ │ │ │ │ - * Create a new clustering strategy. │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: getZoomForExtent │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ - * instance. │ │ │ │ │ + * extent - {} │ │ │ │ │ + * 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); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: activate │ │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ │ + 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: │ │ │ │ │ - * {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; │ │ │ │ │ + getDataExtent: function() { │ │ │ │ │ + //to be implemented by subclasses │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: deactivate │ │ │ │ │ - * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ │ - * tear-down. │ │ │ │ │ + * APIMethod: getResolutionForZoom │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * zoom - {Float} │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Boolean} The strategy was successfully deactivated. │ │ │ │ │ + * {Float} A suitable resolution for the specified zoom. │ │ │ │ │ */ │ │ │ │ │ - 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 │ │ │ │ │ - }); │ │ │ │ │ + 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 deactivated; │ │ │ │ │ + return resolution; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: cacheFeatures │ │ │ │ │ - * Cache features before they are added to the layer. │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: getZoomForResolution │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * event - {Object} The event that this was listening for. This will come │ │ │ │ │ - * with a batch of features to be clustered. │ │ │ │ │ - * │ │ │ │ │ + * 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: │ │ │ │ │ - * {Boolean} False to stop features from being added to the layer. │ │ │ │ │ + * {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. │ │ │ │ │ */ │ │ │ │ │ - cacheFeatures: function(event) { │ │ │ │ │ - var propagate = true; │ │ │ │ │ - if (!this.clustering) { │ │ │ │ │ - this.clearCache(); │ │ │ │ │ - this.features = event.features; │ │ │ │ │ - this.cluster(); │ │ │ │ │ - propagate = false; │ │ │ │ │ + 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 propagate; │ │ │ │ │ + return zoom; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: clearCache │ │ │ │ │ - * Clear out the cached features. │ │ │ │ │ + * APIMethod: getLonLatFromViewPortPx │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * viewPortPx - {|Object} An OpenLayers.Pixel or │ │ │ │ │ + * an object with a 'x' │ │ │ │ │ + * and 'y' properties. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} An OpenLayers.LonLat which is the passed-in │ │ │ │ │ + * view port , translated into lon/lat by the layer. │ │ │ │ │ */ │ │ │ │ │ - clearCache: function() { │ │ │ │ │ - if (!this.clustering) { │ │ │ │ │ - this.features = null; │ │ │ │ │ + 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; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: cluster │ │ │ │ │ - * Cluster features based on some threshold distance. │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: getViewPortPxFromLonLat │ │ │ │ │ + * Returns a pixel location given a map location. This method will return │ │ │ │ │ + * fractional pixel values. │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * event - {Object} The event received when cluster is called as a │ │ │ │ │ - * result of a moveend event. │ │ │ │ │ + * lonlat - {|Object} An OpenLayers.LonLat or │ │ │ │ │ + * an object with a 'lon' │ │ │ │ │ + * and 'lat' properties. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} An which is the passed-in │ │ │ │ │ + * lonlat translated into view port pixels. │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ - } │ │ │ │ │ + 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; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: clustersExist │ │ │ │ │ - * Determine whether calculated clusters are already on the layer. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The calculated clusters are already on the layer. │ │ │ │ │ + * APIMethod: setOpacity │ │ │ │ │ + * Sets the opacity for the entire layer (all images) │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * opacity - {Float} │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ + 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" │ │ │ │ │ + }); │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ - return exist; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: shouldCluster │ │ │ │ │ - * Determine whether to include a feature in a given cluster. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * cluster - {} A cluster. │ │ │ │ │ - * feature - {} A feature. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The feature should be included in the cluster. │ │ │ │ │ + * Method: getZIndex │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Integer} the z-index of this layer │ │ │ │ │ */ │ │ │ │ │ - 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); │ │ │ │ │ + getZIndex: function() { │ │ │ │ │ + return this.div.style.zIndex; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: addToCluster │ │ │ │ │ - * Add a feature to a cluster. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * cluster - {} A cluster. │ │ │ │ │ - * feature - {} A feature. │ │ │ │ │ + * Method: setZIndex │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * zIndex - {Integer} │ │ │ │ │ */ │ │ │ │ │ - addToCluster: function(cluster, feature) { │ │ │ │ │ - cluster.cluster.push(feature); │ │ │ │ │ - cluster.attributes.count += 1; │ │ │ │ │ + setZIndex: function(zIndex) { │ │ │ │ │ + this.div.style.zIndex = zIndex; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: createCluster │ │ │ │ │ - * Given a feature, create a cluster. │ │ │ │ │ - * │ │ │ │ │ + * 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: │ │ │ │ │ - * feature - {} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} A cluster. │ │ │ │ │ + * bounds - {} │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ + 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.Strategy.Cluster" │ │ │ │ │ + CLASS_NAME: "OpenLayers.Layer" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Strategy/BBOX.js │ │ │ │ │ + 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/Strategy.js │ │ │ │ │ - * @requires OpenLayers/Filter/Spatial.js │ │ │ │ │ + * @requires OpenLayers/Layer.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Strategy.BBOX │ │ │ │ │ - * A simple strategy that reads new features when the viewport invalidates │ │ │ │ │ - * some bounds. │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * Class: OpenLayers.Layer.HTTPRequest │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ +OpenLayers.Layer.HTTPRequest = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: bounds │ │ │ │ │ - * {} The current data bounds (in the same projection │ │ │ │ │ - * as the layer - not always the same projection as the map). │ │ │ │ │ + /** │ │ │ │ │ + * 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. │ │ │ │ │ */ │ │ │ │ │ - bounds: null, │ │ │ │ │ + URL_HASH_FACTOR: (Math.sqrt(5) - 1) / 2, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: resolution │ │ │ │ │ - * {Float} The current data resolution. │ │ │ │ │ + * Property: url │ │ │ │ │ + * {Array(String) or String} This is either an array of url strings or │ │ │ │ │ + * a single url string. │ │ │ │ │ */ │ │ │ │ │ - resolution: null, │ │ │ │ │ + url: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: ratio │ │ │ │ │ - * {Float} The ratio of the data bounds to the viewport bounds (in each │ │ │ │ │ - * dimension). Default is 2. │ │ │ │ │ + /** │ │ │ │ │ + * Property: params │ │ │ │ │ + * {Object} Hashtable of key/value parameters │ │ │ │ │ */ │ │ │ │ │ - ratio: 2, │ │ │ │ │ + params: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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). │ │ │ │ │ + * 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. │ │ │ │ │ + * │ │ │ │ │ */ │ │ │ │ │ - resFactor: null, │ │ │ │ │ + reproject: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: response │ │ │ │ │ - * {} The protocol response object returned │ │ │ │ │ - * by the layer protocol. │ │ │ │ │ + * 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 │ │ │ │ │ */ │ │ │ │ │ - response: null, │ │ │ │ │ + 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); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Strategy.BBOX │ │ │ │ │ - * Create a new BBOX strategy. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ - * instance. │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + this.url = null; │ │ │ │ │ + this.params = null; │ │ │ │ │ + OpenLayers.Layer.prototype.destroy.apply(this, arguments); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: activate │ │ │ │ │ - * Set up strategy with regard to reading new batches of remote data. │ │ │ │ │ + * APIMethod: clone │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * obj - {Object} │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Boolean} The strategy was successfully activated. │ │ │ │ │ + * {} An exact clone of this │ │ │ │ │ + * │ │ │ │ │ */ │ │ │ │ │ - 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(); │ │ │ │ │ + clone: function(obj) { │ │ │ │ │ + │ │ │ │ │ + if (obj == null) { │ │ │ │ │ + obj = new OpenLayers.Layer.HTTPRequest(this.name, │ │ │ │ │ + this.url, │ │ │ │ │ + this.params, │ │ │ │ │ + this.getOptions()); │ │ │ │ │ } │ │ │ │ │ - return activated; │ │ │ │ │ + │ │ │ │ │ + //get all additions from superclasses │ │ │ │ │ + obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]); │ │ │ │ │ + │ │ │ │ │ + // copy/set any non-init, non-simple values here │ │ │ │ │ + │ │ │ │ │ + return obj; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: deactivate │ │ │ │ │ - * Tear down strategy with regard to reading new batches of remote data. │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: setUrl │ │ │ │ │ * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The strategy was successfully deactivated. │ │ │ │ │ + * Parameters: │ │ │ │ │ + * newUrl - {String} │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ + setUrl: function(newUrl) { │ │ │ │ │ + this.url = newUrl; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: update │ │ │ │ │ - * Callback function called on "moveend" or "refresh" layer events. │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: mergeNewParams │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * options - {Object} Optional object whose properties will determine │ │ │ │ │ - * the behaviour of this Strategy │ │ │ │ │ + * newParams - {Object} │ │ │ │ │ * │ │ │ │ │ - * Valid options include: │ │ │ │ │ - * force - {Boolean} if true, new data must be unconditionally read. │ │ │ │ │ - * noAbort - {Boolean} if true, do not abort previous requests. │ │ │ │ │ + * Returns: │ │ │ │ │ + * redrawn: {Boolean} whether the layer was actually redrawn. │ │ │ │ │ */ │ │ │ │ │ - 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); │ │ │ │ │ + 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; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getMapBounds │ │ │ │ │ - * Get the map bounds expressed in the same projection as this layer. │ │ │ │ │ + * 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: │ │ │ │ │ - * {} Map bounds in the projection of the layer. │ │ │ │ │ + * {Boolean} The layer was redrawn. │ │ │ │ │ */ │ │ │ │ │ - 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 │ │ │ │ │ - ); │ │ │ │ │ + redraw: function(force) { │ │ │ │ │ + if (force) { │ │ │ │ │ + return this.mergeNewParams({ │ │ │ │ │ + "_olSalt": Math.random() │ │ │ │ │ + }); │ │ │ │ │ + } else { │ │ │ │ │ + return OpenLayers.Layer.prototype.redraw.apply(this, []); │ │ │ │ │ } │ │ │ │ │ - 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 is set, it will be │ │ │ │ │ - * considered. │ │ │ │ │ + * 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: │ │ │ │ │ - * mapBounds - {} the current map extent, will be │ │ │ │ │ - * retrieved from the map object if not provided │ │ │ │ │ - * │ │ │ │ │ + * paramString - {String} │ │ │ │ │ + * urls - {Array(String)} │ │ │ │ │ + * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Boolean} │ │ │ │ │ + * {String} An entry from the urls array, deterministically selected based │ │ │ │ │ + * on the paramString. │ │ │ │ │ */ │ │ │ │ │ - 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)); │ │ │ │ │ + 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 invalid; │ │ │ │ │ + return urls[Math.floor(product * urls.length)]; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: calculateBounds │ │ │ │ │ + /** │ │ │ │ │ + * 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. │ │ │ │ │ * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * mapBounds - {} 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 │ │ │ │ │ + * 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: │ │ │ │ │ - * options - {Object} Additional options for the protocol's read method │ │ │ │ │ - * (optional) │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} The protocol response object │ │ │ │ │ - * returned by the layer protocol. │ │ │ │ │ + * newParams - {Object} │ │ │ │ │ + * altUrl - {String} Use this as the url instead of the layer's url │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {String} │ │ │ │ │ */ │ │ │ │ │ - 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)); │ │ │ │ │ - }, │ │ │ │ │ + getFullRequestString: function(newParams, altUrl) { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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 │ │ │ │ │ - * {} 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] │ │ │ │ │ - }); │ │ │ │ │ + // 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); │ │ │ │ │ } │ │ │ │ │ - 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 - {} 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); │ │ │ │ │ + // 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]; │ │ │ │ │ } │ │ │ │ │ - } else { │ │ │ │ │ - this.bounds = null; │ │ │ │ │ } │ │ │ │ │ - this.response = null; │ │ │ │ │ - this.layer.events.triggerEvent("loadend", { │ │ │ │ │ - response: resp │ │ │ │ │ - }); │ │ │ │ │ + paramsString = OpenLayers.Util.getParameterString(allParams); │ │ │ │ │ + │ │ │ │ │ + return OpenLayers.Util.urlAppend(url, paramsString); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy.BBOX" │ │ │ │ │ + CLASS_NAME: "OpenLayers.Layer.HTTPRequest" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Strategy/Filter.js │ │ │ │ │ + OpenLayers/Tile/Image.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Strategy.js │ │ │ │ │ - * @requires OpenLayers/Filter.js │ │ │ │ │ + * @requires OpenLayers/Tile.js │ │ │ │ │ + * @requires OpenLayers/Animation.js │ │ │ │ │ + * @requires OpenLayers/Util.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.Tile.Image │ │ │ │ │ + * Instances of OpenLayers.Tile.Image are used to manage the image tiles │ │ │ │ │ + * used by various layers. Create a new image tile with the │ │ │ │ │ + * constructor. │ │ │ │ │ * │ │ │ │ │ * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Strategy.Filter = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ +OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: filter │ │ │ │ │ - * {} Filter for limiting features sent to the layer. │ │ │ │ │ - * Use the method to update this filter after construction. │ │ │ │ │ + * APIProperty: events │ │ │ │ │ + * {} An events object that handles all │ │ │ │ │ + * events on the tile. │ │ │ │ │ + * │ │ │ │ │ + * Register a listener for a particular event with the following syntax: │ │ │ │ │ + * (code) │ │ │ │ │ + * tile.events.register(type, obj, listener); │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Supported event types (in addition to the events): │ │ │ │ │ + * beforeload - Triggered before an image is prepared for loading, when the │ │ │ │ │ + * url for the image is known already. Listeners may call on │ │ │ │ │ + * the tile instance. If they do so, that image will be used and no new │ │ │ │ │ + * one will be created. │ │ │ │ │ */ │ │ │ │ │ - filter: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: cache │ │ │ │ │ - * {Array()} List of currently cached │ │ │ │ │ - * features. │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: url │ │ │ │ │ + * {String} The URL of the image being requested. No default. Filled in by │ │ │ │ │ + * layer.getURL() function. May be modified by loadstart listeners. │ │ │ │ │ */ │ │ │ │ │ - cache: null, │ │ │ │ │ + url: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: caching │ │ │ │ │ - * {Boolean} The filter is currently caching features. │ │ │ │ │ + /** │ │ │ │ │ + * Property: imgDiv │ │ │ │ │ + * {HTMLImageElement} The image for this tile. │ │ │ │ │ */ │ │ │ │ │ - caching: false, │ │ │ │ │ + imgDiv: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Strategy.Filter │ │ │ │ │ - * Create a new filter strategy. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ - * instance. │ │ │ │ │ + * Property: frame │ │ │ │ │ + * {DOMElement} The image element is appended to the frame. Any gutter on │ │ │ │ │ + * the image will be hidden behind the frame. If no gutter is set, │ │ │ │ │ + * this will be null. │ │ │ │ │ */ │ │ │ │ │ + frame: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * 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. │ │ │ │ │ + /** │ │ │ │ │ + * Property: imageReloadAttempts │ │ │ │ │ + * {Integer} Attempts to load the image. │ │ │ │ │ */ │ │ │ │ │ - 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; │ │ │ │ │ - }, │ │ │ │ │ + imageReloadAttempts: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * Property: layerAlphaHack │ │ │ │ │ + * {Boolean} True if the png alpha hack needs to be applied on the layer's div. │ │ │ │ │ */ │ │ │ │ │ - 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); │ │ │ │ │ - }, │ │ │ │ │ + layerAlphaHack: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: handleAdd │ │ │ │ │ + * Property: asyncRequestId │ │ │ │ │ + * {Integer} ID of an request to see if request is still valid. This is a │ │ │ │ │ + * number which increments by 1 for each asynchronous request. │ │ │ │ │ */ │ │ │ │ │ - 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); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ + asyncRequestId: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * APIProperty: maxGetUrlLength │ │ │ │ │ + * {Number} If set, requests that would result in GET urls with more │ │ │ │ │ + * characters than the number provided will be made using form-encoded │ │ │ │ │ + * HTTP POST. It is good practice to avoid urls that are longer than 2048 │ │ │ │ │ + * characters. │ │ │ │ │ * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * 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/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 constructor for details on constructing a │ │ │ │ │ - * new instance. │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Tile.UTFGrid = OpenLayers.Class(OpenLayers.Tile, { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: url │ │ │ │ │ - * {String} │ │ │ │ │ - * The URL of the UTFGrid file being requested. Provided by the │ │ │ │ │ - * method. │ │ │ │ │ + * Caution: │ │ │ │ │ + * Older versions of Gecko based browsers (e.g. Firefox < 3.5) and most │ │ │ │ │ + * Opera versions do not fully support this option. On all browsers, │ │ │ │ │ + * transition effects are not supported if POST requests are used. │ │ │ │ │ */ │ │ │ │ │ - url: null, │ │ │ │ │ + maxGetUrlLength: 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. │ │ │ │ │ + * Property: canvasContext │ │ │ │ │ + * {CanvasRenderingContext2D} A canvas context associated with │ │ │ │ │ + * the tile image. │ │ │ │ │ */ │ │ │ │ │ - utfgridResolution: 2, │ │ │ │ │ + canvasContext: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: json │ │ │ │ │ - * {Object} │ │ │ │ │ - * Stores the parsed JSON tile data structure. │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: crossOriginKeyword │ │ │ │ │ + * The value of the crossorigin keyword to use when loading images. This is │ │ │ │ │ + * only relevant when using for tiles from remote │ │ │ │ │ + * origins and should be set to either 'anonymous' or 'use-credentials' │ │ │ │ │ + * for servers that send Access-Control-Allow-Origin headers with their │ │ │ │ │ + * tiles. │ │ │ │ │ */ │ │ │ │ │ - json: null, │ │ │ │ │ + crossOriginKeyword: 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). │ │ │ │ │ + /** TBD 3.0 - reorder the parameters to the init function to remove │ │ │ │ │ + * URL. the getUrl() function on the layer gets called on │ │ │ │ │ + * each draw(), so no need to specify it here. │ │ │ │ │ */ │ │ │ │ │ - format: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Tile.UTFGrid │ │ │ │ │ - * Constructor for a new instance. │ │ │ │ │ + * Constructor: OpenLayers.Tile.Image │ │ │ │ │ + * Constructor for a new instance. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ * layer - {} layer that the tile will go in. │ │ │ │ │ * position - {} │ │ │ │ │ * bounds - {} │ │ │ │ │ * url - {} Deprecated. Remove me in 3.0. │ │ │ │ │ * size - {} │ │ │ │ │ * options - {Object} │ │ │ │ │ */ │ │ │ │ │ + initialize: function(layer, position, bounds, url, size, options) { │ │ │ │ │ + OpenLayers.Tile.prototype.initialize.apply(this, arguments); │ │ │ │ │ + │ │ │ │ │ + this.url = url; //deprecated remove me │ │ │ │ │ + │ │ │ │ │ + this.layerAlphaHack = this.layer.alpha && OpenLayers.Util.alphaHack(); │ │ │ │ │ + │ │ │ │ │ + if (this.maxGetUrlLength != null || this.layer.gutter || this.layerAlphaHack) { │ │ │ │ │ + // only create frame if it's needed │ │ │ │ │ + this.frame = document.createElement("div"); │ │ │ │ │ + this.frame.style.position = "absolute"; │ │ │ │ │ + this.frame.style.overflow = "hidden"; │ │ │ │ │ + } │ │ │ │ │ + if (this.maxGetUrlLength != null) { │ │ │ │ │ + OpenLayers.Util.extend(this, OpenLayers.Tile.Image.IFrame); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ * APIMethod: destroy │ │ │ │ │ - * Clean up. │ │ │ │ │ + * nullify references to prevent circular references and memory leaks │ │ │ │ │ */ │ │ │ │ │ destroy: function() { │ │ │ │ │ - this.clear(); │ │ │ │ │ + if (this.imgDiv) { │ │ │ │ │ + this.clear(); │ │ │ │ │ + this.imgDiv = null; │ │ │ │ │ + this.frame = null; │ │ │ │ │ + } │ │ │ │ │ + // don't handle async requests any more │ │ │ │ │ + this.asyncRequestId = null; │ │ │ │ │ OpenLayers.Tile.prototype.destroy.apply(this, arguments); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ * Method: draw │ │ │ │ │ * Check that a tile should be drawn, and draw it. │ │ │ │ │ - * In the case of UTFGrids, "drawing" it means fetching and │ │ │ │ │ - * parsing the json. │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Boolean} Was a tile drawn? │ │ │ │ │ + * {Boolean} Was a tile drawn? Or null if a beforedraw listener returned │ │ │ │ │ + * false. │ │ │ │ │ */ │ │ │ │ │ draw: function() { │ │ │ │ │ - var drawn = OpenLayers.Tile.prototype.draw.apply(this, arguments); │ │ │ │ │ - if (drawn) { │ │ │ │ │ + var shouldDraw = OpenLayers.Tile.prototype.draw.apply(this, arguments); │ │ │ │ │ + if (shouldDraw) { │ │ │ │ │ + // The layer's reproject option is deprecated. │ │ │ │ │ + if (this.layer != this.layer.map.baseLayer && this.layer.reproject) { │ │ │ │ │ + // getBoundsFromBaseLayer is defined in deprecated.js. │ │ │ │ │ + this.bounds = this.getBoundsFromBaseLayer(this.position); │ │ │ │ │ + } │ │ │ │ │ if (this.isLoading) { │ │ │ │ │ - this.abortLoading(); │ │ │ │ │ //if we're already loading, send 'reload' instead of 'loadstart'. │ │ │ │ │ - this.events.triggerEvent("reload"); │ │ │ │ │ + this._loadEvent = "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 │ │ │ │ │ - }); │ │ │ │ │ + this._loadEvent = "loadstart"; │ │ │ │ │ } │ │ │ │ │ - } else { │ │ │ │ │ + this.renderTile(); │ │ │ │ │ + this.positionTile(); │ │ │ │ │ + } else if (shouldDraw === false) { │ │ │ │ │ this.unload(); │ │ │ │ │ } │ │ │ │ │ - return drawn; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: abortLoading │ │ │ │ │ - * Cancel a pending request. │ │ │ │ │ - */ │ │ │ │ │ - abortLoading: function() { │ │ │ │ │ - if (this.request) { │ │ │ │ │ - this.request.abort(); │ │ │ │ │ - delete this.request; │ │ │ │ │ - } │ │ │ │ │ - this.isLoading = false; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * 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; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * 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; │ │ │ │ │ + return shouldDraw; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * 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. │ │ │ │ │ + * Method: renderTile │ │ │ │ │ + * Internal function to actually initialize the image tile, │ │ │ │ │ + * position it correctly, and set its url. │ │ │ │ │ */ │ │ │ │ │ - indexFromCharCode: function(charCode) { │ │ │ │ │ - if (charCode >= 93) { │ │ │ │ │ - charCode--; │ │ │ │ │ - } │ │ │ │ │ - if (charCode >= 35) { │ │ │ │ │ - charCode--; │ │ │ │ │ + renderTile: function() { │ │ │ │ │ + if (this.layer.async) { │ │ │ │ │ + // Asynchronous image requests call the asynchronous getURL method │ │ │ │ │ + // on the layer to fetch an image that covers 'this.bounds'. │ │ │ │ │ + var id = this.asyncRequestId = (this.asyncRequestId || 0) + 1; │ │ │ │ │ + this.layer.getURLasync(this.bounds, function(url) { │ │ │ │ │ + if (id == this.asyncRequestId) { │ │ │ │ │ + this.url = url; │ │ │ │ │ + this.initImage(); │ │ │ │ │ + } │ │ │ │ │ + }, this); │ │ │ │ │ + } else { │ │ │ │ │ + // synchronous image requests get the url immediately. │ │ │ │ │ + this.url = this.layer.getURL(this.bounds); │ │ │ │ │ + this.initImage(); │ │ │ │ │ } │ │ │ │ │ - return charCode - 32; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: parseData │ │ │ │ │ - * Parse the JSON from a request │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * str - {String} UTFGrid as a JSON string. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} parsed javascript data │ │ │ │ │ + * Method: positionTile │ │ │ │ │ + * Using the properties currenty set on the layer, position the tile correctly. │ │ │ │ │ + * This method is used both by the async and non-async versions of the Tile.Image │ │ │ │ │ + * code. │ │ │ │ │ */ │ │ │ │ │ - parseData: function(str) { │ │ │ │ │ - if (!this.format) { │ │ │ │ │ - this.format = new OpenLayers.Format.JSON(); │ │ │ │ │ + positionTile: function() { │ │ │ │ │ + var style = this.getTile().style, │ │ │ │ │ + size = this.frame ? this.size : │ │ │ │ │ + this.layer.getImageSize(this.bounds), │ │ │ │ │ + ratio = 1; │ │ │ │ │ + if (this.layer instanceof OpenLayers.Layer.Grid) { │ │ │ │ │ + ratio = this.layer.getServerResolution() / this.layer.map.getResolution(); │ │ │ │ │ } │ │ │ │ │ - this.json = this.format.read(str); │ │ │ │ │ + style.left = this.position.x + "px"; │ │ │ │ │ + style.top = this.position.y + "px"; │ │ │ │ │ + style.width = Math.round(ratio * size.w) + "px"; │ │ │ │ │ + style.height = Math.round(ratio * size.h) + "px"; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ * Method: clear │ │ │ │ │ - * Delete data stored with this tile. │ │ │ │ │ + * Remove the tile from the DOM, clear it of any image related data so that │ │ │ │ │ + * it can be reused in a new location. │ │ │ │ │ */ │ │ │ │ │ clear: function() { │ │ │ │ │ - this.json = null; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Tile.UTFGrid" │ │ │ │ │ - │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - 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 instances │ │ │ │ │ - * configured with 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); │ │ │ │ │ - } │ │ │ │ │ + OpenLayers.Tile.prototype.clear.apply(this, arguments); │ │ │ │ │ + var img = this.imgDiv; │ │ │ │ │ + if (img) { │ │ │ │ │ + var tile = this.getTile(); │ │ │ │ │ + if (tile.parentNode === this.layer.div) { │ │ │ │ │ + this.layer.div.removeChild(tile); │ │ │ │ │ + } │ │ │ │ │ + this.setImgSrc(); │ │ │ │ │ + if (this.layerAlphaHack === true) { │ │ │ │ │ + img.style.filter = ""; │ │ │ │ │ } │ │ │ │ │ + OpenLayers.Element.removeClass(img, "olImageLoadError"); │ │ │ │ │ } │ │ │ │ │ - return OpenLayers.Tile.Image.prototype.draw.apply(this, arguments); │ │ │ │ │ + this.canvasContext = null; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ * Method: getImage │ │ │ │ │ - * Creates the content for the frame on the tile. │ │ │ │ │ + * Returns or creates and returns the tile image. │ │ │ │ │ */ │ │ │ │ │ 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('