{"diffoscope-json-version": 1, "source1": "/srv/reproducible-results/rbuild-debian/r-b-build.8gADvR2M/b1/openlayers_2.13.1+ds2-10_amd64.changes", "source2": "/srv/reproducible-results/rbuild-debian/r-b-build.8gADvR2M/b2/openlayers_2.13.1+ds2-10_amd64.changes", "unified_diff": null, "details": [{"source1": "Files", "source2": "Files", "unified_diff": "@@ -1,2 +1,2 @@\n \n- 2c336306eaba9a29f846b73cd6e694e2 708360 javascript optional libjs-openlayers_2.13.1+ds2-10_all.deb\n+ 1911fe32feb5191b50d7c2c66f2ddb29 781204 javascript optional libjs-openlayers_2.13.1+ds2-10_all.deb\n"}, {"source1": "libjs-openlayers_2.13.1+ds2-10_all.deb", "source2": "libjs-openlayers_2.13.1+ds2-10_all.deb", "unified_diff": null, "details": [{"source1": "file list", "source2": "file list", "unified_diff": "@@ -1,3 +1,3 @@\n -rw-r--r-- 0 0 0 4 2023-01-14 13:27:41.000000 debian-binary\n--rw-r--r-- 0 0 0 3680 2023-01-14 13:27:41.000000 control.tar.xz\n--rw-r--r-- 0 0 0 704488 2023-01-14 13:27:41.000000 data.tar.xz\n+-rw-r--r-- 0 0 0 3684 2023-01-14 13:27:41.000000 control.tar.xz\n+-rw-r--r-- 0 0 0 777328 2023-01-14 13:27:41.000000 data.tar.xz\n"}, {"source1": "control.tar.xz", "source2": "control.tar.xz", "unified_diff": null, "details": [{"source1": "control.tar", "source2": "control.tar", "unified_diff": null, "details": [{"source1": "./md5sums", "source2": "./md5sums", "unified_diff": null, "details": [{"source1": "./md5sums", "source2": "./md5sums", "comments": ["Files differ"], "unified_diff": null}]}]}]}, {"source1": "data.tar.xz", "source2": "data.tar.xz", "unified_diff": null, "details": [{"source1": "data.tar", "source2": "data.tar", "unified_diff": null, "details": [{"source1": "./usr/share/javascript/openlayers/OpenLayers.js", "source2": "./usr/share/javascript/openlayers/OpenLayers.js", "unified_diff": null, "details": [{"source1": "js-beautify {}", "source2": "js-beautify {}", "unified_diff": "@@ -136,14 +136,141 @@\n * (code)\n * \n * (end code)\n */\n ImgPath: ''\n };\n /* ======================================================================\n+ OpenLayers/BaseTypes/Class.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/SingleFile.js\n+ */\n+\n+/**\n+ * Constructor: OpenLayers.Class\n+ * Base class used to construct all other classes. Includes support for \n+ * multiple inheritance. \n+ * \n+ * This constructor is new in OpenLayers 2.5. At OpenLayers 3.0, the old \n+ * syntax for creating classes and dealing with inheritance \n+ * will be removed.\n+ * \n+ * To create a new OpenLayers-style class, use the following syntax:\n+ * (code)\n+ * var MyClass = OpenLayers.Class(prototype);\n+ * (end)\n+ *\n+ * To create a new OpenLayers-style class with multiple inheritance, use the\n+ * following syntax:\n+ * (code)\n+ * var MyClass = OpenLayers.Class(Class1, Class2, prototype);\n+ * (end)\n+ * \n+ * Note that instanceof reflection will only reveal Class1 as superclass.\n+ *\n+ */\n+OpenLayers.Class = function() {\n+ var len = arguments.length;\n+ var P = arguments[0];\n+ var F = arguments[len - 1];\n+\n+ var C = typeof F.initialize == \"function\" ?\n+ F.initialize :\n+ function() {\n+ P.prototype.initialize.apply(this, arguments);\n+ };\n+\n+ if (len > 1) {\n+ var newArgs = [C, P].concat(\n+ Array.prototype.slice.call(arguments).slice(1, len - 1), F);\n+ OpenLayers.inherit.apply(null, newArgs);\n+ } else {\n+ C.prototype = F;\n+ }\n+ return C;\n+};\n+\n+/**\n+ * Function: OpenLayers.inherit\n+ *\n+ * Parameters:\n+ * C - {Object} the class that inherits\n+ * P - {Object} the superclass to inherit from\n+ *\n+ * In addition to the mandatory C and P parameters, an arbitrary number of\n+ * objects can be passed, which will extend C.\n+ */\n+OpenLayers.inherit = function(C, P) {\n+ var F = function() {};\n+ F.prototype = P.prototype;\n+ C.prototype = new F;\n+ var i, l, o;\n+ for (i = 2, l = arguments.length; i < l; i++) {\n+ o = arguments[i];\n+ if (typeof o === \"function\") {\n+ o = o.prototype;\n+ }\n+ OpenLayers.Util.extend(C.prototype, o);\n+ }\n+};\n+\n+/**\n+ * APIFunction: extend\n+ * Copy all properties of a source object to a destination object. Modifies\n+ * the passed in destination object. Any properties on the source object\n+ * that are set to undefined will not be (re)set on the destination object.\n+ *\n+ * Parameters:\n+ * destination - {Object} The object that will be modified\n+ * source - {Object} The object with properties to be set on the destination\n+ *\n+ * Returns:\n+ * {Object} The destination object.\n+ */\n+OpenLayers.Util = OpenLayers.Util || {};\n+OpenLayers.Util.extend = function(destination, source) {\n+ destination = destination || {};\n+ if (source) {\n+ for (var property in source) {\n+ var value = source[property];\n+ if (value !== undefined) {\n+ destination[property] = value;\n+ }\n+ }\n+\n+ /**\n+ * IE doesn't include the toString property when iterating over an object's\n+ * properties with the for(property in object) syntax. Explicitly check if\n+ * the source has its own toString property.\n+ */\n+\n+ /*\n+ * FF/Windows < 2.0.0.13 reports \"Illegal operation on WrappedNative\n+ * prototype object\" when calling hawOwnProperty if the source object\n+ * is an instance of window.Event.\n+ */\n+\n+ var sourceIsEvt = typeof window.Event == \"function\" &&\n+ source instanceof window.Event;\n+\n+ if (!sourceIsEvt &&\n+ source.hasOwnProperty && source.hasOwnProperty(\"toString\")) {\n+ destination.toString = source.toString;\n+ }\n+ }\n+ return destination;\n+};\n+/* ======================================================================\n OpenLayers/BaseTypes.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n@@ -603,141 +730,14 @@\n }\n }\n return selected;\n }\n \n };\n /* ======================================================================\n- OpenLayers/BaseTypes/Class.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/SingleFile.js\n- */\n-\n-/**\n- * Constructor: OpenLayers.Class\n- * Base class used to construct all other classes. Includes support for \n- * multiple inheritance. \n- * \n- * This constructor is new in OpenLayers 2.5. At OpenLayers 3.0, the old \n- * syntax for creating classes and dealing with inheritance \n- * will be removed.\n- * \n- * To create a new OpenLayers-style class, use the following syntax:\n- * (code)\n- * var MyClass = OpenLayers.Class(prototype);\n- * (end)\n- *\n- * To create a new OpenLayers-style class with multiple inheritance, use the\n- * following syntax:\n- * (code)\n- * var MyClass = OpenLayers.Class(Class1, Class2, prototype);\n- * (end)\n- * \n- * Note that instanceof reflection will only reveal Class1 as superclass.\n- *\n- */\n-OpenLayers.Class = function() {\n- var len = arguments.length;\n- var P = arguments[0];\n- var F = arguments[len - 1];\n-\n- var C = typeof F.initialize == \"function\" ?\n- F.initialize :\n- function() {\n- P.prototype.initialize.apply(this, arguments);\n- };\n-\n- if (len > 1) {\n- var newArgs = [C, P].concat(\n- Array.prototype.slice.call(arguments).slice(1, len - 1), F);\n- OpenLayers.inherit.apply(null, newArgs);\n- } else {\n- C.prototype = F;\n- }\n- return C;\n-};\n-\n-/**\n- * Function: OpenLayers.inherit\n- *\n- * Parameters:\n- * C - {Object} the class that inherits\n- * P - {Object} the superclass to inherit from\n- *\n- * In addition to the mandatory C and P parameters, an arbitrary number of\n- * objects can be passed, which will extend C.\n- */\n-OpenLayers.inherit = function(C, P) {\n- var F = function() {};\n- F.prototype = P.prototype;\n- C.prototype = new F;\n- var i, l, o;\n- for (i = 2, l = arguments.length; i < l; i++) {\n- o = arguments[i];\n- if (typeof o === \"function\") {\n- o = o.prototype;\n- }\n- OpenLayers.Util.extend(C.prototype, o);\n- }\n-};\n-\n-/**\n- * APIFunction: extend\n- * Copy all properties of a source object to a destination object. Modifies\n- * the passed in destination object. Any properties on the source object\n- * that are set to undefined will not be (re)set on the destination object.\n- *\n- * Parameters:\n- * destination - {Object} The object that will be modified\n- * source - {Object} The object with properties to be set on the destination\n- *\n- * Returns:\n- * {Object} The destination object.\n- */\n-OpenLayers.Util = OpenLayers.Util || {};\n-OpenLayers.Util.extend = function(destination, source) {\n- destination = destination || {};\n- if (source) {\n- for (var property in source) {\n- var value = source[property];\n- if (value !== undefined) {\n- destination[property] = value;\n- }\n- }\n-\n- /**\n- * IE doesn't include the toString property when iterating over an object's\n- * properties with the for(property in object) syntax. Explicitly check if\n- * the source has its own toString property.\n- */\n-\n- /*\n- * FF/Windows < 2.0.0.13 reports \"Illegal operation on WrappedNative\n- * prototype object\" when calling hawOwnProperty if the source object\n- * is an instance of window.Event.\n- */\n-\n- var sourceIsEvt = typeof window.Event == \"function\" &&\n- source instanceof window.Event;\n-\n- if (!sourceIsEvt &&\n- source.hasOwnProperty && source.hasOwnProperty(\"toString\")) {\n- destination.toString = source.toString;\n- }\n- }\n- return destination;\n-};\n-/* ======================================================================\n OpenLayers/BaseTypes/Bounds.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n@@ -4426,14 +4426,155 @@\n } else {\n str += coordinate < 0 ? OpenLayers.i18n(\"S\") : OpenLayers.i18n(\"N\");\n }\n return str;\n };\n \n /* ======================================================================\n+ OpenLayers/Util/vendorPrefix.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/SingleFile.js\n+ */\n+\n+OpenLayers.Util = OpenLayers.Util || {};\n+/**\n+ * Namespace: OpenLayers.Util.vendorPrefix\n+ * A collection of utility functions to detect vendor prefixed features\n+ */\n+OpenLayers.Util.vendorPrefix = (function() {\n+ \"use strict\";\n+\n+ var VENDOR_PREFIXES = [\"\", \"O\", \"ms\", \"Moz\", \"Webkit\"],\n+ divStyle = document.createElement(\"div\").style,\n+ cssCache = {},\n+ jsCache = {};\n+\n+\n+ /**\n+ * Function: domToCss\n+ * Converts a upper camel case DOM style property name to a CSS property\n+ * i.e. transformOrigin -> transform-origin\n+ * or WebkitTransformOrigin -> -webkit-transform-origin\n+ *\n+ * Parameters:\n+ * prefixedDom - {String} The property to convert\n+ *\n+ * Returns:\n+ * {String} The CSS property\n+ */\n+ function domToCss(prefixedDom) {\n+ if (!prefixedDom) {\n+ return null;\n+ }\n+ return prefixedDom.\n+ replace(/([A-Z])/g, function(c) {\n+ return \"-\" + c.toLowerCase();\n+ }).\n+ replace(/^ms-/, \"-ms-\");\n+ }\n+\n+ /**\n+ * APIMethod: css\n+ * Detect which property is used for a CSS property\n+ *\n+ * Parameters:\n+ * property - {String} The standard (unprefixed) CSS property name\n+ *\n+ * Returns:\n+ * {String} The standard CSS property, prefixed property or null if not\n+ * supported\n+ */\n+ function css(property) {\n+ if (cssCache[property] === undefined) {\n+ var domProperty = property.\n+ replace(/(-[\\s\\S])/g, function(c) {\n+ return c.charAt(1).toUpperCase();\n+ });\n+ var prefixedDom = style(domProperty);\n+ cssCache[property] = domToCss(prefixedDom);\n+ }\n+ return cssCache[property];\n+ }\n+\n+ /**\n+ * APIMethod: js\n+ * Detect which property is used for a JS property/method\n+ *\n+ * Parameters:\n+ * obj - {Object} The object to test on\n+ * property - {String} The standard (unprefixed) JS property name\n+ *\n+ * Returns:\n+ * {String} The standard JS property, prefixed property or null if not\n+ * supported\n+ */\n+ function js(obj, property) {\n+ if (jsCache[property] === undefined) {\n+ var tmpProp,\n+ i = 0,\n+ l = VENDOR_PREFIXES.length,\n+ prefix,\n+ isStyleObj = (typeof obj.cssText !== \"undefined\");\n+\n+ jsCache[property] = null;\n+ for (; i < l; i++) {\n+ prefix = VENDOR_PREFIXES[i];\n+ if (prefix) {\n+ if (!isStyleObj) {\n+ // js prefix should be lower-case, while style\n+ // properties have upper case on first character\n+ prefix = prefix.toLowerCase();\n+ }\n+ tmpProp = prefix + property.charAt(0).toUpperCase() + property.slice(1);\n+ } else {\n+ tmpProp = property;\n+ }\n+\n+ if (obj[tmpProp] !== undefined) {\n+ jsCache[property] = tmpProp;\n+ break;\n+ }\n+ }\n+ }\n+ return jsCache[property];\n+ }\n+\n+ /**\n+ * APIMethod: style\n+ * Detect which property is used for a DOM style property\n+ *\n+ * Parameters:\n+ * property - {String} The standard (unprefixed) style property name\n+ *\n+ * Returns:\n+ * {String} The standard style property, prefixed property or null if not\n+ * supported\n+ */\n+ function style(property) {\n+ return js(divStyle, property);\n+ }\n+\n+ return {\n+ css: css,\n+ js: js,\n+ style: style,\n+\n+ // used for testing\n+ cssCache: cssCache,\n+ jsCache: jsCache\n+ };\n+}());\n+/* ======================================================================\n OpenLayers/Events.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n@@ -5602,6300 +5743,2502 @@\n \n OpenLayers.Event.observe(element, 'MSPointerUp', cb);\n },\n \n CLASS_NAME: \"OpenLayers.Events\"\n });\n /* ======================================================================\n- OpenLayers/Handler.js\n+ OpenLayers/Animation.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n /**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Events.js\n+ * @requires OpenLayers/SingleFile.js\n+ * @requires OpenLayers/Util/vendorPrefix.js\n */\n \n /**\n- * Class: OpenLayers.Handler\n- * Base class to construct a higher-level handler for event sequences. All\n- * handlers have activate and deactivate methods. In addition, they have\n- * methods named like browser events. When a handler is activated, any\n- * additional methods named like a browser event is registered as a\n- * listener for the corresponding event. When a handler is deactivated,\n- * those same methods are unregistered as event listeners.\n- *\n- * Handlers also typically have a callbacks object with keys named like\n- * the abstracted events or event sequences that they are in charge of\n- * handling. The controls that wrap handlers define the methods that\n- * correspond to these abstract events - so instead of listening for\n- * individual browser events, they only listen for the abstract events\n- * defined by the handler.\n- * \n- * Handlers are created by controls, which ultimately have the responsibility\n- * of making changes to the the state of the application. Handlers\n- * themselves may make temporary changes, but in general are expected to\n- * return the application in the same state that they found it.\n+ * Namespace: OpenLayers.Animation\n+ * A collection of utility functions for executing methods that repaint a \n+ * portion of the browser window. These methods take advantage of the\n+ * browser's scheduled repaints where requestAnimationFrame is available.\n */\n-OpenLayers.Handler = OpenLayers.Class({\n+OpenLayers.Animation = (function(window) {\n \n /**\n- * Property: id\n- * {String}\n+ * Property: isNative\n+ * {Boolean} true if a native requestAnimationFrame function is available\n */\n- id: null,\n+ var requestAnimationFrame = OpenLayers.Util.vendorPrefix.js(window, \"requestAnimationFrame\");\n+ var isNative = !!(requestAnimationFrame);\n \n /**\n- * APIProperty: control\n- * {}. The control that initialized this handler. The\n- * control is assumed to have a valid map property - that map is used\n- * in the handler's own setMap method.\n+ * Function: requestFrame\n+ * Schedule a function to be called at the next available animation frame.\n+ * Uses the native method where available. Where requestAnimationFrame is\n+ * not available, setTimeout will be called with a 16ms delay.\n+ *\n+ * Parameters:\n+ * callback - {Function} The function to be called at the next animation frame.\n+ * element - {DOMElement} Optional element that visually bounds the animation.\n */\n- control: null,\n+ var requestFrame = (function() {\n+ var request = window[requestAnimationFrame] ||\n+ function(callback, element) {\n+ window.setTimeout(callback, 16);\n+ };\n+ // bind to window to avoid illegal invocation of native function\n+ return function(callback, element) {\n+ request.apply(window, [callback, element]);\n+ };\n+ })();\n \n- /**\n- * Property: map\n- * {}\n- */\n- map: null,\n+ // private variables for animation loops\n+ var counter = 0;\n+ var loops = {};\n \n /**\n- * APIProperty: keyMask\n- * {Integer} Use bitwise operators and one or more of the OpenLayers.Handler\n- * constants to construct a keyMask. The keyMask is used by\n- * . If the keyMask matches the combination of keys\n- * down on an event, checkModifiers returns true.\n+ * Function: start\n+ * Executes a method with in series for some \n+ * duration.\n *\n- * Example:\n- * (code)\n- * // handler only responds if the Shift key is down\n- * handler.keyMask = OpenLayers.Handler.MOD_SHIFT;\n+ * Parameters:\n+ * callback - {Function} The function to be called at the next animation frame.\n+ * duration - {Number} Optional duration for the loop. If not provided, the\n+ * animation loop will execute indefinitely.\n+ * element - {DOMElement} Optional element that visually bounds the animation.\n *\n- * // handler only responds if Ctrl-Shift is down\n- * handler.keyMask = OpenLayers.Handler.MOD_SHIFT |\n- * OpenLayers.Handler.MOD_CTRL;\n- * (end)\n+ * Returns:\n+ * {Number} Identifier for the animation loop. Used to stop animations with\n+ * .\n */\n- keyMask: null,\n+ function start(callback, duration, element) {\n+ duration = duration > 0 ? duration : Number.POSITIVE_INFINITY;\n+ var id = ++counter;\n+ var start = +new Date;\n+ loops[id] = function() {\n+ if (loops[id] && +new Date - start <= duration) {\n+ callback();\n+ if (loops[id]) {\n+ requestFrame(loops[id], element);\n+ }\n+ } else {\n+ delete loops[id];\n+ }\n+ };\n+ requestFrame(loops[id], element);\n+ return id;\n+ }\n \n /**\n- * Property: active\n- * {Boolean}\n+ * Function: stop\n+ * Terminates an animation loop started with .\n+ *\n+ * Parameters:\n+ * id - {Number} Identifier returned from .\n */\n- active: false,\n+ function stop(id) {\n+ delete loops[id];\n+ }\n \n- /**\n- * Property: evt\n- * {Event} This property references the last event handled by the handler.\n- * Note that this property is not part of the stable API. Use of the\n- * evt property should be restricted to controls in the library\n- * or other applications that are willing to update with changes to\n- * the OpenLayers code.\n- */\n- evt: null,\n+ return {\n+ isNative: isNative,\n+ requestFrame: requestFrame,\n+ start: start,\n+ stop: stop\n+ };\n \n- /**\n- * Property: touch\n- * {Boolean} Indicates the support of touch events. When touch events are \n- * started touch will be true and all mouse related listeners will do \n- * nothing.\n- */\n- touch: false,\n+})(window);\n+/* ======================================================================\n+ OpenLayers/Tween.js\n+ ====================================================================== */\n \n- /**\n- * Constructor: OpenLayers.Handler\n- * Construct a handler.\n- *\n- * Parameters:\n- * control - {} The control that initialized this\n- * handler. The control is assumed to have a valid map property; that\n- * map is used in the handler's own setMap method. If a map property\n- * is present in the options argument it will be used instead.\n- * callbacks - {Object} An object whose properties correspond to abstracted\n- * events or sequences of browser events. The values for these\n- * properties are functions defined by the control that get called by\n- * the handler.\n- * options - {Object} An optional object whose properties will be set on\n- * the handler.\n- */\n- initialize: function(control, callbacks, options) {\n- OpenLayers.Util.extend(this, options);\n- this.control = control;\n- this.callbacks = callbacks;\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- var map = this.map || control.map;\n- if (map) {\n- this.setMap(map);\n- }\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Animation.js\n+ */\n \n- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n- },\n+/**\n+ * Namespace: OpenLayers.Tween\n+ */\n+OpenLayers.Tween = OpenLayers.Class({\n \n /**\n- * Method: setMap\n+ * APIProperty: easing\n+ * {(Function)} Easing equation used for the animation\n+ * Defaultly set to OpenLayers.Easing.Expo.easeOut\n */\n- setMap: function(map) {\n- this.map = map;\n- },\n+ easing: null,\n \n /**\n- * Method: checkModifiers\n- * Check the keyMask on the handler. If no is set, this always\n- * returns true. If a is set and it matches the combination\n- * of keys down on an event, this returns true.\n- *\n- * Returns:\n- * {Boolean} The keyMask matches the keys down on an event.\n+ * APIProperty: begin\n+ * {Object} Values to start the animation with\n */\n- checkModifiers: function(evt) {\n- if (this.keyMask == null) {\n- return true;\n- }\n- /* calculate the keyboard modifier mask for this event */\n- var keyModifiers =\n- (evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) |\n- (evt.ctrlKey ? OpenLayers.Handler.MOD_CTRL : 0) |\n- (evt.altKey ? OpenLayers.Handler.MOD_ALT : 0) |\n- (evt.metaKey ? OpenLayers.Handler.MOD_META : 0);\n+ begin: null,\n \n- /* if it differs from the handler object's key mask,\n- bail out of the event handler */\n- return (keyModifiers == this.keyMask);\n- },\n+ /**\n+ * APIProperty: finish\n+ * {Object} Values to finish the animation with\n+ */\n+ finish: null,\n \n /**\n- * APIMethod: activate\n- * Turn on the handler. Returns false if the handler was already active.\n- * \n- * Returns: \n- * {Boolean} The handler was activated.\n+ * APIProperty: duration\n+ * {int} duration of the tween (number of steps)\n */\n- activate: function() {\n- if (this.active) {\n- return false;\n- }\n- // register for event handlers defined on this class.\n- var events = OpenLayers.Events.prototype.BROWSER_EVENTS;\n- for (var i = 0, len = events.length; i < len; i++) {\n- if (this[events[i]]) {\n- this.register(events[i], this[events[i]]);\n- }\n- }\n- this.active = true;\n- return true;\n- },\n+ duration: null,\n \n /**\n- * APIMethod: deactivate\n- * Turn off the handler. Returns false if the handler was already inactive.\n- * \n- * Returns:\n- * {Boolean} The handler was deactivated.\n+ * APIProperty: callbacks\n+ * {Object} An object with start, eachStep and done properties whose values\n+ * are functions to be call during the animation. They are passed the\n+ * current computed value as argument.\n */\n- deactivate: function() {\n- if (!this.active) {\n- return false;\n- }\n- // unregister event handlers defined on this class.\n- var events = OpenLayers.Events.prototype.BROWSER_EVENTS;\n- for (var i = 0, len = events.length; i < len; i++) {\n- if (this[events[i]]) {\n- this.unregister(events[i], this[events[i]]);\n- }\n- }\n- this.touch = false;\n- this.active = false;\n- return true;\n- },\n+ callbacks: null,\n \n /**\n- * Method: startTouch\n- * Start touch events, this method must be called by subclasses in \n- * \"touchstart\" method. When touch events are started will be\n- * true and all mouse related listeners will do nothing.\n+ * Property: time\n+ * {int} Step counter\n */\n- startTouch: function() {\n- if (!this.touch) {\n- this.touch = true;\n- var events = [\n- \"mousedown\", \"mouseup\", \"mousemove\", \"click\", \"dblclick\",\n- \"mouseout\"\n- ];\n- for (var i = 0, len = events.length; i < len; i++) {\n- if (this[events[i]]) {\n- this.unregister(events[i], this[events[i]]);\n- }\n- }\n- }\n- },\n+ time: null,\n \n /**\n- * Method: callback\n- * Trigger the control's named callback with the given arguments\n- *\n- * Parameters:\n- * name - {String} The key for the callback that is one of the properties\n- * of the handler's callbacks object.\n- * args - {Array(*)} An array of arguments (any type) with which to call \n- * the callback (defined by the control).\n+ * APIProperty: minFrameRate\n+ * {Number} The minimum framerate for animations in frames per second. After\n+ * each step, the time spent in the animation is compared to the calculated\n+ * time at this frame rate. If the animation runs longer than the calculated\n+ * time, the next step is skipped. Default is 30.\n */\n- callback: function(name, args) {\n- if (name && this.callbacks[name]) {\n- this.callbacks[name].apply(this.control, args);\n- }\n- },\n+ minFrameRate: null,\n \n /**\n- * Method: register\n- * register an event on the map\n+ * Property: startTime\n+ * {Number} The timestamp of the first execution step. Used for skipping\n+ * frames\n */\n- register: function(name, method) {\n- // TODO: deal with registerPriority in 3.0\n- this.map.events.registerPriority(name, this, method);\n- this.map.events.registerPriority(name, this, this.setEvent);\n- },\n+ startTime: null,\n \n /**\n- * Method: unregister\n- * unregister an event from the map\n+ * Property: animationId\n+ * {int} Loop id returned by OpenLayers.Animation.start\n */\n- unregister: function(name, method) {\n- this.map.events.unregister(name, this, method);\n- this.map.events.unregister(name, this, this.setEvent);\n- },\n+ animationId: null,\n \n /**\n- * Method: setEvent\n- * With each registered browser event, the handler sets its own evt\n- * property. This property can be accessed by controls if needed\n- * to get more information about the event that the handler is\n- * processing.\n- *\n- * This allows modifier keys on the event to be checked (alt, shift, ctrl,\n- * and meta cannot be checked with the keyboard handler). For a\n- * control to determine which modifier keys are associated with the\n- * event that a handler is currently processing, it should access\n- * (code)handler.evt.altKey || handler.evt.shiftKey ||\n- * handler.evt.ctrlKey || handler.evt.metaKey(end).\n+ * Property: playing\n+ * {Boolean} Tells if the easing is currently playing\n+ */\n+ playing: false,\n+\n+ /** \n+ * Constructor: OpenLayers.Tween\n+ * Creates a Tween.\n *\n * Parameters:\n- * evt - {Event} The browser event.\n+ * easing - {(Function)} easing function method to use\n */\n- setEvent: function(evt) {\n- this.evt = evt;\n- return true;\n+ initialize: function(easing) {\n+ this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut;\n },\n \n /**\n- * Method: destroy\n- * Deconstruct the handler.\n+ * APIMethod: start\n+ * Plays the Tween, and calls the callback method on each step\n+ * \n+ * Parameters:\n+ * begin - {Object} values to start the animation with\n+ * finish - {Object} values to finish the animation with\n+ * duration - {int} duration of the tween (number of steps)\n+ * options - {Object} hash of options (callbacks (start, eachStep, done),\n+ * minFrameRate)\n */\n- destroy: function() {\n- // unregister event listeners\n- this.deactivate();\n- // eliminate circular references\n- this.control = this.map = null;\n+ start: function(begin, finish, duration, options) {\n+ this.playing = true;\n+ this.begin = begin;\n+ this.finish = finish;\n+ this.duration = duration;\n+ this.callbacks = options.callbacks;\n+ this.minFrameRate = options.minFrameRate || 30;\n+ this.time = 0;\n+ this.startTime = new Date().getTime();\n+ OpenLayers.Animation.stop(this.animationId);\n+ this.animationId = null;\n+ if (this.callbacks && this.callbacks.start) {\n+ this.callbacks.start.call(this, this.begin);\n+ }\n+ this.animationId = OpenLayers.Animation.start(\n+ OpenLayers.Function.bind(this.play, this)\n+ );\n },\n \n- CLASS_NAME: \"OpenLayers.Handler\"\n-});\n-\n-/**\n- * Constant: OpenLayers.Handler.MOD_NONE\n- * If set as the , returns false if any key is down.\n- */\n-OpenLayers.Handler.MOD_NONE = 0;\n-\n-/**\n- * Constant: OpenLayers.Handler.MOD_SHIFT\n- * If set as the , returns false if Shift is down.\n- */\n-OpenLayers.Handler.MOD_SHIFT = 1;\n+ /**\n+ * APIMethod: stop\n+ * Stops the Tween, and calls the done callback\n+ * Doesn't do anything if animation is already finished\n+ */\n+ stop: function() {\n+ if (!this.playing) {\n+ return;\n+ }\n \n-/**\n- * Constant: OpenLayers.Handler.MOD_CTRL\n- * If set as the , returns false if Ctrl is down.\n- */\n-OpenLayers.Handler.MOD_CTRL = 2;\n+ if (this.callbacks && this.callbacks.done) {\n+ this.callbacks.done.call(this, this.finish);\n+ }\n+ OpenLayers.Animation.stop(this.animationId);\n+ this.animationId = null;\n+ this.playing = false;\n+ },\n \n-/**\n- * Constant: OpenLayers.Handler.MOD_ALT\n- * If set as the , returns false if Alt is down.\n- */\n-OpenLayers.Handler.MOD_ALT = 4;\n+ /**\n+ * Method: play\n+ * Calls the appropriate easing method\n+ */\n+ play: function() {\n+ var value = {};\n+ for (var i in this.begin) {\n+ var b = this.begin[i];\n+ var f = this.finish[i];\n+ if (b == null || f == null || isNaN(b) || isNaN(f)) {\n+ throw new TypeError('invalid value for Tween');\n+ }\n \n-/**\n- * Constant: OpenLayers.Handler.MOD_META\n- * If set as the , returns false if Cmd is down.\n- */\n-OpenLayers.Handler.MOD_META = 8;\n+ var c = f - b;\n+ value[i] = this.easing.apply(this, [this.time, b, c, this.duration]);\n+ }\n+ this.time++;\n \n+ if (this.callbacks && this.callbacks.eachStep) {\n+ // skip frames if frame rate drops below threshold\n+ if ((new Date().getTime() - this.startTime) / this.time <= 1000 / this.minFrameRate) {\n+ this.callbacks.eachStep.call(this, value);\n+ }\n+ }\n \n-/* ======================================================================\n- OpenLayers/Strategy.js\n- ====================================================================== */\n+ if (this.time > this.duration) {\n+ this.stop();\n+ }\n+ },\n \n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n+ /**\n+ * Create empty functions for all easing methods.\n+ */\n+ CLASS_NAME: \"OpenLayers.Tween\"\n+});\n \n /**\n- * @requires OpenLayers/BaseTypes/Class.js\n+ * Namespace: OpenLayers.Easing\n+ * \n+ * Credits:\n+ * Easing Equations by Robert Penner, \n */\n+OpenLayers.Easing = {\n+ /**\n+ * Create empty functions for all easing methods.\n+ */\n+ CLASS_NAME: \"OpenLayers.Easing\"\n+};\n \n /**\n- * Class: OpenLayers.Strategy\n- * Abstract vector layer strategy class. Not to be instantiated directly. Use\n- * one of the strategy subclasses instead.\n+ * Namespace: OpenLayers.Easing.Linear\n */\n-OpenLayers.Strategy = OpenLayers.Class({\n+OpenLayers.Easing.Linear = {\n \n /**\n- * Property: layer\n- * {} The layer this strategy belongs to.\n+ * Function: easeIn\n+ * \n+ * Parameters:\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n+ *\n+ * Returns:\n+ * {Float}\n */\n- layer: null,\n+ easeIn: function(t, b, c, d) {\n+ return c * t / d + b;\n+ },\n \n /**\n- * Property: options\n- * {Object} Any options sent to the constructor.\n- */\n- options: null,\n-\n- /** \n- * Property: active \n- * {Boolean} The control is active.\n+ * Function: easeOut\n+ * \n+ * Parameters:\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n+ *\n+ * Returns:\n+ * {Float}\n */\n- active: null,\n+ easeOut: function(t, b, c, d) {\n+ return c * t / d + b;\n+ },\n \n /**\n- * Property: autoActivate\n- * {Boolean} The creator of the strategy can set autoActivate to false\n- * to fully control when the protocol is activated and deactivated.\n- * Defaults to true.\n+ * Function: easeInOut\n+ * \n+ * Parameters:\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n+ *\n+ * Returns:\n+ * {Float}\n */\n- autoActivate: true,\n+ easeInOut: function(t, b, c, d) {\n+ return c * t / d + b;\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Easing.Linear\"\n+};\n+\n+/**\n+ * Namespace: OpenLayers.Easing.Expo\n+ */\n+OpenLayers.Easing.Expo = {\n \n /**\n- * Property: autoDestroy\n- * {Boolean} The creator of the strategy can set autoDestroy to false\n- * to fully control when the strategy is destroyed. Defaults to\n- * true.\n+ * Function: easeIn\n+ * \n+ * Parameters:\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n+ *\n+ * Returns:\n+ * {Float}\n */\n- autoDestroy: true,\n+ easeIn: function(t, b, c, d) {\n+ return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;\n+ },\n \n /**\n- * Constructor: OpenLayers.Strategy\n- * Abstract class for vector strategies. Create instances of a subclass.\n- *\n+ * Function: easeOut\n+ * \n * Parameters:\n- * options - {Object} Optional object whose properties will be set on the\n- * instance.\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n+ *\n+ * Returns:\n+ * {Float}\n */\n- initialize: function(options) {\n- OpenLayers.Util.extend(this, options);\n- this.options = options;\n- // set the active property here, so that user cannot override it\n- this.active = false;\n+ easeOut: function(t, b, c, d) {\n+ return (t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;\n },\n \n /**\n- * APIMethod: destroy\n- * Clean up the strategy.\n+ * Function: easeInOut\n+ * \n+ * Parameters:\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n+ *\n+ * Returns:\n+ * {Float}\n */\n- destroy: function() {\n- this.deactivate();\n- this.layer = null;\n- this.options = null;\n+ easeInOut: function(t, b, c, d) {\n+ if (t == 0) return b;\n+ if (t == d) return b + c;\n+ if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b;\n+ return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;\n },\n \n+ CLASS_NAME: \"OpenLayers.Easing.Expo\"\n+};\n+\n+/**\n+ * Namespace: OpenLayers.Easing.Quad\n+ */\n+OpenLayers.Easing.Quad = {\n+\n /**\n- * Method: setLayer\n- * Called to set the property.\n- *\n+ * Function: easeIn\n+ * \n * Parameters:\n- * layer - {}\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n+ *\n+ * Returns:\n+ * {Float}\n */\n- setLayer: function(layer) {\n- this.layer = layer;\n+ easeIn: function(t, b, c, d) {\n+ return c * (t /= d) * t + b;\n },\n \n /**\n- * Method: activate\n- * Activate the strategy. Register any listeners, do appropriate setup.\n+ * Function: easeOut\n+ * \n+ * Parameters:\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n *\n * Returns:\n- * {Boolean} True if the strategy was successfully activated or false if\n- * the strategy was already active.\n+ * {Float}\n */\n- activate: function() {\n- if (!this.active) {\n- this.active = true;\n- return true;\n- }\n- return false;\n+ easeOut: function(t, b, c, d) {\n+ return -c * (t /= d) * (t - 2) + b;\n },\n \n /**\n- * Method: deactivate\n- * Deactivate the strategy. Unregister any listeners, do appropriate\n- * tear-down.\n+ * Function: easeInOut\n+ * \n+ * Parameters:\n+ * t - {Float} time\n+ * b - {Float} beginning position\n+ * c - {Float} total change\n+ * d - {Float} duration of the transition\n *\n * Returns:\n- * {Boolean} True if the strategy was successfully deactivated or false if\n- * the strategy was already inactive.\n+ * {Float}\n */\n- deactivate: function() {\n- if (this.active) {\n- this.active = false;\n- return true;\n- }\n- return false;\n+ easeInOut: function(t, b, c, d) {\n+ if ((t /= d / 2) < 1) return c / 2 * t * t + b;\n+ return -c / 2 * ((--t) * (t - 2) - 1) + b;\n },\n \n- CLASS_NAME: \"OpenLayers.Strategy\"\n-});\n+ CLASS_NAME: \"OpenLayers.Easing.Quad\"\n+};\n /* ======================================================================\n- OpenLayers/Feature.js\n+ OpenLayers/Projection.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n-\n /**\n * @requires OpenLayers/BaseTypes/Class.js\n * @requires OpenLayers/Util.js\n */\n \n /**\n- * Class: OpenLayers.Feature\n- * Features are combinations of geography and attributes. The OpenLayers.Feature\n- * class specifically combines a marker and a lonlat.\n+ * Namespace: OpenLayers.Projection\n+ * Methods for coordinate transforms between coordinate systems. By default,\n+ * OpenLayers ships with the ability to transform coordinates between\n+ * geographic (EPSG:4326) and web or spherical mercator (EPSG:900913 et al.)\n+ * coordinate reference systems. See the method for details\n+ * on usage.\n+ *\n+ * Additional transforms may be added by using the \n+ * library. If the proj4js library is included, the method \n+ * will work between any two coordinate reference systems with proj4js \n+ * definitions.\n+ *\n+ * If the proj4js library is not included, or if you wish to allow transforms\n+ * between arbitrary coordinate reference systems, use the \n+ * method to register a custom transform method.\n */\n-OpenLayers.Feature = OpenLayers.Class({\n-\n- /** \n- * Property: layer \n- * {} \n- */\n- layer: null,\n-\n- /** \n- * Property: id \n- * {String} \n- */\n- id: null,\n-\n- /** \n- * Property: lonlat \n- * {} \n- */\n- lonlat: null,\n-\n- /** \n- * Property: data \n- * {Object} \n- */\n- data: null,\n+OpenLayers.Projection = OpenLayers.Class({\n \n- /** \n- * Property: marker \n- * {} \n+ /**\n+ * Property: proj\n+ * {Object} Proj4js.Proj instance.\n */\n- marker: null,\n+ proj: null,\n \n /**\n- * APIProperty: popupClass\n- * {} The class which will be used to instantiate\n- * a new Popup. Default is .\n+ * Property: projCode\n+ * {String}\n */\n- popupClass: null,\n+ projCode: null,\n \n- /** \n- * Property: popup \n- * {} \n+ /**\n+ * Property: titleRegEx\n+ * {RegExp} regular expression to strip the title from a proj4js definition\n */\n- popup: null,\n+ titleRegEx: /\\+title=[^\\+]*/,\n \n- /** \n- * Constructor: OpenLayers.Feature\n- * Constructor for features.\n+ /**\n+ * Constructor: OpenLayers.Projection\n+ * This class offers several methods for interacting with a wrapped \n+ * pro4js projection object. \n *\n * Parameters:\n- * layer - {} \n- * lonlat - {} \n- * data - {Object} \n- * \n+ * projCode - {String} A string identifying the Well Known Identifier for\n+ * the projection.\n+ * options - {Object} An optional object to set additional properties\n+ * on the projection.\n+ *\n * Returns:\n- * {}\n- */\n- initialize: function(layer, lonlat, data) {\n- this.layer = layer;\n- this.lonlat = lonlat;\n- this.data = (data != null) ? data : {};\n- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n- },\n-\n- /** \n- * Method: destroy\n- * nullify references to prevent circular references and memory leaks\n+ * {} A projection object.\n */\n- destroy: function() {\n-\n- //remove the popup from the map\n- if ((this.layer != null) && (this.layer.map != null)) {\n- if (this.popup != null) {\n- this.layer.map.removePopup(this.popup);\n- }\n- }\n- // remove the marker from the layer\n- if (this.layer != null && this.marker != null) {\n- this.layer.removeMarker(this.marker);\n- }\n-\n- this.layer = null;\n- this.id = null;\n- this.lonlat = null;\n- this.data = null;\n- if (this.marker != null) {\n- this.destroyMarker(this.marker);\n- this.marker = null;\n- }\n- if (this.popup != null) {\n- this.destroyPopup(this.popup);\n- this.popup = null;\n+ initialize: function(projCode, options) {\n+ OpenLayers.Util.extend(this, options);\n+ this.projCode = projCode;\n+ if (typeof Proj4js == \"object\") {\n+ this.proj = new Proj4js.Proj(projCode);\n }\n },\n \n /**\n- * Method: onScreen\n- * \n+ * APIMethod: getCode\n+ * Get the string SRS code.\n+ *\n * Returns:\n- * {Boolean} Whether or not the feature is currently visible on screen\n- * (based on its 'lonlat' property)\n+ * {String} The SRS code.\n */\n- onScreen: function() {\n-\n- var onScreen = false;\n- if ((this.layer != null) && (this.layer.map != null)) {\n- var screenBounds = this.layer.map.getExtent();\n- onScreen = screenBounds.containsLonLat(this.lonlat);\n- }\n- return onScreen;\n+ getCode: function() {\n+ return this.proj ? this.proj.srsCode : this.projCode;\n },\n \n-\n /**\n- * Method: createMarker\n- * Based on the data associated with the Feature, create and return a marker object.\n+ * APIMethod: getUnits\n+ * Get the units string for the projection -- returns null if \n+ * proj4js is not available.\n *\n- * Returns: \n- * {} A Marker Object created from the 'lonlat' and 'icon' properties\n- * set in this.data. If no 'lonlat' is set, returns null. If no\n- * 'icon' is set, OpenLayers.Marker() will load the default image.\n- * \n- * Note - this.marker is set to return value\n- * \n+ * Returns:\n+ * {String} The units abbreviation.\n */\n- createMarker: function() {\n-\n- if (this.lonlat != null) {\n- this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon);\n- }\n- return this.marker;\n+ getUnits: function() {\n+ return this.proj ? this.proj.units : null;\n },\n \n /**\n- * Method: destroyMarker\n- * Destroys marker.\n- * If user overrides the createMarker() function, s/he should be able\n- * to also specify an alternative function for destroying it\n+ * Method: toString\n+ * Convert projection to string (getCode wrapper).\n+ *\n+ * Returns:\n+ * {String} The projection code.\n */\n- destroyMarker: function() {\n- this.marker.destroy();\n+ toString: function() {\n+ return this.getCode();\n },\n \n /**\n- * Method: createPopup\n- * Creates a popup object created from the 'lonlat', 'popupSize',\n- * and 'popupContentHTML' properties set in this.data. It uses\n- * this.marker.icon as default anchor. \n- * \n- * If no 'lonlat' is set, returns null. \n- * If no this.marker has been created, no anchor is sent.\n+ * Method: equals\n+ * Test equality of two projection instances. Determines equality based\n+ * soley on the projection code.\n *\n- * Note - the returned popup object is 'owned' by the feature, so you\n- * cannot use the popup's destroy method to discard the popup.\n- * Instead, you must use the feature's destroyPopup\n- * \n- * Note - this.popup is set to return value\n- * \n- * Parameters: \n- * closeBox - {Boolean} create popup with closebox or not\n- * \n * Returns:\n- * {} Returns the created popup, which is also set\n- * as 'popup' property of this feature. Will be of whatever type\n- * specified by this feature's 'popupClass' property, but must be\n- * of type .\n- * \n+ * {Boolean} The two projections are equivalent.\n */\n- createPopup: function(closeBox) {\n-\n- if (this.lonlat != null) {\n- if (!this.popup) {\n- var anchor = (this.marker) ? this.marker.icon : null;\n- var popupClass = this.popupClass ?\n- this.popupClass : OpenLayers.Popup.Anchored;\n- this.popup = new popupClass(this.id + \"_popup\",\n- this.lonlat,\n- this.data.popupSize,\n- this.data.popupContentHTML,\n- anchor,\n- closeBox);\n+ equals: function(projection) {\n+ var p = projection,\n+ equals = false;\n+ if (p) {\n+ if (!(p instanceof OpenLayers.Projection)) {\n+ p = new OpenLayers.Projection(p);\n }\n- if (this.data.overflow != null) {\n- this.popup.contentDiv.style.overflow = this.data.overflow;\n+ if ((typeof Proj4js == \"object\") && this.proj.defData && p.proj.defData) {\n+ equals = this.proj.defData.replace(this.titleRegEx, \"\") ==\n+ p.proj.defData.replace(this.titleRegEx, \"\");\n+ } else if (p.getCode) {\n+ var source = this.getCode(),\n+ target = p.getCode();\n+ equals = source == target ||\n+ !!OpenLayers.Projection.transforms[source] &&\n+ OpenLayers.Projection.transforms[source][target] ===\n+ OpenLayers.Projection.nullTransform;\n }\n-\n- this.popup.feature = this;\n }\n- return this.popup;\n+ return equals;\n },\n \n-\n- /**\n- * Method: destroyPopup\n- * Destroys the popup created via createPopup.\n- *\n- * As with the marker, if user overrides the createPopup() function, s/he \n- * should also be able to override the destruction\n+ /* Method: destroy\n+ * Destroy projection object.\n */\n- destroyPopup: function() {\n- if (this.popup) {\n- this.popup.feature = null;\n- this.popup.destroy();\n- this.popup = null;\n- }\n+ destroy: function() {\n+ delete this.proj;\n+ delete this.projCode;\n },\n \n- CLASS_NAME: \"OpenLayers.Feature\"\n+ CLASS_NAME: \"OpenLayers.Projection\"\n });\n+\n+/**\n+ * Property: transforms\n+ * {Object} Transforms is an object, with from properties, each of which may\n+ * have a to property. This allows you to define projections without \n+ * requiring support for proj4js to be included.\n+ *\n+ * This object has keys which correspond to a 'source' projection object. The\n+ * keys should be strings, corresponding to the projection.getCode() value.\n+ * Each source projection object should have a set of destination projection\n+ * keys included in the object. \n+ * \n+ * Each value in the destination object should be a transformation function,\n+ * where the function is expected to be passed an object with a .x and a .y\n+ * property. The function should return the object, with the .x and .y\n+ * transformed according to the transformation function.\n+ *\n+ * Note - Properties on this object should not be set directly. To add a\n+ * transform method to this object, use the method. For an\n+ * example of usage, see the OpenLayers.Layer.SphericalMercator file.\n+ */\n+OpenLayers.Projection.transforms = {};\n+\n+/**\n+ * APIProperty: defaults\n+ * {Object} Defaults for the SRS codes known to OpenLayers (currently\n+ * EPSG:4326, CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, EPSG:900913, EPSG:3857,\n+ * EPSG:102113 and EPSG:102100). Keys are the SRS code, values are units,\n+ * maxExtent (the validity extent for the SRS) and yx (true if this SRS is\n+ * known to have a reverse axis order).\n+ */\n+OpenLayers.Projection.defaults = {\n+ \"EPSG:4326\": {\n+ units: \"degrees\",\n+ maxExtent: [-180, -90, 180, 90],\n+ yx: true\n+ },\n+ \"CRS:84\": {\n+ units: \"degrees\",\n+ maxExtent: [-180, -90, 180, 90]\n+ },\n+ \"EPSG:900913\": {\n+ units: \"m\",\n+ maxExtent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34]\n+ }\n+};\n+\n+/**\n+ * APIMethod: addTransform\n+ * Set a custom transform method between two projections. Use this method in\n+ * cases where the proj4js lib is not available or where custom projections\n+ * need to be handled.\n+ *\n+ * Parameters:\n+ * from - {String} The code for the source projection\n+ * to - {String} the code for the destination projection\n+ * method - {Function} A function that takes a point as an argument and\n+ * transforms that point from the source to the destination projection\n+ * in place. The original point should be modified.\n+ */\n+OpenLayers.Projection.addTransform = function(from, to, method) {\n+ if (method === OpenLayers.Projection.nullTransform) {\n+ var defaults = OpenLayers.Projection.defaults[from];\n+ if (defaults && !OpenLayers.Projection.defaults[to]) {\n+ OpenLayers.Projection.defaults[to] = defaults;\n+ }\n+ }\n+ if (!OpenLayers.Projection.transforms[from]) {\n+ OpenLayers.Projection.transforms[from] = {};\n+ }\n+ OpenLayers.Projection.transforms[from][to] = method;\n+};\n+\n+/**\n+ * APIMethod: transform\n+ * Transform a point coordinate from one projection to another. Note that\n+ * the input point is transformed in place.\n+ * \n+ * Parameters:\n+ * point - { | Object} An object with x and y\n+ * properties representing coordinates in those dimensions.\n+ * source - {OpenLayers.Projection} Source map coordinate system\n+ * dest - {OpenLayers.Projection} Destination map coordinate system\n+ *\n+ * Returns:\n+ * point - {object} A transformed coordinate. The original point is modified.\n+ */\n+OpenLayers.Projection.transform = function(point, source, dest) {\n+ if (source && dest) {\n+ if (!(source instanceof OpenLayers.Projection)) {\n+ source = new OpenLayers.Projection(source);\n+ }\n+ if (!(dest instanceof OpenLayers.Projection)) {\n+ dest = new OpenLayers.Projection(dest);\n+ }\n+ if (source.proj && dest.proj) {\n+ point = Proj4js.transform(source.proj, dest.proj, point);\n+ } else {\n+ var sourceCode = source.getCode();\n+ var destCode = dest.getCode();\n+ var transforms = OpenLayers.Projection.transforms;\n+ if (transforms[sourceCode] && transforms[sourceCode][destCode]) {\n+ transforms[sourceCode][destCode](point);\n+ }\n+ }\n+ }\n+ return point;\n+};\n+\n+/**\n+ * APIFunction: nullTransform\n+ * A null transformation - useful for defining projection aliases when\n+ * proj4js is not available:\n+ *\n+ * (code)\n+ * OpenLayers.Projection.addTransform(\"EPSG:3857\", \"EPSG:900913\",\n+ * OpenLayers.Projection.nullTransform);\n+ * OpenLayers.Projection.addTransform(\"EPSG:900913\", \"EPSG:3857\",\n+ * OpenLayers.Projection.nullTransform);\n+ * (end)\n+ */\n+OpenLayers.Projection.nullTransform = function(point) {\n+ return point;\n+};\n+\n+/**\n+ * Note: Transforms for web mercator <-> geographic\n+ * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113 and EPSG:102100.\n+ * OpenLayers originally started referring to EPSG:900913 as web mercator.\n+ * The EPSG has declared EPSG:3857 to be web mercator.\n+ * ArcGIS 10 recognizes the EPSG:3857, EPSG:102113, and EPSG:102100 as\n+ * 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.\n+ * For geographic, OpenLayers recognizes EPSG:4326, CRS:84 and\n+ * urn:ogc:def:crs:EPSG:6.6:4326. OpenLayers also knows about the reverse axis\n+ * order for EPSG:4326. \n+ */\n+(function() {\n+\n+ var pole = 20037508.34;\n+\n+ function inverseMercator(xy) {\n+ xy.x = 180 * xy.x / pole;\n+ xy.y = 180 / Math.PI * (2 * Math.atan(Math.exp((xy.y / pole) * Math.PI)) - Math.PI / 2);\n+ return xy;\n+ }\n+\n+ function forwardMercator(xy) {\n+ xy.x = xy.x * pole / 180;\n+ var y = Math.log(Math.tan((90 + xy.y) * Math.PI / 360)) / Math.PI * pole;\n+ xy.y = Math.max(-20037508.34, Math.min(y, 20037508.34));\n+ return xy;\n+ }\n+\n+ function map(base, codes) {\n+ var add = OpenLayers.Projection.addTransform;\n+ var same = OpenLayers.Projection.nullTransform;\n+ var i, len, code, other, j;\n+ for (i = 0, len = codes.length; i < len; ++i) {\n+ code = codes[i];\n+ add(base, code, forwardMercator);\n+ add(code, base, inverseMercator);\n+ for (j = i + 1; j < len; ++j) {\n+ other = codes[j];\n+ add(code, other, same);\n+ add(other, code, same);\n+ }\n+ }\n+ }\n+\n+ // list of equivalent codes for web mercator\n+ var mercator = [\"EPSG:900913\", \"EPSG:3857\", \"EPSG:102113\", \"EPSG:102100\"],\n+ geographic = [\"CRS:84\", \"urn:ogc:def:crs:EPSG:6.6:4326\", \"EPSG:4326\"],\n+ i;\n+ for (i = mercator.length - 1; i >= 0; --i) {\n+ map(mercator[i], geographic);\n+ }\n+ for (i = geographic.length - 1; i >= 0; --i) {\n+ map(geographic[i], mercator);\n+ }\n+\n+})();\n /* ======================================================================\n- OpenLayers/Feature/Vector.js\n+ OpenLayers/Map.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n-// TRASH THIS\n-OpenLayers.State = {\n- /** states */\n- UNKNOWN: 'Unknown',\n- INSERT: 'Insert',\n- UPDATE: 'Update',\n- DELETE: 'Delete'\n-};\n-\n /**\n- * @requires OpenLayers/Feature.js\n+ * @requires OpenLayers/BaseTypes/Class.js\n * @requires OpenLayers/Util.js\n+ * @requires OpenLayers/Util/vendorPrefix.js\n+ * @requires OpenLayers/Events.js\n+ * @requires OpenLayers/Tween.js\n+ * @requires OpenLayers/Projection.js\n */\n \n /**\n- * Class: OpenLayers.Feature.Vector\n- * Vector features use the OpenLayers.Geometry classes as geometry description.\n- * They have an 'attributes' property, which is the data object, and a 'style'\n- * property, the default values of which are defined in the \n- * objects.\n+ * Class: OpenLayers.Map\n+ * Instances of OpenLayers.Map are interactive maps embedded in a web page.\n+ * Create a new map with the constructor.\n * \n- * Inherits from:\n- * - \n+ * On their own maps do not provide much functionality. To extend a map\n+ * it's necessary to add controls () and \n+ * layers () to the map. \n */\n-OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, {\n+OpenLayers.Map = OpenLayers.Class({\n \n- /** \n- * Property: fid \n- * {String} \n+ /**\n+ * Constant: Z_INDEX_BASE\n+ * {Object} Base z-indexes for different classes of thing \n */\n- fid: null,\n+ Z_INDEX_BASE: {\n+ BaseLayer: 100,\n+ Overlay: 325,\n+ Feature: 725,\n+ Popup: 750,\n+ Control: 1000\n+ },\n \n- /** \n- * APIProperty: geometry \n- * {} \n+ /**\n+ * APIProperty: events\n+ * {}\n+ *\n+ * Register a listener for a particular event with the following syntax:\n+ * (code)\n+ * map.events.register(type, obj, listener);\n+ * (end)\n+ *\n+ * Listeners will be called with a reference to an event object. The\n+ * properties of this event depends on exactly what happened.\n+ *\n+ * All event objects have at least the following properties:\n+ * object - {Object} A reference to map.events.object.\n+ * element - {DOMElement} A reference to map.events.element.\n+ *\n+ * Browser events have the following additional properties:\n+ * xy - {} The pixel location of the event (relative\n+ * to the the map viewport).\n+ *\n+ * Supported map event types:\n+ * preaddlayer - triggered before a layer has been added. The event\n+ * object will include a *layer* property that references the layer \n+ * to be added. When a listener returns \"false\" the adding will be \n+ * aborted.\n+ * addlayer - triggered after a layer has been added. The event object\n+ * will include a *layer* property that references the added layer.\n+ * preremovelayer - triggered before a layer has been removed. The event\n+ * object will include a *layer* property that references the layer \n+ * to be removed. When a listener returns \"false\" the removal will be \n+ * aborted.\n+ * removelayer - triggered after a layer has been removed. The event\n+ * object will include a *layer* property that references the removed\n+ * layer.\n+ * changelayer - triggered after a layer name change, order change,\n+ * opacity change, params change, visibility change (actual visibility,\n+ * not the layer's visibility property) or attribution change (due to\n+ * extent change). Listeners will receive an event object with *layer*\n+ * and *property* properties. The *layer* property will be a reference\n+ * to the changed layer. The *property* property will be a key to the\n+ * changed property (name, order, opacity, params, visibility or\n+ * attribution).\n+ * movestart - triggered after the start of a drag, pan, or zoom. The event\n+ * object may include a *zoomChanged* property that tells whether the\n+ * zoom has changed.\n+ * move - triggered after each drag, pan, or zoom\n+ * moveend - triggered after a drag, pan, or zoom completes\n+ * zoomend - triggered after a zoom completes\n+ * mouseover - triggered after mouseover the map\n+ * mouseout - triggered after mouseout the map\n+ * mousemove - triggered after mousemove the map\n+ * changebaselayer - triggered after the base layer changes\n+ * updatesize - triggered after the method was executed\n */\n- geometry: null,\n \n- /** \n- * APIProperty: attributes \n- * {Object} This object holds arbitrary, serializable properties that\n- * describe the feature.\n+ /**\n+ * Property: id\n+ * {String} Unique identifier for the map\n */\n- attributes: null,\n+ id: null,\n \n /**\n- * Property: bounds\n- * {} The box bounding that feature's geometry, that\n- * property can be set by an object when\n- * deserializing the feature, so in most cases it represents an\n- * information set by the server. \n+ * Property: fractionalZoom\n+ * {Boolean} For a base layer that supports it, allow the map resolution\n+ * to be set to a value between one of the values in the resolutions\n+ * array. Default is false.\n+ *\n+ * When fractionalZoom is set to true, it is possible to zoom to\n+ * an arbitrary extent. This requires a base layer from a source\n+ * that supports requests for arbitrary extents (i.e. not cached\n+ * tiles on a regular lattice). This means that fractionalZoom\n+ * will not work with commercial layers (Google, Yahoo, VE), layers\n+ * using TileCache, or any other pre-cached data sources.\n+ *\n+ * If you are using fractionalZoom, then you should also use\n+ * instead of layer.resolutions[zoom] as the\n+ * former works for non-integer zoom levels.\n */\n- bounds: null,\n+ fractionalZoom: false,\n \n- /** \n- * Property: state \n- * {String} \n+ /**\n+ * APIProperty: events\n+ * {} An events object that handles all \n+ * events on the map\n */\n- state: null,\n+ events: null,\n \n- /** \n- * APIProperty: style \n- * {Object} \n+ /**\n+ * APIProperty: allOverlays\n+ * {Boolean} Allow the map to function with \"overlays\" only. Defaults to\n+ * false. If true, the lowest layer in the draw order will act as\n+ * the base layer. In addition, if set to true, all layers will\n+ * have isBaseLayer set to false when they are added to the map.\n+ *\n+ * Note:\n+ * If you set map.allOverlays to true, then you *cannot* use\n+ * map.setBaseLayer or layer.setIsBaseLayer. With allOverlays true,\n+ * the lowest layer in the draw layer is the base layer. So, to change\n+ * the base layer, use or to set the layer\n+ * index to 0.\n */\n- style: null,\n+ allOverlays: false,\n \n /**\n- * APIProperty: url\n- * {String} If this property is set it will be taken into account by\n- * {} when upadting or deleting the feature.\n+ * APIProperty: div\n+ * {DOMElement|String} The element that contains the map (or an id for\n+ * that element). If the constructor is called\n+ * with two arguments, this should be provided as the first argument.\n+ * Alternatively, the map constructor can be called with the options\n+ * object as the only argument. In this case (one argument), a\n+ * div property may or may not be provided. If the div property\n+ * is not provided, the map can be rendered to a container later\n+ * using the method.\n+ * \n+ * Note:\n+ * If you are calling after map construction, do not use\n+ * auto. Instead, divide your by your\n+ * maximum expected dimension.\n */\n- url: null,\n+ div: null,\n \n /**\n- * Property: renderIntent\n- * {String} rendering intent currently being used\n+ * Property: dragging\n+ * {Boolean} The map is currently being dragged.\n */\n- renderIntent: \"default\",\n+ dragging: false,\n \n /**\n- * APIProperty: modified\n- * {Object} An object with the originals of the geometry and attributes of\n- * the feature, if they were changed. Currently this property is only read\n- * by , and written by\n- * , which sets the geometry property.\n- * Applications can set the originals of modified attributes in the\n- * attributes property. Note that applications have to check if this\n- * object and the attributes property is already created before using it.\n- * After a change made with ModifyFeature, this object could look like\n- *\n- * (code)\n- * {\n- * geometry: >Object\n- * }\n- * (end)\n- *\n- * When an application has made changes to feature attributes, it could\n- * have set the attributes to something like this:\n- *\n- * (code)\n- * {\n- * attributes: {\n- * myAttribute: \"original\"\n- * }\n- * }\n- * (end)\n- *\n- * Note that only checks for truthy values in\n- * *modified.geometry* and the attribute names in *modified.attributes*,\n- * but it is recommended to set the original values (and not just true) as\n- * attribute value, so applications could use this information to undo\n- * changes.\n+ * Property: size\n+ * {} Size of the main div (this.div)\n */\n- modified: null,\n+ size: null,\n \n- /** \n- * Constructor: OpenLayers.Feature.Vector\n- * Create a vector feature. \n- * \n- * Parameters:\n- * geometry - {} The geometry that this feature\n- * represents.\n- * attributes - {Object} An optional object that will be mapped to the\n- * property. \n- * style - {Object} An optional style object.\n+ /**\n+ * Property: viewPortDiv\n+ * {HTMLDivElement} The element that represents the map viewport\n */\n- initialize: function(geometry, attributes, style) {\n- OpenLayers.Feature.prototype.initialize.apply(this,\n- [null, null, attributes]);\n- this.lonlat = null;\n- this.geometry = geometry ? geometry : null;\n- this.state = null;\n- this.attributes = {};\n- if (attributes) {\n- this.attributes = OpenLayers.Util.extend(this.attributes,\n- attributes);\n- }\n- this.style = style ? style : null;\n- },\n+ viewPortDiv: null,\n \n- /** \n- * Method: destroy\n- * nullify references to prevent circular references and memory leaks\n+ /**\n+ * Property: layerContainerOrigin\n+ * {} The lonlat at which the later container was\n+ * re-initialized (on-zoom)\n */\n- destroy: function() {\n- if (this.layer) {\n- this.layer.removeFeatures(this);\n- this.layer = null;\n- }\n+ layerContainerOrigin: null,\n \n- this.geometry = null;\n- this.modified = null;\n- OpenLayers.Feature.prototype.destroy.apply(this, arguments);\n- },\n+ /**\n+ * Property: layerContainerDiv\n+ * {HTMLDivElement} The element that contains the layers.\n+ */\n+ layerContainerDiv: null,\n \n /**\n- * Method: clone\n- * Create a clone of this vector feature. Does not set any non-standard\n- * properties.\n- *\n- * Returns:\n- * {} An exact clone of this vector feature.\n+ * APIProperty: layers\n+ * {Array()} Ordered list of layers in the map\n */\n- clone: function() {\n- return new OpenLayers.Feature.Vector(\n- this.geometry ? this.geometry.clone() : null,\n- this.attributes,\n- this.style);\n- },\n+ layers: null,\n \n /**\n- * Method: onScreen\n- * Determine whether the feature is within the map viewport. This method\n- * tests for an intersection between the geometry and the viewport\n- * bounds. If a more effecient but less precise geometry bounds\n- * intersection is desired, call the method with the boundsOnly\n- * parameter true.\n+ * APIProperty: controls\n+ * {Array()} List of controls associated with the map.\n *\n- * Parameters:\n- * boundsOnly - {Boolean} Only test whether a feature's bounds intersects\n- * the viewport bounds. Default is false. If false, the feature's\n- * geometry must intersect the viewport for onScreen to return true.\n- * \n- * Returns:\n- * {Boolean} The feature is currently visible on screen (optionally\n- * based on its bounds if boundsOnly is true).\n+ * If not provided in the map options at construction, the map will\n+ * by default be given the following controls if present in the build:\n+ * - or \n+ * - or \n+ * - \n+ * - \n */\n- onScreen: function(boundsOnly) {\n- var onScreen = false;\n- if (this.layer && this.layer.map) {\n- var screenBounds = this.layer.map.getExtent();\n- if (boundsOnly) {\n- var featureBounds = this.geometry.getBounds();\n- onScreen = screenBounds.intersectsBounds(featureBounds);\n- } else {\n- var screenPoly = screenBounds.toGeometry();\n- onScreen = screenPoly.intersects(this.geometry);\n- }\n- }\n- return onScreen;\n- },\n+ controls: null,\n \n /**\n- * Method: getVisibility\n- * Determine whether the feature is displayed or not. It may not displayed\n- * because:\n- * - its style display property is set to 'none',\n- * - it doesn't belong to any layer,\n- * - the styleMap creates a symbolizer with display property set to 'none'\n- * for it,\n- * - the layer which it belongs to is not visible.\n- * \n- * Returns:\n- * {Boolean} The feature is currently displayed.\n+ * Property: popups\n+ * {Array()} List of popups associated with the map\n */\n- getVisibility: function() {\n- return !(this.style && this.style.display == 'none' ||\n- !this.layer ||\n- this.layer && this.layer.styleMap &&\n- this.layer.styleMap.createSymbolizer(this, this.renderIntent).display == 'none' ||\n- this.layer && !this.layer.getVisibility());\n- },\n+ popups: null,\n \n /**\n- * Method: createMarker\n- * HACK - we need to decide if all vector features should be able to\n- * create markers\n- * \n- * Returns:\n- * {} For now just returns null\n+ * APIProperty: baseLayer\n+ * {} The currently selected base layer. This determines\n+ * min/max zoom level, projection, etc.\n */\n- createMarker: function() {\n- return null;\n- },\n+ baseLayer: null,\n \n /**\n- * Method: destroyMarker\n- * HACK - we need to decide if all vector features should be able to\n- * delete markers\n- * \n- * If user overrides the createMarker() function, s/he should be able\n- * to also specify an alternative function for destroying it\n+ * Property: center\n+ * {} The current center of the map\n */\n- destroyMarker: function() {\n- // pass\n- },\n+ center: null,\n \n /**\n- * Method: createPopup\n- * HACK - we need to decide if all vector features should be able to\n- * create popups\n- * \n- * Returns:\n- * {} For now just returns null\n+ * Property: resolution\n+ * {Float} The resolution of the map.\n */\n- createPopup: function() {\n- return null;\n- },\n+ resolution: null,\n \n /**\n- * Method: atPoint\n- * Determins whether the feature intersects with the specified location.\n- * \n- * Parameters: \n- * lonlat - {|Object} OpenLayers.LonLat or an\n- * object with a 'lon' and 'lat' properties.\n- * toleranceLon - {float} Optional tolerance in Geometric Coords\n- * toleranceLat - {float} Optional tolerance in Geographic Coords\n- * \n- * Returns:\n- * {Boolean} Whether or not the feature is at the specified location\n+ * Property: zoom\n+ * {Integer} The current zoom level of the map\n */\n- atPoint: function(lonlat, toleranceLon, toleranceLat) {\n- var atPoint = false;\n- if (this.geometry) {\n- atPoint = this.geometry.atPoint(lonlat, toleranceLon,\n- toleranceLat);\n- }\n- return atPoint;\n- },\n+ zoom: 0,\n \n /**\n- * Method: destroyPopup\n- * HACK - we need to decide if all vector features should be able to\n- * delete popups\n+ * Property: panRatio\n+ * {Float} The ratio of the current extent within\n+ * which panning will tween.\n */\n- destroyPopup: function() {\n- // pass\n- },\n+ panRatio: 1.5,\n \n /**\n- * Method: move\n- * Moves the feature and redraws it at its new location\n- *\n- * Parameters:\n- * location - { or } the\n- * location to which to move the feature.\n+ * APIProperty: options\n+ * {Object} The options object passed to the class constructor. Read-only.\n */\n- move: function(location) {\n+ options: null,\n \n- if (!this.layer || !this.geometry.move) {\n- //do nothing if no layer or immoveable geometry\n- return undefined;\n- }\n+ // Options\n \n- var pixel;\n- if (location.CLASS_NAME == \"OpenLayers.LonLat\") {\n- pixel = this.layer.getViewPortPxFromLonLat(location);\n- } else {\n- pixel = location;\n- }\n+ /**\n+ * APIProperty: tileSize\n+ * {} Set in the map options to override the default tile\n+ * size for this map.\n+ */\n+ tileSize: null,\n \n- var lastPixel = this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat());\n- var res = this.layer.map.getResolution();\n- this.geometry.move(res * (pixel.x - lastPixel.x),\n- res * (lastPixel.y - pixel.y));\n- this.layer.drawFeature(this);\n- return lastPixel;\n- },\n+ /**\n+ * APIProperty: projection\n+ * {String} Set in the map options to specify the default projection \n+ * for layers added to this map. When using a projection other than EPSG:4326\n+ * (CRS:84, Geographic) or EPSG:3857 (EPSG:900913, Web Mercator),\n+ * also set maxExtent, maxResolution or resolutions. Default is \"EPSG:4326\".\n+ * Note that the projection of the map is usually determined\n+ * by that of the current baseLayer (see and ).\n+ */\n+ projection: \"EPSG:4326\",\n \n /**\n- * Method: toState\n- * Sets the new state\n- *\n- * Parameters:\n- * state - {String} \n+ * APIProperty: units\n+ * {String} The map units. Possible values are 'degrees' (or 'dd'), 'm', \n+ * 'ft', 'km', 'mi', 'inches'. Normally taken from the projection.\n+ * Only required if both map and layers do not define a projection,\n+ * or if they define a projection which does not define units\n */\n- toState: function(state) {\n- if (state == OpenLayers.State.UPDATE) {\n- switch (this.state) {\n- case OpenLayers.State.UNKNOWN:\n- case OpenLayers.State.DELETE:\n- this.state = state;\n- break;\n- case OpenLayers.State.UPDATE:\n- case OpenLayers.State.INSERT:\n- break;\n- }\n- } else if (state == OpenLayers.State.INSERT) {\n- switch (this.state) {\n- case OpenLayers.State.UNKNOWN:\n- break;\n- default:\n- this.state = state;\n- break;\n- }\n- } else if (state == OpenLayers.State.DELETE) {\n- switch (this.state) {\n- case OpenLayers.State.INSERT:\n- // the feature should be destroyed\n- break;\n- case OpenLayers.State.DELETE:\n- break;\n- case OpenLayers.State.UNKNOWN:\n- case OpenLayers.State.UPDATE:\n- this.state = state;\n- break;\n- }\n- } else if (state == OpenLayers.State.UNKNOWN) {\n- this.state = state;\n- }\n- },\n+ units: null,\n \n- CLASS_NAME: \"OpenLayers.Feature.Vector\"\n-});\n+ /**\n+ * APIProperty: resolutions\n+ * {Array(Float)} A list of map resolutions (map units per pixel) in \n+ * descending order. If this is not set in the layer constructor, it \n+ * will be set based on other resolution related properties \n+ * (maxExtent, maxResolution, maxScale, etc.).\n+ */\n+ resolutions: null,\n \n+ /**\n+ * APIProperty: maxResolution\n+ * {Float} Required if you are not displaying the whole world on a tile\n+ * with the size specified in .\n+ */\n+ maxResolution: null,\n \n-/**\n- * Constant: OpenLayers.Feature.Vector.style\n- * OpenLayers features can have a number of style attributes. The 'default' \n- * style will typically be used if no other style is specified. These\n- * styles correspond for the most part, to the styling properties defined\n- * by the SVG standard. \n- * Information on fill properties: http://www.w3.org/TR/SVG/painting.html#FillProperties\n- * Information on stroke properties: http://www.w3.org/TR/SVG/painting.html#StrokeProperties\n- *\n- * Symbolizer properties:\n- * fill - {Boolean} Set to false if no fill is desired.\n- * fillColor - {String} Hex fill color. Default is \"#ee9900\".\n- * fillOpacity - {Number} Fill opacity (0-1). Default is 0.4 \n- * stroke - {Boolean} Set to false if no stroke is desired.\n- * strokeColor - {String} Hex stroke color. Default is \"#ee9900\".\n- * strokeOpacity - {Number} Stroke opacity (0-1). Default is 1.\n- * strokeWidth - {Number} Pixel stroke width. Default is 1.\n- * strokeLinecap - {String} Stroke cap type. Default is \"round\". [butt | round | square]\n- * strokeDashstyle - {String} Stroke dash style. Default is \"solid\". [dot | dash | dashdot | longdash | longdashdot | solid]\n- * graphic - {Boolean} Set to false if no graphic is desired.\n- * pointRadius - {Number} Pixel point radius. Default is 6.\n- * pointerEvents - {String} Default is \"visiblePainted\".\n- * cursor - {String} Default is \"\".\n- * externalGraphic - {String} Url to an external graphic that will be used for rendering points.\n- * graphicWidth - {Number} Pixel width for sizing an external graphic.\n- * graphicHeight - {Number} Pixel height for sizing an external graphic.\n- * graphicOpacity - {Number} Opacity (0-1) for an external graphic.\n- * graphicXOffset - {Number} Pixel offset along the positive x axis for displacing an external graphic.\n- * graphicYOffset - {Number} Pixel offset along the positive y axis for displacing an external graphic.\n- * 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).\n- * graphicZIndex - {Number} The integer z-index value to use in rendering.\n- * graphicName - {String} Named graphic to use when rendering points. Supported values include \"circle\" (default),\n- * \"square\", \"star\", \"x\", \"cross\", \"triangle\".\n- * graphicTitle - {String} Tooltip when hovering over a feature. *deprecated*, use title instead\n- * title - {String} Tooltip when hovering over a feature. Not supported by the canvas renderer.\n- * backgroundGraphic - {String} Url to a graphic to be used as the background under an externalGraphic.\n- * backgroundGraphicZIndex - {Number} The integer z-index value to use in rendering the background graphic.\n- * backgroundXOffset - {Number} The x offset (in pixels) for the background graphic.\n- * backgroundYOffset - {Number} The y offset (in pixels) for the background graphic.\n- * backgroundHeight - {Number} The height of the background graphic. If not provided, the graphicHeight will be used.\n- * backgroundWidth - {Number} The width of the background width. If not provided, the graphicWidth will be used.\n- * label - {String} The text for an optional label. For browsers that use the canvas renderer, this requires either\n- * fillText or mozDrawText to be available.\n- * labelAlign - {String} Label alignment. This specifies the insertion point relative to the text. It is a string\n- * composed of two characters. The first character is for the horizontal alignment, the second for the vertical\n- * alignment. Valid values for horizontal alignment: \"l\"=left, \"c\"=center, \"r\"=right. Valid values for vertical\n- * alignment: \"t\"=top, \"m\"=middle, \"b\"=bottom. Example values: \"lt\", \"cm\", \"rb\". Default is \"cm\".\n- * labelXOffset - {Number} Pixel offset along the positive x axis for displacing the label. Not supported by the canvas renderer.\n- * labelYOffset - {Number} Pixel offset along the positive y axis for displacing the label. Not supported by the canvas renderer.\n- * labelSelect - {Boolean} If set to true, labels will be selectable using SelectFeature or similar controls.\n- * Default is false.\n- * labelOutlineColor - {String} The color of the label outline. Default is 'white'. Only supported by the canvas & SVG renderers.\n- * labelOutlineWidth - {Number} The width of the label outline. Default is 3, set to 0 or null to disable. Only supported by the SVG renderers.\n- * labelOutlineOpacity - {Number} The opacity (0-1) of the label outline. Default is fontOpacity. Only supported by the canvas & SVG renderers.\n- * fontColor - {String} The font color for the label, to be provided like CSS.\n- * fontOpacity - {Number} Opacity (0-1) for the label\n- * fontFamily - {String} The font family for the label, to be provided like in CSS.\n- * fontSize - {String} The font size for the label, to be provided like in CSS.\n- * fontStyle - {String} The font style for the label, to be provided like in CSS.\n- * fontWeight - {String} The font weight for the label, to be provided like in CSS.\n- * display - {String} Symbolizers will have no effect if display is set to \"none\". All other values have no effect.\n- */\n-OpenLayers.Feature.Vector.style = {\n- 'default': {\n- fillColor: \"#ee9900\",\n- fillOpacity: 0.4,\n- hoverFillColor: \"white\",\n- hoverFillOpacity: 0.8,\n- strokeColor: \"#ee9900\",\n- strokeOpacity: 1,\n- strokeWidth: 1,\n- strokeLinecap: \"round\",\n- strokeDashstyle: \"solid\",\n- hoverStrokeColor: \"red\",\n- hoverStrokeOpacity: 1,\n- hoverStrokeWidth: 0.2,\n- pointRadius: 6,\n- hoverPointRadius: 1,\n- hoverPointUnit: \"%\",\n- pointerEvents: \"visiblePainted\",\n- cursor: \"inherit\",\n- fontColor: \"#000000\",\n- labelAlign: \"cm\",\n- labelOutlineColor: \"white\",\n- labelOutlineWidth: 3\n- },\n- 'select': {\n- fillColor: \"blue\",\n- fillOpacity: 0.4,\n- hoverFillColor: \"white\",\n- hoverFillOpacity: 0.8,\n- strokeColor: \"blue\",\n- strokeOpacity: 1,\n- strokeWidth: 2,\n- strokeLinecap: \"round\",\n- strokeDashstyle: \"solid\",\n- hoverStrokeColor: \"red\",\n- hoverStrokeOpacity: 1,\n- hoverStrokeWidth: 0.2,\n- pointRadius: 6,\n- hoverPointRadius: 1,\n- hoverPointUnit: \"%\",\n- pointerEvents: \"visiblePainted\",\n- cursor: \"pointer\",\n- fontColor: \"#000000\",\n- labelAlign: \"cm\",\n- labelOutlineColor: \"white\",\n- labelOutlineWidth: 3\n+ /**\n+ * APIProperty: minResolution\n+ * {Float}\n+ */\n+ minResolution: null,\n \n- },\n- 'temporary': {\n- fillColor: \"#66cccc\",\n- fillOpacity: 0.2,\n- hoverFillColor: \"white\",\n- hoverFillOpacity: 0.8,\n- strokeColor: \"#66cccc\",\n- strokeOpacity: 1,\n- strokeLinecap: \"round\",\n- strokeWidth: 2,\n- strokeDashstyle: \"solid\",\n- hoverStrokeColor: \"red\",\n- hoverStrokeOpacity: 1,\n- hoverStrokeWidth: 0.2,\n- pointRadius: 6,\n- hoverPointRadius: 1,\n- hoverPointUnit: \"%\",\n- pointerEvents: \"visiblePainted\",\n- cursor: \"inherit\",\n- fontColor: \"#000000\",\n- labelAlign: \"cm\",\n- labelOutlineColor: \"white\",\n- labelOutlineWidth: 3\n+ /**\n+ * APIProperty: maxScale\n+ * {Float}\n+ */\n+ maxScale: null,\n \n- },\n- 'delete': {\n- display: \"none\"\n- }\n-};\n-/* ======================================================================\n- OpenLayers/Style.js\n- ====================================================================== */\n+ /**\n+ * APIProperty: minScale\n+ * {Float}\n+ */\n+ minScale: null,\n \n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n+ /**\n+ * APIProperty: maxExtent\n+ * {|Array} If provided as an array, the array\n+ * should consist of four values (left, bottom, right, top).\n+ * The maximum extent for the map.\n+ * Default depends on projection; if this is one of those defined in OpenLayers.Projection.defaults\n+ * (EPSG:4326 or web mercator), maxExtent will be set to the value defined there;\n+ * else, defaults to null.\n+ * To restrict user panning and zooming of the map, use instead.\n+ * The value for will change calculations for tile URLs.\n+ */\n+ maxExtent: null,\n \n+ /**\n+ * APIProperty: minExtent\n+ * {|Array} If provided as an array, the array\n+ * should consist of four values (left, bottom, right, top).\n+ * The minimum extent for the map. Defaults to null.\n+ */\n+ minExtent: null,\n \n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Util.js\n- * @requires OpenLayers/Feature/Vector.js\n- */\n+ /**\n+ * APIProperty: restrictedExtent\n+ * {|Array} If provided as an array, the array\n+ * should consist of four values (left, bottom, right, top).\n+ * Limit map navigation to this extent where possible.\n+ * If a non-null restrictedExtent is set, panning will be restricted\n+ * to the given bounds. In addition, zooming to a resolution that\n+ * displays more than the restricted extent will center the map\n+ * on the restricted extent. If you wish to limit the zoom level\n+ * or resolution, use maxResolution.\n+ */\n+ restrictedExtent: null,\n \n-/**\n- * Class: OpenLayers.Style\n- * This class represents a UserStyle obtained\n- * from a SLD, containing styling rules.\n- */\n-OpenLayers.Style = OpenLayers.Class({\n+ /**\n+ * APIProperty: numZoomLevels\n+ * {Integer} Number of zoom levels for the map. Defaults to 16. Set a\n+ * different value in the map options if needed.\n+ */\n+ numZoomLevels: 16,\n \n /**\n- * Property: id\n- * {String} A unique id for this session.\n+ * APIProperty: theme\n+ * {String} Relative path to a CSS file from which to load theme styles.\n+ * Specify null in the map options (e.g. {theme: null}) if you \n+ * want to get cascading style declarations - by putting links to \n+ * stylesheets or style declarations directly in your page.\n */\n- id: null,\n+ theme: null,\n+\n+ /** \n+ * APIProperty: displayProjection\n+ * {} Requires proj4js support for projections other\n+ * than EPSG:4326 or EPSG:900913/EPSG:3857. Projection used by\n+ * several controls to display data to user. If this property is set,\n+ * it will be set on any control which has a null displayProjection\n+ * property at the time the control is added to the map. \n+ */\n+ displayProjection: null,\n \n /**\n- * APIProperty: name\n- * {String}\n+ * APIProperty: tileManager\n+ * {|Object} By default, and if the build contains\n+ * TileManager.js, the map will use the TileManager to queue image requests\n+ * and to cache tile image elements. To create a map without a TileManager\n+ * configure the map with tileManager: null. To create a TileManager with\n+ * non-default options, supply the options instead or alternatively supply\n+ * an instance of {}.\n */\n- name: null,\n \n /**\n- * Property: title\n- * {String} Title of this style (set if included in SLD)\n+ * APIProperty: fallThrough\n+ * {Boolean} Should OpenLayers allow events on the map to fall through to\n+ * other elements on the page, or should it swallow them? (#457)\n+ * Default is to swallow.\n */\n- title: null,\n+ fallThrough: false,\n \n /**\n- * Property: description\n- * {String} Description of this style (set if abstract is included in SLD)\n+ * APIProperty: autoUpdateSize\n+ * {Boolean} Should OpenLayers automatically update the size of the map\n+ * when the resize event is fired. Default is true.\n */\n- description: null,\n+ autoUpdateSize: true,\n \n /**\n- * APIProperty: layerName\n- * {} name of the layer that this style belongs to, usually\n- * according to the NamedLayer attribute of an SLD document.\n+ * APIProperty: eventListeners\n+ * {Object} If set as an option at construction, the eventListeners\n+ * object will be registered with . Object\n+ * structure must be a listeners object as shown in the example for\n+ * the events.on method.\n */\n- layerName: null,\n+ eventListeners: null,\n \n /**\n- * APIProperty: isDefault\n- * {Boolean}\n+ * Property: panTween\n+ * {} Animated panning tween object, see panTo()\n */\n- isDefault: false,\n+ panTween: null,\n \n- /** \n- * Property: rules \n- * {Array()}\n+ /**\n+ * APIProperty: panMethod\n+ * {Function} The Easing function to be used for tweening. Default is\n+ * OpenLayers.Easing.Expo.easeOut. Setting this to 'null' turns off\n+ * animated panning.\n */\n- rules: null,\n+ panMethod: OpenLayers.Easing.Expo.easeOut,\n \n /**\n- * APIProperty: context\n- * {Object} An optional object with properties that symbolizers' property\n- * values should be evaluated against. If no context is specified,\n- * feature.attributes will be used\n+ * Property: panDuration\n+ * {Integer} The number of steps to be passed to the\n+ * OpenLayers.Tween.start() method when the map is\n+ * panned.\n+ * Default is 50.\n */\n- context: null,\n+ panDuration: 50,\n \n /**\n- * Property: defaultStyle\n- * {Object} hash of style properties to use as default for merging\n- * rule-based style symbolizers onto. If no rules are defined,\n- * createSymbolizer will return this style. If is set to\n- * true, the defaultStyle will only be taken into account if there are\n- * rules defined.\n+ * Property: zoomTween\n+ * {} Animated zooming tween object, see zoomTo()\n */\n- defaultStyle: null,\n+ zoomTween: null,\n \n /**\n- * Property: defaultsPerSymbolizer\n- * {Boolean} If set to true, the will extend the symbolizer\n- * of every rule. Properties of the will also be used to set\n- * missing symbolizer properties if the symbolizer has stroke, fill or\n- * graphic set to true. Default is false.\n+ * APIProperty: zoomMethod\n+ * {Function} The Easing function to be used for tweening. Default is\n+ * OpenLayers.Easing.Quad.easeOut. Setting this to 'null' turns off\n+ * animated zooming.\n */\n- defaultsPerSymbolizer: false,\n+ zoomMethod: OpenLayers.Easing.Quad.easeOut,\n \n /**\n- * Property: propertyStyles\n- * {Hash of Boolean} cache of style properties that need to be parsed for\n- * propertyNames. Property names are keys, values won't be used.\n+ * Property: zoomDuration\n+ * {Integer} The number of steps to be passed to the\n+ * OpenLayers.Tween.start() method when the map is zoomed.\n+ * Default is 20.\n */\n- propertyStyles: null,\n+ zoomDuration: 20,\n \n+ /**\n+ * Property: paddingForPopups\n+ * {} Outside margin of the popup. Used to prevent \n+ * the popup from getting too close to the map border.\n+ */\n+ paddingForPopups: null,\n \n- /** \n- * Constructor: OpenLayers.Style\n- * Creates a UserStyle.\n+ /**\n+ * Property: layerContainerOriginPx\n+ * {Object} Cached object representing the layer container origin (in pixels).\n+ */\n+ layerContainerOriginPx: null,\n+\n+ /**\n+ * Property: minPx\n+ * {Object} An object with a 'x' and 'y' values that is the lower\n+ * left of maxExtent in viewport pixel space.\n+ * Used to verify in moveByPx that the new location we're moving to\n+ * is valid. It is also used in the getLonLatFromViewPortPx function\n+ * of Layer.\n+ */\n+ minPx: null,\n+\n+ /**\n+ * Property: maxPx\n+ * {Object} An object with a 'x' and 'y' values that is the top\n+ * right of maxExtent in viewport pixel space.\n+ * Used to verify in moveByPx that the new location we're moving to\n+ * is valid.\n+ */\n+ maxPx: null,\n+\n+ /**\n+ * Constructor: OpenLayers.Map\n+ * Constructor for a new OpenLayers.Map instance. There are two possible\n+ * ways to call the map constructor. See the examples below.\n *\n * Parameters:\n- * style - {Object} Optional hash of style properties that will be\n- * used as default style for this style object. This style\n- * applies if no rules are specified. Symbolizers defined in\n- * rules will extend this default style.\n- * options - {Object} An optional object with properties to set on the\n- * style.\n+ * div - {DOMElement|String} The element or id of an element in your page\n+ * that will contain the map. May be omitted if the
option is\n+ * provided or if you intend to call the method later.\n+ * options - {Object} Optional object with properties to tag onto the map.\n *\n- * Valid options:\n- * rules - {Array()} List of rules to be added to the\n- * style.\n+ * Valid options (in addition to the listed API properties):\n+ * center - {|Array} The default initial center of the map.\n+ * If provided as array, the first value is the x coordinate,\n+ * and the 2nd value is the y coordinate.\n+ * Only specify if is provided.\n+ * Note that if an ArgParser/Permalink control is present,\n+ * and the querystring contains coordinates, center will be set\n+ * by that, and this option will be ignored.\n+ * zoom - {Number} The initial zoom level for the map. Only specify if\n+ * is provided.\n+ * Note that if an ArgParser/Permalink control is present,\n+ * and the querystring contains a zoom level, zoom will be set\n+ * by that, and this option will be ignored.\n+ * extent - {|Array} The initial extent of the map.\n+ * If provided as an array, the array should consist of\n+ * four values (left, bottom, right, top).\n+ * Only specify if
and are not provided.\n * \n- * Returns:\n- * {}\n+ * Examples:\n+ * (code)\n+ * // create a map with default options in an element with the id \"map1\"\n+ * var map = new OpenLayers.Map(\"map1\");\n+ *\n+ * // create a map with non-default options in an element with id \"map2\"\n+ * var options = {\n+ * projection: \"EPSG:3857\",\n+ * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000),\n+ * center: new OpenLayers.LonLat(-12356463.476333, 5621521.4854095)\n+ * };\n+ * var map = new OpenLayers.Map(\"map2\", options);\n+ *\n+ * // map with non-default options - same as above but with a single argument,\n+ * // a restricted extent, and using arrays for bounds and center\n+ * var map = new OpenLayers.Map({\n+ * div: \"map_id\",\n+ * projection: \"EPSG:3857\",\n+ * maxExtent: [-18924313.432222, -15538711.094146, 18924313.432222, 15538711.094146],\n+ * restrictedExtent: [-13358338.893333, -9608371.5085962, 13358338.893333, 9608371.5085962],\n+ * center: [-12356463.476333, 5621521.4854095]\n+ * });\n+ *\n+ * // create a map without a reference to a container - call render later\n+ * var map = new OpenLayers.Map({\n+ * projection: \"EPSG:3857\",\n+ * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000)\n+ * });\n+ * (end)\n */\n- initialize: function(style, options) {\n+ initialize: function(div, options) {\n+\n+ // If only one argument is provided, check if it is an object.\n+ if (arguments.length === 1 && typeof div === \"object\") {\n+ options = div;\n+ div = options && options.div;\n+ }\n+\n+ // Simple-type defaults are set in class definition. \n+ // Now set complex-type defaults \n+ this.tileSize = new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,\n+ OpenLayers.Map.TILE_HEIGHT);\n+\n+ this.paddingForPopups = new OpenLayers.Bounds(15, 15, 15, 15);\n+\n+ this.theme = OpenLayers._getScriptLocation() +\n+ 'theme/default/style.css';\n \n+ // backup original options\n+ this.options = OpenLayers.Util.extend({}, options);\n+\n+ // now override default options \n OpenLayers.Util.extend(this, options);\n- this.rules = [];\n- if (options && options.rules) {\n- this.addRules(options.rules);\n+\n+ var projCode = this.projection instanceof OpenLayers.Projection ?\n+ this.projection.projCode : this.projection;\n+ OpenLayers.Util.applyDefaults(this, OpenLayers.Projection.defaults[projCode]);\n+\n+ // allow extents and center to be arrays\n+ if (this.maxExtent && !(this.maxExtent instanceof OpenLayers.Bounds)) {\n+ this.maxExtent = new OpenLayers.Bounds(this.maxExtent);\n+ }\n+ if (this.minExtent && !(this.minExtent instanceof OpenLayers.Bounds)) {\n+ this.minExtent = new OpenLayers.Bounds(this.minExtent);\n+ }\n+ if (this.restrictedExtent && !(this.restrictedExtent instanceof OpenLayers.Bounds)) {\n+ this.restrictedExtent = new OpenLayers.Bounds(this.restrictedExtent);\n+ }\n+ if (this.center && !(this.center instanceof OpenLayers.LonLat)) {\n+ this.center = new OpenLayers.LonLat(this.center);\n }\n \n- // use the default style from OpenLayers.Feature.Vector if no style\n- // was given in the constructor\n- this.setDefaultStyle(style ||\n- OpenLayers.Feature.Vector.style[\"default\"]);\n+ // initialize layers array\n+ this.layers = [];\n \n- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n- },\n+ this.id = OpenLayers.Util.createUniqueID(\"OpenLayers.Map_\");\n \n- /** \n- * APIMethod: destroy\n- * nullify references to prevent circular references and memory leaks\n- */\n- destroy: function() {\n- for (var i = 0, len = this.rules.length; i < len; i++) {\n- this.rules[i].destroy();\n- this.rules[i] = null;\n+ this.div = OpenLayers.Util.getElement(div);\n+ if (!this.div) {\n+ this.div = document.createElement(\"div\");\n+ this.div.style.height = \"1px\";\n+ this.div.style.width = \"1px\";\n }\n- this.rules = null;\n- this.defaultStyle = null;\n- },\n \n- /**\n- * Method: createSymbolizer\n- * creates a style by applying all feature-dependent rules to the base\n- * style.\n- * \n- * Parameters:\n- * feature - {} feature to evaluate rules for\n- * \n- * Returns:\n- * {Object} symbolizer hash\n- */\n- createSymbolizer: function(feature) {\n- var style = this.defaultsPerSymbolizer ? {} : this.createLiterals(\n- OpenLayers.Util.extend({}, this.defaultStyle), feature);\n+ OpenLayers.Element.addClass(this.div, 'olMap');\n \n- var rules = this.rules;\n+ // the viewPortDiv is the outermost div we modify\n+ var id = this.id + \"_OpenLayers_ViewPort\";\n+ this.viewPortDiv = OpenLayers.Util.createDiv(id, null, null, null,\n+ \"relative\", null,\n+ \"hidden\");\n+ this.viewPortDiv.style.width = \"100%\";\n+ this.viewPortDiv.style.height = \"100%\";\n+ this.viewPortDiv.className = \"olMapViewport\";\n+ this.div.appendChild(this.viewPortDiv);\n \n- var rule, context;\n- var elseRules = [];\n- var appliedRules = false;\n- for (var i = 0, len = rules.length; i < len; i++) {\n- rule = rules[i];\n- // does the rule apply?\n- var applies = rule.evaluate(feature);\n+ this.events = new OpenLayers.Events(\n+ this, this.viewPortDiv, null, this.fallThrough, {\n+ includeXY: true\n+ }\n+ );\n \n- if (applies) {\n- if (rule instanceof OpenLayers.Rule && rule.elseFilter) {\n- elseRules.push(rule);\n- } else {\n- appliedRules = true;\n- this.applySymbolizer(rule, style, feature);\n+ if (OpenLayers.TileManager && this.tileManager !== null) {\n+ if (!(this.tileManager instanceof OpenLayers.TileManager)) {\n+ this.tileManager = new OpenLayers.TileManager(this.tileManager);\n+ }\n+ this.tileManager.addMap(this);\n+ }\n+\n+ // the layerContainerDiv is the one that holds all the layers\n+ id = this.id + \"_OpenLayers_Container\";\n+ this.layerContainerDiv = OpenLayers.Util.createDiv(id);\n+ this.layerContainerDiv.style.zIndex = this.Z_INDEX_BASE['Popup'] - 1;\n+ this.layerContainerOriginPx = {\n+ x: 0,\n+ y: 0\n+ };\n+ this.applyTransform();\n+\n+ this.viewPortDiv.appendChild(this.layerContainerDiv);\n+\n+ this.updateSize();\n+ if (this.eventListeners instanceof Object) {\n+ this.events.on(this.eventListeners);\n+ }\n+\n+ if (this.autoUpdateSize === true) {\n+ // updateSize on catching the window's resize\n+ // Note that this is ok, as updateSize() does nothing if the \n+ // map's size has not actually changed.\n+ this.updateSizeDestroy = OpenLayers.Function.bind(this.updateSize,\n+ this);\n+ OpenLayers.Event.observe(window, 'resize',\n+ this.updateSizeDestroy);\n+ }\n+\n+ // only append link stylesheet if the theme property is set\n+ if (this.theme) {\n+ // check existing links for equivalent url\n+ var addNode = true;\n+ var nodes = document.getElementsByTagName('link');\n+ for (var i = 0, len = nodes.length; i < len; ++i) {\n+ if (OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,\n+ this.theme)) {\n+ addNode = false;\n+ break;\n }\n }\n+ // only add a new node if one with an equivalent url hasn't already\n+ // been added\n+ if (addNode) {\n+ var cssNode = document.createElement('link');\n+ cssNode.setAttribute('rel', 'stylesheet');\n+ cssNode.setAttribute('type', 'text/css');\n+ cssNode.setAttribute('href', this.theme);\n+ document.getElementsByTagName('head')[0].appendChild(cssNode);\n+ }\n }\n \n- // if no other rules apply, apply the rules with else filters\n- if (appliedRules == false && elseRules.length > 0) {\n- appliedRules = true;\n- for (var i = 0, len = elseRules.length; i < len; i++) {\n- this.applySymbolizer(elseRules[i], style, feature);\n+ if (this.controls == null) { // default controls\n+ this.controls = [];\n+ if (OpenLayers.Control != null) { // running full or lite?\n+ // Navigation or TouchNavigation depending on what is in build\n+ if (OpenLayers.Control.Navigation) {\n+ this.controls.push(new OpenLayers.Control.Navigation());\n+ } else if (OpenLayers.Control.TouchNavigation) {\n+ this.controls.push(new OpenLayers.Control.TouchNavigation());\n+ }\n+ if (OpenLayers.Control.Zoom) {\n+ this.controls.push(new OpenLayers.Control.Zoom());\n+ } else if (OpenLayers.Control.PanZoom) {\n+ this.controls.push(new OpenLayers.Control.PanZoom());\n+ }\n+\n+ if (OpenLayers.Control.ArgParser) {\n+ this.controls.push(new OpenLayers.Control.ArgParser());\n+ }\n+ if (OpenLayers.Control.Attribution) {\n+ this.controls.push(new OpenLayers.Control.Attribution());\n+ }\n }\n }\n \n- // don't display if there were rules but none applied\n- if (rules.length > 0 && appliedRules == false) {\n- style.display = \"none\";\n+ for (var i = 0, len = this.controls.length; i < len; i++) {\n+ this.addControlToMap(this.controls[i]);\n }\n \n- if (style.label != null && typeof style.label !== \"string\") {\n- style.label = String(style.label);\n+ this.popups = [];\n+\n+ this.unloadDestroy = OpenLayers.Function.bind(this.destroy, this);\n+\n+\n+ // always call map.destroy()\n+ OpenLayers.Event.observe(window, 'unload', this.unloadDestroy);\n+\n+ // add any initial layers\n+ if (options && options.layers) {\n+ /** \n+ * If you have set options.center, the map center property will be\n+ * set at this point. However, since setCenter has not been called,\n+ * addLayers gets confused. So we delete the map center in this \n+ * case. Because the check below uses options.center, it will\n+ * be properly set below.\n+ */\n+ delete this.center;\n+ delete this.zoom;\n+ this.addLayers(options.layers);\n+ // set center (and optionally zoom)\n+ if (options.center && !this.getCenter()) {\n+ // zoom can be undefined here\n+ this.setCenter(options.center, options.zoom);\n+ }\n }\n \n- return style;\n+ if (this.panMethod) {\n+ this.panTween = new OpenLayers.Tween(this.panMethod);\n+ }\n+ if (this.zoomMethod && this.applyTransform.transform) {\n+ this.zoomTween = new OpenLayers.Tween(this.zoomMethod);\n+ }\n },\n \n- /**\n- * Method: applySymbolizer\n- *\n- * Parameters:\n- * rule - {}\n- * style - {Object}\n- * feature - {}\n+ /** \n+ * APIMethod: getViewport\n+ * Get the DOMElement representing the view port.\n *\n * Returns:\n- * {Object} A style with new symbolizer applied.\n+ * {DOMElement}\n */\n- applySymbolizer: function(rule, style, feature) {\n- var symbolizerPrefix = feature.geometry ?\n- this.getSymbolizerPrefix(feature.geometry) :\n- OpenLayers.Style.SYMBOLIZER_PREFIXES[0];\n+ getViewport: function() {\n+ return this.viewPortDiv;\n+ },\n \n- var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer;\n+ /**\n+ * APIMethod: render\n+ * Render the map to a specified container.\n+ * \n+ * Parameters:\n+ * div - {String|DOMElement} The container that the map should be rendered\n+ * to. If different than the current container, the map viewport\n+ * will be moved from the current to the new container.\n+ */\n+ render: function(div) {\n+ this.div = OpenLayers.Util.getElement(div);\n+ OpenLayers.Element.addClass(this.div, 'olMap');\n+ this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);\n+ this.div.appendChild(this.viewPortDiv);\n+ this.updateSize();\n+ },\n \n- if (this.defaultsPerSymbolizer === true) {\n- var defaults = this.defaultStyle;\n- OpenLayers.Util.applyDefaults(symbolizer, {\n- pointRadius: defaults.pointRadius\n- });\n- if (symbolizer.stroke === true || symbolizer.graphic === true) {\n- OpenLayers.Util.applyDefaults(symbolizer, {\n- strokeWidth: defaults.strokeWidth,\n- strokeColor: defaults.strokeColor,\n- strokeOpacity: defaults.strokeOpacity,\n- strokeDashstyle: defaults.strokeDashstyle,\n- strokeLinecap: defaults.strokeLinecap\n- });\n- }\n- if (symbolizer.fill === true || symbolizer.graphic === true) {\n- OpenLayers.Util.applyDefaults(symbolizer, {\n- fillColor: defaults.fillColor,\n- fillOpacity: defaults.fillOpacity\n- });\n+ /**\n+ * Method: unloadDestroy\n+ * Function that is called to destroy the map on page unload. stored here\n+ * so that if map is manually destroyed, we can unregister this.\n+ */\n+ unloadDestroy: null,\n+\n+ /**\n+ * Method: updateSizeDestroy\n+ * When the map is destroyed, we need to stop listening to updateSize\n+ * events: this method stores the function we need to unregister in \n+ * non-IE browsers.\n+ */\n+ updateSizeDestroy: null,\n+\n+ /**\n+ * APIMethod: destroy\n+ * Destroy this map.\n+ * Note that if you are using an application which removes a container\n+ * of the map from the DOM, you need to ensure that you destroy the\n+ * map *before* this happens; otherwise, the page unload handler\n+ * will fail because the DOM elements that map.destroy() wants\n+ * to clean up will be gone. (See \n+ * http://trac.osgeo.org/openlayers/ticket/2277 for more information).\n+ * This will apply to GeoExt and also to other applications which\n+ * modify the DOM of the container of the OpenLayers Map.\n+ */\n+ destroy: function() {\n+ // if unloadDestroy is null, we've already been destroyed\n+ if (!this.unloadDestroy) {\n+ return false;\n+ }\n+\n+ // make sure panning doesn't continue after destruction\n+ if (this.panTween) {\n+ this.panTween.stop();\n+ this.panTween = null;\n+ }\n+ // make sure zooming doesn't continue after destruction\n+ if (this.zoomTween) {\n+ this.zoomTween.stop();\n+ this.zoomTween = null;\n+ }\n+\n+ // map has been destroyed. dont do it again!\n+ OpenLayers.Event.stopObserving(window, 'unload', this.unloadDestroy);\n+ this.unloadDestroy = null;\n+\n+ if (this.updateSizeDestroy) {\n+ OpenLayers.Event.stopObserving(window, 'resize',\n+ this.updateSizeDestroy);\n+ }\n+\n+ this.paddingForPopups = null;\n+\n+ if (this.controls != null) {\n+ for (var i = this.controls.length - 1; i >= 0; --i) {\n+ this.controls[i].destroy();\n }\n- if (symbolizer.graphic === true) {\n- OpenLayers.Util.applyDefaults(symbolizer, {\n- pointRadius: this.defaultStyle.pointRadius,\n- externalGraphic: this.defaultStyle.externalGraphic,\n- graphicName: this.defaultStyle.graphicName,\n- graphicOpacity: this.defaultStyle.graphicOpacity,\n- graphicWidth: this.defaultStyle.graphicWidth,\n- graphicHeight: this.defaultStyle.graphicHeight,\n- graphicXOffset: this.defaultStyle.graphicXOffset,\n- graphicYOffset: this.defaultStyle.graphicYOffset\n- });\n+ this.controls = null;\n+ }\n+ if (this.layers != null) {\n+ for (var i = this.layers.length - 1; i >= 0; --i) {\n+ //pass 'false' to destroy so that map wont try to set a new \n+ // baselayer after each baselayer is removed\n+ this.layers[i].destroy(false);\n }\n+ this.layers = null;\n+ }\n+ if (this.viewPortDiv && this.viewPortDiv.parentNode) {\n+ this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);\n }\n+ this.viewPortDiv = null;\n \n- // merge the style with the current style\n- return this.createLiterals(\n- OpenLayers.Util.extend(style, symbolizer), feature);\n+ if (this.tileManager) {\n+ this.tileManager.removeMap(this);\n+ this.tileManager = null;\n+ }\n+\n+ if (this.eventListeners) {\n+ this.events.un(this.eventListeners);\n+ this.eventListeners = null;\n+ }\n+ this.events.destroy();\n+ this.events = null;\n+\n+ this.options = null;\n },\n \n /**\n- * Method: createLiterals\n- * creates literals for all style properties that have an entry in\n- * .\n- * \n+ * APIMethod: setOptions\n+ * Change the map options\n+ *\n * Parameters:\n- * style - {Object} style to create literals for. Will be modified\n- * inline.\n- * feature - {Object}\n- * \n- * Returns:\n- * {Object} the modified style\n+ * options - {Object} Hashtable of options to tag to the map\n */\n- createLiterals: function(style, feature) {\n- var context = OpenLayers.Util.extend({}, feature.attributes || feature.data);\n- OpenLayers.Util.extend(context, this.context);\n-\n- for (var i in this.propertyStyles) {\n- style[i] = OpenLayers.Style.createLiteral(style[i], context, feature, i);\n- }\n- return style;\n+ setOptions: function(options) {\n+ var updatePxExtent = this.minPx &&\n+ options.restrictedExtent != this.restrictedExtent;\n+ OpenLayers.Util.extend(this, options);\n+ // force recalculation of minPx and maxPx\n+ updatePxExtent && this.moveTo(this.getCachedCenter(), this.zoom, {\n+ forceZoomChange: true\n+ });\n },\n \n /**\n- * Method: findPropertyStyles\n- * Looks into all rules for this style and the defaultStyle to collect\n- * all the style hash property names containing ${...} strings that have\n- * to be replaced using the createLiteral method before returning them.\n- * \n+ * APIMethod: getTileSize\n+ * Get the tile size for the map\n+ *\n * Returns:\n- * {Object} hash of property names that need createLiteral parsing. The\n- * name of the property is the key, and the value is true;\n+ * {}\n */\n- findPropertyStyles: function() {\n- var propertyStyles = {};\n-\n- // check the default style\n- var style = this.defaultStyle;\n- this.addPropertyStyles(propertyStyles, style);\n-\n- // walk through all rules to check for properties in their symbolizer\n- var rules = this.rules;\n- var symbolizer, value;\n- for (var i = 0, len = rules.length; i < len; i++) {\n- symbolizer = rules[i].symbolizer;\n- for (var key in symbolizer) {\n- value = symbolizer[key];\n- if (typeof value == \"object\") {\n- // symbolizer key is \"Point\", \"Line\" or \"Polygon\"\n- this.addPropertyStyles(propertyStyles, value);\n- } else {\n- // symbolizer is a hash of style properties\n- this.addPropertyStyles(propertyStyles, symbolizer);\n- break;\n- }\n- }\n- }\n- return propertyStyles;\n+ getTileSize: function() {\n+ return this.tileSize;\n },\n \n+\n /**\n- * Method: addPropertyStyles\n- * \n+ * APIMethod: getBy\n+ * Get a list of objects given a property and a match item.\n+ *\n * Parameters:\n- * propertyStyles - {Object} hash to add new property styles to. Will be\n- * modified inline\n- * symbolizer - {Object} search this symbolizer for property styles\n- * \n+ * array - {String} A property on the map whose value is an array.\n+ * property - {String} A property on each item of the given array.\n+ * match - {String | Object} A string to match. Can also be a regular\n+ * expression literal or object. In addition, it can be any object\n+ * with a method named test. For reqular expressions or other, if\n+ * match.test(map[array][i][property]) evaluates to true, the item will\n+ * be included in the array returned. If no items are found, an empty\n+ * array is returned.\n+ *\n * Returns:\n- * {Object} propertyStyles hash\n+ * {Array} An array of items where the given property matches the given\n+ * criteria.\n */\n- addPropertyStyles: function(propertyStyles, symbolizer) {\n- var property;\n- for (var key in symbolizer) {\n- property = symbolizer[key];\n- if (typeof property == \"string\" &&\n- property.match(/\\$\\{\\w+\\}/)) {\n- propertyStyles[key] = true;\n- }\n- }\n- return propertyStyles;\n+ getBy: function(array, property, match) {\n+ var test = (typeof match.test == \"function\");\n+ var found = OpenLayers.Array.filter(this[array], function(item) {\n+ return item[property] == match || (test && match.test(item[property]));\n+ });\n+ return found;\n },\n \n /**\n- * APIMethod: addRules\n- * Adds rules to this style.\n- * \n+ * APIMethod: getLayersBy\n+ * Get a list of layers with properties matching the given criteria.\n+ *\n * Parameters:\n- * rules - {Array()}\n+ * property - {String} A layer property to be matched.\n+ * match - {String | Object} A string to match. Can also be a regular\n+ * expression literal or object. In addition, it can be any object\n+ * with a method named test. For reqular expressions or other, if\n+ * match.test(layer[property]) evaluates to true, the layer will be\n+ * included in the array returned. If no layers are found, an empty\n+ * array is returned.\n+ *\n+ * Returns:\n+ * {Array()} A list of layers matching the given criteria.\n+ * An empty array is returned if no matches are found.\n */\n- addRules: function(rules) {\n- Array.prototype.push.apply(this.rules, rules);\n- this.propertyStyles = this.findPropertyStyles();\n+ getLayersBy: function(property, match) {\n+ return this.getBy(\"layers\", property, match);\n },\n \n /**\n- * APIMethod: setDefaultStyle\n- * Sets the default style for this style object.\n- * \n+ * APIMethod: getLayersByName\n+ * Get a list of layers with names matching the given name.\n+ *\n * Parameters:\n- * style - {Object} Hash of style properties\n+ * match - {String | Object} A layer name. The name can also be a regular\n+ * expression literal or object. In addition, it can be any object\n+ * with a method named test. For reqular expressions or other, if\n+ * name.test(layer.name) evaluates to true, the layer will be included\n+ * in the list of layers returned. If no layers are found, an empty\n+ * array is returned.\n+ *\n+ * Returns:\n+ * {Array()} A list of layers matching the given name.\n+ * An empty array is returned if no matches are found.\n */\n- setDefaultStyle: function(style) {\n- this.defaultStyle = style;\n- this.propertyStyles = this.findPropertyStyles();\n+ getLayersByName: function(match) {\n+ return this.getLayersBy(\"name\", match);\n },\n \n /**\n- * Method: getSymbolizerPrefix\n- * Returns the correct symbolizer prefix according to the\n- * geometry type of the passed geometry\n- * \n+ * APIMethod: getLayersByClass\n+ * Get a list of layers of a given class (CLASS_NAME).\n+ *\n * Parameters:\n- * geometry - {}\n- * \n+ * match - {String | Object} A layer class name. The match can also be a\n+ * regular expression literal or object. In addition, it can be any\n+ * object with a method named test. For reqular expressions or other,\n+ * if type.test(layer.CLASS_NAME) evaluates to true, the layer will\n+ * be included in the list of layers returned. If no layers are\n+ * found, an empty array is returned.\n+ *\n * Returns:\n- * {String} key of the according symbolizer\n+ * {Array()} A list of layers matching the given class.\n+ * An empty array is returned if no matches are found.\n */\n- getSymbolizerPrefix: function(geometry) {\n- var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES;\n- for (var i = 0, len = prefixes.length; i < len; i++) {\n- if (geometry.CLASS_NAME.indexOf(prefixes[i]) != -1) {\n- return prefixes[i];\n- }\n- }\n+ getLayersByClass: function(match) {\n+ return this.getLayersBy(\"CLASS_NAME\", match);\n },\n \n /**\n- * APIMethod: clone\n- * Clones this style.\n- * \n+ * APIMethod: getControlsBy\n+ * Get a list of controls with properties matching the given criteria.\n+ *\n+ * Parameters:\n+ * property - {String} A control property to be matched.\n+ * match - {String | Object} A string to match. Can also be a regular\n+ * expression literal or object. In addition, it can be any object\n+ * with a method named test. For reqular expressions or other, if\n+ * match.test(layer[property]) evaluates to true, the layer will be\n+ * included in the array returned. If no layers are found, an empty\n+ * array is returned.\n+ *\n * Returns:\n- * {} Clone of this style.\n+ * {Array()} A list of controls matching the given\n+ * criteria. An empty array is returned if no matches are found.\n */\n- clone: function() {\n- var options = OpenLayers.Util.extend({}, this);\n- // clone rules\n- if (this.rules) {\n- options.rules = [];\n- for (var i = 0, len = this.rules.length; i < len; ++i) {\n- options.rules.push(this.rules[i].clone());\n- }\n- }\n- // clone context\n- options.context = this.context && OpenLayers.Util.extend({}, this.context);\n- //clone default style\n- var defaultStyle = OpenLayers.Util.extend({}, this.defaultStyle);\n- return new OpenLayers.Style(defaultStyle, options);\n+ getControlsBy: function(property, match) {\n+ return this.getBy(\"controls\", property, match);\n },\n \n- CLASS_NAME: \"OpenLayers.Style\"\n-});\n-\n-\n-/**\n- * Function: createLiteral\n- * converts a style value holding a combination of PropertyName and Literal\n- * into a Literal, taking the property values from the passed features.\n- * \n- * Parameters:\n- * value - {String} value to parse. If this string contains a construct like\n- * \"foo ${bar}\", then \"foo \" will be taken as literal, and \"${bar}\"\n- * will be replaced by the value of the \"bar\" attribute of the passed\n- * feature.\n- * context - {Object} context to take attribute values from\n- * feature - {} optional feature to pass to\n- * for evaluating functions in the\n- * context.\n- * property - {String} optional, name of the property for which the literal is\n- * being created for evaluating functions in the context.\n- * \n- * Returns:\n- * {String} the parsed value. In the example of the value parameter above, the\n- * result would be \"foo valueOfBar\", assuming that the passed feature has an\n- * attribute named \"bar\" with the value \"valueOfBar\".\n- */\n-OpenLayers.Style.createLiteral = function(value, context, feature, property) {\n- if (typeof value == \"string\" && value.indexOf(\"${\") != -1) {\n- value = OpenLayers.String.format(value, context, [feature, property]);\n- value = (isNaN(value) || !value) ? value : parseFloat(value);\n- }\n- return value;\n-};\n-\n-/**\n- * Constant: OpenLayers.Style.SYMBOLIZER_PREFIXES\n- * {Array} prefixes of the sld symbolizers. These are the\n- * same as the main geometry types\n- */\n-OpenLayers.Style.SYMBOLIZER_PREFIXES = ['Point', 'Line', 'Polygon', 'Text',\n- 'Raster'\n-];\n-/* ======================================================================\n- OpenLayers/StyleMap.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Style.js\n- * @requires OpenLayers/Feature/Vector.js\n- */\n-\n-/**\n- * Class: OpenLayers.StyleMap\n- */\n-OpenLayers.StyleMap = OpenLayers.Class({\n-\n /**\n- * Property: styles\n- * {Object} Hash of {}, keyed by names of well known\n- * rendering intents (e.g. \"default\", \"temporary\", \"select\", \"delete\").\n+ * APIMethod: getControlsByClass\n+ * Get a list of controls of a given class (CLASS_NAME).\n+ *\n+ * Parameters:\n+ * match - {String | Object} A control class name. The match can also be a\n+ * regular expression literal or object. In addition, it can be any\n+ * object with a method named test. For reqular expressions or other,\n+ * if type.test(control.CLASS_NAME) evaluates to true, the control will\n+ * be included in the list of controls returned. If no controls are\n+ * found, an empty array is returned.\n+ *\n+ * Returns:\n+ * {Array()} A list of controls matching the given class.\n+ * An empty array is returned if no matches are found.\n */\n- styles: null,\n+ getControlsByClass: function(match) {\n+ return this.getControlsBy(\"CLASS_NAME\", match);\n+ },\n+\n+ /********************************************************/\n+ /* */\n+ /* Layer Functions */\n+ /* */\n+ /* The following functions deal with adding and */\n+ /* removing Layers to and from the Map */\n+ /* */\n+ /********************************************************/\n \n /**\n- * Property: extendDefault\n- * {Boolean} if true, every render intent will extend the symbolizers\n- * specified for the \"default\" intent at rendering time. Otherwise, every\n- * rendering intent will be treated as a completely independent style.\n+ * APIMethod: getLayer\n+ * Get a layer based on its id\n+ *\n+ * Parameters:\n+ * id - {String} A layer id\n+ *\n+ * Returns:\n+ * {} The Layer with the corresponding id from the map's \n+ * layer collection, or null if not found.\n */\n- extendDefault: true,\n+ getLayer: function(id) {\n+ var foundLayer = null;\n+ for (var i = 0, len = this.layers.length; i < len; i++) {\n+ var layer = this.layers[i];\n+ if (layer.id == id) {\n+ foundLayer = layer;\n+ break;\n+ }\n+ }\n+ return foundLayer;\n+ },\n \n /**\n- * Constructor: OpenLayers.StyleMap\n+ * Method: setLayerZIndex\n * \n * Parameters:\n- * style - {Object} Optional. Either a style hash, or a style object, or\n- * a hash of style objects (style hashes) keyed by rendering\n- * intent. If just one style hash or style object is passed,\n- * this will be used for all known render intents (default,\n- * select, temporary)\n- * options - {Object} optional hash of additional options for this\n- * instance\n+ * layer - {} \n+ * zIdx - {int} \n */\n- initialize: function(style, options) {\n- this.styles = {\n- \"default\": new OpenLayers.Style(\n- OpenLayers.Feature.Vector.style[\"default\"]),\n- \"select\": new OpenLayers.Style(\n- OpenLayers.Feature.Vector.style[\"select\"]),\n- \"temporary\": new OpenLayers.Style(\n- OpenLayers.Feature.Vector.style[\"temporary\"]),\n- \"delete\": new OpenLayers.Style(\n- OpenLayers.Feature.Vector.style[\"delete\"])\n- };\n-\n- // take whatever the user passed as style parameter and convert it\n- // into parts of stylemap.\n- if (style instanceof OpenLayers.Style) {\n- // user passed a style object\n- this.styles[\"default\"] = style;\n- this.styles[\"select\"] = style;\n- this.styles[\"temporary\"] = style;\n- this.styles[\"delete\"] = style;\n- } else if (typeof style == \"object\") {\n- for (var key in style) {\n- if (style[key] instanceof OpenLayers.Style) {\n- // user passed a hash of style objects\n- this.styles[key] = style[key];\n- } else if (typeof style[key] == \"object\") {\n- // user passsed a hash of style hashes\n- this.styles[key] = new OpenLayers.Style(style[key]);\n- } else {\n- // user passed a style hash (i.e. symbolizer)\n- this.styles[\"default\"] = new OpenLayers.Style(style);\n- this.styles[\"select\"] = new OpenLayers.Style(style);\n- this.styles[\"temporary\"] = new OpenLayers.Style(style);\n- this.styles[\"delete\"] = new OpenLayers.Style(style);\n- break;\n- }\n- }\n- }\n- OpenLayers.Util.extend(this, options);\n+ setLayerZIndex: function(layer, zIdx) {\n+ layer.setZIndex(\n+ this.Z_INDEX_BASE[layer.isBaseLayer ? 'BaseLayer' : 'Overlay'] +\n+ zIdx * 5);\n },\n \n /**\n- * Method: destroy\n+ * Method: resetLayersZIndex\n+ * Reset each layer's z-index based on layer's array index\n */\n- destroy: function() {\n- for (var key in this.styles) {\n- this.styles[key].destroy();\n+ resetLayersZIndex: function() {\n+ for (var i = 0, len = this.layers.length; i < len; i++) {\n+ var layer = this.layers[i];\n+ this.setLayerZIndex(layer, i);\n }\n- this.styles = null;\n },\n \n /**\n- * Method: createSymbolizer\n- * Creates the symbolizer for a feature for a render intent.\n- * \n+ * APIMethod: addLayer\n+ *\n * Parameters:\n- * feature - {} The feature to evaluate the rules\n- * of the intended style against.\n- * intent - {String} The intent determines the symbolizer that will be\n- * used to draw the feature. Well known intents are \"default\"\n- * (for just drawing the features), \"select\" (for selected\n- * features) and \"temporary\" (for drawing features).\n- * \n+ * layer - {} \n+ *\n * Returns:\n- * {Object} symbolizer hash\n+ * {Boolean} True if the layer has been added to the map.\n */\n- createSymbolizer: function(feature, intent) {\n- if (!feature) {\n- feature = new OpenLayers.Feature.Vector();\n+ addLayer: function(layer) {\n+ for (var i = 0, len = this.layers.length; i < len; i++) {\n+ if (this.layers[i] == layer) {\n+ return false;\n+ }\n }\n- if (!this.styles[intent]) {\n- intent = \"default\";\n+ if (this.events.triggerEvent(\"preaddlayer\", {\n+ layer: layer\n+ }) === false) {\n+ return false;\n }\n- feature.renderIntent = intent;\n- var defaultSymbolizer = {};\n- if (this.extendDefault && intent != \"default\") {\n- defaultSymbolizer = this.styles[\"default\"].createSymbolizer(feature);\n+ if (this.allOverlays) {\n+ layer.isBaseLayer = false;\n }\n- return OpenLayers.Util.extend(defaultSymbolizer,\n- this.styles[intent].createSymbolizer(feature));\n+\n+ layer.div.className = \"olLayerDiv\";\n+ layer.div.style.overflow = \"\";\n+ this.setLayerZIndex(layer, this.layers.length);\n+\n+ if (layer.isFixed) {\n+ this.viewPortDiv.appendChild(layer.div);\n+ } else {\n+ this.layerContainerDiv.appendChild(layer.div);\n+ }\n+ this.layers.push(layer);\n+ layer.setMap(this);\n+\n+ if (layer.isBaseLayer || (this.allOverlays && !this.baseLayer)) {\n+ if (this.baseLayer == null) {\n+ // set the first baselaye we add as the baselayer\n+ this.setBaseLayer(layer);\n+ } else {\n+ layer.setVisibility(false);\n+ }\n+ } else {\n+ layer.redraw();\n+ }\n+\n+ this.events.triggerEvent(\"addlayer\", {\n+ layer: layer\n+ });\n+ layer.events.triggerEvent(\"added\", {\n+ map: this,\n+ layer: layer\n+ });\n+ layer.afterAdd();\n+\n+ return true;\n },\n \n /**\n- * Method: addUniqueValueRules\n- * Convenience method to create comparison rules for unique values of a\n- * property. The rules will be added to the style object for a specified\n- * rendering intent. This method is a shortcut for creating something like\n- * the \"unique value legends\" familiar from well known desktop GIS systems\n- * \n+ * APIMethod: addLayers \n+ *\n * Parameters:\n- * renderIntent - {String} rendering intent to add the rules to\n- * property - {String} values of feature attributes to create the\n- * rules for\n- * symbolizers - {Object} Hash of symbolizers, keyed by the desired\n- * property values \n- * context - {Object} An optional object with properties that\n- * symbolizers' property values should be evaluated\n- * against. If no context is specified, feature.attributes\n- * will be used\n+ * layers - {Array()} \n */\n- addUniqueValueRules: function(renderIntent, property, symbolizers, context) {\n- var rules = [];\n- for (var value in symbolizers) {\n- rules.push(new OpenLayers.Rule({\n- symbolizer: symbolizers[value],\n- context: context,\n- filter: new OpenLayers.Filter.Comparison({\n- type: OpenLayers.Filter.Comparison.EQUAL_TO,\n- property: property,\n- value: value\n- })\n- }));\n+ addLayers: function(layers) {\n+ for (var i = 0, len = layers.length; i < len; i++) {\n+ this.addLayer(layers[i]);\n }\n- this.styles[renderIntent].addRules(rules);\n },\n \n- CLASS_NAME: \"OpenLayers.StyleMap\"\n-});\n-/* ======================================================================\n- OpenLayers/Icon.js\n- ====================================================================== */\n+ /** \n+ * APIMethod: removeLayer\n+ * Removes a layer from the map by removing its visual element (the \n+ * layer.div property), then removing it from the map's internal list \n+ * of layers, setting the layer's map property to null. \n+ * \n+ * a \"removelayer\" event is triggered.\n+ * \n+ * very worthy of mention is that simply removing a layer from a map\n+ * will not cause the removal of any popups which may have been created\n+ * by the layer. this is due to the fact that it was decided at some\n+ * point that popups would not belong to layers. thus there is no way \n+ * for us to know here to which layer the popup belongs.\n+ * \n+ * A simple solution to this is simply to call destroy() on the layer.\n+ * the default OpenLayers.Layer class's destroy() function\n+ * automatically takes care to remove itself from whatever map it has\n+ * been attached to. \n+ * \n+ * The correct solution is for the layer itself to register an \n+ * event-handler on \"removelayer\" and when it is called, if it \n+ * recognizes itself as the layer being removed, then it cycles through\n+ * its own personal list of popups, removing them from the map.\n+ * \n+ * Parameters:\n+ * layer - {} \n+ * setNewBaseLayer - {Boolean} Default is true\n+ */\n+ removeLayer: function(layer, setNewBaseLayer) {\n+ if (this.events.triggerEvent(\"preremovelayer\", {\n+ layer: layer\n+ }) === false) {\n+ return;\n+ }\n+ if (setNewBaseLayer == null) {\n+ setNewBaseLayer = true;\n+ }\n \n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n+ if (layer.isFixed) {\n+ this.viewPortDiv.removeChild(layer.div);\n+ } else {\n+ this.layerContainerDiv.removeChild(layer.div);\n+ }\n+ OpenLayers.Util.removeItem(this.layers, layer);\n+ layer.removeMap(this);\n+ layer.map = null;\n \n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- */\n+ // if we removed the base layer, need to set a new one\n+ if (this.baseLayer == layer) {\n+ this.baseLayer = null;\n+ if (setNewBaseLayer) {\n+ for (var i = 0, len = this.layers.length; i < len; i++) {\n+ var iLayer = this.layers[i];\n+ if (iLayer.isBaseLayer || this.allOverlays) {\n+ this.setBaseLayer(iLayer);\n+ break;\n+ }\n+ }\n+ }\n+ }\n \n-/**\n- * Class: OpenLayers.Icon\n- * \n- * The icon represents a graphical icon on the screen. Typically used in\n- * conjunction with a to represent markers on a screen.\n- *\n- * An icon has a url, size and position. It also contains an offset which \n- * allows the center point to be represented correctly. This can be\n- * provided either as a fixed offset or a function provided to calculate\n- * the desired offset. \n- * \n- */\n-OpenLayers.Icon = OpenLayers.Class({\n+ this.resetLayersZIndex();\n \n- /** \n- * Property: url \n- * {String} image url\n- */\n- url: null,\n+ this.events.triggerEvent(\"removelayer\", {\n+ layer: layer\n+ });\n+ layer.events.triggerEvent(\"removed\", {\n+ map: this,\n+ layer: layer\n+ });\n+ },\n \n- /** \n- * Property: size \n- * {|Object} An OpenLayers.Size or\n- * an object with a 'w' and 'h' properties.\n+ /**\n+ * APIMethod: getNumLayers\n+ * \n+ * Returns:\n+ * {Int} The number of layers attached to the map.\n */\n- size: null,\n+ getNumLayers: function() {\n+ return this.layers.length;\n+ },\n \n /** \n- * Property: offset \n- * {|Object} distance in pixels to offset the\n- * image when being rendered. An OpenLayers.Pixel or an object\n- * with a 'x' and 'y' properties.\n+ * APIMethod: getLayerIndex\n+ *\n+ * Parameters:\n+ * layer - {}\n+ *\n+ * Returns:\n+ * {Integer} The current (zero-based) index of the given layer in the map's\n+ * layer stack. Returns -1 if the layer isn't on the map.\n */\n- offset: null,\n+ getLayerIndex: function(layer) {\n+ return OpenLayers.Util.indexOf(this.layers, layer);\n+ },\n \n /** \n- * Property: calculateOffset \n- * {Function} Function to calculate the offset (based on the size)\n+ * APIMethod: setLayerIndex\n+ * Move the given layer to the specified (zero-based) index in the layer\n+ * list, changing its z-index in the map display. Use\n+ * map.getLayerIndex() to find out the current index of a layer. Note\n+ * that this cannot (or at least should not) be effectively used to\n+ * raise base layers above overlays.\n+ *\n+ * Parameters:\n+ * layer - {} \n+ * idx - {int} \n */\n- calculateOffset: null,\n+ setLayerIndex: function(layer, idx) {\n+ var base = this.getLayerIndex(layer);\n+ if (idx < 0) {\n+ idx = 0;\n+ } else if (idx > this.layers.length) {\n+ idx = this.layers.length;\n+ }\n+ if (base != idx) {\n+ this.layers.splice(base, 1);\n+ this.layers.splice(idx, 0, layer);\n+ for (var i = 0, len = this.layers.length; i < len; i++) {\n+ this.setLayerZIndex(this.layers[i], i);\n+ }\n+ this.events.triggerEvent(\"changelayer\", {\n+ layer: layer,\n+ property: \"order\"\n+ });\n+ if (this.allOverlays) {\n+ if (idx === 0) {\n+ this.setBaseLayer(layer);\n+ } else if (this.baseLayer !== this.layers[0]) {\n+ this.setBaseLayer(this.layers[0]);\n+ }\n+ }\n+ }\n+ },\n \n /** \n- * Property: imageDiv \n- * {DOMElement} \n+ * APIMethod: raiseLayer\n+ * Change the index of the given layer by delta. If delta is positive, \n+ * the layer is moved up the map's layer stack; if delta is negative,\n+ * the layer is moved down. Again, note that this cannot (or at least\n+ * should not) be effectively used to raise base layers above overlays.\n+ *\n+ * Paremeters:\n+ * layer - {} \n+ * delta - {int} \n */\n- imageDiv: null,\n+ raiseLayer: function(layer, delta) {\n+ var idx = this.getLayerIndex(layer) + delta;\n+ this.setLayerIndex(layer, idx);\n+ },\n \n /** \n- * Property: px \n- * {|Object} An OpenLayers.Pixel or an object\n- * with a 'x' and 'y' properties.\n+ * APIMethod: setBaseLayer\n+ * Allows user to specify one of the currently-loaded layers as the Map's\n+ * new base layer.\n+ * \n+ * Parameters:\n+ * newBaseLayer - {}\n */\n- px: null,\n+ setBaseLayer: function(newBaseLayer) {\n \n- /** \n- * Constructor: OpenLayers.Icon\n- * Creates an icon, which is an image tag in a div. \n- *\n- * url - {String} \n- * size - {|Object} An OpenLayers.Size or an\n- * object with a 'w' and 'h'\n- * properties.\n- * offset - {|Object} An OpenLayers.Pixel or an\n- * object with a 'x' and 'y'\n- * properties.\n- * calculateOffset - {Function} \n- */\n- initialize: function(url, size, offset, calculateOffset) {\n- this.url = url;\n- this.size = size || {\n- w: 20,\n- h: 20\n- };\n- this.offset = offset || {\n- x: -(this.size.w / 2),\n- y: -(this.size.h / 2)\n- };\n- this.calculateOffset = calculateOffset;\n+ if (newBaseLayer != this.baseLayer) {\n \n- var id = OpenLayers.Util.createUniqueID(\"OL_Icon_\");\n- this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);\n- },\n+ // ensure newBaseLayer is already loaded\n+ if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) {\n \n- /** \n- * Method: destroy\n- * Nullify references and remove event listeners to prevent circular \n- * references and memory leaks\n- */\n- destroy: function() {\n- // erase any drawn elements\n- this.erase();\n+ // preserve center and scale when changing base layers\n+ var center = this.getCachedCenter();\n+ var newResolution = OpenLayers.Util.getResolutionFromScale(\n+ this.getScale(), newBaseLayer.units\n+ );\n \n- OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);\n- this.imageDiv.innerHTML = \"\";\n- this.imageDiv = null;\n+ // make the old base layer invisible \n+ if (this.baseLayer != null && !this.allOverlays) {\n+ this.baseLayer.setVisibility(false);\n+ }\n+\n+ // set new baselayer\n+ this.baseLayer = newBaseLayer;\n+\n+ if (!this.allOverlays || this.baseLayer.visibility) {\n+ this.baseLayer.setVisibility(true);\n+ // Layer may previously have been visible but not in range.\n+ // In this case we need to redraw it to make it visible.\n+ if (this.baseLayer.inRange === false) {\n+ this.baseLayer.redraw();\n+ }\n+ }\n+\n+ // recenter the map\n+ if (center != null) {\n+ // new zoom level derived from old scale\n+ var newZoom = this.getZoomForResolution(\n+ newResolution || this.resolution, true\n+ );\n+ // zoom and force zoom change\n+ this.setCenter(center, newZoom, false, true);\n+ }\n+\n+ this.events.triggerEvent(\"changebaselayer\", {\n+ layer: this.baseLayer\n+ });\n+ }\n+ }\n },\n \n- /** \n- * Method: clone\n+\n+ /********************************************************/\n+ /* */\n+ /* Control Functions */\n+ /* */\n+ /* The following functions deal with adding and */\n+ /* removing Controls to and from the Map */\n+ /* */\n+ /********************************************************/\n+\n+ /**\n+ * APIMethod: addControl\n+ * Add the passed over control to the map. Optionally \n+ * position the control at the given pixel.\n * \n- * Returns:\n- * {} A fresh copy of the icon.\n+ * Parameters:\n+ * control - {}\n+ * px - {}\n */\n- clone: function() {\n- return new OpenLayers.Icon(this.url,\n- this.size,\n- this.offset,\n- this.calculateOffset);\n+ addControl: function(control, px) {\n+ this.controls.push(control);\n+ this.addControlToMap(control, px);\n },\n \n /**\n- * Method: setSize\n- * \n+ * APIMethod: addControls\n+ * Add all of the passed over controls to the map. \n+ * You can pass over an optional second array\n+ * with pixel-objects to position the controls.\n+ * The indices of the two arrays should match and\n+ * you can add null as pixel for those controls \n+ * you want to be autopositioned. \n+ * \n * Parameters:\n- * size - {|Object} An OpenLayers.Size or\n- * an object with a 'w' and 'h' properties.\n+ * controls - {Array()}\n+ * pixels - {Array()}\n */\n- setSize: function(size) {\n- if (size != null) {\n- this.size = size;\n+ addControls: function(controls, pixels) {\n+ var pxs = (arguments.length === 1) ? [] : pixels;\n+ for (var i = 0, len = controls.length; i < len; i++) {\n+ var ctrl = controls[i];\n+ var px = (pxs[i]) ? pxs[i] : null;\n+ this.addControl(ctrl, px);\n }\n- this.draw();\n },\n \n /**\n- * Method: setUrl\n+ * Method: addControlToMap\n * \n * Parameters:\n- * url - {String} \n+ * \n+ * control - {}\n+ * px - {}\n */\n- setUrl: function(url) {\n- if (url != null) {\n- this.url = url;\n+ addControlToMap: function(control, px) {\n+ // If a control doesn't have a div at this point, it belongs in the\n+ // viewport.\n+ control.outsideViewport = (control.div != null);\n+\n+ // If the map has a displayProjection, and the control doesn't, set \n+ // the display projection.\n+ if (this.displayProjection && !control.displayProjection) {\n+ control.displayProjection = this.displayProjection;\n+ }\n+\n+ control.setMap(this);\n+ var div = control.draw(px);\n+ if (div) {\n+ if (!control.outsideViewport) {\n+ div.style.zIndex = this.Z_INDEX_BASE['Control'] +\n+ this.controls.length;\n+ this.viewPortDiv.appendChild(div);\n+ }\n+ }\n+ if (control.autoActivate) {\n+ control.activate();\n }\n- this.draw();\n },\n \n- /** \n- * Method: draw\n- * Move the div to the given pixel.\n+ /**\n+ * APIMethod: getControl\n * \n * Parameters:\n- * px - {|Object} An OpenLayers.Pixel or an\n- * object with a 'x' and 'y' properties.\n+ * id - {String} ID of the control to return.\n * \n * Returns:\n- * {DOMElement} A new DOM Image of this icon set at the location passed-in\n+ * {} The control from the map's list of controls \n+ * which has a matching 'id'. If none found, \n+ * returns null.\n */\n- draw: function(px) {\n- OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,\n- null,\n- null,\n- this.size,\n- this.url,\n- \"absolute\");\n- this.moveTo(px);\n- return this.imageDiv;\n+ getControl: function(id) {\n+ var returnControl = null;\n+ for (var i = 0, len = this.controls.length; i < len; i++) {\n+ var control = this.controls[i];\n+ if (control.id == id) {\n+ returnControl = control;\n+ break;\n+ }\n+ }\n+ return returnControl;\n },\n \n /** \n- * Method: erase\n- * Erase the underlying image element.\n+ * APIMethod: removeControl\n+ * Remove a control from the map. Removes the control both from the map \n+ * object's internal array of controls, as well as from the map's \n+ * viewPort (assuming the control was not added outsideViewport)\n+ * \n+ * Parameters:\n+ * control - {} The control to remove.\n */\n- erase: function() {\n- if (this.imageDiv != null && this.imageDiv.parentNode != null) {\n- OpenLayers.Element.remove(this.imageDiv);\n+ removeControl: function(control) {\n+ //make sure control is non-null and actually part of our map\n+ if ((control) && (control == this.getControl(control.id))) {\n+ if (control.div && (control.div.parentNode == this.viewPortDiv)) {\n+ this.viewPortDiv.removeChild(control.div);\n+ }\n+ OpenLayers.Util.removeItem(this.controls, control);\n }\n },\n \n+ /********************************************************/\n+ /* */\n+ /* Popup Functions */\n+ /* */\n+ /* The following functions deal with adding and */\n+ /* removing Popups to and from the Map */\n+ /* */\n+ /********************************************************/\n+\n /** \n- * Method: setOpacity\n- * Change the icon's opacity\n- *\n+ * APIMethod: addPopup\n+ * \n * Parameters:\n- * opacity - {float} \n+ * popup - {}\n+ * exclusive - {Boolean} If true, closes all other popups first\n */\n- setOpacity: function(opacity) {\n- OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null,\n- null, null, null, null, opacity);\n-\n- },\n+ addPopup: function(popup, exclusive) {\n \n- /**\n- * Method: moveTo\n- * move icon to passed in px.\n- *\n- * Parameters:\n- * px - {|Object} the pixel position to move to.\n- * An OpenLayers.Pixel or an object with a 'x' and 'y' properties.\n- */\n- moveTo: function(px) {\n- //if no px passed in, use stored location\n- if (px != null) {\n- this.px = px;\n+ if (exclusive) {\n+ //remove all other popups from screen\n+ for (var i = this.popups.length - 1; i >= 0; --i) {\n+ this.removePopup(this.popups[i]);\n+ }\n }\n \n- if (this.imageDiv != null) {\n- if (this.px == null) {\n- this.display(false);\n- } else {\n- if (this.calculateOffset) {\n- this.offset = this.calculateOffset(this.size);\n- }\n- OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, {\n- x: this.px.x + this.offset.x,\n- y: this.px.y + this.offset.y\n- });\n- }\n+ popup.map = this;\n+ this.popups.push(popup);\n+ var popupDiv = popup.draw();\n+ if (popupDiv) {\n+ popupDiv.style.zIndex = this.Z_INDEX_BASE['Popup'] +\n+ this.popups.length;\n+ this.layerContainerDiv.appendChild(popupDiv);\n }\n },\n \n /** \n- * Method: display\n- * Hide or show the icon\n- *\n+ * APIMethod: removePopup\n+ * \n * Parameters:\n- * display - {Boolean} \n+ * popup - {}\n */\n- display: function(display) {\n- this.imageDiv.style.display = (display) ? \"\" : \"none\";\n+ removePopup: function(popup) {\n+ OpenLayers.Util.removeItem(this.popups, popup);\n+ if (popup.div) {\n+ try {\n+ this.layerContainerDiv.removeChild(popup.div);\n+ } catch (e) {} // Popups sometimes apparently get disconnected\n+ // from the layerContainerDiv, and cause complaints.\n+ }\n+ popup.map = null;\n },\n \n+ /********************************************************/\n+ /* */\n+ /* Container Div Functions */\n+ /* */\n+ /* The following functions deal with the access to */\n+ /* and maintenance of the size of the container div */\n+ /* */\n+ /********************************************************/\n \n /**\n- * APIMethod: isDrawn\n+ * APIMethod: getSize\n * \n * Returns:\n- * {Boolean} Whether or not the icon is drawn.\n+ * {} An object that represents the \n+ * size, in pixels, of the div into which OpenLayers \n+ * has been loaded. \n+ * Note - A clone() of this locally cached variable is\n+ * returned, so as not to allow users to modify it.\n */\n- isDrawn: function() {\n- // nodeType 11 for ie, whose nodes *always* have a parentNode\n- // (of type document fragment)\n- var isDrawn = (this.imageDiv && this.imageDiv.parentNode &&\n- (this.imageDiv.parentNode.nodeType != 11));\n-\n- return isDrawn;\n+ getSize: function() {\n+ var size = null;\n+ if (this.size != null) {\n+ size = this.size.clone();\n+ }\n+ return size;\n },\n \n- CLASS_NAME: \"OpenLayers.Icon\"\n-});\n-/* ======================================================================\n- OpenLayers/Marker.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Events.js\n- * @requires OpenLayers/Icon.js\n- */\n-\n-/**\n- * Class: OpenLayers.Marker\n- * Instances of OpenLayers.Marker are a combination of a \n- * and an . \n- *\n- * Markers are generally added to a special layer called\n- * .\n- *\n- * Example:\n- * (code)\n- * var markers = new OpenLayers.Layer.Markers( \"Markers\" );\n- * map.addLayer(markers);\n- *\n- * var size = new OpenLayers.Size(21,25);\n- * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);\n- * var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset);\n- * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon));\n- * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone()));\n- *\n- * (end)\n- *\n- * Note that if you pass an icon into the Marker constructor, it will take\n- * that icon and use it. This means that you should not share icons between\n- * markers -- you use them once, but you should clone() for any additional\n- * markers using that same icon.\n- */\n-OpenLayers.Marker = OpenLayers.Class({\n-\n- /** \n- * Property: icon \n- * {} The icon used by this marker.\n+ /**\n+ * APIMethod: updateSize\n+ * This function should be called by any external code which dynamically\n+ * changes the size of the map div (because mozilla wont let us catch \n+ * the \"onresize\" for an element)\n */\n- icon: null,\n+ updateSize: function() {\n+ // the div might have moved on the page, also\n+ var newSize = this.getCurrentSize();\n+ if (newSize && !isNaN(newSize.h) && !isNaN(newSize.w)) {\n+ this.events.clearMouseCache();\n+ var oldSize = this.getSize();\n+ if (oldSize == null) {\n+ this.size = oldSize = newSize;\n+ }\n+ if (!newSize.equals(oldSize)) {\n \n- /** \n- * Property: lonlat \n- * {} location of object\n- */\n- lonlat: null,\n+ // store the new size\n+ this.size = newSize;\n \n- /** \n- * Property: events \n- * {} the event handler.\n- */\n- events: null,\n+ //notify layers of mapresize\n+ for (var i = 0, len = this.layers.length; i < len; i++) {\n+ this.layers[i].onMapResize();\n+ }\n \n- /** \n- * Property: map \n- * {} the map this marker is attached to\n- */\n- map: null,\n+ var center = this.getCachedCenter();\n \n- /** \n- * Constructor: OpenLayers.Marker\n- *\n- * Parameters:\n- * lonlat - {} the position of this marker\n- * icon - {} the icon for this marker\n- */\n- initialize: function(lonlat, icon) {\n- this.lonlat = lonlat;\n+ if (this.baseLayer != null && center != null) {\n+ var zoom = this.getZoom();\n+ this.zoom = null;\n+ this.setCenter(center, zoom);\n+ }\n \n- var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon();\n- if (this.icon == null) {\n- this.icon = newIcon;\n- } else {\n- this.icon.url = newIcon.url;\n- this.icon.size = newIcon.size;\n- this.icon.offset = newIcon.offset;\n- this.icon.calculateOffset = newIcon.calculateOffset;\n+ }\n }\n- this.events = new OpenLayers.Events(this, this.icon.imageDiv);\n+ this.events.triggerEvent(\"updatesize\");\n },\n \n /**\n- * APIMethod: destroy\n- * Destroy the marker. You must first remove the marker from any \n- * layer which it has been added to, or you will get buggy behavior.\n- * (This can not be done within the marker since the marker does not\n- * know which layer it is attached to.)\n+ * Method: getCurrentSize\n+ * \n+ * Returns:\n+ * {} A new object with the dimensions \n+ * of the map div\n */\n- destroy: function() {\n- // erase any drawn features\n- this.erase();\n-\n- this.map = null;\n+ getCurrentSize: function() {\n \n- this.events.destroy();\n- this.events = null;\n+ var size = new OpenLayers.Size(this.div.clientWidth,\n+ this.div.clientHeight);\n \n- if (this.icon != null) {\n- this.icon.destroy();\n- this.icon = null;\n+ if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {\n+ size.w = this.div.offsetWidth;\n+ size.h = this.div.offsetHeight;\n+ }\n+ if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {\n+ size.w = parseInt(this.div.style.width);\n+ size.h = parseInt(this.div.style.height);\n }\n+ return size;\n },\n \n /** \n- * Method: draw\n- * Calls draw on the icon, and returns that output.\n+ * Method: calculateBounds\n * \n * Parameters:\n- * px - {}\n+ * center - {} Default is this.getCenter()\n+ * resolution - {float} Default is this.getResolution() \n * \n * Returns:\n- * {DOMElement} A new DOM Image with this marker's icon set at the \n- * location passed-in\n+ * {} A bounds based on resolution, center, and \n+ * current mapsize.\n */\n- draw: function(px) {\n- return this.icon.draw(px);\n- },\n+ calculateBounds: function(center, resolution) {\n \n- /** \n- * Method: erase\n- * Erases any drawn elements for this marker.\n- */\n- erase: function() {\n- if (this.icon != null) {\n- this.icon.erase();\n+ var extent = null;\n+\n+ if (center == null) {\n+ center = this.getCachedCenter();\n+ }\n+ if (resolution == null) {\n+ resolution = this.getResolution();\n }\n- },\n \n- /**\n- * Method: moveTo\n- * Move the marker to the new location.\n- *\n- * Parameters:\n- * px - {|Object} the pixel position to move to.\n- * An OpenLayers.Pixel or an object with a 'x' and 'y' properties.\n- */\n- moveTo: function(px) {\n- if ((px != null) && (this.icon != null)) {\n- this.icon.moveTo(px);\n+ if ((center != null) && (resolution != null)) {\n+ var halfWDeg = (this.size.w * resolution) / 2;\n+ var halfHDeg = (this.size.h * resolution) / 2;\n+\n+ extent = new OpenLayers.Bounds(center.lon - halfWDeg,\n+ center.lat - halfHDeg,\n+ center.lon + halfWDeg,\n+ center.lat + halfHDeg);\n }\n- this.lonlat = this.map.getLonLatFromLayerPx(px);\n+\n+ return extent;\n },\n \n+\n+ /********************************************************/\n+ /* */\n+ /* Zoom, Center, Pan Functions */\n+ /* */\n+ /* The following functions handle the validation, */\n+ /* getting and setting of the Zoom Level and Center */\n+ /* as well as the panning of the Map */\n+ /* */\n+ /********************************************************/\n /**\n- * APIMethod: isDrawn\n+ * APIMethod: getCenter\n * \n * Returns:\n- * {Boolean} Whether or not the marker is drawn.\n+ * {}\n */\n- isDrawn: function() {\n- var isDrawn = (this.icon && this.icon.isDrawn());\n- return isDrawn;\n+ getCenter: function() {\n+ var center = null;\n+ var cachedCenter = this.getCachedCenter();\n+ if (cachedCenter) {\n+ center = cachedCenter.clone();\n+ }\n+ return center;\n },\n \n /**\n- * Method: onScreen\n+ * Method: getCachedCenter\n *\n * Returns:\n- * {Boolean} Whether or not the marker is currently visible on screen.\n+ * {}\n */\n- onScreen: function() {\n-\n- var onScreen = false;\n- if (this.map) {\n- var screenBounds = this.map.getExtent();\n- onScreen = screenBounds.containsLonLat(this.lonlat);\n+ getCachedCenter: function() {\n+ if (!this.center && this.size) {\n+ this.center = this.getLonLatFromViewPortPx({\n+ x: this.size.w / 2,\n+ y: this.size.h / 2\n+ });\n }\n- return onScreen;\n+ return this.center;\n },\n \n /**\n- * Method: inflate\n- * Englarges the markers icon by the specified ratio.\n- *\n- * Parameters:\n- * inflate - {float} the ratio to enlarge the marker by (passing 2\n- * will double the size).\n- */\n- inflate: function(inflate) {\n- if (this.icon) {\n- this.icon.setSize({\n- w: this.icon.size.w * inflate,\n- h: this.icon.size.h * inflate\n- });\n- }\n- },\n-\n- /** \n- * Method: setOpacity\n- * Change the opacity of the marker by changin the opacity of \n- * its icon\n- * \n- * Parameters:\n- * opacity - {float} Specified as fraction (0.4, etc)\n- */\n- setOpacity: function(opacity) {\n- this.icon.setOpacity(opacity);\n- },\n-\n- /**\n- * Method: setUrl\n- * Change URL of the Icon Image.\n- * \n- * url - {String} \n- */\n- setUrl: function(url) {\n- this.icon.setUrl(url);\n- },\n-\n- /** \n- * Method: display\n- * Hide or show the icon\n- * \n- * display - {Boolean} \n- */\n- display: function(display) {\n- this.icon.display(display);\n- },\n-\n- CLASS_NAME: \"OpenLayers.Marker\"\n-});\n-\n-\n-/**\n- * Function: defaultIcon\n- * Creates a default .\n- * \n- * Returns:\n- * {} A default OpenLayers.Icon to use for a marker\n- */\n-OpenLayers.Marker.defaultIcon = function() {\n- return new OpenLayers.Icon(OpenLayers.Util.getImageLocation(\"marker.png\"), {\n- w: 21,\n- h: 25\n- }, {\n- x: -10.5,\n- y: -25\n- });\n-};\n-\n-\n-/* ======================================================================\n- OpenLayers/Request/XMLHttpRequest.js\n- ====================================================================== */\n-\n-// XMLHttpRequest.js Copyright (C) 2010 Sergey Ilinsky (http://www.ilinsky.com)\n-//\n-// Licensed under the Apache License, Version 2.0 (the \"License\");\n-// you may not use this file except in compliance with the License.\n-// You may obtain a copy of the License at\n-//\n-// http://www.apache.org/licenses/LICENSE-2.0\n-//\n-// Unless required by applicable law or agreed to in writing, software\n-// distributed under the License is distributed on an \"AS IS\" BASIS,\n-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n-// See the License for the specific language governing permissions and\n-// limitations under the License.\n-\n-/**\n- * @requires OpenLayers/Request.js\n- */\n-\n-(function() {\n-\n- // Save reference to earlier defined object implementation (if any)\n- var oXMLHttpRequest = window.XMLHttpRequest;\n-\n- // Define on browser type\n- var bGecko = !!window.controllers,\n- bIE = window.document.all && !window.opera,\n- bIE7 = bIE && window.navigator.userAgent.match(/MSIE 7.0/);\n-\n- // Enables \"XMLHttpRequest()\" call next to \"new XMLHttpReques()\"\n- function fXMLHttpRequest() {\n- this._object = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject(\"Microsoft.XMLHTTP\");\n- this._listeners = [];\n- };\n-\n- // Constructor\n- function cXMLHttpRequest() {\n- return new fXMLHttpRequest;\n- };\n- cXMLHttpRequest.prototype = fXMLHttpRequest.prototype;\n-\n- // BUGFIX: Firefox with Firebug installed would break pages if not executed\n- if (bGecko && oXMLHttpRequest.wrapped)\n- cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped;\n-\n- // Constants\n- cXMLHttpRequest.UNSENT = 0;\n- cXMLHttpRequest.OPENED = 1;\n- cXMLHttpRequest.HEADERS_RECEIVED = 2;\n- cXMLHttpRequest.LOADING = 3;\n- cXMLHttpRequest.DONE = 4;\n-\n- // Public Properties\n- cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT;\n- cXMLHttpRequest.prototype.responseText = '';\n- cXMLHttpRequest.prototype.responseXML = null;\n- cXMLHttpRequest.prototype.status = 0;\n- cXMLHttpRequest.prototype.statusText = '';\n-\n- // Priority proposal\n- cXMLHttpRequest.prototype.priority = \"NORMAL\";\n-\n- // Instance-level Events Handlers\n- cXMLHttpRequest.prototype.onreadystatechange = null;\n-\n- // Class-level Events Handlers\n- cXMLHttpRequest.onreadystatechange = null;\n- cXMLHttpRequest.onopen = null;\n- cXMLHttpRequest.onsend = null;\n- cXMLHttpRequest.onabort = null;\n-\n- // Public Methods\n- cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) {\n- // Delete headers, required when object is reused\n- delete this._headers;\n-\n- // When bAsync parameter value is omitted, use true as default\n- if (arguments.length < 3)\n- bAsync = true;\n-\n- // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests\n- this._async = bAsync;\n-\n- // Set the onreadystatechange handler\n- var oRequest = this,\n- nState = this.readyState,\n- fOnUnload;\n-\n- // BUGFIX: IE - memory leak on page unload (inter-page leak)\n- if (bIE && bAsync) {\n- fOnUnload = function() {\n- if (nState != cXMLHttpRequest.DONE) {\n- fCleanTransport(oRequest);\n- // Safe to abort here since onreadystatechange handler removed\n- oRequest.abort();\n- }\n- };\n- window.attachEvent(\"onunload\", fOnUnload);\n- }\n-\n- // Add method sniffer\n- if (cXMLHttpRequest.onopen)\n- cXMLHttpRequest.onopen.apply(this, arguments);\n-\n- if (arguments.length > 4)\n- this._object.open(sMethod, sUrl, bAsync, sUser, sPassword);\n- else\n- if (arguments.length > 3)\n- this._object.open(sMethod, sUrl, bAsync, sUser);\n- else\n- this._object.open(sMethod, sUrl, bAsync);\n-\n- this.readyState = cXMLHttpRequest.OPENED;\n- fReadyStateChange(this);\n-\n- this._object.onreadystatechange = function() {\n- if (bGecko && !bAsync)\n- return;\n-\n- // Synchronize state\n- oRequest.readyState = oRequest._object.readyState;\n-\n- //\n- fSynchronizeValues(oRequest);\n-\n- // BUGFIX: Firefox fires unnecessary DONE when aborting\n- if (oRequest._aborted) {\n- // Reset readyState to UNSENT\n- oRequest.readyState = cXMLHttpRequest.UNSENT;\n-\n- // Return now\n- return;\n- }\n-\n- if (oRequest.readyState == cXMLHttpRequest.DONE) {\n- // Free up queue\n- delete oRequest._data;\n- /* if (bAsync)\n- fQueue_remove(oRequest);*/\n- //\n- fCleanTransport(oRequest);\n- // Uncomment this block if you need a fix for IE cache\n- /*\n- // BUGFIX: IE - cache issue\n- if (!oRequest._object.getResponseHeader(\"Date\")) {\n- // Save object to cache\n- oRequest._cached = oRequest._object;\n-\n- // Instantiate a new transport object\n- cXMLHttpRequest.call(oRequest);\n-\n- // Re-send request\n- if (sUser) {\n- if (sPassword)\n- oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword);\n- else\n- oRequest._object.open(sMethod, sUrl, bAsync, sUser);\n- }\n- else\n- oRequest._object.open(sMethod, sUrl, bAsync);\n- oRequest._object.setRequestHeader(\"If-Modified-Since\", oRequest._cached.getResponseHeader(\"Last-Modified\") || new window.Date(0));\n- // Copy headers set\n- if (oRequest._headers)\n- for (var sHeader in oRequest._headers)\n- if (typeof oRequest._headers[sHeader] == \"string\") // Some frameworks prototype objects with functions\n- oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]);\n-\n- oRequest._object.onreadystatechange = function() {\n- // Synchronize state\n- oRequest.readyState = oRequest._object.readyState;\n-\n- if (oRequest._aborted) {\n- //\n- oRequest.readyState = cXMLHttpRequest.UNSENT;\n-\n- // Return\n- return;\n- }\n-\n- if (oRequest.readyState == cXMLHttpRequest.DONE) {\n- // Clean Object\n- fCleanTransport(oRequest);\n-\n- // get cached request\n- if (oRequest.status == 304)\n- oRequest._object = oRequest._cached;\n-\n- //\n- delete oRequest._cached;\n-\n- //\n- fSynchronizeValues(oRequest);\n-\n- //\n- fReadyStateChange(oRequest);\n-\n- // BUGFIX: IE - memory leak in interrupted\n- if (bIE && bAsync)\n- window.detachEvent(\"onunload\", fOnUnload);\n- }\n- };\n- oRequest._object.send(null);\n-\n- // Return now - wait until re-sent request is finished\n- return;\n- };\n- */\n- // BUGFIX: IE - memory leak in interrupted\n- if (bIE && bAsync)\n- window.detachEvent(\"onunload\", fOnUnload);\n- }\n-\n- // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice\n- if (nState != oRequest.readyState)\n- fReadyStateChange(oRequest);\n-\n- nState = oRequest.readyState;\n- }\n- };\n-\n- function fXMLHttpRequest_send(oRequest) {\n- oRequest._object.send(oRequest._data);\n-\n- // BUGFIX: Gecko - missing readystatechange calls in synchronous requests\n- if (bGecko && !oRequest._async) {\n- oRequest.readyState = cXMLHttpRequest.OPENED;\n-\n- // Synchronize state\n- fSynchronizeValues(oRequest);\n-\n- // Simulate missing states\n- while (oRequest.readyState < cXMLHttpRequest.DONE) {\n- oRequest.readyState++;\n- fReadyStateChange(oRequest);\n- // Check if we are aborted\n- if (oRequest._aborted)\n- return;\n- }\n- }\n- };\n- cXMLHttpRequest.prototype.send = function(vData) {\n- // Add method sniffer\n- if (cXMLHttpRequest.onsend)\n- cXMLHttpRequest.onsend.apply(this, arguments);\n-\n- if (!arguments.length)\n- vData = null;\n-\n- // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required\n- // BUGFIX: IE - rewrites any custom mime-type to \"text/xml\" in case an XMLNode is sent\n- // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard)\n- if (vData && vData.nodeType) {\n- vData = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml;\n- if (!this._headers[\"Content-Type\"])\n- this._object.setRequestHeader(\"Content-Type\", \"application/xml\");\n- }\n-\n- this._data = vData;\n- /*\n- // Add to queue\n- if (this._async)\n- fQueue_add(this);\n- else*/\n- fXMLHttpRequest_send(this);\n- };\n- cXMLHttpRequest.prototype.abort = function() {\n- // Add method sniffer\n- if (cXMLHttpRequest.onabort)\n- cXMLHttpRequest.onabort.apply(this, arguments);\n-\n- // BUGFIX: Gecko - unnecessary DONE when aborting\n- if (this.readyState > cXMLHttpRequest.UNSENT)\n- this._aborted = true;\n-\n- this._object.abort();\n-\n- // BUGFIX: IE - memory leak\n- fCleanTransport(this);\n-\n- this.readyState = cXMLHttpRequest.UNSENT;\n-\n- delete this._data;\n- /* if (this._async)\n- fQueue_remove(this);*/\n- };\n- cXMLHttpRequest.prototype.getAllResponseHeaders = function() {\n- return this._object.getAllResponseHeaders();\n- };\n- cXMLHttpRequest.prototype.getResponseHeader = function(sName) {\n- return this._object.getResponseHeader(sName);\n- };\n- cXMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) {\n- // BUGFIX: IE - cache issue\n- if (!this._headers)\n- this._headers = {};\n- this._headers[sName] = sValue;\n-\n- return this._object.setRequestHeader(sName, sValue);\n- };\n-\n- // EventTarget interface implementation\n- cXMLHttpRequest.prototype.addEventListener = function(sName, fHandler, bUseCapture) {\n- for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)\n- if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)\n- return;\n- // Add listener\n- this._listeners.push([sName, fHandler, bUseCapture]);\n- };\n-\n- cXMLHttpRequest.prototype.removeEventListener = function(sName, fHandler, bUseCapture) {\n- for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)\n- if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)\n- break;\n- // Remove listener\n- if (oListener)\n- this._listeners.splice(nIndex, 1);\n- };\n-\n- cXMLHttpRequest.prototype.dispatchEvent = function(oEvent) {\n- var oEventPseudo = {\n- 'type': oEvent.type,\n- 'target': this,\n- 'currentTarget': this,\n- 'eventPhase': 2,\n- 'bubbles': oEvent.bubbles,\n- 'cancelable': oEvent.cancelable,\n- 'timeStamp': oEvent.timeStamp,\n- 'stopPropagation': function() {}, // There is no flow\n- 'preventDefault': function() {}, // There is no default action\n- 'initEvent': function() {} // Original event object should be initialized\n- };\n-\n- // Execute onreadystatechange\n- if (oEventPseudo.type == \"readystatechange\" && this.onreadystatechange)\n- (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]);\n-\n- // Execute listeners\n- for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)\n- if (oListener[0] == oEventPseudo.type && !oListener[2])\n- (oListener[1].handleEvent || oListener[1]).apply(this, [oEventPseudo]);\n- };\n-\n- //\n- cXMLHttpRequest.prototype.toString = function() {\n- return '[' + \"object\" + ' ' + \"XMLHttpRequest\" + ']';\n- };\n-\n- cXMLHttpRequest.toString = function() {\n- return '[' + \"XMLHttpRequest\" + ']';\n- };\n-\n- // Helper function\n- function fReadyStateChange(oRequest) {\n- // Sniffing code\n- if (cXMLHttpRequest.onreadystatechange)\n- cXMLHttpRequest.onreadystatechange.apply(oRequest);\n-\n- // Fake event\n- oRequest.dispatchEvent({\n- 'type': \"readystatechange\",\n- 'bubbles': false,\n- 'cancelable': false,\n- 'timeStamp': new Date + 0\n- });\n- };\n-\n- function fGetDocument(oRequest) {\n- var oDocument = oRequest.responseXML,\n- sResponse = oRequest.responseText;\n- // Try parsing responseText\n- if (bIE && sResponse && oDocument && !oDocument.documentElement && oRequest.getResponseHeader(\"Content-Type\").match(/[^\\/]+\\/[^\\+]+\\+xml/)) {\n- oDocument = new window.ActiveXObject(\"Microsoft.XMLDOM\");\n- oDocument.async = false;\n- oDocument.validateOnParse = false;\n- oDocument.loadXML(sResponse);\n- }\n- // Check if there is no error in document\n- if (oDocument)\n- if ((bIE && oDocument.parseError != 0) || !oDocument.documentElement || (oDocument.documentElement && oDocument.documentElement.tagName == \"parsererror\"))\n- return null;\n- return oDocument;\n- };\n-\n- function fSynchronizeValues(oRequest) {\n- try {\n- oRequest.responseText = oRequest._object.responseText;\n- } catch (e) {}\n- try {\n- oRequest.responseXML = fGetDocument(oRequest._object);\n- } catch (e) {}\n- try {\n- oRequest.status = oRequest._object.status;\n- } catch (e) {}\n- try {\n- oRequest.statusText = oRequest._object.statusText;\n- } catch (e) {}\n- };\n-\n- function fCleanTransport(oRequest) {\n- // BUGFIX: IE - memory leak (on-page leak)\n- oRequest._object.onreadystatechange = new window.Function;\n- };\n- /*\n- // Queue manager\n- var oQueuePending = {\"CRITICAL\":[],\"HIGH\":[],\"NORMAL\":[],\"LOW\":[],\"LOWEST\":[]},\n- aQueueRunning = [];\n- function fQueue_add(oRequest) {\n- oQueuePending[oRequest.priority in oQueuePending ? oRequest.priority : \"NORMAL\"].push(oRequest);\n- //\n- setTimeout(fQueue_process);\n- };\n-\n- function fQueue_remove(oRequest) {\n- for (var nIndex = 0, bFound = false; nIndex < aQueueRunning.length; nIndex++)\n- if (bFound)\n- aQueueRunning[nIndex - 1] = aQueueRunning[nIndex];\n- else\n- if (aQueueRunning[nIndex] == oRequest)\n- bFound = true;\n- if (bFound)\n- aQueueRunning.length--;\n- //\n- setTimeout(fQueue_process);\n- };\n-\n- function fQueue_process() {\n- if (aQueueRunning.length < 6) {\n- for (var sPriority in oQueuePending) {\n- if (oQueuePending[sPriority].length) {\n- var oRequest = oQueuePending[sPriority][0];\n- oQueuePending[sPriority] = oQueuePending[sPriority].slice(1);\n- //\n- aQueueRunning.push(oRequest);\n- // Send request\n- fXMLHttpRequest_send(oRequest);\n- break;\n- }\n- }\n- }\n- };\n- */\n- // Internet Explorer 5.0 (missing apply)\n- if (!window.Function.prototype.apply) {\n- window.Function.prototype.apply = function(oRequest, oArguments) {\n- if (!oArguments)\n- oArguments = [];\n- oRequest.__func = this;\n- oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]);\n- delete oRequest.__func;\n- };\n- };\n-\n- // Register new object with window\n- /**\n- * Class: OpenLayers.Request.XMLHttpRequest\n- * Standard-compliant (W3C) cross-browser implementation of the\n- * XMLHttpRequest object. From\n- * http://code.google.com/p/xmlhttprequest/.\n- */\n- if (!OpenLayers.Request) {\n- /**\n- * This allows for OpenLayers/Request.js to be included\n- * before or after this script.\n- */\n- OpenLayers.Request = {};\n- }\n- OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest;\n-})();\n-/* ======================================================================\n- OpenLayers/Request.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/Events.js\n- * @requires OpenLayers/Request/XMLHttpRequest.js\n- */\n-\n-/**\n- * TODO: deprecate me\n- * Use OpenLayers.Request.proxy instead.\n- */\n-OpenLayers.ProxyHost = \"\";\n-\n-/**\n- * Namespace: OpenLayers.Request\n- * The OpenLayers.Request namespace contains convenience methods for working\n- * with XMLHttpRequests. These methods work with a cross-browser\n- * W3C compliant class.\n- */\n-if (!OpenLayers.Request) {\n- /**\n- * This allows for OpenLayers/Request/XMLHttpRequest.js to be included\n- * before or after this script.\n- */\n- OpenLayers.Request = {};\n-}\n-OpenLayers.Util.extend(OpenLayers.Request, {\n-\n- /**\n- * Constant: DEFAULT_CONFIG\n- * {Object} Default configuration for all requests.\n- */\n- DEFAULT_CONFIG: {\n- method: \"GET\",\n- url: window.location.href,\n- async: true,\n- user: undefined,\n- password: undefined,\n- params: null,\n- proxy: OpenLayers.ProxyHost,\n- headers: {},\n- data: null,\n- callback: function() {},\n- success: null,\n- failure: null,\n- scope: null\n- },\n-\n- /**\n- * Constant: URL_SPLIT_REGEX\n- */\n- URL_SPLIT_REGEX: /([^:]*:)\\/\\/([^:]*:?[^@]*@)?([^:\\/\\?]*):?([^\\/\\?]*)/,\n-\n- /**\n- * APIProperty: events\n- * {} An events object that handles all \n- * events on the {} object.\n- *\n- * All event listeners will receive an event object with three properties:\n- * request - {} The request object.\n- * config - {Object} The config object sent to the specific request method.\n- * requestUrl - {String} The request url.\n- * \n- * Supported event types:\n- * complete - Triggered when we have a response from the request, if a\n- * listener returns false, no further response processing will take\n- * place.\n- * success - Triggered when the HTTP response has a success code (200-299).\n- * failure - Triggered when the HTTP response does not have a success code.\n- */\n- events: new OpenLayers.Events(this),\n-\n- /**\n- * Method: makeSameOrigin\n- * Using the specified proxy, returns a same origin url of the provided url.\n- *\n- * Parameters:\n- * url - {String} An arbitrary url\n- * proxy {String|Function} The proxy to use to make the provided url a\n- * same origin url.\n- *\n- * Returns\n- * {String} the same origin url. If no proxy is provided, the returned url\n- * will be the same as the provided url.\n- */\n- makeSameOrigin: function(url, proxy) {\n- var sameOrigin = url.indexOf(\"http\") !== 0;\n- var urlParts = !sameOrigin && url.match(this.URL_SPLIT_REGEX);\n- if (urlParts) {\n- var location = window.location;\n- sameOrigin =\n- urlParts[1] == location.protocol &&\n- urlParts[3] == location.hostname;\n- var uPort = urlParts[4],\n- lPort = location.port;\n- if (uPort != 80 && uPort != \"\" || lPort != \"80\" && lPort != \"\") {\n- sameOrigin = sameOrigin && uPort == lPort;\n- }\n- }\n- if (!sameOrigin) {\n- if (proxy) {\n- if (typeof proxy == \"function\") {\n- url = proxy(url);\n- } else {\n- url = proxy + encodeURIComponent(url);\n- }\n- }\n- }\n- return url;\n- },\n-\n- /**\n- * APIMethod: issue\n- * Create a new XMLHttpRequest object, open it, set any headers, bind\n- * a callback to done state, and send any data. It is recommended that\n- * you use one , , , , , or .\n- * This method is only documented to provide detail on the configuration\n- * options available to all request methods.\n- *\n- * Parameters:\n- * config - {Object} Object containing properties for configuring the\n- * request. Allowed configuration properties are described below.\n- * This object is modified and should not be reused.\n- *\n- * Allowed config properties:\n- * method - {String} One of GET, POST, PUT, DELETE, HEAD, or\n- * OPTIONS. Default is GET.\n- * url - {String} URL for the request.\n- * async - {Boolean} Open an asynchronous request. Default is true.\n- * user - {String} User for relevant authentication scheme. Set\n- * to null to clear current user.\n- * password - {String} Password for relevant authentication scheme.\n- * Set to null to clear current password.\n- * proxy - {String} Optional proxy. Defaults to\n- * .\n- * params - {Object} Any key:value pairs to be appended to the\n- * url as a query string. Assumes url doesn't already include a query\n- * string or hash. Typically, this is only appropriate for \n- * requests where the query string will be appended to the url.\n- * Parameter values that are arrays will be\n- * concatenated with a comma (note that this goes against form-encoding)\n- * as is done with .\n- * headers - {Object} Object with header:value pairs to be set on\n- * the request.\n- * data - {String | Document} Optional data to send with the request.\n- * Typically, this is only used with and requests.\n- * Make sure to provide the appropriate \"Content-Type\" header for your\n- * data. For and requests, the content type defaults to\n- * \"application-xml\". If your data is a different content type, or\n- * if you are using a different HTTP method, set the \"Content-Type\"\n- * header to match your data type.\n- * callback - {Function} Function to call when request is done.\n- * To determine if the request failed, check request.status (200\n- * indicates success).\n- * success - {Function} Optional function to call if request status is in\n- * the 200s. This will be called in addition to callback above and\n- * would typically only be used as an alternative.\n- * failure - {Function} Optional function to call if request status is not\n- * in the 200s. This will be called in addition to callback above and\n- * would typically only be used as an alternative.\n- * scope - {Object} If callback is a public method on some object,\n- * set the scope to that object.\n- *\n- * Returns:\n- * {XMLHttpRequest} Request object. To abort the request before a response\n- * is received, call abort() on the request object.\n- */\n- issue: function(config) {\n- // apply default config - proxy host may have changed\n- var defaultConfig = OpenLayers.Util.extend(\n- this.DEFAULT_CONFIG, {\n- proxy: OpenLayers.ProxyHost\n- }\n- );\n- config = config || {};\n- config.headers = config.headers || {};\n- config = OpenLayers.Util.applyDefaults(config, defaultConfig);\n- config.headers = OpenLayers.Util.applyDefaults(config.headers, defaultConfig.headers);\n- // Always set the \"X-Requested-With\" header to signal that this request\n- // was issued through the XHR-object. Since header keys are case \n- // insensitive and we want to allow overriding of the \"X-Requested-With\"\n- // header through the user we cannot use applyDefaults, but have to \n- // check manually whether we were called with a \"X-Requested-With\"\n- // header.\n- var customRequestedWithHeader = false,\n- headerKey;\n- for (headerKey in config.headers) {\n- if (config.headers.hasOwnProperty(headerKey)) {\n- if (headerKey.toLowerCase() === 'x-requested-with') {\n- customRequestedWithHeader = true;\n- }\n- }\n- }\n- if (customRequestedWithHeader === false) {\n- // we did not have a custom \"X-Requested-With\" header\n- config.headers['X-Requested-With'] = 'XMLHttpRequest';\n- }\n-\n- // create request, open, and set headers\n- var request = new OpenLayers.Request.XMLHttpRequest();\n- var url = OpenLayers.Util.urlAppend(config.url,\n- OpenLayers.Util.getParameterString(config.params || {}));\n- url = OpenLayers.Request.makeSameOrigin(url, config.proxy);\n- request.open(\n- config.method, url, config.async, config.user, config.password\n- );\n- for (var header in config.headers) {\n- request.setRequestHeader(header, config.headers[header]);\n- }\n-\n- var events = this.events;\n-\n- // we want to execute runCallbacks with \"this\" as the\n- // execution scope\n- var self = this;\n-\n- request.onreadystatechange = function() {\n- if (request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {\n- var proceed = events.triggerEvent(\n- \"complete\", {\n- request: request,\n- config: config,\n- requestUrl: url\n- }\n- );\n- if (proceed !== false) {\n- self.runCallbacks({\n- request: request,\n- config: config,\n- requestUrl: url\n- });\n- }\n- }\n- };\n-\n- // send request (optionally with data) and return\n- // call in a timeout for asynchronous requests so the return is\n- // available before readyState == 4 for cached docs\n- if (config.async === false) {\n- request.send(config.data);\n- } else {\n- window.setTimeout(function() {\n- if (request.readyState !== 0) { // W3C: 0-UNSENT\n- request.send(config.data);\n- }\n- }, 0);\n- }\n- return request;\n- },\n-\n- /**\n- * Method: runCallbacks\n- * Calls the complete, success and failure callbacks. Application\n- * can listen to the \"complete\" event, have the listener \n- * display a confirm window and always return false, and\n- * execute OpenLayers.Request.runCallbacks if the user\n- * hits \"yes\" in the confirm window.\n- *\n- * Parameters:\n- * options - {Object} Hash containing request, config and requestUrl keys\n- */\n- runCallbacks: function(options) {\n- var request = options.request;\n- var config = options.config;\n-\n- // bind callbacks to readyState 4 (done)\n- var complete = (config.scope) ?\n- OpenLayers.Function.bind(config.callback, config.scope) :\n- config.callback;\n-\n- // optional success callback\n- var success;\n- if (config.success) {\n- success = (config.scope) ?\n- OpenLayers.Function.bind(config.success, config.scope) :\n- config.success;\n- }\n-\n- // optional failure callback\n- var failure;\n- if (config.failure) {\n- failure = (config.scope) ?\n- OpenLayers.Function.bind(config.failure, config.scope) :\n- config.failure;\n- }\n-\n- if (OpenLayers.Util.createUrlObject(config.url).protocol == \"file:\" &&\n- request.responseText) {\n- request.status = 200;\n- }\n- complete(request);\n-\n- if (!request.status || (request.status >= 200 && request.status < 300)) {\n- this.events.triggerEvent(\"success\", options);\n- if (success) {\n- success(request);\n- }\n- }\n- if (request.status && (request.status < 200 || request.status >= 300)) {\n- this.events.triggerEvent(\"failure\", options);\n- if (failure) {\n- failure(request);\n- }\n- }\n- },\n-\n- /**\n- * APIMethod: GET\n- * Send an HTTP GET request. Additional configuration properties are\n- * documented in the method, with the method property set\n- * to GET.\n- *\n- * Parameters:\n- * config - {Object} Object with properties for configuring the request.\n- * See the method for documentation of allowed properties.\n- * This object is modified and should not be reused.\n- * \n- * Returns:\n- * {XMLHttpRequest} Request object.\n- */\n- GET: function(config) {\n- config = OpenLayers.Util.extend(config, {\n- method: \"GET\"\n- });\n- return OpenLayers.Request.issue(config);\n- },\n-\n- /**\n- * APIMethod: POST\n- * Send a POST request. Additional configuration properties are\n- * documented in the method, with the method property set\n- * to POST and \"Content-Type\" header set to \"application/xml\".\n- *\n- * Parameters:\n- * config - {Object} Object with properties for configuring the request.\n- * See the method for documentation of allowed properties. The\n- * default \"Content-Type\" header will be set to \"application-xml\" if\n- * none is provided. This object is modified and should not be reused.\n- * \n- * Returns:\n- * {XMLHttpRequest} Request object.\n- */\n- POST: function(config) {\n- config = OpenLayers.Util.extend(config, {\n- method: \"POST\"\n- });\n- // set content type to application/xml if it isn't already set\n- config.headers = config.headers ? config.headers : {};\n- if (!(\"CONTENT-TYPE\" in OpenLayers.Util.upperCaseObject(config.headers))) {\n- config.headers[\"Content-Type\"] = \"application/xml\";\n- }\n- return OpenLayers.Request.issue(config);\n- },\n-\n- /**\n- * APIMethod: PUT\n- * Send an HTTP PUT request. Additional configuration properties are\n- * documented in the method, with the method property set\n- * to PUT and \"Content-Type\" header set to \"application/xml\".\n- *\n- * Parameters:\n- * config - {Object} Object with properties for configuring the request.\n- * See the method for documentation of allowed properties. The\n- * default \"Content-Type\" header will be set to \"application-xml\" if\n- * none is provided. This object is modified and should not be reused.\n- * \n- * Returns:\n- * {XMLHttpRequest} Request object.\n- */\n- PUT: function(config) {\n- config = OpenLayers.Util.extend(config, {\n- method: \"PUT\"\n- });\n- // set content type to application/xml if it isn't already set\n- config.headers = config.headers ? config.headers : {};\n- if (!(\"CONTENT-TYPE\" in OpenLayers.Util.upperCaseObject(config.headers))) {\n- config.headers[\"Content-Type\"] = \"application/xml\";\n- }\n- return OpenLayers.Request.issue(config);\n- },\n-\n- /**\n- * APIMethod: DELETE\n- * Send an HTTP DELETE request. Additional configuration properties are\n- * documented in the method, with the method property set\n- * to DELETE.\n- *\n- * Parameters:\n- * config - {Object} Object with properties for configuring the request.\n- * See the method for documentation of allowed properties.\n- * This object is modified and should not be reused.\n- * \n- * Returns:\n- * {XMLHttpRequest} Request object.\n- */\n- DELETE: function(config) {\n- config = OpenLayers.Util.extend(config, {\n- method: \"DELETE\"\n- });\n- return OpenLayers.Request.issue(config);\n- },\n-\n- /**\n- * APIMethod: HEAD\n- * Send an HTTP HEAD request. Additional configuration properties are\n- * documented in the method, with the method property set\n- * to HEAD.\n- *\n- * Parameters:\n- * config - {Object} Object with properties for configuring the request.\n- * See the method for documentation of allowed properties.\n- * This object is modified and should not be reused.\n- * \n- * Returns:\n- * {XMLHttpRequest} Request object.\n- */\n- HEAD: function(config) {\n- config = OpenLayers.Util.extend(config, {\n- method: \"HEAD\"\n- });\n- return OpenLayers.Request.issue(config);\n- },\n-\n- /**\n- * APIMethod: OPTIONS\n- * Send an HTTP OPTIONS request. Additional configuration properties are\n- * documented in the method, with the method property set\n- * to OPTIONS.\n- *\n- * Parameters:\n- * config - {Object} Object with properties for configuring the request.\n- * See the method for documentation of allowed properties.\n- * This object is modified and should not be reused.\n- * \n- * Returns:\n- * {XMLHttpRequest} Request object.\n- */\n- OPTIONS: function(config) {\n- config = OpenLayers.Util.extend(config, {\n- method: \"OPTIONS\"\n- });\n- return OpenLayers.Request.issue(config);\n- }\n-\n-});\n-/* ======================================================================\n- OpenLayers/Format.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Util.js\n- */\n-\n-/**\n- * Class: OpenLayers.Format\n- * Base class for format reading/writing a variety of formats. Subclasses\n- * of OpenLayers.Format are expected to have read and write methods.\n- */\n-OpenLayers.Format = OpenLayers.Class({\n-\n- /**\n- * Property: options\n- * {Object} A reference to options passed to the constructor.\n- */\n- options: null,\n-\n- /**\n- * APIProperty: externalProjection\n- * {} When passed a externalProjection and\n- * internalProjection, the format will reproject the geometries it\n- * reads or writes. The externalProjection is the projection used by\n- * the content which is passed into read or which comes out of write.\n- * In order to reproject, a projection transformation function for the\n- * specified projections must be available. This support may be \n- * provided via proj4js or via a custom transformation function. See\n- * {} for more information on\n- * custom transformations.\n- */\n- externalProjection: null,\n-\n- /**\n- * APIProperty: internalProjection\n- * {} When passed a externalProjection and\n- * internalProjection, the format will reproject the geometries it\n- * reads or writes. The internalProjection is the projection used by\n- * the geometries which are returned by read or which are passed into\n- * write. In order to reproject, a projection transformation function\n- * for the specified projections must be available. This support may be\n- * provided via proj4js or via a custom transformation function. See\n- * {} for more information on\n- * custom transformations.\n- */\n- internalProjection: null,\n-\n- /**\n- * APIProperty: data\n- * {Object} When is true, this is the parsed string sent to\n- * .\n- */\n- data: null,\n-\n- /**\n- * APIProperty: keepData\n- * {Object} Maintain a reference () to the most recently read data.\n- * Default is false.\n- */\n- keepData: false,\n-\n- /**\n- * Constructor: OpenLayers.Format\n- * Instances of this class are not useful. See one of the subclasses.\n- *\n- * Parameters:\n- * options - {Object} An optional object with properties to set on the\n- * format\n- *\n- * Valid options:\n- * keepData - {Boolean} If true, upon , the data property will be\n- * set to the parsed object (e.g. the json or xml object).\n- *\n- * Returns:\n- * An instance of OpenLayers.Format\n- */\n- initialize: function(options) {\n- OpenLayers.Util.extend(this, options);\n- this.options = options;\n- },\n-\n- /**\n- * APIMethod: destroy\n- * Clean up.\n- */\n- destroy: function() {},\n-\n- /**\n- * Method: read\n- * Read data from a string, and return an object whose type depends on the\n- * subclass. \n- * \n- * Parameters:\n- * data - {string} Data to read/parse.\n- *\n- * Returns:\n- * Depends on the subclass\n- */\n- read: function(data) {\n- throw new Error('Read not implemented.');\n- },\n-\n- /**\n- * Method: write\n- * Accept an object, and return a string. \n- *\n- * Parameters:\n- * object - {Object} Object to be serialized\n- *\n- * Returns:\n- * {String} A string representation of the object.\n- */\n- write: function(object) {\n- throw new Error('Write not implemented.');\n- },\n-\n- CLASS_NAME: \"OpenLayers.Format\"\n-});\n-/* ======================================================================\n- OpenLayers/Util/vendorPrefix.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/SingleFile.js\n- */\n-\n-OpenLayers.Util = OpenLayers.Util || {};\n-/**\n- * Namespace: OpenLayers.Util.vendorPrefix\n- * A collection of utility functions to detect vendor prefixed features\n- */\n-OpenLayers.Util.vendorPrefix = (function() {\n- \"use strict\";\n-\n- var VENDOR_PREFIXES = [\"\", \"O\", \"ms\", \"Moz\", \"Webkit\"],\n- divStyle = document.createElement(\"div\").style,\n- cssCache = {},\n- jsCache = {};\n-\n-\n- /**\n- * Function: domToCss\n- * Converts a upper camel case DOM style property name to a CSS property\n- * i.e. transformOrigin -> transform-origin\n- * or WebkitTransformOrigin -> -webkit-transform-origin\n- *\n- * Parameters:\n- * prefixedDom - {String} The property to convert\n- *\n- * Returns:\n- * {String} The CSS property\n- */\n- function domToCss(prefixedDom) {\n- if (!prefixedDom) {\n- return null;\n- }\n- return prefixedDom.\n- replace(/([A-Z])/g, function(c) {\n- return \"-\" + c.toLowerCase();\n- }).\n- replace(/^ms-/, \"-ms-\");\n- }\n-\n- /**\n- * APIMethod: css\n- * Detect which property is used for a CSS property\n- *\n- * Parameters:\n- * property - {String} The standard (unprefixed) CSS property name\n- *\n- * Returns:\n- * {String} The standard CSS property, prefixed property or null if not\n- * supported\n- */\n- function css(property) {\n- if (cssCache[property] === undefined) {\n- var domProperty = property.\n- replace(/(-[\\s\\S])/g, function(c) {\n- return c.charAt(1).toUpperCase();\n- });\n- var prefixedDom = style(domProperty);\n- cssCache[property] = domToCss(prefixedDom);\n- }\n- return cssCache[property];\n- }\n-\n- /**\n- * APIMethod: js\n- * Detect which property is used for a JS property/method\n- *\n- * Parameters:\n- * obj - {Object} The object to test on\n- * property - {String} The standard (unprefixed) JS property name\n- *\n- * Returns:\n- * {String} The standard JS property, prefixed property or null if not\n- * supported\n- */\n- function js(obj, property) {\n- if (jsCache[property] === undefined) {\n- var tmpProp,\n- i = 0,\n- l = VENDOR_PREFIXES.length,\n- prefix,\n- isStyleObj = (typeof obj.cssText !== \"undefined\");\n-\n- jsCache[property] = null;\n- for (; i < l; i++) {\n- prefix = VENDOR_PREFIXES[i];\n- if (prefix) {\n- if (!isStyleObj) {\n- // js prefix should be lower-case, while style\n- // properties have upper case on first character\n- prefix = prefix.toLowerCase();\n- }\n- tmpProp = prefix + property.charAt(0).toUpperCase() + property.slice(1);\n- } else {\n- tmpProp = property;\n- }\n-\n- if (obj[tmpProp] !== undefined) {\n- jsCache[property] = tmpProp;\n- break;\n- }\n- }\n- }\n- return jsCache[property];\n- }\n-\n- /**\n- * APIMethod: style\n- * Detect which property is used for a DOM style property\n- *\n- * Parameters:\n- * property - {String} The standard (unprefixed) style property name\n- *\n- * Returns:\n- * {String} The standard style property, prefixed property or null if not\n- * supported\n- */\n- function style(property) {\n- return js(divStyle, property);\n- }\n-\n- return {\n- css: css,\n- js: js,\n- style: style,\n-\n- // used for testing\n- cssCache: cssCache,\n- jsCache: jsCache\n- };\n-}());\n-/* ======================================================================\n- OpenLayers/Animation.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/SingleFile.js\n- * @requires OpenLayers/Util/vendorPrefix.js\n- */\n-\n-/**\n- * Namespace: OpenLayers.Animation\n- * A collection of utility functions for executing methods that repaint a \n- * portion of the browser window. These methods take advantage of the\n- * browser's scheduled repaints where requestAnimationFrame is available.\n- */\n-OpenLayers.Animation = (function(window) {\n-\n- /**\n- * Property: isNative\n- * {Boolean} true if a native requestAnimationFrame function is available\n- */\n- var requestAnimationFrame = OpenLayers.Util.vendorPrefix.js(window, \"requestAnimationFrame\");\n- var isNative = !!(requestAnimationFrame);\n-\n- /**\n- * Function: requestFrame\n- * Schedule a function to be called at the next available animation frame.\n- * Uses the native method where available. Where requestAnimationFrame is\n- * not available, setTimeout will be called with a 16ms delay.\n- *\n- * Parameters:\n- * callback - {Function} The function to be called at the next animation frame.\n- * element - {DOMElement} Optional element that visually bounds the animation.\n- */\n- var requestFrame = (function() {\n- var request = window[requestAnimationFrame] ||\n- function(callback, element) {\n- window.setTimeout(callback, 16);\n- };\n- // bind to window to avoid illegal invocation of native function\n- return function(callback, element) {\n- request.apply(window, [callback, element]);\n- };\n- })();\n-\n- // private variables for animation loops\n- var counter = 0;\n- var loops = {};\n-\n- /**\n- * Function: start\n- * Executes a method with in series for some \n- * duration.\n- *\n- * Parameters:\n- * callback - {Function} The function to be called at the next animation frame.\n- * duration - {Number} Optional duration for the loop. If not provided, the\n- * animation loop will execute indefinitely.\n- * element - {DOMElement} Optional element that visually bounds the animation.\n- *\n- * Returns:\n- * {Number} Identifier for the animation loop. Used to stop animations with\n- * .\n- */\n- function start(callback, duration, element) {\n- duration = duration > 0 ? duration : Number.POSITIVE_INFINITY;\n- var id = ++counter;\n- var start = +new Date;\n- loops[id] = function() {\n- if (loops[id] && +new Date - start <= duration) {\n- callback();\n- if (loops[id]) {\n- requestFrame(loops[id], element);\n- }\n- } else {\n- delete loops[id];\n- }\n- };\n- requestFrame(loops[id], element);\n- return id;\n- }\n-\n- /**\n- * Function: stop\n- * Terminates an animation loop started with .\n- *\n- * Parameters:\n- * id - {Number} Identifier returned from .\n- */\n- function stop(id) {\n- delete loops[id];\n- }\n-\n- return {\n- isNative: isNative,\n- requestFrame: requestFrame,\n- start: start,\n- stop: stop\n- };\n-\n-})(window);\n-/* ======================================================================\n- OpenLayers/Protocol.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- */\n-\n-/**\n- * Class: OpenLayers.Protocol\n- * Abstract vector layer protocol class. Not to be instantiated directly. Use\n- * one of the protocol subclasses instead.\n- */\n-OpenLayers.Protocol = OpenLayers.Class({\n-\n- /**\n- * Property: format\n- * {} The format used by this protocol.\n- */\n- format: null,\n-\n- /**\n- * Property: options\n- * {Object} Any options sent to the constructor.\n- */\n- options: null,\n-\n- /**\n- * Property: autoDestroy\n- * {Boolean} The creator of the protocol can set autoDestroy to false\n- * to fully control when the protocol is destroyed. Defaults to\n- * true.\n- */\n- autoDestroy: true,\n-\n- /**\n- * Property: defaultFilter\n- * {} Optional default filter to read requests\n- */\n- defaultFilter: null,\n-\n- /**\n- * Constructor: OpenLayers.Protocol\n- * Abstract class for vector protocols. Create instances of a subclass.\n- *\n- * Parameters:\n- * options - {Object} Optional object whose properties will be set on the\n- * instance.\n- */\n- initialize: function(options) {\n- options = options || {};\n- OpenLayers.Util.extend(this, options);\n- this.options = options;\n- },\n-\n- /**\n- * Method: mergeWithDefaultFilter\n- * Merge filter passed to the read method with the default one\n- *\n- * Parameters:\n- * filter - {}\n- */\n- mergeWithDefaultFilter: function(filter) {\n- var merged;\n- if (filter && this.defaultFilter) {\n- merged = new OpenLayers.Filter.Logical({\n- type: OpenLayers.Filter.Logical.AND,\n- filters: [this.defaultFilter, filter]\n- });\n- } else {\n- merged = filter || this.defaultFilter || undefined;\n- }\n- return merged;\n- },\n-\n- /**\n- * APIMethod: destroy\n- * Clean up the protocol.\n- */\n- destroy: function() {\n- this.options = null;\n- this.format = null;\n- },\n-\n- /**\n- * APIMethod: read\n- * Construct a request for reading new features.\n- *\n- * Parameters:\n- * options - {Object} Optional object for configuring the request.\n- *\n- * Returns:\n- * {} An \n- * object, the same object will be passed to the callback function passed\n- * if one exists in the options object.\n- */\n- read: function(options) {\n- options = options || {};\n- options.filter = this.mergeWithDefaultFilter(options.filter);\n- },\n-\n-\n- /**\n- * APIMethod: create\n- * Construct a request for writing newly created features.\n- *\n- * Parameters:\n- * features - {Array({})} or\n- * {}\n- * options - {Object} Optional object for configuring the request.\n- *\n- * Returns:\n- * {} An \n- * object, the same object will be passed to the callback function passed\n- * if one exists in the options object.\n- */\n- create: function() {},\n-\n- /**\n- * APIMethod: update\n- * Construct a request updating modified features.\n- *\n- * Parameters:\n- * features - {Array({})} or\n- * {}\n- * options - {Object} Optional object for configuring the request.\n- *\n- * Returns:\n- * {} An \n- * object, the same object will be passed to the callback function passed\n- * if one exists in the options object.\n- */\n- update: function() {},\n-\n- /**\n- * APIMethod: delete\n- * Construct a request deleting a removed feature.\n- *\n- * Parameters:\n- * feature - {}\n- * options - {Object} Optional object for configuring the request.\n- *\n- * Returns:\n- * {} An \n- * object, the same object will be passed to the callback function passed\n- * if one exists in the options object.\n- */\n- \"delete\": function() {},\n-\n- /**\n- * APIMethod: commit\n- * Go over the features and for each take action\n- * based on the feature state. Possible actions are create,\n- * update and delete.\n- *\n- * Parameters:\n- * features - {Array({})}\n- * options - {Object} Object whose possible keys are \"create\", \"update\",\n- * \"delete\", \"callback\" and \"scope\", the values referenced by the\n- * first three are objects as passed to the \"create\", \"update\", and\n- * \"delete\" methods, the value referenced by the \"callback\" key is\n- * a function which is called when the commit operation is complete\n- * using the scope referenced by the \"scope\" key.\n- *\n- * Returns:\n- * {Array({})} An array of\n- * objects.\n- */\n- commit: function() {},\n-\n- /**\n- * Method: abort\n- * Abort an ongoing request.\n- *\n- * Parameters:\n- * response - {}\n- */\n- abort: function(response) {},\n-\n- /**\n- * Method: createCallback\n- * Returns a function that applies the given public method with resp and\n- * options arguments.\n- *\n- * Parameters:\n- * method - {Function} The method to be applied by the callback.\n- * response - {} The protocol response object.\n- * options - {Object} Options sent to the protocol method\n- */\n- createCallback: function(method, response, options) {\n- return OpenLayers.Function.bind(function() {\n- method.apply(this, [response, options]);\n- }, this);\n- },\n-\n- CLASS_NAME: \"OpenLayers.Protocol\"\n-});\n-\n-/**\n- * Class: OpenLayers.Protocol.Response\n- * Protocols return Response objects to their users.\n- */\n-OpenLayers.Protocol.Response = OpenLayers.Class({\n- /**\n- * Property: code\n- * {Number} - OpenLayers.Protocol.Response.SUCCESS or\n- * OpenLayers.Protocol.Response.FAILURE\n- */\n- code: null,\n-\n- /**\n- * Property: requestType\n- * {String} The type of request this response corresponds to. Either\n- * \"create\", \"read\", \"update\" or \"delete\".\n- */\n- requestType: null,\n-\n- /**\n- * Property: last\n- * {Boolean} - true if this is the last response expected in a commit,\n- * false otherwise, defaults to true.\n- */\n- last: true,\n-\n- /**\n- * Property: features\n- * {Array({})} or {}\n- * The features returned in the response by the server. Depending on the \n- * protocol's read payload, either features or data will be populated.\n- */\n- features: null,\n-\n- /**\n- * Property: data\n- * {Object}\n- * The data returned in the response by the server. Depending on the \n- * protocol's read payload, either features or data will be populated.\n- */\n- data: null,\n-\n- /**\n- * Property: reqFeatures\n- * {Array({})} or {}\n- * The features provided by the user and placed in the request by the\n- * protocol.\n- */\n- reqFeatures: null,\n-\n- /**\n- * Property: priv\n- */\n- priv: null,\n-\n- /**\n- * Property: error\n- * {Object} The error object in case a service exception was encountered.\n- */\n- error: null,\n-\n- /**\n- * Constructor: OpenLayers.Protocol.Response\n- *\n- * Parameters:\n- * options - {Object} Optional object whose properties will be set on the\n- * instance.\n- */\n- initialize: function(options) {\n- OpenLayers.Util.extend(this, options);\n- },\n-\n- /**\n- * Method: success\n- *\n- * Returns:\n- * {Boolean} - true on success, false otherwise\n- */\n- success: function() {\n- return this.code > 0;\n- },\n-\n- CLASS_NAME: \"OpenLayers.Protocol.Response\"\n-});\n-\n-OpenLayers.Protocol.Response.SUCCESS = 1;\n-OpenLayers.Protocol.Response.FAILURE = 0;\n-/* ======================================================================\n- OpenLayers/Tween.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Animation.js\n- */\n-\n-/**\n- * Namespace: OpenLayers.Tween\n- */\n-OpenLayers.Tween = OpenLayers.Class({\n-\n- /**\n- * APIProperty: easing\n- * {(Function)} Easing equation used for the animation\n- * Defaultly set to OpenLayers.Easing.Expo.easeOut\n- */\n- easing: null,\n-\n- /**\n- * APIProperty: begin\n- * {Object} Values to start the animation with\n- */\n- begin: null,\n-\n- /**\n- * APIProperty: finish\n- * {Object} Values to finish the animation with\n- */\n- finish: null,\n-\n- /**\n- * APIProperty: duration\n- * {int} duration of the tween (number of steps)\n- */\n- duration: null,\n-\n- /**\n- * APIProperty: callbacks\n- * {Object} An object with start, eachStep and done properties whose values\n- * are functions to be call during the animation. They are passed the\n- * current computed value as argument.\n- */\n- callbacks: null,\n-\n- /**\n- * Property: time\n- * {int} Step counter\n- */\n- time: null,\n-\n- /**\n- * APIProperty: minFrameRate\n- * {Number} The minimum framerate for animations in frames per second. After\n- * each step, the time spent in the animation is compared to the calculated\n- * time at this frame rate. If the animation runs longer than the calculated\n- * time, the next step is skipped. Default is 30.\n- */\n- minFrameRate: null,\n-\n- /**\n- * Property: startTime\n- * {Number} The timestamp of the first execution step. Used for skipping\n- * frames\n- */\n- startTime: null,\n-\n- /**\n- * Property: animationId\n- * {int} Loop id returned by OpenLayers.Animation.start\n- */\n- animationId: null,\n-\n- /**\n- * Property: playing\n- * {Boolean} Tells if the easing is currently playing\n- */\n- playing: false,\n-\n- /** \n- * Constructor: OpenLayers.Tween\n- * Creates a Tween.\n- *\n- * Parameters:\n- * easing - {(Function)} easing function method to use\n- */\n- initialize: function(easing) {\n- this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut;\n- },\n-\n- /**\n- * APIMethod: start\n- * Plays the Tween, and calls the callback method on each step\n- * \n- * Parameters:\n- * begin - {Object} values to start the animation with\n- * finish - {Object} values to finish the animation with\n- * duration - {int} duration of the tween (number of steps)\n- * options - {Object} hash of options (callbacks (start, eachStep, done),\n- * minFrameRate)\n- */\n- start: function(begin, finish, duration, options) {\n- this.playing = true;\n- this.begin = begin;\n- this.finish = finish;\n- this.duration = duration;\n- this.callbacks = options.callbacks;\n- this.minFrameRate = options.minFrameRate || 30;\n- this.time = 0;\n- this.startTime = new Date().getTime();\n- OpenLayers.Animation.stop(this.animationId);\n- this.animationId = null;\n- if (this.callbacks && this.callbacks.start) {\n- this.callbacks.start.call(this, this.begin);\n- }\n- this.animationId = OpenLayers.Animation.start(\n- OpenLayers.Function.bind(this.play, this)\n- );\n- },\n-\n- /**\n- * APIMethod: stop\n- * Stops the Tween, and calls the done callback\n- * Doesn't do anything if animation is already finished\n- */\n- stop: function() {\n- if (!this.playing) {\n- return;\n- }\n-\n- if (this.callbacks && this.callbacks.done) {\n- this.callbacks.done.call(this, this.finish);\n- }\n- OpenLayers.Animation.stop(this.animationId);\n- this.animationId = null;\n- this.playing = false;\n- },\n-\n- /**\n- * Method: play\n- * Calls the appropriate easing method\n- */\n- play: function() {\n- var value = {};\n- for (var i in this.begin) {\n- var b = this.begin[i];\n- var f = this.finish[i];\n- if (b == null || f == null || isNaN(b) || isNaN(f)) {\n- throw new TypeError('invalid value for Tween');\n- }\n-\n- var c = f - b;\n- value[i] = this.easing.apply(this, [this.time, b, c, this.duration]);\n- }\n- this.time++;\n-\n- if (this.callbacks && this.callbacks.eachStep) {\n- // skip frames if frame rate drops below threshold\n- if ((new Date().getTime() - this.startTime) / this.time <= 1000 / this.minFrameRate) {\n- this.callbacks.eachStep.call(this, value);\n- }\n- }\n-\n- if (this.time > this.duration) {\n- this.stop();\n- }\n- },\n-\n- /**\n- * Create empty functions for all easing methods.\n- */\n- CLASS_NAME: \"OpenLayers.Tween\"\n-});\n-\n-/**\n- * Namespace: OpenLayers.Easing\n- * \n- * Credits:\n- * Easing Equations by Robert Penner, \n- */\n-OpenLayers.Easing = {\n- /**\n- * Create empty functions for all easing methods.\n- */\n- CLASS_NAME: \"OpenLayers.Easing\"\n-};\n-\n-/**\n- * Namespace: OpenLayers.Easing.Linear\n- */\n-OpenLayers.Easing.Linear = {\n-\n- /**\n- * Function: easeIn\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeIn: function(t, b, c, d) {\n- return c * t / d + b;\n- },\n-\n- /**\n- * Function: easeOut\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeOut: function(t, b, c, d) {\n- return c * t / d + b;\n- },\n-\n- /**\n- * Function: easeInOut\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeInOut: function(t, b, c, d) {\n- return c * t / d + b;\n- },\n-\n- CLASS_NAME: \"OpenLayers.Easing.Linear\"\n-};\n-\n-/**\n- * Namespace: OpenLayers.Easing.Expo\n- */\n-OpenLayers.Easing.Expo = {\n-\n- /**\n- * Function: easeIn\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeIn: function(t, b, c, d) {\n- return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;\n- },\n-\n- /**\n- * Function: easeOut\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeOut: function(t, b, c, d) {\n- return (t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;\n- },\n-\n- /**\n- * Function: easeInOut\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeInOut: function(t, b, c, d) {\n- if (t == 0) return b;\n- if (t == d) return b + c;\n- if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b;\n- return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;\n- },\n-\n- CLASS_NAME: \"OpenLayers.Easing.Expo\"\n-};\n-\n-/**\n- * Namespace: OpenLayers.Easing.Quad\n- */\n-OpenLayers.Easing.Quad = {\n-\n- /**\n- * Function: easeIn\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeIn: function(t, b, c, d) {\n- return c * (t /= d) * t + b;\n- },\n-\n- /**\n- * Function: easeOut\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeOut: function(t, b, c, d) {\n- return -c * (t /= d) * (t - 2) + b;\n- },\n-\n- /**\n- * Function: easeInOut\n- * \n- * Parameters:\n- * t - {Float} time\n- * b - {Float} beginning position\n- * c - {Float} total change\n- * d - {Float} duration of the transition\n- *\n- * Returns:\n- * {Float}\n- */\n- easeInOut: function(t, b, c, d) {\n- if ((t /= d / 2) < 1) return c / 2 * t * t + b;\n- return -c / 2 * ((--t) * (t - 2) - 1) + b;\n- },\n-\n- CLASS_NAME: \"OpenLayers.Easing.Quad\"\n-};\n-/* ======================================================================\n- OpenLayers/Projection.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Util.js\n- */\n-\n-/**\n- * Namespace: OpenLayers.Projection\n- * Methods for coordinate transforms between coordinate systems. By default,\n- * OpenLayers ships with the ability to transform coordinates between\n- * geographic (EPSG:4326) and web or spherical mercator (EPSG:900913 et al.)\n- * coordinate reference systems. See the method for details\n- * on usage.\n- *\n- * Additional transforms may be added by using the \n- * library. If the proj4js library is included, the method \n- * will work between any two coordinate reference systems with proj4js \n- * definitions.\n- *\n- * If the proj4js library is not included, or if you wish to allow transforms\n- * between arbitrary coordinate reference systems, use the \n- * method to register a custom transform method.\n- */\n-OpenLayers.Projection = OpenLayers.Class({\n-\n- /**\n- * Property: proj\n- * {Object} Proj4js.Proj instance.\n- */\n- proj: null,\n-\n- /**\n- * Property: projCode\n- * {String}\n- */\n- projCode: null,\n-\n- /**\n- * Property: titleRegEx\n- * {RegExp} regular expression to strip the title from a proj4js definition\n- */\n- titleRegEx: /\\+title=[^\\+]*/,\n-\n- /**\n- * Constructor: OpenLayers.Projection\n- * This class offers several methods for interacting with a wrapped \n- * pro4js projection object. \n- *\n- * Parameters:\n- * projCode - {String} A string identifying the Well Known Identifier for\n- * the projection.\n- * options - {Object} An optional object to set additional properties\n- * on the projection.\n- *\n- * Returns:\n- * {} A projection object.\n- */\n- initialize: function(projCode, options) {\n- OpenLayers.Util.extend(this, options);\n- this.projCode = projCode;\n- if (typeof Proj4js == \"object\") {\n- this.proj = new Proj4js.Proj(projCode);\n- }\n- },\n-\n- /**\n- * APIMethod: getCode\n- * Get the string SRS code.\n- *\n- * Returns:\n- * {String} The SRS code.\n- */\n- getCode: function() {\n- return this.proj ? this.proj.srsCode : this.projCode;\n- },\n-\n- /**\n- * APIMethod: getUnits\n- * Get the units string for the projection -- returns null if \n- * proj4js is not available.\n- *\n- * Returns:\n- * {String} The units abbreviation.\n- */\n- getUnits: function() {\n- return this.proj ? this.proj.units : null;\n- },\n-\n- /**\n- * Method: toString\n- * Convert projection to string (getCode wrapper).\n- *\n- * Returns:\n- * {String} The projection code.\n- */\n- toString: function() {\n- return this.getCode();\n- },\n-\n- /**\n- * Method: equals\n- * Test equality of two projection instances. Determines equality based\n- * soley on the projection code.\n- *\n- * Returns:\n- * {Boolean} The two projections are equivalent.\n- */\n- equals: function(projection) {\n- var p = projection,\n- equals = false;\n- if (p) {\n- if (!(p instanceof OpenLayers.Projection)) {\n- p = new OpenLayers.Projection(p);\n- }\n- if ((typeof Proj4js == \"object\") && this.proj.defData && p.proj.defData) {\n- equals = this.proj.defData.replace(this.titleRegEx, \"\") ==\n- p.proj.defData.replace(this.titleRegEx, \"\");\n- } else if (p.getCode) {\n- var source = this.getCode(),\n- target = p.getCode();\n- equals = source == target ||\n- !!OpenLayers.Projection.transforms[source] &&\n- OpenLayers.Projection.transforms[source][target] ===\n- OpenLayers.Projection.nullTransform;\n- }\n- }\n- return equals;\n- },\n-\n- /* Method: destroy\n- * Destroy projection object.\n- */\n- destroy: function() {\n- delete this.proj;\n- delete this.projCode;\n- },\n-\n- CLASS_NAME: \"OpenLayers.Projection\"\n-});\n-\n-/**\n- * Property: transforms\n- * {Object} Transforms is an object, with from properties, each of which may\n- * have a to property. This allows you to define projections without \n- * requiring support for proj4js to be included.\n- *\n- * This object has keys which correspond to a 'source' projection object. The\n- * keys should be strings, corresponding to the projection.getCode() value.\n- * Each source projection object should have a set of destination projection\n- * keys included in the object. \n- * \n- * Each value in the destination object should be a transformation function,\n- * where the function is expected to be passed an object with a .x and a .y\n- * property. The function should return the object, with the .x and .y\n- * transformed according to the transformation function.\n- *\n- * Note - Properties on this object should not be set directly. To add a\n- * transform method to this object, use the method. For an\n- * example of usage, see the OpenLayers.Layer.SphericalMercator file.\n- */\n-OpenLayers.Projection.transforms = {};\n-\n-/**\n- * APIProperty: defaults\n- * {Object} Defaults for the SRS codes known to OpenLayers (currently\n- * EPSG:4326, CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, EPSG:900913, EPSG:3857,\n- * EPSG:102113 and EPSG:102100). Keys are the SRS code, values are units,\n- * maxExtent (the validity extent for the SRS) and yx (true if this SRS is\n- * known to have a reverse axis order).\n- */\n-OpenLayers.Projection.defaults = {\n- \"EPSG:4326\": {\n- units: \"degrees\",\n- maxExtent: [-180, -90, 180, 90],\n- yx: true\n- },\n- \"CRS:84\": {\n- units: \"degrees\",\n- maxExtent: [-180, -90, 180, 90]\n- },\n- \"EPSG:900913\": {\n- units: \"m\",\n- maxExtent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34]\n- }\n-};\n-\n-/**\n- * APIMethod: addTransform\n- * Set a custom transform method between two projections. Use this method in\n- * cases where the proj4js lib is not available or where custom projections\n- * need to be handled.\n- *\n- * Parameters:\n- * from - {String} The code for the source projection\n- * to - {String} the code for the destination projection\n- * method - {Function} A function that takes a point as an argument and\n- * transforms that point from the source to the destination projection\n- * in place. The original point should be modified.\n- */\n-OpenLayers.Projection.addTransform = function(from, to, method) {\n- if (method === OpenLayers.Projection.nullTransform) {\n- var defaults = OpenLayers.Projection.defaults[from];\n- if (defaults && !OpenLayers.Projection.defaults[to]) {\n- OpenLayers.Projection.defaults[to] = defaults;\n- }\n- }\n- if (!OpenLayers.Projection.transforms[from]) {\n- OpenLayers.Projection.transforms[from] = {};\n- }\n- OpenLayers.Projection.transforms[from][to] = method;\n-};\n-\n-/**\n- * APIMethod: transform\n- * Transform a point coordinate from one projection to another. Note that\n- * the input point is transformed in place.\n- * \n- * Parameters:\n- * point - { | Object} An object with x and y\n- * properties representing coordinates in those dimensions.\n- * source - {OpenLayers.Projection} Source map coordinate system\n- * dest - {OpenLayers.Projection} Destination map coordinate system\n- *\n- * Returns:\n- * point - {object} A transformed coordinate. The original point is modified.\n- */\n-OpenLayers.Projection.transform = function(point, source, dest) {\n- if (source && dest) {\n- if (!(source instanceof OpenLayers.Projection)) {\n- source = new OpenLayers.Projection(source);\n- }\n- if (!(dest instanceof OpenLayers.Projection)) {\n- dest = new OpenLayers.Projection(dest);\n- }\n- if (source.proj && dest.proj) {\n- point = Proj4js.transform(source.proj, dest.proj, point);\n- } else {\n- var sourceCode = source.getCode();\n- var destCode = dest.getCode();\n- var transforms = OpenLayers.Projection.transforms;\n- if (transforms[sourceCode] && transforms[sourceCode][destCode]) {\n- transforms[sourceCode][destCode](point);\n- }\n- }\n- }\n- return point;\n-};\n-\n-/**\n- * APIFunction: nullTransform\n- * A null transformation - useful for defining projection aliases when\n- * proj4js is not available:\n- *\n- * (code)\n- * OpenLayers.Projection.addTransform(\"EPSG:3857\", \"EPSG:900913\",\n- * OpenLayers.Projection.nullTransform);\n- * OpenLayers.Projection.addTransform(\"EPSG:900913\", \"EPSG:3857\",\n- * OpenLayers.Projection.nullTransform);\n- * (end)\n- */\n-OpenLayers.Projection.nullTransform = function(point) {\n- return point;\n-};\n-\n-/**\n- * Note: Transforms for web mercator <-> geographic\n- * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113 and EPSG:102100.\n- * OpenLayers originally started referring to EPSG:900913 as web mercator.\n- * The EPSG has declared EPSG:3857 to be web mercator.\n- * ArcGIS 10 recognizes the EPSG:3857, EPSG:102113, and EPSG:102100 as\n- * 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.\n- * For geographic, OpenLayers recognizes EPSG:4326, CRS:84 and\n- * urn:ogc:def:crs:EPSG:6.6:4326. OpenLayers also knows about the reverse axis\n- * order for EPSG:4326. \n- */\n-(function() {\n-\n- var pole = 20037508.34;\n-\n- function inverseMercator(xy) {\n- xy.x = 180 * xy.x / pole;\n- xy.y = 180 / Math.PI * (2 * Math.atan(Math.exp((xy.y / pole) * Math.PI)) - Math.PI / 2);\n- return xy;\n- }\n-\n- function forwardMercator(xy) {\n- xy.x = xy.x * pole / 180;\n- var y = Math.log(Math.tan((90 + xy.y) * Math.PI / 360)) / Math.PI * pole;\n- xy.y = Math.max(-20037508.34, Math.min(y, 20037508.34));\n- return xy;\n- }\n-\n- function map(base, codes) {\n- var add = OpenLayers.Projection.addTransform;\n- var same = OpenLayers.Projection.nullTransform;\n- var i, len, code, other, j;\n- for (i = 0, len = codes.length; i < len; ++i) {\n- code = codes[i];\n- add(base, code, forwardMercator);\n- add(code, base, inverseMercator);\n- for (j = i + 1; j < len; ++j) {\n- other = codes[j];\n- add(code, other, same);\n- add(other, code, same);\n- }\n- }\n- }\n-\n- // list of equivalent codes for web mercator\n- var mercator = [\"EPSG:900913\", \"EPSG:3857\", \"EPSG:102113\", \"EPSG:102100\"],\n- geographic = [\"CRS:84\", \"urn:ogc:def:crs:EPSG:6.6:4326\", \"EPSG:4326\"],\n- i;\n- for (i = mercator.length - 1; i >= 0; --i) {\n- map(mercator[i], geographic);\n- }\n- for (i = geographic.length - 1; i >= 0; --i) {\n- map(geographic[i], mercator);\n- }\n-\n-})();\n-/* ======================================================================\n- OpenLayers/Map.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Util.js\n- * @requires OpenLayers/Util/vendorPrefix.js\n- * @requires OpenLayers/Events.js\n- * @requires OpenLayers/Tween.js\n- * @requires OpenLayers/Projection.js\n- */\n-\n-/**\n- * Class: OpenLayers.Map\n- * Instances of OpenLayers.Map are interactive maps embedded in a web page.\n- * Create a new map with the constructor.\n- * \n- * On their own maps do not provide much functionality. To extend a map\n- * it's necessary to add controls () and \n- * layers () to the map. \n- */\n-OpenLayers.Map = OpenLayers.Class({\n-\n- /**\n- * Constant: Z_INDEX_BASE\n- * {Object} Base z-indexes for different classes of thing \n- */\n- Z_INDEX_BASE: {\n- BaseLayer: 100,\n- Overlay: 325,\n- Feature: 725,\n- Popup: 750,\n- Control: 1000\n- },\n-\n- /**\n- * APIProperty: events\n- * {}\n- *\n- * Register a listener for a particular event with the following syntax:\n- * (code)\n- * map.events.register(type, obj, listener);\n- * (end)\n- *\n- * Listeners will be called with a reference to an event object. The\n- * properties of this event depends on exactly what happened.\n- *\n- * All event objects have at least the following properties:\n- * object - {Object} A reference to map.events.object.\n- * element - {DOMElement} A reference to map.events.element.\n- *\n- * Browser events have the following additional properties:\n- * xy - {} The pixel location of the event (relative\n- * to the the map viewport).\n- *\n- * Supported map event types:\n- * preaddlayer - triggered before a layer has been added. The event\n- * object will include a *layer* property that references the layer \n- * to be added. When a listener returns \"false\" the adding will be \n- * aborted.\n- * addlayer - triggered after a layer has been added. The event object\n- * will include a *layer* property that references the added layer.\n- * preremovelayer - triggered before a layer has been removed. The event\n- * object will include a *layer* property that references the layer \n- * to be removed. When a listener returns \"false\" the removal will be \n- * aborted.\n- * removelayer - triggered after a layer has been removed. The event\n- * object will include a *layer* property that references the removed\n- * layer.\n- * changelayer - triggered after a layer name change, order change,\n- * opacity change, params change, visibility change (actual visibility,\n- * not the layer's visibility property) or attribution change (due to\n- * extent change). Listeners will receive an event object with *layer*\n- * and *property* properties. The *layer* property will be a reference\n- * to the changed layer. The *property* property will be a key to the\n- * changed property (name, order, opacity, params, visibility or\n- * attribution).\n- * movestart - triggered after the start of a drag, pan, or zoom. The event\n- * object may include a *zoomChanged* property that tells whether the\n- * zoom has changed.\n- * move - triggered after each drag, pan, or zoom\n- * moveend - triggered after a drag, pan, or zoom completes\n- * zoomend - triggered after a zoom completes\n- * mouseover - triggered after mouseover the map\n- * mouseout - triggered after mouseout the map\n- * mousemove - triggered after mousemove the map\n- * changebaselayer - triggered after the base layer changes\n- * updatesize - triggered after the method was executed\n- */\n-\n- /**\n- * Property: id\n- * {String} Unique identifier for the map\n- */\n- id: null,\n-\n- /**\n- * Property: fractionalZoom\n- * {Boolean} For a base layer that supports it, allow the map resolution\n- * to be set to a value between one of the values in the resolutions\n- * array. Default is false.\n- *\n- * When fractionalZoom is set to true, it is possible to zoom to\n- * an arbitrary extent. This requires a base layer from a source\n- * that supports requests for arbitrary extents (i.e. not cached\n- * tiles on a regular lattice). This means that fractionalZoom\n- * will not work with commercial layers (Google, Yahoo, VE), layers\n- * using TileCache, or any other pre-cached data sources.\n- *\n- * If you are using fractionalZoom, then you should also use\n- * instead of layer.resolutions[zoom] as the\n- * former works for non-integer zoom levels.\n- */\n- fractionalZoom: false,\n-\n- /**\n- * APIProperty: events\n- * {} An events object that handles all \n- * events on the map\n- */\n- events: null,\n-\n- /**\n- * APIProperty: allOverlays\n- * {Boolean} Allow the map to function with \"overlays\" only. Defaults to\n- * false. If true, the lowest layer in the draw order will act as\n- * the base layer. In addition, if set to true, all layers will\n- * have isBaseLayer set to false when they are added to the map.\n- *\n- * Note:\n- * If you set map.allOverlays to true, then you *cannot* use\n- * map.setBaseLayer or layer.setIsBaseLayer. With allOverlays true,\n- * the lowest layer in the draw layer is the base layer. So, to change\n- * the base layer, use or to set the layer\n- * index to 0.\n- */\n- allOverlays: false,\n-\n- /**\n- * APIProperty: div\n- * {DOMElement|String} The element that contains the map (or an id for\n- * that element). If the constructor is called\n- * with two arguments, this should be provided as the first argument.\n- * Alternatively, the map constructor can be called with the options\n- * object as the only argument. In this case (one argument), a\n- * div property may or may not be provided. If the div property\n- * is not provided, the map can be rendered to a container later\n- * using the method.\n- * \n- * Note:\n- * If you are calling after map construction, do not use\n- * auto. Instead, divide your by your\n- * maximum expected dimension.\n- */\n- div: null,\n-\n- /**\n- * Property: dragging\n- * {Boolean} The map is currently being dragged.\n- */\n- dragging: false,\n-\n- /**\n- * Property: size\n- * {} Size of the main div (this.div)\n- */\n- size: null,\n-\n- /**\n- * Property: viewPortDiv\n- * {HTMLDivElement} The element that represents the map viewport\n- */\n- viewPortDiv: null,\n-\n- /**\n- * Property: layerContainerOrigin\n- * {} The lonlat at which the later container was\n- * re-initialized (on-zoom)\n- */\n- layerContainerOrigin: null,\n-\n- /**\n- * Property: layerContainerDiv\n- * {HTMLDivElement} The element that contains the layers.\n- */\n- layerContainerDiv: null,\n-\n- /**\n- * APIProperty: layers\n- * {Array()} Ordered list of layers in the map\n- */\n- layers: null,\n-\n- /**\n- * APIProperty: controls\n- * {Array()} List of controls associated with the map.\n- *\n- * If not provided in the map options at construction, the map will\n- * by default be given the following controls if present in the build:\n- * - or \n- * - or \n- * - \n- * - \n- */\n- controls: null,\n-\n- /**\n- * Property: popups\n- * {Array()} List of popups associated with the map\n- */\n- popups: null,\n-\n- /**\n- * APIProperty: baseLayer\n- * {} The currently selected base layer. This determines\n- * min/max zoom level, projection, etc.\n- */\n- baseLayer: null,\n-\n- /**\n- * Property: center\n- * {} The current center of the map\n- */\n- center: null,\n-\n- /**\n- * Property: resolution\n- * {Float} The resolution of the map.\n- */\n- resolution: null,\n-\n- /**\n- * Property: zoom\n- * {Integer} The current zoom level of the map\n- */\n- zoom: 0,\n-\n- /**\n- * Property: panRatio\n- * {Float} The ratio of the current extent within\n- * which panning will tween.\n- */\n- panRatio: 1.5,\n-\n- /**\n- * APIProperty: options\n- * {Object} The options object passed to the class constructor. Read-only.\n- */\n- options: null,\n-\n- // Options\n-\n- /**\n- * APIProperty: tileSize\n- * {} Set in the map options to override the default tile\n- * size for this map.\n- */\n- tileSize: null,\n-\n- /**\n- * APIProperty: projection\n- * {String} Set in the map options to specify the default projection \n- * for layers added to this map. When using a projection other than EPSG:4326\n- * (CRS:84, Geographic) or EPSG:3857 (EPSG:900913, Web Mercator),\n- * also set maxExtent, maxResolution or resolutions. Default is \"EPSG:4326\".\n- * Note that the projection of the map is usually determined\n- * by that of the current baseLayer (see and ).\n- */\n- projection: \"EPSG:4326\",\n-\n- /**\n- * APIProperty: units\n- * {String} The map units. Possible values are 'degrees' (or 'dd'), 'm', \n- * 'ft', 'km', 'mi', 'inches'. Normally taken from the projection.\n- * Only required if both map and layers do not define a projection,\n- * or if they define a projection which does not define units\n- */\n- units: null,\n-\n- /**\n- * APIProperty: resolutions\n- * {Array(Float)} A list of map resolutions (map units per pixel) in \n- * descending order. If this is not set in the layer constructor, it \n- * will be set based on other resolution related properties \n- * (maxExtent, maxResolution, maxScale, etc.).\n- */\n- resolutions: null,\n-\n- /**\n- * APIProperty: maxResolution\n- * {Float} Required if you are not displaying the whole world on a tile\n- * with the size specified in .\n- */\n- maxResolution: null,\n-\n- /**\n- * APIProperty: minResolution\n- * {Float}\n- */\n- minResolution: null,\n-\n- /**\n- * APIProperty: maxScale\n- * {Float}\n- */\n- maxScale: null,\n-\n- /**\n- * APIProperty: minScale\n- * {Float}\n- */\n- minScale: null,\n-\n- /**\n- * APIProperty: maxExtent\n- * {|Array} If provided as an array, the array\n- * should consist of four values (left, bottom, right, top).\n- * The maximum extent for the map.\n- * Default depends on projection; if this is one of those defined in OpenLayers.Projection.defaults\n- * (EPSG:4326 or web mercator), maxExtent will be set to the value defined there;\n- * else, defaults to null.\n- * To restrict user panning and zooming of the map, use instead.\n- * The value for will change calculations for tile URLs.\n- */\n- maxExtent: null,\n-\n- /**\n- * APIProperty: minExtent\n- * {|Array} If provided as an array, the array\n- * should consist of four values (left, bottom, right, top).\n- * The minimum extent for the map. Defaults to null.\n- */\n- minExtent: null,\n-\n- /**\n- * APIProperty: restrictedExtent\n- * {|Array} If provided as an array, the array\n- * should consist of four values (left, bottom, right, top).\n- * Limit map navigation to this extent where possible.\n- * If a non-null restrictedExtent is set, panning will be restricted\n- * to the given bounds. In addition, zooming to a resolution that\n- * displays more than the restricted extent will center the map\n- * on the restricted extent. If you wish to limit the zoom level\n- * or resolution, use maxResolution.\n- */\n- restrictedExtent: null,\n-\n- /**\n- * APIProperty: numZoomLevels\n- * {Integer} Number of zoom levels for the map. Defaults to 16. Set a\n- * different value in the map options if needed.\n- */\n- numZoomLevels: 16,\n-\n- /**\n- * APIProperty: theme\n- * {String} Relative path to a CSS file from which to load theme styles.\n- * Specify null in the map options (e.g. {theme: null}) if you \n- * want to get cascading style declarations - by putting links to \n- * stylesheets or style declarations directly in your page.\n- */\n- theme: null,\n-\n- /** \n- * APIProperty: displayProjection\n- * {} Requires proj4js support for projections other\n- * than EPSG:4326 or EPSG:900913/EPSG:3857. Projection used by\n- * several controls to display data to user. If this property is set,\n- * it will be set on any control which has a null displayProjection\n- * property at the time the control is added to the map. \n- */\n- displayProjection: null,\n-\n- /**\n- * APIProperty: tileManager\n- * {|Object} By default, and if the build contains\n- * TileManager.js, the map will use the TileManager to queue image requests\n- * and to cache tile image elements. To create a map without a TileManager\n- * configure the map with tileManager: null. To create a TileManager with\n- * non-default options, supply the options instead or alternatively supply\n- * an instance of {}.\n- */\n-\n- /**\n- * APIProperty: fallThrough\n- * {Boolean} Should OpenLayers allow events on the map to fall through to\n- * other elements on the page, or should it swallow them? (#457)\n- * Default is to swallow.\n- */\n- fallThrough: false,\n-\n- /**\n- * APIProperty: autoUpdateSize\n- * {Boolean} Should OpenLayers automatically update the size of the map\n- * when the resize event is fired. Default is true.\n- */\n- autoUpdateSize: true,\n-\n- /**\n- * APIProperty: eventListeners\n- * {Object} If set as an option at construction, the eventListeners\n- * object will be registered with . Object\n- * structure must be a listeners object as shown in the example for\n- * the events.on method.\n- */\n- eventListeners: null,\n-\n- /**\n- * Property: panTween\n- * {} Animated panning tween object, see panTo()\n- */\n- panTween: null,\n-\n- /**\n- * APIProperty: panMethod\n- * {Function} The Easing function to be used for tweening. Default is\n- * OpenLayers.Easing.Expo.easeOut. Setting this to 'null' turns off\n- * animated panning.\n- */\n- panMethod: OpenLayers.Easing.Expo.easeOut,\n-\n- /**\n- * Property: panDuration\n- * {Integer} The number of steps to be passed to the\n- * OpenLayers.Tween.start() method when the map is\n- * panned.\n- * Default is 50.\n- */\n- panDuration: 50,\n-\n- /**\n- * Property: zoomTween\n- * {} Animated zooming tween object, see zoomTo()\n- */\n- zoomTween: null,\n-\n- /**\n- * APIProperty: zoomMethod\n- * {Function} The Easing function to be used for tweening. Default is\n- * OpenLayers.Easing.Quad.easeOut. Setting this to 'null' turns off\n- * animated zooming.\n- */\n- zoomMethod: OpenLayers.Easing.Quad.easeOut,\n-\n- /**\n- * Property: zoomDuration\n- * {Integer} The number of steps to be passed to the\n- * OpenLayers.Tween.start() method when the map is zoomed.\n- * Default is 20.\n- */\n- zoomDuration: 20,\n-\n- /**\n- * Property: paddingForPopups\n- * {} Outside margin of the popup. Used to prevent \n- * the popup from getting too close to the map border.\n- */\n- paddingForPopups: null,\n-\n- /**\n- * Property: layerContainerOriginPx\n- * {Object} Cached object representing the layer container origin (in pixels).\n- */\n- layerContainerOriginPx: null,\n-\n- /**\n- * Property: minPx\n- * {Object} An object with a 'x' and 'y' values that is the lower\n- * left of maxExtent in viewport pixel space.\n- * Used to verify in moveByPx that the new location we're moving to\n- * is valid. It is also used in the getLonLatFromViewPortPx function\n- * of Layer.\n- */\n- minPx: null,\n-\n- /**\n- * Property: maxPx\n- * {Object} An object with a 'x' and 'y' values that is the top\n- * right of maxExtent in viewport pixel space.\n- * Used to verify in moveByPx that the new location we're moving to\n- * is valid.\n- */\n- maxPx: null,\n-\n- /**\n- * Constructor: OpenLayers.Map\n- * Constructor for a new OpenLayers.Map instance. There are two possible\n- * ways to call the map constructor. See the examples below.\n- *\n- * Parameters:\n- * div - {DOMElement|String} The element or id of an element in your page\n- * that will contain the map. May be omitted if the
option is\n- * provided or if you intend to call the method later.\n- * options - {Object} Optional object with properties to tag onto the map.\n- *\n- * Valid options (in addition to the listed API properties):\n- * center - {|Array} The default initial center of the map.\n- * If provided as array, the first value is the x coordinate,\n- * and the 2nd value is the y coordinate.\n- * Only specify if is provided.\n- * Note that if an ArgParser/Permalink control is present,\n- * and the querystring contains coordinates, center will be set\n- * by that, and this option will be ignored.\n- * zoom - {Number} The initial zoom level for the map. Only specify if\n- * is provided.\n- * Note that if an ArgParser/Permalink control is present,\n- * and the querystring contains a zoom level, zoom will be set\n- * by that, and this option will be ignored.\n- * extent - {|Array} The initial extent of the map.\n- * If provided as an array, the array should consist of\n- * four values (left, bottom, right, top).\n- * Only specify if
and are not provided.\n- * \n- * Examples:\n- * (code)\n- * // create a map with default options in an element with the id \"map1\"\n- * var map = new OpenLayers.Map(\"map1\");\n- *\n- * // create a map with non-default options in an element with id \"map2\"\n- * var options = {\n- * projection: \"EPSG:3857\",\n- * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000),\n- * center: new OpenLayers.LonLat(-12356463.476333, 5621521.4854095)\n- * };\n- * var map = new OpenLayers.Map(\"map2\", options);\n- *\n- * // map with non-default options - same as above but with a single argument,\n- * // a restricted extent, and using arrays for bounds and center\n- * var map = new OpenLayers.Map({\n- * div: \"map_id\",\n- * projection: \"EPSG:3857\",\n- * maxExtent: [-18924313.432222, -15538711.094146, 18924313.432222, 15538711.094146],\n- * restrictedExtent: [-13358338.893333, -9608371.5085962, 13358338.893333, 9608371.5085962],\n- * center: [-12356463.476333, 5621521.4854095]\n- * });\n- *\n- * // create a map without a reference to a container - call render later\n- * var map = new OpenLayers.Map({\n- * projection: \"EPSG:3857\",\n- * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000)\n- * });\n- * (end)\n- */\n- initialize: function(div, options) {\n-\n- // If only one argument is provided, check if it is an object.\n- if (arguments.length === 1 && typeof div === \"object\") {\n- options = div;\n- div = options && options.div;\n- }\n-\n- // Simple-type defaults are set in class definition. \n- // Now set complex-type defaults \n- this.tileSize = new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,\n- OpenLayers.Map.TILE_HEIGHT);\n-\n- this.paddingForPopups = new OpenLayers.Bounds(15, 15, 15, 15);\n-\n- this.theme = OpenLayers._getScriptLocation() +\n- 'theme/default/style.css';\n-\n- // backup original options\n- this.options = OpenLayers.Util.extend({}, options);\n-\n- // now override default options \n- OpenLayers.Util.extend(this, options);\n-\n- var projCode = this.projection instanceof OpenLayers.Projection ?\n- this.projection.projCode : this.projection;\n- OpenLayers.Util.applyDefaults(this, OpenLayers.Projection.defaults[projCode]);\n-\n- // allow extents and center to be arrays\n- if (this.maxExtent && !(this.maxExtent instanceof OpenLayers.Bounds)) {\n- this.maxExtent = new OpenLayers.Bounds(this.maxExtent);\n- }\n- if (this.minExtent && !(this.minExtent instanceof OpenLayers.Bounds)) {\n- this.minExtent = new OpenLayers.Bounds(this.minExtent);\n- }\n- if (this.restrictedExtent && !(this.restrictedExtent instanceof OpenLayers.Bounds)) {\n- this.restrictedExtent = new OpenLayers.Bounds(this.restrictedExtent);\n- }\n- if (this.center && !(this.center instanceof OpenLayers.LonLat)) {\n- this.center = new OpenLayers.LonLat(this.center);\n- }\n-\n- // initialize layers array\n- this.layers = [];\n-\n- this.id = OpenLayers.Util.createUniqueID(\"OpenLayers.Map_\");\n-\n- this.div = OpenLayers.Util.getElement(div);\n- if (!this.div) {\n- this.div = document.createElement(\"div\");\n- this.div.style.height = \"1px\";\n- this.div.style.width = \"1px\";\n- }\n-\n- OpenLayers.Element.addClass(this.div, 'olMap');\n-\n- // the viewPortDiv is the outermost div we modify\n- var id = this.id + \"_OpenLayers_ViewPort\";\n- this.viewPortDiv = OpenLayers.Util.createDiv(id, null, null, null,\n- \"relative\", null,\n- \"hidden\");\n- this.viewPortDiv.style.width = \"100%\";\n- this.viewPortDiv.style.height = \"100%\";\n- this.viewPortDiv.className = \"olMapViewport\";\n- this.div.appendChild(this.viewPortDiv);\n-\n- this.events = new OpenLayers.Events(\n- this, this.viewPortDiv, null, this.fallThrough, {\n- includeXY: true\n- }\n- );\n-\n- if (OpenLayers.TileManager && this.tileManager !== null) {\n- if (!(this.tileManager instanceof OpenLayers.TileManager)) {\n- this.tileManager = new OpenLayers.TileManager(this.tileManager);\n- }\n- this.tileManager.addMap(this);\n- }\n-\n- // the layerContainerDiv is the one that holds all the layers\n- id = this.id + \"_OpenLayers_Container\";\n- this.layerContainerDiv = OpenLayers.Util.createDiv(id);\n- this.layerContainerDiv.style.zIndex = this.Z_INDEX_BASE['Popup'] - 1;\n- this.layerContainerOriginPx = {\n- x: 0,\n- y: 0\n- };\n- this.applyTransform();\n-\n- this.viewPortDiv.appendChild(this.layerContainerDiv);\n-\n- this.updateSize();\n- if (this.eventListeners instanceof Object) {\n- this.events.on(this.eventListeners);\n- }\n-\n- if (this.autoUpdateSize === true) {\n- // updateSize on catching the window's resize\n- // Note that this is ok, as updateSize() does nothing if the \n- // map's size has not actually changed.\n- this.updateSizeDestroy = OpenLayers.Function.bind(this.updateSize,\n- this);\n- OpenLayers.Event.observe(window, 'resize',\n- this.updateSizeDestroy);\n- }\n-\n- // only append link stylesheet if the theme property is set\n- if (this.theme) {\n- // check existing links for equivalent url\n- var addNode = true;\n- var nodes = document.getElementsByTagName('link');\n- for (var i = 0, len = nodes.length; i < len; ++i) {\n- if (OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,\n- this.theme)) {\n- addNode = false;\n- break;\n- }\n- }\n- // only add a new node if one with an equivalent url hasn't already\n- // been added\n- if (addNode) {\n- var cssNode = document.createElement('link');\n- cssNode.setAttribute('rel', 'stylesheet');\n- cssNode.setAttribute('type', 'text/css');\n- cssNode.setAttribute('href', this.theme);\n- document.getElementsByTagName('head')[0].appendChild(cssNode);\n- }\n- }\n-\n- if (this.controls == null) { // default controls\n- this.controls = [];\n- if (OpenLayers.Control != null) { // running full or lite?\n- // Navigation or TouchNavigation depending on what is in build\n- if (OpenLayers.Control.Navigation) {\n- this.controls.push(new OpenLayers.Control.Navigation());\n- } else if (OpenLayers.Control.TouchNavigation) {\n- this.controls.push(new OpenLayers.Control.TouchNavigation());\n- }\n- if (OpenLayers.Control.Zoom) {\n- this.controls.push(new OpenLayers.Control.Zoom());\n- } else if (OpenLayers.Control.PanZoom) {\n- this.controls.push(new OpenLayers.Control.PanZoom());\n- }\n-\n- if (OpenLayers.Control.ArgParser) {\n- this.controls.push(new OpenLayers.Control.ArgParser());\n- }\n- if (OpenLayers.Control.Attribution) {\n- this.controls.push(new OpenLayers.Control.Attribution());\n- }\n- }\n- }\n-\n- for (var i = 0, len = this.controls.length; i < len; i++) {\n- this.addControlToMap(this.controls[i]);\n- }\n-\n- this.popups = [];\n-\n- this.unloadDestroy = OpenLayers.Function.bind(this.destroy, this);\n-\n-\n- // always call map.destroy()\n- OpenLayers.Event.observe(window, 'unload', this.unloadDestroy);\n-\n- // add any initial layers\n- if (options && options.layers) {\n- /** \n- * If you have set options.center, the map center property will be\n- * set at this point. However, since setCenter has not been called,\n- * addLayers gets confused. So we delete the map center in this \n- * case. Because the check below uses options.center, it will\n- * be properly set below.\n- */\n- delete this.center;\n- delete this.zoom;\n- this.addLayers(options.layers);\n- // set center (and optionally zoom)\n- if (options.center && !this.getCenter()) {\n- // zoom can be undefined here\n- this.setCenter(options.center, options.zoom);\n- }\n- }\n-\n- if (this.panMethod) {\n- this.panTween = new OpenLayers.Tween(this.panMethod);\n- }\n- if (this.zoomMethod && this.applyTransform.transform) {\n- this.zoomTween = new OpenLayers.Tween(this.zoomMethod);\n- }\n- },\n-\n- /** \n- * APIMethod: getViewport\n- * Get the DOMElement representing the view port.\n- *\n- * Returns:\n- * {DOMElement}\n- */\n- getViewport: function() {\n- return this.viewPortDiv;\n- },\n-\n- /**\n- * APIMethod: render\n- * Render the map to a specified container.\n- * \n- * Parameters:\n- * div - {String|DOMElement} The container that the map should be rendered\n- * to. If different than the current container, the map viewport\n- * will be moved from the current to the new container.\n- */\n- render: function(div) {\n- this.div = OpenLayers.Util.getElement(div);\n- OpenLayers.Element.addClass(this.div, 'olMap');\n- this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);\n- this.div.appendChild(this.viewPortDiv);\n- this.updateSize();\n- },\n-\n- /**\n- * Method: unloadDestroy\n- * Function that is called to destroy the map on page unload. stored here\n- * so that if map is manually destroyed, we can unregister this.\n- */\n- unloadDestroy: null,\n-\n- /**\n- * Method: updateSizeDestroy\n- * When the map is destroyed, we need to stop listening to updateSize\n- * events: this method stores the function we need to unregister in \n- * non-IE browsers.\n- */\n- updateSizeDestroy: null,\n-\n- /**\n- * APIMethod: destroy\n- * Destroy this map.\n- * Note that if you are using an application which removes a container\n- * of the map from the DOM, you need to ensure that you destroy the\n- * map *before* this happens; otherwise, the page unload handler\n- * will fail because the DOM elements that map.destroy() wants\n- * to clean up will be gone. (See \n- * http://trac.osgeo.org/openlayers/ticket/2277 for more information).\n- * This will apply to GeoExt and also to other applications which\n- * modify the DOM of the container of the OpenLayers Map.\n- */\n- destroy: function() {\n- // if unloadDestroy is null, we've already been destroyed\n- if (!this.unloadDestroy) {\n- return false;\n- }\n-\n- // make sure panning doesn't continue after destruction\n- if (this.panTween) {\n- this.panTween.stop();\n- this.panTween = null;\n- }\n- // make sure zooming doesn't continue after destruction\n- if (this.zoomTween) {\n- this.zoomTween.stop();\n- this.zoomTween = null;\n- }\n-\n- // map has been destroyed. dont do it again!\n- OpenLayers.Event.stopObserving(window, 'unload', this.unloadDestroy);\n- this.unloadDestroy = null;\n-\n- if (this.updateSizeDestroy) {\n- OpenLayers.Event.stopObserving(window, 'resize',\n- this.updateSizeDestroy);\n- }\n-\n- this.paddingForPopups = null;\n-\n- if (this.controls != null) {\n- for (var i = this.controls.length - 1; i >= 0; --i) {\n- this.controls[i].destroy();\n- }\n- this.controls = null;\n- }\n- if (this.layers != null) {\n- for (var i = this.layers.length - 1; i >= 0; --i) {\n- //pass 'false' to destroy so that map wont try to set a new \n- // baselayer after each baselayer is removed\n- this.layers[i].destroy(false);\n- }\n- this.layers = null;\n- }\n- if (this.viewPortDiv && this.viewPortDiv.parentNode) {\n- this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);\n- }\n- this.viewPortDiv = null;\n-\n- if (this.tileManager) {\n- this.tileManager.removeMap(this);\n- this.tileManager = null;\n- }\n-\n- if (this.eventListeners) {\n- this.events.un(this.eventListeners);\n- this.eventListeners = null;\n- }\n- this.events.destroy();\n- this.events = null;\n-\n- this.options = null;\n- },\n-\n- /**\n- * APIMethod: setOptions\n- * Change the map options\n- *\n- * Parameters:\n- * options - {Object} Hashtable of options to tag to the map\n- */\n- setOptions: function(options) {\n- var updatePxExtent = this.minPx &&\n- options.restrictedExtent != this.restrictedExtent;\n- OpenLayers.Util.extend(this, options);\n- // force recalculation of minPx and maxPx\n- updatePxExtent && this.moveTo(this.getCachedCenter(), this.zoom, {\n- forceZoomChange: true\n- });\n- },\n-\n- /**\n- * APIMethod: getTileSize\n- * Get the tile size for the map\n- *\n- * Returns:\n- * {}\n- */\n- getTileSize: function() {\n- return this.tileSize;\n- },\n-\n-\n- /**\n- * APIMethod: getBy\n- * Get a list of objects given a property and a match item.\n- *\n- * Parameters:\n- * array - {String} A property on the map whose value is an array.\n- * property - {String} A property on each item of the given array.\n- * match - {String | Object} A string to match. Can also be a regular\n- * expression literal or object. In addition, it can be any object\n- * with a method named test. For reqular expressions or other, if\n- * match.test(map[array][i][property]) evaluates to true, the item will\n- * be included in the array returned. If no items are found, an empty\n- * array is returned.\n- *\n- * Returns:\n- * {Array} An array of items where the given property matches the given\n- * criteria.\n- */\n- getBy: function(array, property, match) {\n- var test = (typeof match.test == \"function\");\n- var found = OpenLayers.Array.filter(this[array], function(item) {\n- return item[property] == match || (test && match.test(item[property]));\n- });\n- return found;\n- },\n-\n- /**\n- * APIMethod: getLayersBy\n- * Get a list of layers with properties matching the given criteria.\n- *\n- * Parameters:\n- * property - {String} A layer property to be matched.\n- * match - {String | Object} A string to match. Can also be a regular\n- * expression literal or object. In addition, it can be any object\n- * with a method named test. For reqular expressions or other, if\n- * match.test(layer[property]) evaluates to true, the layer will be\n- * included in the array returned. If no layers are found, an empty\n- * array is returned.\n- *\n- * Returns:\n- * {Array()} A list of layers matching the given criteria.\n- * An empty array is returned if no matches are found.\n- */\n- getLayersBy: function(property, match) {\n- return this.getBy(\"layers\", property, match);\n- },\n-\n- /**\n- * APIMethod: getLayersByName\n- * Get a list of layers with names matching the given name.\n- *\n- * Parameters:\n- * match - {String | Object} A layer name. The name can also be a regular\n- * expression literal or object. In addition, it can be any object\n- * with a method named test. For reqular expressions or other, if\n- * name.test(layer.name) evaluates to true, the layer will be included\n- * in the list of layers returned. If no layers are found, an empty\n- * array is returned.\n- *\n- * Returns:\n- * {Array()} A list of layers matching the given name.\n- * An empty array is returned if no matches are found.\n- */\n- getLayersByName: function(match) {\n- return this.getLayersBy(\"name\", match);\n- },\n-\n- /**\n- * APIMethod: getLayersByClass\n- * Get a list of layers of a given class (CLASS_NAME).\n- *\n- * Parameters:\n- * match - {String | Object} A layer class name. The match can also be a\n- * regular expression literal or object. In addition, it can be any\n- * object with a method named test. For reqular expressions or other,\n- * if type.test(layer.CLASS_NAME) evaluates to true, the layer will\n- * be included in the list of layers returned. If no layers are\n- * found, an empty array is returned.\n- *\n- * Returns:\n- * {Array()} A list of layers matching the given class.\n- * An empty array is returned if no matches are found.\n- */\n- getLayersByClass: function(match) {\n- return this.getLayersBy(\"CLASS_NAME\", match);\n- },\n-\n- /**\n- * APIMethod: getControlsBy\n- * Get a list of controls with properties matching the given criteria.\n- *\n- * Parameters:\n- * property - {String} A control property to be matched.\n- * match - {String | Object} A string to match. Can also be a regular\n- * expression literal or object. In addition, it can be any object\n- * with a method named test. For reqular expressions or other, if\n- * match.test(layer[property]) evaluates to true, the layer will be\n- * included in the array returned. If no layers are found, an empty\n- * array is returned.\n- *\n- * Returns:\n- * {Array()} A list of controls matching the given\n- * criteria. An empty array is returned if no matches are found.\n- */\n- getControlsBy: function(property, match) {\n- return this.getBy(\"controls\", property, match);\n- },\n-\n- /**\n- * APIMethod: getControlsByClass\n- * Get a list of controls of a given class (CLASS_NAME).\n- *\n- * Parameters:\n- * match - {String | Object} A control class name. The match can also be a\n- * regular expression literal or object. In addition, it can be any\n- * object with a method named test. For reqular expressions or other,\n- * if type.test(control.CLASS_NAME) evaluates to true, the control will\n- * be included in the list of controls returned. If no controls are\n- * found, an empty array is returned.\n- *\n- * Returns:\n- * {Array()} A list of controls matching the given class.\n- * An empty array is returned if no matches are found.\n- */\n- getControlsByClass: function(match) {\n- return this.getControlsBy(\"CLASS_NAME\", match);\n- },\n-\n- /********************************************************/\n- /* */\n- /* Layer Functions */\n- /* */\n- /* The following functions deal with adding and */\n- /* removing Layers to and from the Map */\n- /* */\n- /********************************************************/\n-\n- /**\n- * APIMethod: getLayer\n- * Get a layer based on its id\n- *\n- * Parameters:\n- * id - {String} A layer id\n- *\n- * Returns:\n- * {} The Layer with the corresponding id from the map's \n- * layer collection, or null if not found.\n- */\n- getLayer: function(id) {\n- var foundLayer = null;\n- for (var i = 0, len = this.layers.length; i < len; i++) {\n- var layer = this.layers[i];\n- if (layer.id == id) {\n- foundLayer = layer;\n- break;\n- }\n- }\n- return foundLayer;\n- },\n-\n- /**\n- * Method: setLayerZIndex\n- * \n- * Parameters:\n- * layer - {} \n- * zIdx - {int} \n- */\n- setLayerZIndex: function(layer, zIdx) {\n- layer.setZIndex(\n- this.Z_INDEX_BASE[layer.isBaseLayer ? 'BaseLayer' : 'Overlay'] +\n- zIdx * 5);\n- },\n-\n- /**\n- * Method: resetLayersZIndex\n- * Reset each layer's z-index based on layer's array index\n- */\n- resetLayersZIndex: function() {\n- for (var i = 0, len = this.layers.length; i < len; i++) {\n- var layer = this.layers[i];\n- this.setLayerZIndex(layer, i);\n- }\n- },\n-\n- /**\n- * APIMethod: addLayer\n- *\n- * Parameters:\n- * layer - {} \n- *\n- * Returns:\n- * {Boolean} True if the layer has been added to the map.\n- */\n- addLayer: function(layer) {\n- for (var i = 0, len = this.layers.length; i < len; i++) {\n- if (this.layers[i] == layer) {\n- return false;\n- }\n- }\n- if (this.events.triggerEvent(\"preaddlayer\", {\n- layer: layer\n- }) === false) {\n- return false;\n- }\n- if (this.allOverlays) {\n- layer.isBaseLayer = false;\n- }\n-\n- layer.div.className = \"olLayerDiv\";\n- layer.div.style.overflow = \"\";\n- this.setLayerZIndex(layer, this.layers.length);\n-\n- if (layer.isFixed) {\n- this.viewPortDiv.appendChild(layer.div);\n- } else {\n- this.layerContainerDiv.appendChild(layer.div);\n- }\n- this.layers.push(layer);\n- layer.setMap(this);\n-\n- if (layer.isBaseLayer || (this.allOverlays && !this.baseLayer)) {\n- if (this.baseLayer == null) {\n- // set the first baselaye we add as the baselayer\n- this.setBaseLayer(layer);\n- } else {\n- layer.setVisibility(false);\n- }\n- } else {\n- layer.redraw();\n- }\n-\n- this.events.triggerEvent(\"addlayer\", {\n- layer: layer\n- });\n- layer.events.triggerEvent(\"added\", {\n- map: this,\n- layer: layer\n- });\n- layer.afterAdd();\n-\n- return true;\n- },\n-\n- /**\n- * APIMethod: addLayers \n- *\n- * Parameters:\n- * layers - {Array()} \n- */\n- addLayers: function(layers) {\n- for (var i = 0, len = layers.length; i < len; i++) {\n- this.addLayer(layers[i]);\n- }\n- },\n-\n- /** \n- * APIMethod: removeLayer\n- * Removes a layer from the map by removing its visual element (the \n- * layer.div property), then removing it from the map's internal list \n- * of layers, setting the layer's map property to null. \n- * \n- * a \"removelayer\" event is triggered.\n- * \n- * very worthy of mention is that simply removing a layer from a map\n- * will not cause the removal of any popups which may have been created\n- * by the layer. this is due to the fact that it was decided at some\n- * point that popups would not belong to layers. thus there is no way \n- * for us to know here to which layer the popup belongs.\n- * \n- * A simple solution to this is simply to call destroy() on the layer.\n- * the default OpenLayers.Layer class's destroy() function\n- * automatically takes care to remove itself from whatever map it has\n- * been attached to. \n- * \n- * The correct solution is for the layer itself to register an \n- * event-handler on \"removelayer\" and when it is called, if it \n- * recognizes itself as the layer being removed, then it cycles through\n- * its own personal list of popups, removing them from the map.\n- * \n- * Parameters:\n- * layer - {} \n- * setNewBaseLayer - {Boolean} Default is true\n- */\n- removeLayer: function(layer, setNewBaseLayer) {\n- if (this.events.triggerEvent(\"preremovelayer\", {\n- layer: layer\n- }) === false) {\n- return;\n- }\n- if (setNewBaseLayer == null) {\n- setNewBaseLayer = true;\n- }\n-\n- if (layer.isFixed) {\n- this.viewPortDiv.removeChild(layer.div);\n- } else {\n- this.layerContainerDiv.removeChild(layer.div);\n- }\n- OpenLayers.Util.removeItem(this.layers, layer);\n- layer.removeMap(this);\n- layer.map = null;\n-\n- // if we removed the base layer, need to set a new one\n- if (this.baseLayer == layer) {\n- this.baseLayer = null;\n- if (setNewBaseLayer) {\n- for (var i = 0, len = this.layers.length; i < len; i++) {\n- var iLayer = this.layers[i];\n- if (iLayer.isBaseLayer || this.allOverlays) {\n- this.setBaseLayer(iLayer);\n- break;\n- }\n- }\n- }\n- }\n-\n- this.resetLayersZIndex();\n-\n- this.events.triggerEvent(\"removelayer\", {\n- layer: layer\n- });\n- layer.events.triggerEvent(\"removed\", {\n- map: this,\n- layer: layer\n- });\n- },\n-\n- /**\n- * APIMethod: getNumLayers\n- * \n- * Returns:\n- * {Int} The number of layers attached to the map.\n- */\n- getNumLayers: function() {\n- return this.layers.length;\n- },\n-\n- /** \n- * APIMethod: getLayerIndex\n- *\n- * Parameters:\n- * layer - {}\n- *\n- * Returns:\n- * {Integer} The current (zero-based) index of the given layer in the map's\n- * layer stack. Returns -1 if the layer isn't on the map.\n- */\n- getLayerIndex: function(layer) {\n- return OpenLayers.Util.indexOf(this.layers, layer);\n- },\n-\n- /** \n- * APIMethod: setLayerIndex\n- * Move the given layer to the specified (zero-based) index in the layer\n- * list, changing its z-index in the map display. Use\n- * map.getLayerIndex() to find out the current index of a layer. Note\n- * that this cannot (or at least should not) be effectively used to\n- * raise base layers above overlays.\n- *\n- * Parameters:\n- * layer - {} \n- * idx - {int} \n- */\n- setLayerIndex: function(layer, idx) {\n- var base = this.getLayerIndex(layer);\n- if (idx < 0) {\n- idx = 0;\n- } else if (idx > this.layers.length) {\n- idx = this.layers.length;\n- }\n- if (base != idx) {\n- this.layers.splice(base, 1);\n- this.layers.splice(idx, 0, layer);\n- for (var i = 0, len = this.layers.length; i < len; i++) {\n- this.setLayerZIndex(this.layers[i], i);\n- }\n- this.events.triggerEvent(\"changelayer\", {\n- layer: layer,\n- property: \"order\"\n- });\n- if (this.allOverlays) {\n- if (idx === 0) {\n- this.setBaseLayer(layer);\n- } else if (this.baseLayer !== this.layers[0]) {\n- this.setBaseLayer(this.layers[0]);\n- }\n- }\n- }\n- },\n-\n- /** \n- * APIMethod: raiseLayer\n- * Change the index of the given layer by delta. If delta is positive, \n- * the layer is moved up the map's layer stack; if delta is negative,\n- * the layer is moved down. Again, note that this cannot (or at least\n- * should not) be effectively used to raise base layers above overlays.\n- *\n- * Paremeters:\n- * layer - {} \n- * delta - {int} \n- */\n- raiseLayer: function(layer, delta) {\n- var idx = this.getLayerIndex(layer) + delta;\n- this.setLayerIndex(layer, idx);\n- },\n-\n- /** \n- * APIMethod: setBaseLayer\n- * Allows user to specify one of the currently-loaded layers as the Map's\n- * new base layer.\n- * \n- * Parameters:\n- * newBaseLayer - {}\n- */\n- setBaseLayer: function(newBaseLayer) {\n-\n- if (newBaseLayer != this.baseLayer) {\n-\n- // ensure newBaseLayer is already loaded\n- if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) {\n-\n- // preserve center and scale when changing base layers\n- var center = this.getCachedCenter();\n- var newResolution = OpenLayers.Util.getResolutionFromScale(\n- this.getScale(), newBaseLayer.units\n- );\n-\n- // make the old base layer invisible \n- if (this.baseLayer != null && !this.allOverlays) {\n- this.baseLayer.setVisibility(false);\n- }\n-\n- // set new baselayer\n- this.baseLayer = newBaseLayer;\n-\n- if (!this.allOverlays || this.baseLayer.visibility) {\n- this.baseLayer.setVisibility(true);\n- // Layer may previously have been visible but not in range.\n- // In this case we need to redraw it to make it visible.\n- if (this.baseLayer.inRange === false) {\n- this.baseLayer.redraw();\n- }\n- }\n-\n- // recenter the map\n- if (center != null) {\n- // new zoom level derived from old scale\n- var newZoom = this.getZoomForResolution(\n- newResolution || this.resolution, true\n- );\n- // zoom and force zoom change\n- this.setCenter(center, newZoom, false, true);\n- }\n-\n- this.events.triggerEvent(\"changebaselayer\", {\n- layer: this.baseLayer\n- });\n- }\n- }\n- },\n-\n-\n- /********************************************************/\n- /* */\n- /* Control Functions */\n- /* */\n- /* The following functions deal with adding and */\n- /* removing Controls to and from the Map */\n- /* */\n- /********************************************************/\n-\n- /**\n- * APIMethod: addControl\n- * Add the passed over control to the map. Optionally \n- * position the control at the given pixel.\n- * \n- * Parameters:\n- * control - {}\n- * px - {}\n- */\n- addControl: function(control, px) {\n- this.controls.push(control);\n- this.addControlToMap(control, px);\n- },\n-\n- /**\n- * APIMethod: addControls\n- * Add all of the passed over controls to the map. \n- * You can pass over an optional second array\n- * with pixel-objects to position the controls.\n- * The indices of the two arrays should match and\n- * you can add null as pixel for those controls \n- * you want to be autopositioned. \n- * \n- * Parameters:\n- * controls - {Array()}\n- * pixels - {Array()}\n- */\n- addControls: function(controls, pixels) {\n- var pxs = (arguments.length === 1) ? [] : pixels;\n- for (var i = 0, len = controls.length; i < len; i++) {\n- var ctrl = controls[i];\n- var px = (pxs[i]) ? pxs[i] : null;\n- this.addControl(ctrl, px);\n- }\n- },\n-\n- /**\n- * Method: addControlToMap\n- * \n- * Parameters:\n- * \n- * control - {}\n- * px - {}\n- */\n- addControlToMap: function(control, px) {\n- // If a control doesn't have a div at this point, it belongs in the\n- // viewport.\n- control.outsideViewport = (control.div != null);\n-\n- // If the map has a displayProjection, and the control doesn't, set \n- // the display projection.\n- if (this.displayProjection && !control.displayProjection) {\n- control.displayProjection = this.displayProjection;\n- }\n-\n- control.setMap(this);\n- var div = control.draw(px);\n- if (div) {\n- if (!control.outsideViewport) {\n- div.style.zIndex = this.Z_INDEX_BASE['Control'] +\n- this.controls.length;\n- this.viewPortDiv.appendChild(div);\n- }\n- }\n- if (control.autoActivate) {\n- control.activate();\n- }\n- },\n-\n- /**\n- * APIMethod: getControl\n- * \n- * Parameters:\n- * id - {String} ID of the control to return.\n- * \n- * Returns:\n- * {} The control from the map's list of controls \n- * which has a matching 'id'. If none found, \n- * returns null.\n- */\n- getControl: function(id) {\n- var returnControl = null;\n- for (var i = 0, len = this.controls.length; i < len; i++) {\n- var control = this.controls[i];\n- if (control.id == id) {\n- returnControl = control;\n- break;\n- }\n- }\n- return returnControl;\n- },\n-\n- /** \n- * APIMethod: removeControl\n- * Remove a control from the map. Removes the control both from the map \n- * object's internal array of controls, as well as from the map's \n- * viewPort (assuming the control was not added outsideViewport)\n- * \n- * Parameters:\n- * control - {} The control to remove.\n- */\n- removeControl: function(control) {\n- //make sure control is non-null and actually part of our map\n- if ((control) && (control == this.getControl(control.id))) {\n- if (control.div && (control.div.parentNode == this.viewPortDiv)) {\n- this.viewPortDiv.removeChild(control.div);\n- }\n- OpenLayers.Util.removeItem(this.controls, control);\n- }\n- },\n-\n- /********************************************************/\n- /* */\n- /* Popup Functions */\n- /* */\n- /* The following functions deal with adding and */\n- /* removing Popups to and from the Map */\n- /* */\n- /********************************************************/\n-\n- /** \n- * APIMethod: addPopup\n- * \n- * Parameters:\n- * popup - {}\n- * exclusive - {Boolean} If true, closes all other popups first\n- */\n- addPopup: function(popup, exclusive) {\n-\n- if (exclusive) {\n- //remove all other popups from screen\n- for (var i = this.popups.length - 1; i >= 0; --i) {\n- this.removePopup(this.popups[i]);\n- }\n- }\n-\n- popup.map = this;\n- this.popups.push(popup);\n- var popupDiv = popup.draw();\n- if (popupDiv) {\n- popupDiv.style.zIndex = this.Z_INDEX_BASE['Popup'] +\n- this.popups.length;\n- this.layerContainerDiv.appendChild(popupDiv);\n- }\n- },\n-\n- /** \n- * APIMethod: removePopup\n- * \n- * Parameters:\n- * popup - {}\n- */\n- removePopup: function(popup) {\n- OpenLayers.Util.removeItem(this.popups, popup);\n- if (popup.div) {\n- try {\n- this.layerContainerDiv.removeChild(popup.div);\n- } catch (e) {} // Popups sometimes apparently get disconnected\n- // from the layerContainerDiv, and cause complaints.\n- }\n- popup.map = null;\n- },\n-\n- /********************************************************/\n- /* */\n- /* Container Div Functions */\n- /* */\n- /* The following functions deal with the access to */\n- /* and maintenance of the size of the container div */\n- /* */\n- /********************************************************/\n-\n- /**\n- * APIMethod: getSize\n- * \n- * Returns:\n- * {} An object that represents the \n- * size, in pixels, of the div into which OpenLayers \n- * has been loaded. \n- * Note - A clone() of this locally cached variable is\n- * returned, so as not to allow users to modify it.\n- */\n- getSize: function() {\n- var size = null;\n- if (this.size != null) {\n- size = this.size.clone();\n- }\n- return size;\n- },\n-\n- /**\n- * APIMethod: updateSize\n- * This function should be called by any external code which dynamically\n- * changes the size of the map div (because mozilla wont let us catch \n- * the \"onresize\" for an element)\n- */\n- updateSize: function() {\n- // the div might have moved on the page, also\n- var newSize = this.getCurrentSize();\n- if (newSize && !isNaN(newSize.h) && !isNaN(newSize.w)) {\n- this.events.clearMouseCache();\n- var oldSize = this.getSize();\n- if (oldSize == null) {\n- this.size = oldSize = newSize;\n- }\n- if (!newSize.equals(oldSize)) {\n-\n- // store the new size\n- this.size = newSize;\n-\n- //notify layers of mapresize\n- for (var i = 0, len = this.layers.length; i < len; i++) {\n- this.layers[i].onMapResize();\n- }\n-\n- var center = this.getCachedCenter();\n-\n- if (this.baseLayer != null && center != null) {\n- var zoom = this.getZoom();\n- this.zoom = null;\n- this.setCenter(center, zoom);\n- }\n-\n- }\n- }\n- this.events.triggerEvent(\"updatesize\");\n- },\n-\n- /**\n- * Method: getCurrentSize\n- * \n- * Returns:\n- * {} A new object with the dimensions \n- * of the map div\n- */\n- getCurrentSize: function() {\n-\n- var size = new OpenLayers.Size(this.div.clientWidth,\n- this.div.clientHeight);\n-\n- if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {\n- size.w = this.div.offsetWidth;\n- size.h = this.div.offsetHeight;\n- }\n- if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {\n- size.w = parseInt(this.div.style.width);\n- size.h = parseInt(this.div.style.height);\n- }\n- return size;\n- },\n-\n- /** \n- * Method: calculateBounds\n- * \n- * Parameters:\n- * center - {} Default is this.getCenter()\n- * resolution - {float} Default is this.getResolution() \n- * \n- * Returns:\n- * {} A bounds based on resolution, center, and \n- * current mapsize.\n- */\n- calculateBounds: function(center, resolution) {\n-\n- var extent = null;\n-\n- if (center == null) {\n- center = this.getCachedCenter();\n- }\n- if (resolution == null) {\n- resolution = this.getResolution();\n- }\n-\n- if ((center != null) && (resolution != null)) {\n- var halfWDeg = (this.size.w * resolution) / 2;\n- var halfHDeg = (this.size.h * resolution) / 2;\n-\n- extent = new OpenLayers.Bounds(center.lon - halfWDeg,\n- center.lat - halfHDeg,\n- center.lon + halfWDeg,\n- center.lat + halfHDeg);\n- }\n-\n- return extent;\n- },\n-\n-\n- /********************************************************/\n- /* */\n- /* Zoom, Center, Pan Functions */\n- /* */\n- /* The following functions handle the validation, */\n- /* getting and setting of the Zoom Level and Center */\n- /* as well as the panning of the Map */\n- /* */\n- /********************************************************/\n- /**\n- * APIMethod: getCenter\n- * \n- * Returns:\n- * {}\n- */\n- getCenter: function() {\n- var center = null;\n- var cachedCenter = this.getCachedCenter();\n- if (cachedCenter) {\n- center = cachedCenter.clone();\n- }\n- return center;\n- },\n-\n- /**\n- * Method: getCachedCenter\n- *\n- * Returns:\n- * {}\n- */\n- getCachedCenter: function() {\n- if (!this.center && this.size) {\n- this.center = this.getLonLatFromViewPortPx({\n- x: this.size.w / 2,\n- y: this.size.h / 2\n- });\n- }\n- return this.center;\n- },\n-\n- /**\n- * APIMethod: getZoom\n- * \n- * Returns:\n- * {Integer}\n+ * APIMethod: getZoom\n+ * \n+ * Returns:\n+ * {Integer}\n */\n getZoom: function() {\n return this.zoom;\n },\n \n /** \n * APIMethod: pan\n@@ -13114,1631 +9457,1815 @@\n OpenLayers.Map.TILE_WIDTH = 256;\n /**\n * Constant: TILE_HEIGHT\n * {Integer} 256 Default tile height (unless otherwise specified)\n */\n OpenLayers.Map.TILE_HEIGHT = 256;\n /* ======================================================================\n- OpenLayers/Layer.js\n+ OpenLayers/Renderer.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n-\n /**\n * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Map.js\n- * @requires OpenLayers/Projection.js\n */\n \n /**\n- * Class: OpenLayers.Layer\n+ * Class: OpenLayers.Renderer \n+ * This is the base class for all renderers.\n+ *\n+ * This is based on a merger code written by Paul Spencer and Bertil Chapuis.\n+ * It is largely composed of virtual functions that are to be implemented\n+ * in technology-specific subclasses, but there is some generic code too.\n+ * \n+ * The functions that *are* implemented here merely deal with the maintenance\n+ * of the size and extent variables, as well as the cached 'resolution' \n+ * value. \n+ * \n+ * A note to the user that all subclasses should use getResolution() instead\n+ * of directly accessing this.resolution in order to correctly use the \n+ * cacheing system.\n+ *\n */\n-OpenLayers.Layer = OpenLayers.Class({\n+OpenLayers.Renderer = OpenLayers.Class({\n \n- /**\n- * APIProperty: id\n- * {String}\n+ /** \n+ * Property: container\n+ * {DOMElement} \n */\n- id: null,\n+ container: null,\n \n- /** \n- * APIProperty: name\n- * {String}\n+ /**\n+ * Property: root\n+ * {DOMElement}\n */\n- name: null,\n+ root: null,\n \n /** \n- * APIProperty: div\n- * {DOMElement}\n+ * Property: extent\n+ * {}\n */\n- div: null,\n+ extent: null,\n \n /**\n- * APIProperty: opacity\n- * {Float} The layer's opacity. Float number between 0.0 and 1.0. Default\n- * is 1.\n+ * Property: locked\n+ * {Boolean} If the renderer is currently in a state where many things\n+ * are changing, the 'locked' property is set to true. This means \n+ * that renderers can expect at least one more drawFeature event to be\n+ * called with the 'locked' property set to 'true': In some renderers,\n+ * this might make sense to use as a 'only update local information'\n+ * flag. \n */\n- opacity: 1,\n+ locked: false,\n+\n+ /** \n+ * Property: size\n+ * {} \n+ */\n+ size: null,\n \n /**\n- * APIProperty: alwaysInRange\n- * {Boolean} If a layer's display should not be scale-based, this should \n- * be set to true. This will cause the layer, as an overlay, to always \n- * be 'active', by always returning true from the calculateInRange() \n- * function. \n- * \n- * If not explicitly specified for a layer, its value will be \n- * determined on startup in initResolutions() based on whether or not \n- * any scale-specific properties have been set as options on the \n- * layer. If no scale-specific options have been set on the layer, we \n- * assume that it should always be in range.\n- * \n- * See #987 for more info.\n+ * Property: resolution\n+ * {Float} cache of current map resolution\n */\n- alwaysInRange: null,\n+ resolution: null,\n \n /**\n- * Constant: RESOLUTION_PROPERTIES\n- * {Array} The properties that are used for calculating resolutions\n- * information.\n+ * Property: map \n+ * {} Reference to the map -- this is set in Vector's setMap()\n */\n- RESOLUTION_PROPERTIES: [\n- 'scales', 'resolutions',\n- 'maxScale', 'minScale',\n- 'maxResolution', 'minResolution',\n- 'numZoomLevels', 'maxZoomLevel'\n- ],\n+ map: null,\n \n /**\n- * APIProperty: events\n- * {}\n- *\n- * Register a listener for a particular event with the following syntax:\n- * (code)\n- * layer.events.register(type, obj, listener);\n- * (end)\n- *\n- * Listeners will be called with a reference to an event object. The\n- * properties of this event depends on exactly what happened.\n- *\n- * All event objects have at least the following properties:\n- * object - {Object} A reference to layer.events.object.\n- * element - {DOMElement} A reference to layer.events.element.\n- *\n- * Supported map event types:\n- * loadstart - Triggered when layer loading starts. When using a Vector \n- * layer with a Fixed or BBOX strategy, the event object includes \n- * a *filter* property holding the OpenLayers.Filter used when \n- * calling read on the protocol.\n- * loadend - Triggered when layer loading ends. When using a Vector layer\n- * with a Fixed or BBOX strategy, the event object includes a \n- * *response* property holding an OpenLayers.Protocol.Response object.\n- * visibilitychanged - Triggered when the layer's visibility property is\n- * changed, e.g. by turning the layer on or off in the layer switcher.\n- * Note that the actual visibility of the layer can also change if it\n- * gets out of range (see ). If you also want to catch\n- * these cases, register for the map's 'changelayer' event instead.\n- * move - Triggered when layer moves (triggered with every mousemove\n- * during a drag).\n- * moveend - Triggered when layer is done moving, object passed as\n- * argument has a zoomChanged boolean property which tells that the\n- * zoom has changed.\n- * added - Triggered after the layer is added to a map. Listeners will\n- * receive an object with a *map* property referencing the map and a\n- * *layer* property referencing the layer.\n- * removed - Triggered after the layer is removed from the map. Listeners\n- * will receive an object with a *map* property referencing the map and\n- * a *layer* property referencing the layer.\n+ * Property: featureDx\n+ * {Number} Feature offset in x direction. Will be calculated for and\n+ * applied to the current feature while rendering (see\n+ * ).\n */\n- events: null,\n+ featureDx: 0,\n \n /**\n- * APIProperty: map\n- * {} This variable is set when the layer is added to \n- * the map, via the accessor function setMap().\n+ * Constructor: OpenLayers.Renderer \n+ *\n+ * Parameters:\n+ * containerID - {} \n+ * options - {Object} options for this renderer. See sublcasses for\n+ * supported options.\n */\n- map: null,\n+ initialize: function(containerID, options) {\n+ this.container = OpenLayers.Util.getElement(containerID);\n+ OpenLayers.Util.extend(this, options);\n+ },\n \n /**\n- * APIProperty: isBaseLayer\n- * {Boolean} Whether or not the layer is a base layer. This should be set \n- * individually by all subclasses. Default is false\n+ * APIMethod: destroy\n */\n- isBaseLayer: false,\n+ destroy: function() {\n+ this.container = null;\n+ this.extent = null;\n+ this.size = null;\n+ this.resolution = null;\n+ this.map = null;\n+ },\n \n /**\n- * Property: alpha\n- * {Boolean} The layer's images have an alpha channel. Default is false.\n- */\n- alpha: false,\n-\n- /** \n- * APIProperty: displayInLayerSwitcher\n- * {Boolean} Display the layer's name in the layer switcher. Default is\n- * true.\n+ * APIMethod: supported\n+ * This should be overridden by specific subclasses\n+ * \n+ * Returns:\n+ * {Boolean} Whether or not the browser supports the renderer class\n */\n- displayInLayerSwitcher: true,\n+ supported: function() {\n+ return false;\n+ },\n \n /**\n- * APIProperty: visibility\n- * {Boolean} The layer should be displayed in the map. Default is true.\n+ * Method: setExtent\n+ * Set the visible part of the layer.\n+ *\n+ * Resolution has probably changed, so we nullify the resolution \n+ * cache (this.resolution) -- this way it will be re-computed when \n+ * next it is needed.\n+ * We nullify the resolution cache (this.resolution) if resolutionChanged\n+ * is set to true - this way it will be re-computed on the next\n+ * getResolution() request.\n+ *\n+ * Parameters:\n+ * extent - {}\n+ * resolutionChanged - {Boolean}\n+ *\n+ * Returns:\n+ * {Boolean} true to notify the layer that the new extent does not exceed\n+ * the coordinate range, and the features will not need to be redrawn.\n+ * False otherwise.\n */\n- visibility: true,\n+ setExtent: function(extent, resolutionChanged) {\n+ this.extent = extent.clone();\n+ if (this.map.baseLayer && this.map.baseLayer.wrapDateLine) {\n+ var ratio = extent.getWidth() / this.map.getExtent().getWidth(),\n+ extent = extent.scale(1 / ratio);\n+ this.extent = extent.wrapDateLine(this.map.getMaxExtent()).scale(ratio);\n+ }\n+ if (resolutionChanged) {\n+ this.resolution = null;\n+ }\n+ return true;\n+ },\n \n /**\n- * APIProperty: attribution\n- * {String} Attribution string, displayed when an \n- * has been added to the map.\n+ * Method: setSize\n+ * Sets the size of the drawing surface.\n+ * \n+ * Resolution has probably changed, so we nullify the resolution \n+ * cache (this.resolution) -- this way it will be re-computed when \n+ * next it is needed.\n+ *\n+ * Parameters:\n+ * size - {} \n */\n- attribution: null,\n+ setSize: function(size) {\n+ this.size = size.clone();\n+ this.resolution = null;\n+ },\n \n /** \n- * Property: inRange\n- * {Boolean} The current map resolution is within the layer's min/max \n- * range. This is set in whenever the zoom \n- * changes.\n+ * Method: getResolution\n+ * Uses cached copy of resolution if available to minimize computing\n+ * \n+ * Returns:\n+ * {Float} The current map's resolution\n */\n- inRange: false,\n+ getResolution: function() {\n+ this.resolution = this.resolution || this.map.getResolution();\n+ return this.resolution;\n+ },\n \n /**\n- * Propery: imageSize\n- * {} For layers with a gutter, the image is larger than \n- * the tile by twice the gutter in each dimension.\n+ * Method: drawFeature\n+ * Draw the feature. The optional style argument can be used\n+ * to override the feature's own style. This method should only\n+ * be called from layer.drawFeature().\n+ *\n+ * Parameters:\n+ * feature - {} \n+ * style - {}\n+ * \n+ * Returns:\n+ * {Boolean} true if the feature has been drawn completely, false if not,\n+ * undefined if the feature had no geometry\n */\n- imageSize: null,\n+ drawFeature: function(feature, style) {\n+ if (style == null) {\n+ style = feature.style;\n+ }\n+ if (feature.geometry) {\n+ var bounds = feature.geometry.getBounds();\n+ if (bounds) {\n+ var worldBounds;\n+ if (this.map.baseLayer && this.map.baseLayer.wrapDateLine) {\n+ worldBounds = this.map.getMaxExtent();\n+ }\n+ if (!bounds.intersectsBounds(this.extent, {\n+ worldBounds: worldBounds\n+ })) {\n+ style = {\n+ display: \"none\"\n+ };\n+ } else {\n+ this.calculateFeatureDx(bounds, worldBounds);\n+ }\n+ var rendered = this.drawGeometry(feature.geometry, style, feature.id);\n+ if (style.display != \"none\" && style.label && rendered !== false) {\n \n- // OPTIONS\n+ var location = feature.geometry.getCentroid();\n+ if (style.labelXOffset || style.labelYOffset) {\n+ var xOffset = isNaN(style.labelXOffset) ? 0 : style.labelXOffset;\n+ var yOffset = isNaN(style.labelYOffset) ? 0 : style.labelYOffset;\n+ var res = this.getResolution();\n+ location.move(xOffset * res, yOffset * res);\n+ }\n+ this.drawText(feature.id, style, location);\n+ } else {\n+ this.removeText(feature.id);\n+ }\n+ return rendered;\n+ }\n+ }\n+ },\n \n- /** \n- * Property: options\n- * {Object} An optional object whose properties will be set on the layer.\n- * Any of the layer properties can be set as a property of the options\n- * object and sent to the constructor when the layer is created.\n+ /**\n+ * Method: calculateFeatureDx\n+ * {Number} Calculates the feature offset in x direction. Looking at the\n+ * center of the feature bounds and the renderer extent, we calculate how\n+ * many world widths the two are away from each other. This distance is\n+ * used to shift the feature as close as possible to the center of the\n+ * current enderer extent, which ensures that the feature is visible in the\n+ * current viewport.\n+ *\n+ * Parameters:\n+ * bounds - {} Bounds of the feature\n+ * worldBounds - {} Bounds of the world\n */\n- options: null,\n+ calculateFeatureDx: function(bounds, worldBounds) {\n+ this.featureDx = 0;\n+ if (worldBounds) {\n+ var worldWidth = worldBounds.getWidth(),\n+ rendererCenterX = (this.extent.left + this.extent.right) / 2,\n+ featureCenterX = (bounds.left + bounds.right) / 2,\n+ worldsAway = Math.round((featureCenterX - rendererCenterX) / worldWidth);\n+ this.featureDx = worldsAway * worldWidth;\n+ }\n+ },\n \n- /**\n- * APIProperty: eventListeners\n- * {Object} If set as an option at construction, the eventListeners\n- * object will be registered with . Object\n- * structure must be a listeners object as shown in the example for\n- * the events.on method.\n+ /** \n+ * Method: drawGeometry\n+ * \n+ * Draw a geometry. This should only be called from the renderer itself.\n+ * Use layer.drawFeature() from outside the renderer.\n+ * virtual function\n+ *\n+ * Parameters:\n+ * geometry - {} \n+ * style - {Object} \n+ * featureId - {} \n */\n- eventListeners: null,\n+ drawGeometry: function(geometry, style, featureId) {},\n \n /**\n- * APIProperty: gutter\n- * {Integer} Determines the width (in pixels) of the gutter around image\n- * tiles to ignore. By setting this property to a non-zero value,\n- * images will be requested that are wider and taller than the tile\n- * size by a value of 2 x gutter. This allows artifacts of rendering\n- * at tile edges to be ignored. Set a gutter value that is equal to\n- * half the size of the widest symbol that needs to be displayed.\n- * Defaults to zero. Non-tiled layers always have zero gutter.\n+ * Method: drawText\n+ * Function for drawing text labels.\n+ * This method is only called by the renderer itself.\n+ * \n+ * Parameters: \n+ * featureId - {String}\n+ * style -\n+ * location - {}\n */\n- gutter: 0,\n+ drawText: function(featureId, style, location) {},\n \n /**\n- * APIProperty: projection\n- * {} or {} Specifies the projection of the layer.\n- * Can be set in the layer options. If not specified in the layer options,\n- * it is set to the default projection specified in the map,\n- * when the layer is added to the map.\n- * Projection along with default maxExtent and resolutions\n- * are set automatically with commercial baselayers in EPSG:3857,\n- * such as Google, Bing and OpenStreetMap, and do not need to be specified.\n- * Otherwise, if specifying projection, also set maxExtent,\n- * maxResolution or resolutions as appropriate.\n- * When using vector layers with strategies, layer projection should be set\n- * to the projection of the source data if that is different from the map default.\n- * \n- * Can be either a string or an object;\n- * if a string is passed, will be converted to an object when\n- * the layer is added to the map.\n+ * Method: removeText\n+ * Function for removing text labels.\n+ * This method is only called by the renderer itself.\n * \n+ * Parameters: \n+ * featureId - {String}\n */\n- projection: null,\n+ removeText: function(featureId) {},\n \n /**\n- * APIProperty: units\n- * {String} The layer map units. Defaults to null. Possible values\n- * are 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.\n- * Normally taken from the projection.\n- * Only required if both map and layers do not define a projection,\n- * or if they define a projection which does not define units.\n+ * Method: clear\n+ * Clear all vectors from the renderer.\n+ * virtual function.\n */\n- units: null,\n+ clear: function() {},\n \n /**\n- * APIProperty: scales\n- * {Array} An array of map scales in descending order. The values in the\n- * array correspond to the map scale denominator. Note that these\n- * values only make sense if the display (monitor) resolution of the\n- * client is correctly guessed by whomever is configuring the\n- * application. In addition, the units property must also be set.\n- * Use instead wherever possible.\n+ * Method: getFeatureIdFromEvent\n+ * Returns a feature id from an event on the renderer. \n+ * How this happens is specific to the renderer. This should be\n+ * called from layer.getFeatureFromEvent().\n+ * Virtual function.\n+ * \n+ * Parameters:\n+ * evt - {} \n+ *\n+ * Returns:\n+ * {String} A feature id or undefined.\n */\n- scales: null,\n+ getFeatureIdFromEvent: function(evt) {},\n \n /**\n- * APIProperty: resolutions\n- * {Array} A list of map resolutions (map units per pixel) in descending\n- * order. If this is not set in the layer constructor, it will be set\n- * based on other resolution related properties (maxExtent,\n- * maxResolution, maxScale, etc.).\n+ * Method: eraseFeatures \n+ * This is called by the layer to erase features\n+ * \n+ * Parameters:\n+ * features - {Array()} \n */\n- resolutions: null,\n+ eraseFeatures: function(features) {\n+ if (!(OpenLayers.Util.isArray(features))) {\n+ features = [features];\n+ }\n+ for (var i = 0, len = features.length; i < len; ++i) {\n+ var feature = features[i];\n+ this.eraseGeometry(feature.geometry, feature.id);\n+ this.removeText(feature.id);\n+ }\n+ },\n \n /**\n- * APIProperty: maxExtent\n- * {|Array} If provided as an array, the array\n- * should consist of four values (left, bottom, right, top).\n- * The maximum extent for the layer. Defaults to null.\n+ * Method: eraseGeometry\n+ * Remove a geometry from the renderer (by id).\n+ * virtual function.\n * \n- * The center of these bounds will not stray outside\n- * of the viewport extent during panning. In addition, if\n- * is set to false, data will not be\n- * requested that falls completely outside of these bounds.\n+ * Parameters:\n+ * geometry - {} \n+ * featureId - {String}\n */\n- maxExtent: null,\n+ eraseGeometry: function(geometry, featureId) {},\n \n /**\n- * APIProperty: minExtent\n- * {|Array} If provided as an array, the array\n- * should consist of four values (left, bottom, right, top).\n- * The minimum extent for the layer. Defaults to null.\n+ * Method: moveRoot\n+ * moves this renderer's root to a (different) renderer.\n+ * To be implemented by subclasses that require a common renderer root for\n+ * feature selection.\n+ * \n+ * Parameters:\n+ * renderer - {} target renderer for the moved root\n */\n- minExtent: null,\n+ moveRoot: function(renderer) {},\n \n /**\n- * APIProperty: maxResolution\n- * {Float} Default max is 360 deg / 256 px, which corresponds to\n- * zoom level 0 on gmaps. Specify a different value in the layer \n- * options if you are not using the default \n- * and displaying the whole world.\n+ * Method: getRenderLayerId\n+ * Gets the layer that this renderer's output appears on. If moveRoot was\n+ * used, this will be different from the id of the layer containing the\n+ * features rendered by this renderer.\n+ * \n+ * Returns:\n+ * {String} the id of the output layer.\n */\n- maxResolution: null,\n+ getRenderLayerId: function() {\n+ return this.container.id;\n+ },\n \n /**\n- * APIProperty: minResolution\n- * {Float}\n+ * Method: applyDefaultSymbolizer\n+ * \n+ * Parameters:\n+ * symbolizer - {Object}\n+ * \n+ * Returns:\n+ * {Object}\n */\n- minResolution: null,\n+ applyDefaultSymbolizer: function(symbolizer) {\n+ var result = OpenLayers.Util.extend({},\n+ OpenLayers.Renderer.defaultSymbolizer);\n+ if (symbolizer.stroke === false) {\n+ delete result.strokeWidth;\n+ delete result.strokeColor;\n+ }\n+ if (symbolizer.fill === false) {\n+ delete result.fillColor;\n+ }\n+ OpenLayers.Util.extend(result, symbolizer);\n+ return result;\n+ },\n \n- /**\n- * APIProperty: numZoomLevels\n- * {Integer}\n+ CLASS_NAME: \"OpenLayers.Renderer\"\n+});\n+\n+/**\n+ * Constant: OpenLayers.Renderer.defaultSymbolizer\n+ * {Object} Properties from this symbolizer will be applied to symbolizers\n+ * with missing properties. This can also be used to set a global\n+ * symbolizer default in OpenLayers. To be SLD 1.x compliant, add the\n+ * following code before rendering any vector features:\n+ * (code)\n+ * OpenLayers.Renderer.defaultSymbolizer = {\n+ * fillColor: \"#808080\",\n+ * fillOpacity: 1,\n+ * strokeColor: \"#000000\",\n+ * strokeOpacity: 1,\n+ * strokeWidth: 1,\n+ * pointRadius: 3,\n+ * graphicName: \"square\"\n+ * };\n+ * (end)\n+ */\n+OpenLayers.Renderer.defaultSymbolizer = {\n+ fillColor: \"#000000\",\n+ strokeColor: \"#000000\",\n+ strokeWidth: 2,\n+ fillOpacity: 1,\n+ strokeOpacity: 1,\n+ pointRadius: 0,\n+ labelAlign: 'cm'\n+};\n+\n+\n+\n+/**\n+ * Constant: OpenLayers.Renderer.symbol\n+ * Coordinate arrays for well known (named) symbols.\n+ */\n+OpenLayers.Renderer.symbol = {\n+ \"star\": [350, 75, 379, 161, 469, 161, 397, 215, 423, 301, 350, 250, 277, 301,\n+ 303, 215, 231, 161, 321, 161, 350, 75\n+ ],\n+ \"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,\n+ 4, 0\n+ ],\n+ \"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],\n+ \"square\": [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],\n+ \"triangle\": [0, 10, 10, 10, 5, 0, 0, 10]\n+};\n+/* ======================================================================\n+ OpenLayers/Feature.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Util.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Feature\n+ * Features are combinations of geography and attributes. The OpenLayers.Feature\n+ * class specifically combines a marker and a lonlat.\n+ */\n+OpenLayers.Feature = OpenLayers.Class({\n+\n+ /** \n+ * Property: layer \n+ * {} \n */\n- numZoomLevels: null,\n+ layer: null,\n \n- /**\n- * APIProperty: minScale\n- * {Float}\n+ /** \n+ * Property: id \n+ * {String} \n */\n- minScale: null,\n+ id: null,\n \n- /**\n- * APIProperty: maxScale\n- * {Float}\n+ /** \n+ * Property: lonlat \n+ * {} \n */\n- maxScale: null,\n+ lonlat: null,\n \n- /**\n- * APIProperty: displayOutsideMaxExtent\n- * {Boolean} Request map tiles that are completely outside of the max \n- * extent for this layer. Defaults to false.\n+ /** \n+ * Property: data \n+ * {Object} \n */\n- displayOutsideMaxExtent: false,\n+ data: null,\n \n- /**\n- * APIProperty: wrapDateLine\n- * {Boolean} Wraps the world at the international dateline, so the map can\n- * be panned infinitely in longitudinal direction. Only use this on the\n- * base layer, and only if the layer's maxExtent equals the world bounds.\n- * #487 for more info. \n+ /** \n+ * Property: marker \n+ * {} \n */\n- wrapDateLine: false,\n+ marker: null,\n \n /**\n- * Property: metadata\n- * {Object} This object can be used to store additional information on a\n- * layer object.\n+ * APIProperty: popupClass\n+ * {} The class which will be used to instantiate\n+ * a new Popup. Default is .\n */\n- metadata: null,\n+ popupClass: null,\n \n- /**\n- * Constructor: OpenLayers.Layer\n+ /** \n+ * Property: popup \n+ * {} \n+ */\n+ popup: null,\n+\n+ /** \n+ * Constructor: OpenLayers.Feature\n+ * Constructor for features.\n *\n * Parameters:\n- * name - {String} The layer name\n- * options - {Object} Hashtable of extra options to tag onto the layer\n+ * layer - {} \n+ * lonlat - {} \n+ * data - {Object} \n+ * \n+ * Returns:\n+ * {}\n */\n- initialize: function(name, options) {\n-\n- this.metadata = {};\n-\n- options = OpenLayers.Util.extend({}, options);\n- // make sure we respect alwaysInRange if set on the prototype\n- if (this.alwaysInRange != null) {\n- options.alwaysInRange = this.alwaysInRange;\n- }\n- this.addOptions(options);\n-\n- this.name = name;\n-\n- if (this.id == null) {\n-\n- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n+ initialize: function(layer, lonlat, data) {\n+ this.layer = layer;\n+ this.lonlat = lonlat;\n+ this.data = (data != null) ? data : {};\n+ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n+ },\n \n- this.div = OpenLayers.Util.createDiv(this.id);\n- this.div.style.width = \"100%\";\n- this.div.style.height = \"100%\";\n- this.div.dir = \"ltr\";\n+ /** \n+ * Method: destroy\n+ * nullify references to prevent circular references and memory leaks\n+ */\n+ destroy: function() {\n \n- this.events = new OpenLayers.Events(this, this.div);\n- if (this.eventListeners instanceof Object) {\n- this.events.on(this.eventListeners);\n+ //remove the popup from the map\n+ if ((this.layer != null) && (this.layer.map != null)) {\n+ if (this.popup != null) {\n+ this.layer.map.removePopup(this.popup);\n }\n+ }\n+ // remove the marker from the layer\n+ if (this.layer != null && this.marker != null) {\n+ this.layer.removeMarker(this.marker);\n+ }\n \n+ this.layer = null;\n+ this.id = null;\n+ this.lonlat = null;\n+ this.data = null;\n+ if (this.marker != null) {\n+ this.destroyMarker(this.marker);\n+ this.marker = null;\n+ }\n+ if (this.popup != null) {\n+ this.destroyPopup(this.popup);\n+ this.popup = null;\n }\n },\n \n /**\n- * Method: destroy\n- * Destroy is a destructor: this is to alleviate cyclic references which\n- * the Javascript garbage cleaner can not take care of on its own.\n- *\n- * Parameters:\n- * setNewBaseLayer - {Boolean} Set a new base layer when this layer has\n- * been destroyed. Default is true.\n+ * Method: onScreen\n+ * \n+ * Returns:\n+ * {Boolean} Whether or not the feature is currently visible on screen\n+ * (based on its 'lonlat' property)\n */\n- destroy: function(setNewBaseLayer) {\n- if (setNewBaseLayer == null) {\n- setNewBaseLayer = true;\n- }\n- if (this.map != null) {\n- this.map.removeLayer(this, setNewBaseLayer);\n- }\n- this.projection = null;\n- this.map = null;\n- this.name = null;\n- this.div = null;\n- this.options = null;\n+ onScreen: function() {\n \n- if (this.events) {\n- if (this.eventListeners) {\n- this.events.un(this.eventListeners);\n- }\n- this.events.destroy();\n+ var onScreen = false;\n+ if ((this.layer != null) && (this.layer.map != null)) {\n+ var screenBounds = this.layer.map.getExtent();\n+ onScreen = screenBounds.containsLonLat(this.lonlat);\n }\n- this.eventListeners = null;\n- this.events = null;\n+ return onScreen;\n },\n \n+\n /**\n- * Method: clone\n- *\n- * Parameters:\n- * obj - {} The layer to be cloned\n+ * Method: createMarker\n+ * Based on the data associated with the Feature, create and return a marker object.\n *\n- * Returns:\n- * {} An exact clone of this \n+ * Returns: \n+ * {} A Marker Object created from the 'lonlat' and 'icon' properties\n+ * set in this.data. If no 'lonlat' is set, returns null. If no\n+ * 'icon' is set, OpenLayers.Marker() will load the default image.\n+ * \n+ * Note - this.marker is set to return value\n+ * \n */\n- clone: function(obj) {\n+ createMarker: function() {\n \n- if (obj == null) {\n- obj = new OpenLayers.Layer(this.name, this.getOptions());\n+ if (this.lonlat != null) {\n+ this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon);\n }\n+ return this.marker;\n+ },\n \n- // catch any randomly tagged-on properties\n- OpenLayers.Util.applyDefaults(obj, this);\n-\n- // a cloned layer should never have its map property set\n- // because it has not been added to a map yet. \n- obj.map = null;\n-\n- return obj;\n+ /**\n+ * Method: destroyMarker\n+ * Destroys marker.\n+ * If user overrides the createMarker() function, s/he should be able\n+ * to also specify an alternative function for destroying it\n+ */\n+ destroyMarker: function() {\n+ this.marker.destroy();\n },\n \n /**\n- * Method: getOptions\n- * Extracts an object from the layer with the properties that were set as\n- * options, but updates them with the values currently set on the\n- * instance.\n+ * Method: createPopup\n+ * Creates a popup object created from the 'lonlat', 'popupSize',\n+ * and 'popupContentHTML' properties set in this.data. It uses\n+ * this.marker.icon as default anchor. \n+ * \n+ * If no 'lonlat' is set, returns null. \n+ * If no this.marker has been created, no anchor is sent.\n+ *\n+ * Note - the returned popup object is 'owned' by the feature, so you\n+ * cannot use the popup's destroy method to discard the popup.\n+ * Instead, you must use the feature's destroyPopup\n+ * \n+ * Note - this.popup is set to return value\n+ * \n+ * Parameters: \n+ * closeBox - {Boolean} create popup with closebox or not\n * \n * Returns:\n- * {Object} the of the layer, representing the current state.\n+ * {} Returns the created popup, which is also set\n+ * as 'popup' property of this feature. Will be of whatever type\n+ * specified by this feature's 'popupClass' property, but must be\n+ * of type .\n+ * \n */\n- getOptions: function() {\n- var options = {};\n- for (var o in this.options) {\n- options[o] = this[o];\n+ createPopup: function(closeBox) {\n+\n+ if (this.lonlat != null) {\n+ if (!this.popup) {\n+ var anchor = (this.marker) ? this.marker.icon : null;\n+ var popupClass = this.popupClass ?\n+ this.popupClass : OpenLayers.Popup.Anchored;\n+ this.popup = new popupClass(this.id + \"_popup\",\n+ this.lonlat,\n+ this.data.popupSize,\n+ this.data.popupContentHTML,\n+ anchor,\n+ closeBox);\n+ }\n+ if (this.data.overflow != null) {\n+ this.popup.contentDiv.style.overflow = this.data.overflow;\n+ }\n+\n+ this.popup.feature = this;\n }\n- return options;\n+ return this.popup;\n },\n \n- /** \n- * APIMethod: setName\n- * Sets the new layer name for this layer. Can trigger a changelayer event\n- * on the map.\n+\n+ /**\n+ * Method: destroyPopup\n+ * Destroys the popup created via createPopup.\n *\n- * Parameters:\n- * newName - {String} The new name.\n+ * As with the marker, if user overrides the createPopup() function, s/he \n+ * should also be able to override the destruction\n */\n- setName: function(newName) {\n- if (newName != this.name) {\n- this.name = newName;\n- if (this.map != null) {\n- this.map.events.triggerEvent(\"changelayer\", {\n- layer: this,\n- property: \"name\"\n- });\n- }\n+ destroyPopup: function() {\n+ if (this.popup) {\n+ this.popup.feature = null;\n+ this.popup.destroy();\n+ this.popup = null;\n }\n },\n \n- /**\n- * APIMethod: addOptions\n- * \n- * Parameters:\n- * newOptions - {Object}\n- * reinitialize - {Boolean} If set to true, and if resolution options of the\n- * current baseLayer were changed, the map will be recentered to make\n- * sure that it is displayed with a valid resolution, and a\n- * changebaselayer event will be triggered.\n- */\n- addOptions: function(newOptions, reinitialize) {\n+ CLASS_NAME: \"OpenLayers.Feature\"\n+});\n+/* ======================================================================\n+ OpenLayers/Feature/Vector.js\n+ ====================================================================== */\n \n- if (this.options == null) {\n- this.options = {};\n- }\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- if (newOptions) {\n- // make sure this.projection references a projection object\n- if (typeof newOptions.projection == \"string\") {\n- newOptions.projection = new OpenLayers.Projection(newOptions.projection);\n- }\n- if (newOptions.projection) {\n- // get maxResolution, units and maxExtent from projection defaults if\n- // they are not defined already\n- OpenLayers.Util.applyDefaults(newOptions,\n- OpenLayers.Projection.defaults[newOptions.projection.getCode()]);\n- }\n- // allow array for extents\n- if (newOptions.maxExtent && !(newOptions.maxExtent instanceof OpenLayers.Bounds)) {\n- newOptions.maxExtent = new OpenLayers.Bounds(newOptions.maxExtent);\n- }\n- if (newOptions.minExtent && !(newOptions.minExtent instanceof OpenLayers.Bounds)) {\n- newOptions.minExtent = new OpenLayers.Bounds(newOptions.minExtent);\n- }\n- }\n+// TRASH THIS\n+OpenLayers.State = {\n+ /** states */\n+ UNKNOWN: 'Unknown',\n+ INSERT: 'Insert',\n+ UPDATE: 'Update',\n+ DELETE: 'Delete'\n+};\n \n- // update our copy for clone\n- OpenLayers.Util.extend(this.options, newOptions);\n+/**\n+ * @requires OpenLayers/Feature.js\n+ * @requires OpenLayers/Util.js\n+ */\n \n- // add new options to this\n- OpenLayers.Util.extend(this, newOptions);\n+/**\n+ * Class: OpenLayers.Feature.Vector\n+ * Vector features use the OpenLayers.Geometry classes as geometry description.\n+ * They have an 'attributes' property, which is the data object, and a 'style'\n+ * property, the default values of which are defined in the \n+ * objects.\n+ * \n+ * Inherits from:\n+ * - \n+ */\n+OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, {\n \n- // get the units from the projection, if we have a projection\n- // and it it has units\n- if (this.projection && this.projection.getUnits()) {\n- this.units = this.projection.getUnits();\n- }\n+ /** \n+ * Property: fid \n+ * {String} \n+ */\n+ fid: null,\n \n- // re-initialize resolutions if necessary, i.e. if any of the\n- // properties of the \"properties\" array defined below is set\n- // in the new options\n- if (this.map) {\n- // store current resolution so we can try to restore it later\n- var resolution = this.map.getResolution();\n- var properties = this.RESOLUTION_PROPERTIES.concat(\n- [\"projection\", \"units\", \"minExtent\", \"maxExtent\"]\n- );\n- for (var o in newOptions) {\n- if (newOptions.hasOwnProperty(o) &&\n- OpenLayers.Util.indexOf(properties, o) >= 0) {\n+ /** \n+ * APIProperty: geometry \n+ * {} \n+ */\n+ geometry: null,\n \n- this.initResolutions();\n- if (reinitialize && this.map.baseLayer === this) {\n- // update map position, and restore previous resolution\n- this.map.setCenter(this.map.getCenter(),\n- this.map.getZoomForResolution(resolution),\n- false, true\n- );\n- // trigger a changebaselayer event to make sure that\n- // all controls (especially\n- // OpenLayers.Control.PanZoomBar) get notified of the\n- // new options\n- this.map.events.triggerEvent(\"changebaselayer\", {\n- layer: this\n- });\n- }\n- break;\n- }\n- }\n- }\n- },\n+ /** \n+ * APIProperty: attributes \n+ * {Object} This object holds arbitrary, serializable properties that\n+ * describe the feature.\n+ */\n+ attributes: null,\n \n /**\n- * APIMethod: onMapResize\n- * This function can be implemented by subclasses\n+ * Property: bounds\n+ * {} The box bounding that feature's geometry, that\n+ * property can be set by an object when\n+ * deserializing the feature, so in most cases it represents an\n+ * information set by the server. \n */\n- onMapResize: function() {\n- //this function can be implemented by subclasses \n- },\n+ bounds: null,\n \n- /**\n- * APIMethod: redraw\n- * Redraws the layer. Returns true if the layer was redrawn, false if not.\n- *\n- * Returns:\n- * {Boolean} The layer was redrawn.\n+ /** \n+ * Property: state \n+ * {String} \n */\n- redraw: function() {\n- var redrawn = false;\n- if (this.map) {\n+ state: null,\n \n- // min/max Range may have changed\n- this.inRange = this.calculateInRange();\n+ /** \n+ * APIProperty: style \n+ * {Object} \n+ */\n+ style: null,\n \n- // map's center might not yet be set\n- var extent = this.getExtent();\n+ /**\n+ * APIProperty: url\n+ * {String} If this property is set it will be taken into account by\n+ * {} when upadting or deleting the feature.\n+ */\n+ url: null,\n \n- if (extent && this.inRange && this.visibility) {\n- var zoomChanged = true;\n- this.moveTo(extent, zoomChanged, false);\n- this.events.triggerEvent(\"moveend\", {\n- \"zoomChanged\": zoomChanged\n- });\n- redrawn = true;\n- }\n- }\n- return redrawn;\n- },\n+ /**\n+ * Property: renderIntent\n+ * {String} rendering intent currently being used\n+ */\n+ renderIntent: \"default\",\n \n /**\n- * Method: moveTo\n+ * APIProperty: modified\n+ * {Object} An object with the originals of the geometry and attributes of\n+ * the feature, if they were changed. Currently this property is only read\n+ * by , and written by\n+ * , which sets the geometry property.\n+ * Applications can set the originals of modified attributes in the\n+ * attributes property. Note that applications have to check if this\n+ * object and the attributes property is already created before using it.\n+ * After a change made with ModifyFeature, this object could look like\n+ *\n+ * (code)\n+ * {\n+ * geometry: >Object\n+ * }\n+ * (end)\n+ *\n+ * When an application has made changes to feature attributes, it could\n+ * have set the attributes to something like this:\n+ *\n+ * (code)\n+ * {\n+ * attributes: {\n+ * myAttribute: \"original\"\n+ * }\n+ * }\n+ * (end)\n+ *\n+ * Note that only checks for truthy values in\n+ * *modified.geometry* and the attribute names in *modified.attributes*,\n+ * but it is recommended to set the original values (and not just true) as\n+ * attribute value, so applications could use this information to undo\n+ * changes.\n+ */\n+ modified: null,\n+\n+ /** \n+ * Constructor: OpenLayers.Feature.Vector\n+ * Create a vector feature. \n * \n * Parameters:\n- * bounds - {}\n- * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to\n- * do some init work in that case.\n- * dragging - {Boolean}\n+ * geometry - {} The geometry that this feature\n+ * represents.\n+ * attributes - {Object} An optional object that will be mapped to the\n+ * property. \n+ * style - {Object} An optional style object.\n */\n- moveTo: function(bounds, zoomChanged, dragging) {\n- var display = this.visibility;\n- if (!this.isBaseLayer) {\n- display = display && this.inRange;\n+ initialize: function(geometry, attributes, style) {\n+ OpenLayers.Feature.prototype.initialize.apply(this,\n+ [null, null, attributes]);\n+ this.lonlat = null;\n+ this.geometry = geometry ? geometry : null;\n+ this.state = null;\n+ this.attributes = {};\n+ if (attributes) {\n+ this.attributes = OpenLayers.Util.extend(this.attributes,\n+ attributes);\n }\n- this.display(display);\n+ this.style = style ? style : null;\n+ },\n+\n+ /** \n+ * Method: destroy\n+ * nullify references to prevent circular references and memory leaks\n+ */\n+ destroy: function() {\n+ if (this.layer) {\n+ this.layer.removeFeatures(this);\n+ this.layer = null;\n+ }\n+\n+ this.geometry = null;\n+ this.modified = null;\n+ OpenLayers.Feature.prototype.destroy.apply(this, arguments);\n },\n \n /**\n- * Method: moveByPx\n- * Move the layer based on pixel vector. To be implemented by subclasses.\n+ * Method: clone\n+ * Create a clone of this vector feature. Does not set any non-standard\n+ * properties.\n *\n- * Parameters:\n- * dx - {Number} The x coord of the displacement vector.\n- * dy - {Number} The y coord of the displacement vector.\n+ * Returns:\n+ * {} An exact clone of this vector feature.\n */\n- moveByPx: function(dx, dy) {},\n+ clone: function() {\n+ return new OpenLayers.Feature.Vector(\n+ this.geometry ? this.geometry.clone() : null,\n+ this.attributes,\n+ this.style);\n+ },\n \n /**\n- * Method: setMap\n- * Set the map property for the layer. This is done through an accessor\n- * so that subclasses can override this and take special action once \n- * they have their map variable set. \n- * \n- * Here we take care to bring over any of the necessary default \n- * properties from the map. \n- * \n+ * Method: onScreen\n+ * Determine whether the feature is within the map viewport. This method\n+ * tests for an intersection between the geometry and the viewport\n+ * bounds. If a more effecient but less precise geometry bounds\n+ * intersection is desired, call the method with the boundsOnly\n+ * parameter true.\n+ *\n * Parameters:\n- * map - {}\n+ * boundsOnly - {Boolean} Only test whether a feature's bounds intersects\n+ * the viewport bounds. Default is false. If false, the feature's\n+ * geometry must intersect the viewport for onScreen to return true.\n+ * \n+ * Returns:\n+ * {Boolean} The feature is currently visible on screen (optionally\n+ * based on its bounds if boundsOnly is true).\n */\n- setMap: function(map) {\n- if (this.map == null) {\n-\n- this.map = map;\n-\n- // grab some essential layer data from the map if it hasn't already\n- // been set\n- this.maxExtent = this.maxExtent || this.map.maxExtent;\n- this.minExtent = this.minExtent || this.map.minExtent;\n-\n- this.projection = this.projection || this.map.projection;\n- if (typeof this.projection == \"string\") {\n- this.projection = new OpenLayers.Projection(this.projection);\n- }\n-\n- // Check the projection to see if we can get units -- if not, refer\n- // to properties.\n- this.units = this.projection.getUnits() ||\n- this.units || this.map.units;\n-\n- this.initResolutions();\n-\n- if (!this.isBaseLayer) {\n- this.inRange = this.calculateInRange();\n- var show = ((this.visibility) && (this.inRange));\n- this.div.style.display = show ? \"\" : \"none\";\n+ onScreen: function(boundsOnly) {\n+ var onScreen = false;\n+ if (this.layer && this.layer.map) {\n+ var screenBounds = this.layer.map.getExtent();\n+ if (boundsOnly) {\n+ var featureBounds = this.geometry.getBounds();\n+ onScreen = screenBounds.intersectsBounds(featureBounds);\n+ } else {\n+ var screenPoly = screenBounds.toGeometry();\n+ onScreen = screenPoly.intersects(this.geometry);\n }\n-\n- // deal with gutters\n- this.setTileSize();\n }\n+ return onScreen;\n },\n \n /**\n- * Method: afterAdd\n- * Called at the end of the map.addLayer sequence. At this point, the map\n- * will have a base layer. To be overridden by subclasses.\n- */\n- afterAdd: function() {},\n-\n- /**\n- * APIMethod: removeMap\n- * Just as setMap() allows each layer the possibility to take a \n- * personalized action on being added to the map, removeMap() allows\n- * each layer to take a personalized action on being removed from it. \n- * For now, this will be mostly unused, except for the EventPane layer,\n- * which needs this hook so that it can remove the special invisible\n- * pane. \n+ * Method: getVisibility\n+ * Determine whether the feature is displayed or not. It may not displayed\n+ * because:\n+ * - its style display property is set to 'none',\n+ * - it doesn't belong to any layer,\n+ * - the styleMap creates a symbolizer with display property set to 'none'\n+ * for it,\n+ * - the layer which it belongs to is not visible.\n * \n- * Parameters:\n- * map - {}\n+ * Returns:\n+ * {Boolean} The feature is currently displayed.\n */\n- removeMap: function(map) {\n- //to be overridden by subclasses\n+ getVisibility: function() {\n+ return !(this.style && this.style.display == 'none' ||\n+ !this.layer ||\n+ this.layer && this.layer.styleMap &&\n+ this.layer.styleMap.createSymbolizer(this, this.renderIntent).display == 'none' ||\n+ this.layer && !this.layer.getVisibility());\n },\n \n /**\n- * APIMethod: getImageSize\n- *\n- * Parameters:\n- * bounds - {} optional tile bounds, can be used\n- * by subclasses that have to deal with different tile sizes at the\n- * layer extent edges (e.g. Zoomify)\n+ * Method: createMarker\n+ * HACK - we need to decide if all vector features should be able to\n+ * create markers\n * \n * Returns:\n- * {} The size that the image should be, taking into \n- * account gutters.\n+ * {} For now just returns null\n */\n- getImageSize: function(bounds) {\n- return (this.imageSize || this.tileSize);\n+ createMarker: function() {\n+ return null;\n },\n \n /**\n- * APIMethod: setTileSize\n- * Set the tile size based on the map size. This also sets layer.imageSize\n- * or use by Tile.Image.\n+ * Method: destroyMarker\n+ * HACK - we need to decide if all vector features should be able to\n+ * delete markers\n * \n- * Parameters:\n- * size - {}\n+ * If user overrides the createMarker() function, s/he should be able\n+ * to also specify an alternative function for destroying it\n */\n- setTileSize: function(size) {\n- var tileSize = (size) ? size :\n- ((this.tileSize) ? this.tileSize :\n- this.map.getTileSize());\n- this.tileSize = tileSize;\n- if (this.gutter) {\n- // layers with gutters need non-null tile sizes\n- //if(tileSize == null) {\n- // OpenLayers.console.error(\"Error in layer.setMap() for \" +\n- // this.name + \": layers with \" +\n- // \"gutters need non-null tile sizes\");\n- //}\n- this.imageSize = new OpenLayers.Size(tileSize.w + (2 * this.gutter),\n- tileSize.h + (2 * this.gutter));\n- }\n+ destroyMarker: function() {\n+ // pass\n },\n \n /**\n- * APIMethod: getVisibility\n+ * Method: createPopup\n+ * HACK - we need to decide if all vector features should be able to\n+ * create popups\n * \n * Returns:\n- * {Boolean} The layer should be displayed (if in range).\n+ * {} For now just returns null\n */\n- getVisibility: function() {\n- return this.visibility;\n+ createPopup: function() {\n+ return null;\n },\n \n- /** \n- * APIMethod: setVisibility\n- * Set the visibility flag for the layer and hide/show & redraw \n- * accordingly. Fire event unless otherwise specified\n+ /**\n+ * Method: atPoint\n+ * Determins whether the feature intersects with the specified location.\n * \n- * Note that visibility is no longer simply whether or not the layer's\n- * style.display is set to \"block\". Now we store a 'visibility' state \n- * property on the layer class, this allows us to remember whether or \n- * not we *desire* for a layer to be visible. In the case where the \n- * map's resolution is out of the layer's range, this desire may be \n- * subverted.\n+ * Parameters: \n+ * lonlat - {|Object} OpenLayers.LonLat or an\n+ * object with a 'lon' and 'lat' properties.\n+ * toleranceLon - {float} Optional tolerance in Geometric Coords\n+ * toleranceLat - {float} Optional tolerance in Geographic Coords\n * \n- * Parameters:\n- * visibility - {Boolean} Whether or not to display the layer (if in range)\n+ * Returns:\n+ * {Boolean} Whether or not the feature is at the specified location\n */\n- setVisibility: function(visibility) {\n- if (visibility != this.visibility) {\n- this.visibility = visibility;\n- this.display(visibility);\n- this.redraw();\n- if (this.map != null) {\n- this.map.events.triggerEvent(\"changelayer\", {\n- layer: this,\n- property: \"visibility\"\n- });\n- }\n- this.events.triggerEvent(\"visibilitychanged\");\n+ atPoint: function(lonlat, toleranceLon, toleranceLat) {\n+ var atPoint = false;\n+ if (this.geometry) {\n+ atPoint = this.geometry.atPoint(lonlat, toleranceLon,\n+ toleranceLat);\n }\n+ return atPoint;\n },\n \n- /** \n- * APIMethod: display\n- * Hide or show the Layer. This is designed to be used internally, and \n- * is not generally the way to enable or disable the layer. For that,\n- * use the setVisibility function instead..\n- * \n- * Parameters:\n- * display - {Boolean}\n+ /**\n+ * Method: destroyPopup\n+ * HACK - we need to decide if all vector features should be able to\n+ * delete popups\n */\n- display: function(display) {\n- if (display != (this.div.style.display != \"none\")) {\n- this.div.style.display = (display && this.calculateInRange()) ? \"block\" : \"none\";\n- }\n+ destroyPopup: function() {\n+ // pass\n },\n \n /**\n- * APIMethod: calculateInRange\n- * \n- * Returns:\n- * {Boolean} The layer is displayable at the current map's current\n- * resolution. Note that if 'alwaysInRange' is true for the layer, \n- * this function will always return true.\n+ * Method: move\n+ * Moves the feature and redraws it at its new location\n+ *\n+ * Parameters:\n+ * location - { or } the\n+ * location to which to move the feature.\n */\n- calculateInRange: function() {\n- var inRange = false;\n+ move: function(location) {\n \n- if (this.alwaysInRange) {\n- inRange = true;\n+ if (!this.layer || !this.geometry.move) {\n+ //do nothing if no layer or immoveable geometry\n+ return undefined;\n+ }\n+\n+ var pixel;\n+ if (location.CLASS_NAME == \"OpenLayers.LonLat\") {\n+ pixel = this.layer.getViewPortPxFromLonLat(location);\n } else {\n- if (this.map) {\n- var resolution = this.map.getResolution();\n- inRange = ((resolution >= this.minResolution) &&\n- (resolution <= this.maxResolution));\n- }\n+ pixel = location;\n }\n- return inRange;\n+\n+ var lastPixel = this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat());\n+ var res = this.layer.map.getResolution();\n+ this.geometry.move(res * (pixel.x - lastPixel.x),\n+ res * (lastPixel.y - pixel.y));\n+ this.layer.drawFeature(this);\n+ return lastPixel;\n },\n \n- /** \n- * APIMethod: setIsBaseLayer\n- * \n+ /**\n+ * Method: toState\n+ * Sets the new state\n+ *\n * Parameters:\n- * isBaseLayer - {Boolean}\n+ * state - {String} \n */\n- setIsBaseLayer: function(isBaseLayer) {\n- if (isBaseLayer != this.isBaseLayer) {\n- this.isBaseLayer = isBaseLayer;\n- if (this.map != null) {\n- this.map.events.triggerEvent(\"changebaselayer\", {\n- layer: this\n- });\n+ toState: function(state) {\n+ if (state == OpenLayers.State.UPDATE) {\n+ switch (this.state) {\n+ case OpenLayers.State.UNKNOWN:\n+ case OpenLayers.State.DELETE:\n+ this.state = state;\n+ break;\n+ case OpenLayers.State.UPDATE:\n+ case OpenLayers.State.INSERT:\n+ break;\n+ }\n+ } else if (state == OpenLayers.State.INSERT) {\n+ switch (this.state) {\n+ case OpenLayers.State.UNKNOWN:\n+ break;\n+ default:\n+ this.state = state;\n+ break;\n+ }\n+ } else if (state == OpenLayers.State.DELETE) {\n+ switch (this.state) {\n+ case OpenLayers.State.INSERT:\n+ // the feature should be destroyed\n+ break;\n+ case OpenLayers.State.DELETE:\n+ break;\n+ case OpenLayers.State.UNKNOWN:\n+ case OpenLayers.State.UPDATE:\n+ this.state = state;\n+ break;\n }\n+ } else if (state == OpenLayers.State.UNKNOWN) {\n+ this.state = state;\n }\n },\n \n- /********************************************************/\n- /* */\n- /* Baselayer Functions */\n- /* */\n- /********************************************************/\n+ CLASS_NAME: \"OpenLayers.Feature.Vector\"\n+});\n \n- /** \n- * Method: initResolutions\n- * This method's responsibility is to set up the 'resolutions' array \n- * for the layer -- this array is what the layer will use to interface\n- * between the zoom levels of the map and the resolution display \n- * of the layer.\n- * \n- * The user has several options that determine how the array is set up.\n- * \n- * For a detailed explanation, see the following wiki from the \n- * openlayers.org homepage:\n- * http://trac.openlayers.org/wiki/SettingZoomLevels\n- */\n- initResolutions: function() {\n \n- // ok we want resolutions, here's our strategy:\n- //\n- // 1. if resolutions are defined in the layer config, use them\n- // 2. else, if scales are defined in the layer config then derive\n- // resolutions from these scales\n- // 3. else, attempt to calculate resolutions from maxResolution,\n- // minResolution, numZoomLevels, maxZoomLevel set in the\n- // layer config\n- // 4. if we still don't have resolutions, and if resolutions\n- // are defined in the same, use them\n- // 5. else, if scales are defined in the map then derive\n- // resolutions from these scales\n- // 6. else, attempt to calculate resolutions from maxResolution,\n- // minResolution, numZoomLevels, maxZoomLevel set in the\n- // map\n- // 7. hope for the best!\n+/**\n+ * Constant: OpenLayers.Feature.Vector.style\n+ * OpenLayers features can have a number of style attributes. The 'default' \n+ * style will typically be used if no other style is specified. These\n+ * styles correspond for the most part, to the styling properties defined\n+ * by the SVG standard. \n+ * Information on fill properties: http://www.w3.org/TR/SVG/painting.html#FillProperties\n+ * Information on stroke properties: http://www.w3.org/TR/SVG/painting.html#StrokeProperties\n+ *\n+ * Symbolizer properties:\n+ * fill - {Boolean} Set to false if no fill is desired.\n+ * fillColor - {String} Hex fill color. Default is \"#ee9900\".\n+ * fillOpacity - {Number} Fill opacity (0-1). Default is 0.4 \n+ * stroke - {Boolean} Set to false if no stroke is desired.\n+ * strokeColor - {String} Hex stroke color. Default is \"#ee9900\".\n+ * strokeOpacity - {Number} Stroke opacity (0-1). Default is 1.\n+ * strokeWidth - {Number} Pixel stroke width. Default is 1.\n+ * strokeLinecap - {String} Stroke cap type. Default is \"round\". [butt | round | square]\n+ * strokeDashstyle - {String} Stroke dash style. Default is \"solid\". [dot | dash | dashdot | longdash | longdashdot | solid]\n+ * graphic - {Boolean} Set to false if no graphic is desired.\n+ * pointRadius - {Number} Pixel point radius. Default is 6.\n+ * pointerEvents - {String} Default is \"visiblePainted\".\n+ * cursor - {String} Default is \"\".\n+ * externalGraphic - {String} Url to an external graphic that will be used for rendering points.\n+ * graphicWidth - {Number} Pixel width for sizing an external graphic.\n+ * graphicHeight - {Number} Pixel height for sizing an external graphic.\n+ * graphicOpacity - {Number} Opacity (0-1) for an external graphic.\n+ * graphicXOffset - {Number} Pixel offset along the positive x axis for displacing an external graphic.\n+ * graphicYOffset - {Number} Pixel offset along the positive y axis for displacing an external graphic.\n+ * 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).\n+ * graphicZIndex - {Number} The integer z-index value to use in rendering.\n+ * graphicName - {String} Named graphic to use when rendering points. Supported values include \"circle\" (default),\n+ * \"square\", \"star\", \"x\", \"cross\", \"triangle\".\n+ * graphicTitle - {String} Tooltip when hovering over a feature. *deprecated*, use title instead\n+ * title - {String} Tooltip when hovering over a feature. Not supported by the canvas renderer.\n+ * backgroundGraphic - {String} Url to a graphic to be used as the background under an externalGraphic.\n+ * backgroundGraphicZIndex - {Number} The integer z-index value to use in rendering the background graphic.\n+ * backgroundXOffset - {Number} The x offset (in pixels) for the background graphic.\n+ * backgroundYOffset - {Number} The y offset (in pixels) for the background graphic.\n+ * backgroundHeight - {Number} The height of the background graphic. If not provided, the graphicHeight will be used.\n+ * backgroundWidth - {Number} The width of the background width. If not provided, the graphicWidth will be used.\n+ * label - {String} The text for an optional label. For browsers that use the canvas renderer, this requires either\n+ * fillText or mozDrawText to be available.\n+ * labelAlign - {String} Label alignment. This specifies the insertion point relative to the text. It is a string\n+ * composed of two characters. The first character is for the horizontal alignment, the second for the vertical\n+ * alignment. Valid values for horizontal alignment: \"l\"=left, \"c\"=center, \"r\"=right. Valid values for vertical\n+ * alignment: \"t\"=top, \"m\"=middle, \"b\"=bottom. Example values: \"lt\", \"cm\", \"rb\". Default is \"cm\".\n+ * labelXOffset - {Number} Pixel offset along the positive x axis for displacing the label. Not supported by the canvas renderer.\n+ * labelYOffset - {Number} Pixel offset along the positive y axis for displacing the label. Not supported by the canvas renderer.\n+ * labelSelect - {Boolean} If set to true, labels will be selectable using SelectFeature or similar controls.\n+ * Default is false.\n+ * labelOutlineColor - {String} The color of the label outline. Default is 'white'. Only supported by the canvas & SVG renderers.\n+ * labelOutlineWidth - {Number} The width of the label outline. Default is 3, set to 0 or null to disable. Only supported by the SVG renderers.\n+ * labelOutlineOpacity - {Number} The opacity (0-1) of the label outline. Default is fontOpacity. Only supported by the canvas & SVG renderers.\n+ * fontColor - {String} The font color for the label, to be provided like CSS.\n+ * fontOpacity - {Number} Opacity (0-1) for the label\n+ * fontFamily - {String} The font family for the label, to be provided like in CSS.\n+ * fontSize - {String} The font size for the label, to be provided like in CSS.\n+ * fontStyle - {String} The font style for the label, to be provided like in CSS.\n+ * fontWeight - {String} The font weight for the label, to be provided like in CSS.\n+ * display - {String} Symbolizers will have no effect if display is set to \"none\". All other values have no effect.\n+ */\n+OpenLayers.Feature.Vector.style = {\n+ 'default': {\n+ fillColor: \"#ee9900\",\n+ fillOpacity: 0.4,\n+ hoverFillColor: \"white\",\n+ hoverFillOpacity: 0.8,\n+ strokeColor: \"#ee9900\",\n+ strokeOpacity: 1,\n+ strokeWidth: 1,\n+ strokeLinecap: \"round\",\n+ strokeDashstyle: \"solid\",\n+ hoverStrokeColor: \"red\",\n+ hoverStrokeOpacity: 1,\n+ hoverStrokeWidth: 0.2,\n+ pointRadius: 6,\n+ hoverPointRadius: 1,\n+ hoverPointUnit: \"%\",\n+ pointerEvents: \"visiblePainted\",\n+ cursor: \"inherit\",\n+ fontColor: \"#000000\",\n+ labelAlign: \"cm\",\n+ labelOutlineColor: \"white\",\n+ labelOutlineWidth: 3\n+ },\n+ 'select': {\n+ fillColor: \"blue\",\n+ fillOpacity: 0.4,\n+ hoverFillColor: \"white\",\n+ hoverFillOpacity: 0.8,\n+ strokeColor: \"blue\",\n+ strokeOpacity: 1,\n+ strokeWidth: 2,\n+ strokeLinecap: \"round\",\n+ strokeDashstyle: \"solid\",\n+ hoverStrokeColor: \"red\",\n+ hoverStrokeOpacity: 1,\n+ hoverStrokeWidth: 0.2,\n+ pointRadius: 6,\n+ hoverPointRadius: 1,\n+ hoverPointUnit: \"%\",\n+ pointerEvents: \"visiblePainted\",\n+ cursor: \"pointer\",\n+ fontColor: \"#000000\",\n+ labelAlign: \"cm\",\n+ labelOutlineColor: \"white\",\n+ labelOutlineWidth: 3\n \n- var i, len, p;\n- var props = {},\n- alwaysInRange = true;\n+ },\n+ 'temporary': {\n+ fillColor: \"#66cccc\",\n+ fillOpacity: 0.2,\n+ hoverFillColor: \"white\",\n+ hoverFillOpacity: 0.8,\n+ strokeColor: \"#66cccc\",\n+ strokeOpacity: 1,\n+ strokeLinecap: \"round\",\n+ strokeWidth: 2,\n+ strokeDashstyle: \"solid\",\n+ hoverStrokeColor: \"red\",\n+ hoverStrokeOpacity: 1,\n+ hoverStrokeWidth: 0.2,\n+ pointRadius: 6,\n+ hoverPointRadius: 1,\n+ hoverPointUnit: \"%\",\n+ pointerEvents: \"visiblePainted\",\n+ cursor: \"inherit\",\n+ fontColor: \"#000000\",\n+ labelAlign: \"cm\",\n+ labelOutlineColor: \"white\",\n+ labelOutlineWidth: 3\n \n- // get resolution data from layer config\n- // (we also set alwaysInRange in the layer as appropriate)\n- for (i = 0, len = this.RESOLUTION_PROPERTIES.length; i < len; i++) {\n- p = this.RESOLUTION_PROPERTIES[i];\n- props[p] = this.options[p];\n- if (alwaysInRange && this.options[p]) {\n- alwaysInRange = false;\n- }\n- }\n- if (this.options.alwaysInRange == null) {\n- this.alwaysInRange = alwaysInRange;\n- }\n+ },\n+ 'delete': {\n+ display: \"none\"\n+ }\n+};\n+/* ======================================================================\n+ OpenLayers/Style.js\n+ ====================================================================== */\n \n- // if we don't have resolutions then attempt to derive them from scales\n- if (props.resolutions == null) {\n- props.resolutions = this.resolutionsFromScales(props.scales);\n- }\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n \n- // if we still don't have resolutions then attempt to calculate them\n- if (props.resolutions == null) {\n- props.resolutions = this.calculateResolutions(props);\n- }\n \n- // if we couldn't calculate resolutions then we look at we have\n- // in the map\n- if (props.resolutions == null) {\n- for (i = 0, len = this.RESOLUTION_PROPERTIES.length; i < len; i++) {\n- p = this.RESOLUTION_PROPERTIES[i];\n- props[p] = this.options[p] != null ?\n- this.options[p] : this.map[p];\n- }\n- if (props.resolutions == null) {\n- props.resolutions = this.resolutionsFromScales(props.scales);\n- }\n- if (props.resolutions == null) {\n- props.resolutions = this.calculateResolutions(props);\n- }\n- }\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Util.js\n+ * @requires OpenLayers/Feature/Vector.js\n+ */\n \n- // ok, we new need to set properties in the instance\n+/**\n+ * Class: OpenLayers.Style\n+ * This class represents a UserStyle obtained\n+ * from a SLD, containing styling rules.\n+ */\n+OpenLayers.Style = OpenLayers.Class({\n \n- // get maxResolution from the config if it's defined there\n- var maxResolution;\n- if (this.options.maxResolution &&\n- this.options.maxResolution !== \"auto\") {\n- maxResolution = this.options.maxResolution;\n- }\n- if (this.options.minScale) {\n- maxResolution = OpenLayers.Util.getResolutionFromScale(\n- this.options.minScale, this.units);\n- }\n+ /**\n+ * Property: id\n+ * {String} A unique id for this session.\n+ */\n+ id: null,\n \n- // get minResolution from the config if it's defined there\n- var minResolution;\n- if (this.options.minResolution &&\n- this.options.minResolution !== \"auto\") {\n- minResolution = this.options.minResolution;\n- }\n- if (this.options.maxScale) {\n- minResolution = OpenLayers.Util.getResolutionFromScale(\n- this.options.maxScale, this.units);\n- }\n+ /**\n+ * APIProperty: name\n+ * {String}\n+ */\n+ name: null,\n \n- if (props.resolutions) {\n+ /**\n+ * Property: title\n+ * {String} Title of this style (set if included in SLD)\n+ */\n+ title: null,\n \n- //sort resolutions array descendingly\n- props.resolutions.sort(function(a, b) {\n- return (b - a);\n- });\n+ /**\n+ * Property: description\n+ * {String} Description of this style (set if abstract is included in SLD)\n+ */\n+ description: null,\n \n- // if we still don't have a maxResolution get it from the\n- // resolutions array\n- if (!maxResolution) {\n- maxResolution = props.resolutions[0];\n- }\n+ /**\n+ * APIProperty: layerName\n+ * {} name of the layer that this style belongs to, usually\n+ * according to the NamedLayer attribute of an SLD document.\n+ */\n+ layerName: null,\n \n- // if we still don't have a minResolution get it from the\n- // resolutions array\n- if (!minResolution) {\n- var lastIdx = props.resolutions.length - 1;\n- minResolution = props.resolutions[lastIdx];\n- }\n- }\n+ /**\n+ * APIProperty: isDefault\n+ * {Boolean}\n+ */\n+ isDefault: false,\n \n- this.resolutions = props.resolutions;\n- if (this.resolutions) {\n- len = this.resolutions.length;\n- this.scales = new Array(len);\n- for (i = 0; i < len; i++) {\n- this.scales[i] = OpenLayers.Util.getScaleFromResolution(\n- this.resolutions[i], this.units);\n- }\n- this.numZoomLevels = len;\n- }\n- this.minResolution = minResolution;\n- if (minResolution) {\n- this.maxScale = OpenLayers.Util.getScaleFromResolution(\n- minResolution, this.units);\n- }\n- this.maxResolution = maxResolution;\n- if (maxResolution) {\n- this.minScale = OpenLayers.Util.getScaleFromResolution(\n- maxResolution, this.units);\n- }\n- },\n+ /** \n+ * Property: rules \n+ * {Array()}\n+ */\n+ rules: null,\n \n /**\n- * Method: resolutionsFromScales\n- * Derive resolutions from scales.\n- *\n- * Parameters:\n- * scales - {Array(Number)} Scales\n- *\n- * Returns\n- * {Array(Number)} Resolutions\n+ * APIProperty: context\n+ * {Object} An optional object with properties that symbolizers' property\n+ * values should be evaluated against. If no context is specified,\n+ * feature.attributes will be used\n */\n- resolutionsFromScales: function(scales) {\n- if (scales == null) {\n- return;\n- }\n- var resolutions, i, len;\n- len = scales.length;\n- resolutions = new Array(len);\n- for (i = 0; i < len; i++) {\n- resolutions[i] = OpenLayers.Util.getResolutionFromScale(\n- scales[i], this.units);\n- }\n- return resolutions;\n- },\n+ context: null,\n \n /**\n- * Method: calculateResolutions\n- * Calculate resolutions based on the provided properties.\n+ * Property: defaultStyle\n+ * {Object} hash of style properties to use as default for merging\n+ * rule-based style symbolizers onto. If no rules are defined,\n+ * createSymbolizer will return this style. If is set to\n+ * true, the defaultStyle will only be taken into account if there are\n+ * rules defined.\n+ */\n+ defaultStyle: null,\n+\n+ /**\n+ * Property: defaultsPerSymbolizer\n+ * {Boolean} If set to true, the will extend the symbolizer\n+ * of every rule. Properties of the will also be used to set\n+ * missing symbolizer properties if the symbolizer has stroke, fill or\n+ * graphic set to true. Default is false.\n+ */\n+ defaultsPerSymbolizer: false,\n+\n+ /**\n+ * Property: propertyStyles\n+ * {Hash of Boolean} cache of style properties that need to be parsed for\n+ * propertyNames. Property names are keys, values won't be used.\n+ */\n+ propertyStyles: null,\n+\n+\n+ /** \n+ * Constructor: OpenLayers.Style\n+ * Creates a UserStyle.\n *\n * Parameters:\n- * props - {Object} Properties\n+ * style - {Object} Optional hash of style properties that will be\n+ * used as default style for this style object. This style\n+ * applies if no rules are specified. Symbolizers defined in\n+ * rules will extend this default style.\n+ * options - {Object} An optional object with properties to set on the\n+ * style.\n *\n+ * Valid options:\n+ * rules - {Array()} List of rules to be added to the\n+ * style.\n+ * \n * Returns:\n- * {Array({Number})} Array of resolutions.\n+ * {}\n */\n- calculateResolutions: function(props) {\n-\n- var viewSize, wRes, hRes;\n+ initialize: function(style, options) {\n \n- // determine maxResolution\n- var maxResolution = props.maxResolution;\n- if (props.minScale != null) {\n- maxResolution =\n- OpenLayers.Util.getResolutionFromScale(props.minScale,\n- this.units);\n- } else if (maxResolution == \"auto\" && this.maxExtent != null) {\n- viewSize = this.map.getSize();\n- wRes = this.maxExtent.getWidth() / viewSize.w;\n- hRes = this.maxExtent.getHeight() / viewSize.h;\n- maxResolution = Math.max(wRes, hRes);\n+ OpenLayers.Util.extend(this, options);\n+ this.rules = [];\n+ if (options && options.rules) {\n+ this.addRules(options.rules);\n }\n \n- // determine minResolution\n- var minResolution = props.minResolution;\n- if (props.maxScale != null) {\n- minResolution =\n- OpenLayers.Util.getResolutionFromScale(props.maxScale,\n- this.units);\n- } else if (props.minResolution == \"auto\" && this.minExtent != null) {\n- viewSize = this.map.getSize();\n- wRes = this.minExtent.getWidth() / viewSize.w;\n- hRes = this.minExtent.getHeight() / viewSize.h;\n- minResolution = Math.max(wRes, hRes);\n- }\n+ // use the default style from OpenLayers.Feature.Vector if no style\n+ // was given in the constructor\n+ this.setDefaultStyle(style ||\n+ OpenLayers.Feature.Vector.style[\"default\"]);\n \n- if (typeof maxResolution !== \"number\" &&\n- typeof minResolution !== \"number\" &&\n- this.maxExtent != null) {\n- // maxResolution for default grid sets assumes that at zoom\n- // level zero, the whole world fits on one tile.\n- var tileSize = this.map.getTileSize();\n- maxResolution = Math.max(\n- this.maxExtent.getWidth() / tileSize.w,\n- this.maxExtent.getHeight() / tileSize.h\n- );\n- }\n+ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n+ },\n \n- // determine numZoomLevels\n- var maxZoomLevel = props.maxZoomLevel;\n- var numZoomLevels = props.numZoomLevels;\n- if (typeof minResolution === \"number\" &&\n- typeof maxResolution === \"number\" && numZoomLevels === undefined) {\n- var ratio = maxResolution / minResolution;\n- numZoomLevels = Math.floor(Math.log(ratio) / Math.log(2)) + 1;\n- } else if (numZoomLevels === undefined && maxZoomLevel != null) {\n- numZoomLevels = maxZoomLevel + 1;\n+ /** \n+ * APIMethod: destroy\n+ * nullify references to prevent circular references and memory leaks\n+ */\n+ destroy: function() {\n+ for (var i = 0, len = this.rules.length; i < len; i++) {\n+ this.rules[i].destroy();\n+ this.rules[i] = null;\n }\n+ this.rules = null;\n+ this.defaultStyle = null;\n+ },\n \n- // are we able to calculate resolutions?\n- if (typeof numZoomLevels !== \"number\" || numZoomLevels <= 0 ||\n- (typeof maxResolution !== \"number\" &&\n- typeof minResolution !== \"number\")) {\n- return;\n- }\n+ /**\n+ * Method: createSymbolizer\n+ * creates a style by applying all feature-dependent rules to the base\n+ * style.\n+ * \n+ * Parameters:\n+ * feature - {} feature to evaluate rules for\n+ * \n+ * Returns:\n+ * {Object} symbolizer hash\n+ */\n+ createSymbolizer: function(feature) {\n+ var style = this.defaultsPerSymbolizer ? {} : this.createLiterals(\n+ OpenLayers.Util.extend({}, this.defaultStyle), feature);\n \n- // now we have numZoomLevels and at least one of maxResolution\n- // or minResolution, we can populate the resolutions array\n+ var rules = this.rules;\n \n- var resolutions = new Array(numZoomLevels);\n- var base = 2;\n- if (typeof minResolution == \"number\" &&\n- typeof maxResolution == \"number\") {\n- // if maxResolution and minResolution are set, we calculate\n- // the base for exponential scaling that starts at\n- // maxResolution and ends at minResolution in numZoomLevels\n- // steps.\n- base = Math.pow(\n- (maxResolution / minResolution),\n- (1 / (numZoomLevels - 1))\n- );\n- }\n+ var rule, context;\n+ var elseRules = [];\n+ var appliedRules = false;\n+ for (var i = 0, len = rules.length; i < len; i++) {\n+ rule = rules[i];\n+ // does the rule apply?\n+ var applies = rule.evaluate(feature);\n \n- var i;\n- if (typeof maxResolution === \"number\") {\n- for (i = 0; i < numZoomLevels; i++) {\n- resolutions[i] = maxResolution / Math.pow(base, i);\n+ if (applies) {\n+ if (rule instanceof OpenLayers.Rule && rule.elseFilter) {\n+ elseRules.push(rule);\n+ } else {\n+ appliedRules = true;\n+ this.applySymbolizer(rule, style, feature);\n+ }\n }\n- } else {\n- for (i = 0; i < numZoomLevels; i++) {\n- resolutions[numZoomLevels - 1 - i] =\n- minResolution * Math.pow(base, i);\n+ }\n+\n+ // if no other rules apply, apply the rules with else filters\n+ if (appliedRules == false && elseRules.length > 0) {\n+ appliedRules = true;\n+ for (var i = 0, len = elseRules.length; i < len; i++) {\n+ this.applySymbolizer(elseRules[i], style, feature);\n }\n }\n \n- return resolutions;\n- },\n+ // don't display if there were rules but none applied\n+ if (rules.length > 0 && appliedRules == false) {\n+ style.display = \"none\";\n+ }\n \n- /**\n- * APIMethod: getResolution\n- * \n- * Returns:\n- * {Float} The currently selected resolution of the map, taken from the\n- * resolutions array, indexed by current zoom level.\n- */\n- getResolution: function() {\n- var zoom = this.map.getZoom();\n- return this.getResolutionForZoom(zoom);\n- },\n+ if (style.label != null && typeof style.label !== \"string\") {\n+ style.label = String(style.label);\n+ }\n \n- /** \n- * APIMethod: getExtent\n- * \n- * Returns:\n- * {} A Bounds object which represents the lon/lat \n- * bounds of the current viewPort.\n- */\n- getExtent: function() {\n- // just use stock map calculateBounds function -- passing no arguments\n- // means it will user map's current center & resolution\n- //\n- return this.map.calculateBounds();\n+ return style;\n },\n \n /**\n- * APIMethod: getZoomForExtent\n- * \n+ * Method: applySymbolizer\n+ *\n * Parameters:\n- * extent - {}\n- * closest - {Boolean} Find the zoom level that most closely fits the \n- * specified bounds. Note that this may result in a zoom that does \n- * not exactly contain the entire extent.\n- * Default is false.\n+ * rule - {}\n+ * style - {Object}\n+ * feature - {}\n *\n * Returns:\n- * {Integer} The index of the zoomLevel (entry in the resolutions array) \n- * for the passed-in extent. We do this by calculating the ideal \n- * resolution for the given extent (based on the map size) and then \n- * calling getZoomForResolution(), passing along the 'closest'\n- * parameter.\n+ * {Object} A style with new symbolizer applied.\n */\n- getZoomForExtent: function(extent, closest) {\n- var viewSize = this.map.getSize();\n- var idealResolution = Math.max(extent.getWidth() / viewSize.w,\n- extent.getHeight() / viewSize.h);\n+ applySymbolizer: function(rule, style, feature) {\n+ var symbolizerPrefix = feature.geometry ?\n+ this.getSymbolizerPrefix(feature.geometry) :\n+ OpenLayers.Style.SYMBOLIZER_PREFIXES[0];\n \n- return this.getZoomForResolution(idealResolution, closest);\n- },\n+ var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer;\n \n- /** \n- * Method: getDataExtent\n- * Calculates the max extent which includes all of the data for the layer.\n- * This function is to be implemented by subclasses.\n- * \n- * Returns:\n- * {}\n- */\n- getDataExtent: function() {\n- //to be implemented by subclasses\n+ if (this.defaultsPerSymbolizer === true) {\n+ var defaults = this.defaultStyle;\n+ OpenLayers.Util.applyDefaults(symbolizer, {\n+ pointRadius: defaults.pointRadius\n+ });\n+ if (symbolizer.stroke === true || symbolizer.graphic === true) {\n+ OpenLayers.Util.applyDefaults(symbolizer, {\n+ strokeWidth: defaults.strokeWidth,\n+ strokeColor: defaults.strokeColor,\n+ strokeOpacity: defaults.strokeOpacity,\n+ strokeDashstyle: defaults.strokeDashstyle,\n+ strokeLinecap: defaults.strokeLinecap\n+ });\n+ }\n+ if (symbolizer.fill === true || symbolizer.graphic === true) {\n+ OpenLayers.Util.applyDefaults(symbolizer, {\n+ fillColor: defaults.fillColor,\n+ fillOpacity: defaults.fillOpacity\n+ });\n+ }\n+ if (symbolizer.graphic === true) {\n+ OpenLayers.Util.applyDefaults(symbolizer, {\n+ pointRadius: this.defaultStyle.pointRadius,\n+ externalGraphic: this.defaultStyle.externalGraphic,\n+ graphicName: this.defaultStyle.graphicName,\n+ graphicOpacity: this.defaultStyle.graphicOpacity,\n+ graphicWidth: this.defaultStyle.graphicWidth,\n+ graphicHeight: this.defaultStyle.graphicHeight,\n+ graphicXOffset: this.defaultStyle.graphicXOffset,\n+ graphicYOffset: this.defaultStyle.graphicYOffset\n+ });\n+ }\n+ }\n+\n+ // merge the style with the current style\n+ return this.createLiterals(\n+ OpenLayers.Util.extend(style, symbolizer), feature);\n },\n \n /**\n- * APIMethod: getResolutionForZoom\n+ * Method: createLiterals\n+ * creates literals for all style properties that have an entry in\n+ * .\n * \n * Parameters:\n- * zoom - {Float}\n+ * style - {Object} style to create literals for. Will be modified\n+ * inline.\n+ * feature - {Object}\n * \n * Returns:\n- * {Float} A suitable resolution for the specified zoom.\n+ * {Object} the modified style\n */\n- getResolutionForZoom: function(zoom) {\n- zoom = Math.max(0, Math.min(zoom, this.resolutions.length - 1));\n- var resolution;\n- if (this.map.fractionalZoom) {\n- var low = Math.floor(zoom);\n- var high = Math.ceil(zoom);\n- resolution = this.resolutions[low] -\n- ((zoom - low) * (this.resolutions[low] - this.resolutions[high]));\n- } else {\n- resolution = this.resolutions[Math.round(zoom)];\n+ createLiterals: function(style, feature) {\n+ var context = OpenLayers.Util.extend({}, feature.attributes || feature.data);\n+ OpenLayers.Util.extend(context, this.context);\n+\n+ for (var i in this.propertyStyles) {\n+ style[i] = OpenLayers.Style.createLiteral(style[i], context, feature, i);\n }\n- return resolution;\n+ return style;\n },\n \n /**\n- * APIMethod: getZoomForResolution\n- * \n- * Parameters:\n- * resolution - {Float}\n- * closest - {Boolean} Find the zoom level that corresponds to the absolute \n- * closest resolution, which may result in a zoom whose corresponding\n- * resolution is actually smaller than we would have desired (if this\n- * is being called from a getZoomForExtent() call, then this means that\n- * the returned zoom index might not actually contain the entire \n- * extent specified... but it'll be close).\n- * Default is false.\n+ * Method: findPropertyStyles\n+ * Looks into all rules for this style and the defaultStyle to collect\n+ * all the style hash property names containing ${...} strings that have\n+ * to be replaced using the createLiteral method before returning them.\n * \n * Returns:\n- * {Integer} The index of the zoomLevel (entry in the resolutions array) \n- * that corresponds to the best fit resolution given the passed in \n- * value and the 'closest' specification.\n+ * {Object} hash of property names that need createLiteral parsing. The\n+ * name of the property is the key, and the value is true;\n */\n- getZoomForResolution: function(resolution, closest) {\n- var zoom, i, len;\n- if (this.map.fractionalZoom) {\n- var lowZoom = 0;\n- var highZoom = this.resolutions.length - 1;\n- var highRes = this.resolutions[lowZoom];\n- var lowRes = this.resolutions[highZoom];\n- var res;\n- for (i = 0, len = this.resolutions.length; i < len; ++i) {\n- res = this.resolutions[i];\n- if (res >= resolution) {\n- highRes = res;\n- lowZoom = i;\n- }\n- if (res <= resolution) {\n- lowRes = res;\n- highZoom = i;\n- break;\n- }\n- }\n- var dRes = highRes - lowRes;\n- if (dRes > 0) {\n- zoom = lowZoom + ((highRes - resolution) / dRes);\n- } else {\n- zoom = lowZoom;\n- }\n- } else {\n- var diff;\n- var minDiff = Number.POSITIVE_INFINITY;\n- for (i = 0, len = this.resolutions.length; i < len; i++) {\n- if (closest) {\n- diff = Math.abs(this.resolutions[i] - resolution);\n- if (diff > minDiff) {\n- break;\n- }\n- minDiff = diff;\n+ findPropertyStyles: function() {\n+ var propertyStyles = {};\n+\n+ // check the default style\n+ var style = this.defaultStyle;\n+ this.addPropertyStyles(propertyStyles, style);\n+\n+ // walk through all rules to check for properties in their symbolizer\n+ var rules = this.rules;\n+ var symbolizer, value;\n+ for (var i = 0, len = rules.length; i < len; i++) {\n+ symbolizer = rules[i].symbolizer;\n+ for (var key in symbolizer) {\n+ value = symbolizer[key];\n+ if (typeof value == \"object\") {\n+ // symbolizer key is \"Point\", \"Line\" or \"Polygon\"\n+ this.addPropertyStyles(propertyStyles, value);\n } else {\n- if (this.resolutions[i] < resolution) {\n- break;\n- }\n+ // symbolizer is a hash of style properties\n+ this.addPropertyStyles(propertyStyles, symbolizer);\n+ break;\n }\n }\n- zoom = Math.max(0, i - 1);\n }\n- return zoom;\n+ return propertyStyles;\n },\n \n /**\n- * APIMethod: getLonLatFromViewPortPx\n+ * Method: addPropertyStyles\n * \n * Parameters:\n- * viewPortPx - {|Object} An OpenLayers.Pixel or\n- * an object with a 'x'\n- * and 'y' properties.\n- *\n+ * propertyStyles - {Object} hash to add new property styles to. Will be\n+ * modified inline\n+ * symbolizer - {Object} search this symbolizer for property styles\n+ * \n * Returns:\n- * {} An OpenLayers.LonLat which is the passed-in \n- * view port , translated into lon/lat by the layer.\n+ * {Object} propertyStyles hash\n */\n- getLonLatFromViewPortPx: function(viewPortPx) {\n- var lonlat = null;\n- var map = this.map;\n- if (viewPortPx != null && map.minPx) {\n- var res = map.getResolution();\n- var maxExtent = map.getMaxExtent({\n- restricted: true\n- });\n- var lon = (viewPortPx.x - map.minPx.x) * res + maxExtent.left;\n- var lat = (map.minPx.y - viewPortPx.y) * res + maxExtent.top;\n- lonlat = new OpenLayers.LonLat(lon, lat);\n-\n- if (this.wrapDateLine) {\n- lonlat = lonlat.wrapDateLine(this.maxExtent);\n+ addPropertyStyles: function(propertyStyles, symbolizer) {\n+ var property;\n+ for (var key in symbolizer) {\n+ property = symbolizer[key];\n+ if (typeof property == \"string\" &&\n+ property.match(/\\$\\{\\w+\\}/)) {\n+ propertyStyles[key] = true;\n }\n }\n- return lonlat;\n+ return propertyStyles;\n },\n \n /**\n- * APIMethod: getViewPortPxFromLonLat\n- * Returns a pixel location given a map location. This method will return\n- * fractional pixel values.\n+ * APIMethod: addRules\n+ * Adds rules to this style.\n * \n * Parameters:\n- * lonlat - {|Object} An OpenLayers.LonLat or\n- * an object with a 'lon'\n- * and 'lat' properties.\n- *\n- * Returns: \n- * {} An which is the passed-in \n- * lonlat translated into view port pixels.\n+ * rules - {Array()}\n */\n- getViewPortPxFromLonLat: function(lonlat, resolution) {\n- var px = null;\n- if (lonlat != null) {\n- resolution = resolution || this.map.getResolution();\n- var extent = this.map.calculateBounds(null, resolution);\n- px = new OpenLayers.Pixel(\n- (1 / resolution * (lonlat.lon - extent.left)),\n- (1 / resolution * (extent.top - lonlat.lat))\n- );\n- }\n- return px;\n+ addRules: function(rules) {\n+ Array.prototype.push.apply(this.rules, rules);\n+ this.propertyStyles = this.findPropertyStyles();\n },\n \n /**\n- * APIMethod: setOpacity\n- * Sets the opacity for the entire layer (all images)\n+ * APIMethod: setDefaultStyle\n+ * Sets the default style for this style object.\n * \n * Parameters:\n- * opacity - {Float}\n+ * style - {Object} Hash of style properties\n */\n- setOpacity: function(opacity) {\n- if (opacity != this.opacity) {\n- this.opacity = opacity;\n- var childNodes = this.div.childNodes;\n- for (var i = 0, len = childNodes.length; i < len; ++i) {\n- var element = childNodes[i].firstChild || childNodes[i];\n- var lastChild = childNodes[i].lastChild;\n- //TODO de-uglify this\n- if (lastChild && lastChild.nodeName.toLowerCase() === \"iframe\") {\n- element = lastChild.parentNode;\n- }\n- OpenLayers.Util.modifyDOMElement(element, null, null, null,\n- null, null, null, opacity);\n- }\n- if (this.map != null) {\n- this.map.events.triggerEvent(\"changelayer\", {\n- layer: this,\n- property: \"opacity\"\n- });\n- }\n- }\n+ setDefaultStyle: function(style) {\n+ this.defaultStyle = style;\n+ this.propertyStyles = this.findPropertyStyles();\n },\n \n /**\n- * Method: getZIndex\n+ * Method: getSymbolizerPrefix\n+ * Returns the correct symbolizer prefix according to the\n+ * geometry type of the passed geometry\n * \n- * Returns: \n- * {Integer} the z-index of this layer\n- */\n- getZIndex: function() {\n- return this.div.style.zIndex;\n- },\n-\n- /**\n- * Method: setZIndex\n+ * Parameters:\n+ * geometry - {}\n * \n- * Parameters: \n- * zIndex - {Integer}\n+ * Returns:\n+ * {String} key of the according symbolizer\n */\n- setZIndex: function(zIndex) {\n- this.div.style.zIndex = zIndex;\n+ getSymbolizerPrefix: function(geometry) {\n+ var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES;\n+ for (var i = 0, len = prefixes.length; i < len; i++) {\n+ if (geometry.CLASS_NAME.indexOf(prefixes[i]) != -1) {\n+ return prefixes[i];\n+ }\n+ }\n },\n \n /**\n- * Method: adjustBounds\n- * This function will take a bounds, and if wrapDateLine option is set\n- * on the layer, it will return a bounds which is wrapped around the \n- * world. We do not wrap for bounds which *cross* the \n- * maxExtent.left/right, only bounds which are entirely to the left \n- * or entirely to the right.\n+ * APIMethod: clone\n+ * Clones this style.\n * \n- * Parameters:\n- * bounds - {}\n+ * Returns:\n+ * {} Clone of this style.\n */\n- adjustBounds: function(bounds) {\n-\n- if (this.gutter) {\n- // Adjust the extent of a bounds in map units by the \n- // layer's gutter in pixels.\n- var mapGutter = this.gutter * this.map.getResolution();\n- bounds = new OpenLayers.Bounds(bounds.left - mapGutter,\n- bounds.bottom - mapGutter,\n- bounds.right + mapGutter,\n- bounds.top + mapGutter);\n- }\n-\n- if (this.wrapDateLine) {\n- // wrap around the date line, within the limits of rounding error\n- var wrappingOptions = {\n- 'rightTolerance': this.getResolution(),\n- 'leftTolerance': this.getResolution()\n- };\n- bounds = bounds.wrapDateLine(this.maxExtent, wrappingOptions);\n-\n+ clone: function() {\n+ var options = OpenLayers.Util.extend({}, this);\n+ // clone rules\n+ if (this.rules) {\n+ options.rules = [];\n+ for (var i = 0, len = this.rules.length; i < len; ++i) {\n+ options.rules.push(this.rules[i].clone());\n+ }\n }\n- return bounds;\n+ // clone context\n+ options.context = this.context && OpenLayers.Util.extend({}, this.context);\n+ //clone default style\n+ var defaultStyle = OpenLayers.Util.extend({}, this.defaultStyle);\n+ return new OpenLayers.Style(defaultStyle, options);\n },\n \n- CLASS_NAME: \"OpenLayers.Layer\"\n+ CLASS_NAME: \"OpenLayers.Style\"\n });\n+\n+\n+/**\n+ * Function: createLiteral\n+ * converts a style value holding a combination of PropertyName and Literal\n+ * into a Literal, taking the property values from the passed features.\n+ * \n+ * Parameters:\n+ * value - {String} value to parse. If this string contains a construct like\n+ * \"foo ${bar}\", then \"foo \" will be taken as literal, and \"${bar}\"\n+ * will be replaced by the value of the \"bar\" attribute of the passed\n+ * feature.\n+ * context - {Object} context to take attribute values from\n+ * feature - {} optional feature to pass to\n+ * for evaluating functions in the\n+ * context.\n+ * property - {String} optional, name of the property for which the literal is\n+ * being created for evaluating functions in the context.\n+ * \n+ * Returns:\n+ * {String} the parsed value. In the example of the value parameter above, the\n+ * result would be \"foo valueOfBar\", assuming that the passed feature has an\n+ * attribute named \"bar\" with the value \"valueOfBar\".\n+ */\n+OpenLayers.Style.createLiteral = function(value, context, feature, property) {\n+ if (typeof value == \"string\" && value.indexOf(\"${\") != -1) {\n+ value = OpenLayers.String.format(value, context, [feature, property]);\n+ value = (isNaN(value) || !value) ? value : parseFloat(value);\n+ }\n+ return value;\n+};\n+\n+/**\n+ * Constant: OpenLayers.Style.SYMBOLIZER_PREFIXES\n+ * {Array} prefixes of the sld symbolizers. These are the\n+ * same as the main geometry types\n+ */\n+OpenLayers.Style.SYMBOLIZER_PREFIXES = ['Point', 'Line', 'Polygon', 'Text',\n+ 'Raster'\n+];\n /* ======================================================================\n- OpenLayers/Layer/HTTPRequest.js\n+ OpenLayers/StyleMap.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n-\n /**\n- * @requires OpenLayers/Layer.js\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Style.js\n+ * @requires OpenLayers/Feature/Vector.js\n */\n \n /**\n- * Class: OpenLayers.Layer.HTTPRequest\n- * \n- * Inherits from: \n- * - \n+ * Class: OpenLayers.StyleMap\n */\n-OpenLayers.Layer.HTTPRequest = OpenLayers.Class(OpenLayers.Layer, {\n-\n- /** \n- * Constant: URL_HASH_FACTOR\n- * {Float} Used to hash URL param strings for multi-WMS server selection.\n- * Set to the Golden Ratio per Knuth's recommendation.\n- */\n- URL_HASH_FACTOR: (Math.sqrt(5) - 1) / 2,\n-\n- /** \n- * Property: url\n- * {Array(String) or String} This is either an array of url strings or \n- * a single url string. \n- */\n- url: null,\n+OpenLayers.StyleMap = OpenLayers.Class({\n \n- /** \n- * Property: params\n- * {Object} Hashtable of key/value parameters\n+ /**\n+ * Property: styles\n+ * {Object} Hash of {}, keyed by names of well known\n+ * rendering intents (e.g. \"default\", \"temporary\", \"select\", \"delete\").\n */\n- params: null,\n+ styles: null,\n \n- /** \n- * APIProperty: reproject\n- * *Deprecated*. See http://docs.openlayers.org/library/spherical_mercator.html\n- * for information on the replacement for this functionality. \n- * {Boolean} Whether layer should reproject itself based on base layer \n- * locations. This allows reprojection onto commercial layers. \n- * Default is false: Most layers can't reproject, but layers \n- * which can create non-square geographic pixels can, like WMS.\n- * \n+ /**\n+ * Property: extendDefault\n+ * {Boolean} if true, every render intent will extend the symbolizers\n+ * specified for the \"default\" intent at rendering time. Otherwise, every\n+ * rendering intent will be treated as a completely independent style.\n */\n- reproject: false,\n+ extendDefault: true,\n \n /**\n- * Constructor: OpenLayers.Layer.HTTPRequest\n+ * Constructor: OpenLayers.StyleMap\n * \n * Parameters:\n- * name - {String}\n- * url - {Array(String) or String}\n- * params - {Object}\n- * options - {Object} Hashtable of extra options to tag onto the layer\n+ * style - {Object} Optional. Either a style hash, or a style object, or\n+ * a hash of style objects (style hashes) keyed by rendering\n+ * intent. If just one style hash or style object is passed,\n+ * this will be used for all known render intents (default,\n+ * select, temporary)\n+ * options - {Object} optional hash of additional options for this\n+ * instance\n */\n- initialize: function(name, url, params, options) {\n- OpenLayers.Layer.prototype.initialize.apply(this, [name, options]);\n- this.url = url;\n- if (!this.params) {\n- this.params = OpenLayers.Util.extend({}, params);\n+ initialize: function(style, options) {\n+ this.styles = {\n+ \"default\": new OpenLayers.Style(\n+ OpenLayers.Feature.Vector.style[\"default\"]),\n+ \"select\": new OpenLayers.Style(\n+ OpenLayers.Feature.Vector.style[\"select\"]),\n+ \"temporary\": new OpenLayers.Style(\n+ OpenLayers.Feature.Vector.style[\"temporary\"]),\n+ \"delete\": new OpenLayers.Style(\n+ OpenLayers.Feature.Vector.style[\"delete\"])\n+ };\n+\n+ // take whatever the user passed as style parameter and convert it\n+ // into parts of stylemap.\n+ if (style instanceof OpenLayers.Style) {\n+ // user passed a style object\n+ this.styles[\"default\"] = style;\n+ this.styles[\"select\"] = style;\n+ this.styles[\"temporary\"] = style;\n+ this.styles[\"delete\"] = style;\n+ } else if (typeof style == \"object\") {\n+ for (var key in style) {\n+ if (style[key] instanceof OpenLayers.Style) {\n+ // user passed a hash of style objects\n+ this.styles[key] = style[key];\n+ } else if (typeof style[key] == \"object\") {\n+ // user passsed a hash of style hashes\n+ this.styles[key] = new OpenLayers.Style(style[key]);\n+ } else {\n+ // user passed a style hash (i.e. symbolizer)\n+ this.styles[\"default\"] = new OpenLayers.Style(style);\n+ this.styles[\"select\"] = new OpenLayers.Style(style);\n+ this.styles[\"temporary\"] = new OpenLayers.Style(style);\n+ this.styles[\"delete\"] = new OpenLayers.Style(style);\n+ break;\n+ }\n+ }\n }\n+ OpenLayers.Util.extend(this, options);\n },\n \n /**\n- * APIMethod: destroy\n+ * Method: destroy\n */\n destroy: function() {\n- this.url = null;\n- this.params = null;\n- OpenLayers.Layer.prototype.destroy.apply(this, arguments);\n+ for (var key in this.styles) {\n+ this.styles[key].destroy();\n+ }\n+ this.styles = null;\n },\n \n /**\n- * APIMethod: clone\n+ * Method: createSymbolizer\n+ * Creates the symbolizer for a feature for a render intent.\n * \n * Parameters:\n- * obj - {Object}\n+ * feature - {} The feature to evaluate the rules\n+ * of the intended style against.\n+ * intent - {String} The intent determines the symbolizer that will be\n+ * used to draw the feature. Well known intents are \"default\"\n+ * (for just drawing the features), \"select\" (for selected\n+ * features) and \"temporary\" (for drawing features).\n * \n * Returns:\n- * {} An exact clone of this \n- * \n+ * {Object} symbolizer hash\n */\n- clone: function(obj) {\n-\n- if (obj == null) {\n- obj = new OpenLayers.Layer.HTTPRequest(this.name,\n- this.url,\n- this.params,\n- this.getOptions());\n+ createSymbolizer: function(feature, intent) {\n+ if (!feature) {\n+ feature = new OpenLayers.Feature.Vector();\n }\n-\n- //get all additions from superclasses\n- obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]);\n-\n- // copy/set any non-init, non-simple values here\n-\n- return obj;\n- },\n-\n- /** \n- * APIMethod: setUrl\n- * \n- * Parameters:\n- * newUrl - {String}\n- */\n- setUrl: function(newUrl) {\n- this.url = newUrl;\n- },\n-\n- /**\n- * APIMethod: mergeNewParams\n- * \n- * Parameters:\n- * newParams - {Object}\n- *\n- * Returns:\n- * redrawn: {Boolean} whether the layer was actually redrawn.\n- */\n- mergeNewParams: function(newParams) {\n- this.params = OpenLayers.Util.extend(this.params, newParams);\n- var ret = this.redraw();\n- if (this.map != null) {\n- this.map.events.triggerEvent(\"changelayer\", {\n- layer: this,\n- property: \"params\"\n- });\n+ if (!this.styles[intent]) {\n+ intent = \"default\";\n }\n- return ret;\n- },\n-\n- /**\n- * APIMethod: redraw\n- * Redraws the layer. Returns true if the layer was redrawn, false if not.\n- *\n- * Parameters:\n- * force - {Boolean} Force redraw by adding random parameter.\n- *\n- * Returns:\n- * {Boolean} The layer was redrawn.\n- */\n- redraw: function(force) {\n- if (force) {\n- return this.mergeNewParams({\n- \"_olSalt\": Math.random()\n- });\n- } else {\n- return OpenLayers.Layer.prototype.redraw.apply(this, []);\n+ feature.renderIntent = intent;\n+ var defaultSymbolizer = {};\n+ if (this.extendDefault && intent != \"default\") {\n+ defaultSymbolizer = this.styles[\"default\"].createSymbolizer(feature);\n }\n+ return OpenLayers.Util.extend(defaultSymbolizer,\n+ this.styles[intent].createSymbolizer(feature));\n },\n \n /**\n- * Method: selectUrl\n- * selectUrl() implements the standard floating-point multiplicative\n- * hash function described by Knuth, and hashes the contents of the \n- * given param string into a float between 0 and 1. This float is then\n- * scaled to the size of the provided urls array, and used to select\n- * a URL.\n- *\n- * Parameters:\n- * paramString - {String}\n- * urls - {Array(String)}\n- * \n- * Returns:\n- * {String} An entry from the urls array, deterministically selected based\n- * on the paramString.\n- */\n- selectUrl: function(paramString, urls) {\n- var product = 1;\n- for (var i = 0, len = paramString.length; i < len; i++) {\n- product *= paramString.charCodeAt(i) * this.URL_HASH_FACTOR;\n- product -= Math.floor(product);\n- }\n- return urls[Math.floor(product * urls.length)];\n- },\n-\n- /** \n- * Method: getFullRequestString\n- * Combine url with layer's params and these newParams. \n- * \n- * does checking on the serverPath variable, allowing for cases when it \n- * is supplied with trailing ? or &, as well as cases where not. \n- *\n- * return in formatted string like this:\n- * \"server?key1=value1&key2=value2&key3=value3\"\n+ * Method: addUniqueValueRules\n+ * Convenience method to create comparison rules for unique values of a\n+ * property. The rules will be added to the style object for a specified\n+ * rendering intent. This method is a shortcut for creating something like\n+ * the \"unique value legends\" familiar from well known desktop GIS systems\n * \n- * WARNING: The altUrl parameter is deprecated and will be removed in 3.0.\n- *\n * Parameters:\n- * newParams - {Object}\n- * altUrl - {String} Use this as the url instead of the layer's url\n- * \n- * Returns: \n- * {String}\n+ * renderIntent - {String} rendering intent to add the rules to\n+ * property - {String} values of feature attributes to create the\n+ * rules for\n+ * symbolizers - {Object} Hash of symbolizers, keyed by the desired\n+ * property values \n+ * context - {Object} An optional object with properties that\n+ * symbolizers' property values should be evaluated\n+ * against. If no context is specified, feature.attributes\n+ * will be used\n */\n- getFullRequestString: function(newParams, altUrl) {\n-\n- // if not altUrl passed in, use layer's url\n- var url = altUrl || this.url;\n-\n- // create a new params hashtable with all the layer params and the \n- // new params together. then convert to string\n- var allParams = OpenLayers.Util.extend({}, this.params);\n- allParams = OpenLayers.Util.extend(allParams, newParams);\n- var paramsString = OpenLayers.Util.getParameterString(allParams);\n-\n- // if url is not a string, it should be an array of strings, \n- // in which case we will deterministically select one of them in \n- // order to evenly distribute requests to different urls.\n- //\n- if (OpenLayers.Util.isArray(url)) {\n- url = this.selectUrl(paramsString, url);\n- }\n-\n- // ignore parameters that are already in the url search string\n- var urlParams =\n- OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));\n- for (var key in allParams) {\n- if (key.toUpperCase() in urlParams) {\n- delete allParams[key];\n- }\n+ addUniqueValueRules: function(renderIntent, property, symbolizers, context) {\n+ var rules = [];\n+ for (var value in symbolizers) {\n+ rules.push(new OpenLayers.Rule({\n+ symbolizer: symbolizers[value],\n+ context: context,\n+ filter: new OpenLayers.Filter.Comparison({\n+ type: OpenLayers.Filter.Comparison.EQUAL_TO,\n+ property: property,\n+ value: value\n+ })\n+ }));\n }\n- paramsString = OpenLayers.Util.getParameterString(allParams);\n-\n- return OpenLayers.Util.urlAppend(url, paramsString);\n+ this.styles[renderIntent].addRules(rules);\n },\n \n- CLASS_NAME: \"OpenLayers.Layer.HTTPRequest\"\n+ CLASS_NAME: \"OpenLayers.StyleMap\"\n });\n /* ======================================================================\n OpenLayers/Tile.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n@@ -15032,3940 +11559,785 @@\n clear: function(draw) {\n // to be extended by subclasses\n },\n \n CLASS_NAME: \"OpenLayers.Tile\"\n });\n /* ======================================================================\n- OpenLayers/Tile/Image.js\n+ OpenLayers/Format.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n-\n /**\n- * @requires OpenLayers/Tile.js\n- * @requires OpenLayers/Animation.js\n+ * @requires OpenLayers/BaseTypes/Class.js\n * @requires OpenLayers/Util.js\n */\n \n /**\n- * Class: OpenLayers.Tile.Image\n- * Instances of OpenLayers.Tile.Image are used to manage the image tiles\n- * used by various layers. Create a new image tile with the\n- * constructor.\n- *\n- * Inherits from:\n- * - \n+ * Class: OpenLayers.Format\n+ * Base class for format reading/writing a variety of formats. Subclasses\n+ * of OpenLayers.Format are expected to have read and write methods.\n */\n-OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {\n-\n- /**\n- * APIProperty: events\n- * {} An events object that handles all \n- * events on the tile.\n- *\n- * Register a listener for a particular event with the following syntax:\n- * (code)\n- * tile.events.register(type, obj, listener);\n- * (end)\n- *\n- * Supported event types (in addition to the events):\n- * beforeload - Triggered before an image is prepared for loading, when the\n- * url for the image is known already. Listeners may call on\n- * the tile instance. If they do so, that image will be used and no new\n- * one will be created.\n- */\n-\n- /** \n- * APIProperty: url\n- * {String} The URL of the image being requested. No default. Filled in by\n- * layer.getURL() function. May be modified by loadstart listeners.\n- */\n- url: null,\n-\n- /** \n- * Property: imgDiv\n- * {HTMLImageElement} The image for this tile.\n- */\n- imgDiv: null,\n-\n- /**\n- * Property: frame\n- * {DOMElement} The image element is appended to the frame. Any gutter on\n- * the image will be hidden behind the frame. If no gutter is set,\n- * this will be null.\n- */\n- frame: null,\n-\n- /** \n- * Property: imageReloadAttempts\n- * {Integer} Attempts to load the image.\n- */\n- imageReloadAttempts: null,\n-\n- /**\n- * Property: layerAlphaHack\n- * {Boolean} True if the png alpha hack needs to be applied on the layer's div.\n- */\n- layerAlphaHack: null,\n-\n- /**\n- * Property: asyncRequestId\n- * {Integer} ID of an request to see if request is still valid. This is a\n- * number which increments by 1 for each asynchronous request.\n- */\n- asyncRequestId: null,\n-\n- /**\n- * APIProperty: maxGetUrlLength\n- * {Number} If set, requests that would result in GET urls with more\n- * characters than the number provided will be made using form-encoded\n- * HTTP POST. It is good practice to avoid urls that are longer than 2048\n- * characters.\n- *\n- * Caution:\n- * Older versions of Gecko based browsers (e.g. Firefox < 3.5) and most\n- * Opera versions do not fully support this option. On all browsers,\n- * transition effects are not supported if POST requests are used.\n- */\n- maxGetUrlLength: null,\n-\n- /**\n- * Property: canvasContext\n- * {CanvasRenderingContext2D} A canvas context associated with\n- * the tile image.\n- */\n- canvasContext: null,\n-\n- /**\n- * APIProperty: crossOriginKeyword\n- * The value of the crossorigin keyword to use when loading images. This is\n- * only relevant when using for tiles from remote\n- * origins and should be set to either 'anonymous' or 'use-credentials'\n- * for servers that send Access-Control-Allow-Origin headers with their\n- * tiles.\n- */\n- crossOriginKeyword: null,\n-\n- /** TBD 3.0 - reorder the parameters to the init function to remove \n- * URL. the getUrl() function on the layer gets called on \n- * each draw(), so no need to specify it here.\n- */\n-\n- /** \n- * Constructor: OpenLayers.Tile.Image\n- * Constructor for a new instance.\n- * \n- * Parameters:\n- * layer - {} layer that the tile will go in.\n- * position - {}\n- * bounds - {}\n- * url - {} Deprecated. Remove me in 3.0.\n- * size - {}\n- * options - {Object}\n- */\n- initialize: function(layer, position, bounds, url, size, options) {\n- OpenLayers.Tile.prototype.initialize.apply(this, arguments);\n-\n- this.url = url; //deprecated remove me\n-\n- this.layerAlphaHack = this.layer.alpha && OpenLayers.Util.alphaHack();\n-\n- if (this.maxGetUrlLength != null || this.layer.gutter || this.layerAlphaHack) {\n- // only create frame if it's needed\n- this.frame = document.createElement(\"div\");\n- this.frame.style.position = \"absolute\";\n- this.frame.style.overflow = \"hidden\";\n- }\n- if (this.maxGetUrlLength != null) {\n- OpenLayers.Util.extend(this, OpenLayers.Tile.Image.IFrame);\n- }\n- },\n-\n- /** \n- * APIMethod: destroy\n- * nullify references to prevent circular references and memory leaks\n- */\n- destroy: function() {\n- if (this.imgDiv) {\n- this.clear();\n- this.imgDiv = null;\n- this.frame = null;\n- }\n- // don't handle async requests any more\n- this.asyncRequestId = null;\n- OpenLayers.Tile.prototype.destroy.apply(this, arguments);\n- },\n-\n- /**\n- * Method: draw\n- * Check that a tile should be drawn, and draw it.\n- * \n- * Returns:\n- * {Boolean} Was a tile drawn? Or null if a beforedraw listener returned\n- * false.\n- */\n- draw: function() {\n- var shouldDraw = OpenLayers.Tile.prototype.draw.apply(this, arguments);\n- if (shouldDraw) {\n- // The layer's reproject option is deprecated.\n- if (this.layer != this.layer.map.baseLayer && this.layer.reproject) {\n- // getBoundsFromBaseLayer is defined in deprecated.js.\n- this.bounds = this.getBoundsFromBaseLayer(this.position);\n- }\n- if (this.isLoading) {\n- //if we're already loading, send 'reload' instead of 'loadstart'.\n- this._loadEvent = \"reload\";\n- } else {\n- this.isLoading = true;\n- this._loadEvent = \"loadstart\";\n- }\n- this.renderTile();\n- this.positionTile();\n- } else if (shouldDraw === false) {\n- this.unload();\n- }\n- return shouldDraw;\n- },\n+OpenLayers.Format = OpenLayers.Class({\n \n /**\n- * Method: renderTile\n- * Internal function to actually initialize the image tile,\n- * position it correctly, and set its url.\n+ * Property: options\n+ * {Object} A reference to options passed to the constructor.\n */\n- renderTile: function() {\n- if (this.layer.async) {\n- // Asynchronous image requests call the asynchronous getURL method\n- // on the layer to fetch an image that covers 'this.bounds'.\n- var id = this.asyncRequestId = (this.asyncRequestId || 0) + 1;\n- this.layer.getURLasync(this.bounds, function(url) {\n- if (id == this.asyncRequestId) {\n- this.url = url;\n- this.initImage();\n- }\n- }, this);\n- } else {\n- // synchronous image requests get the url immediately.\n- this.url = this.layer.getURL(this.bounds);\n- this.initImage();\n- }\n- },\n+ options: null,\n \n /**\n- * Method: positionTile\n- * Using the properties currenty set on the layer, position the tile correctly.\n- * This method is used both by the async and non-async versions of the Tile.Image\n- * code.\n- */\n- positionTile: function() {\n- var style = this.getTile().style,\n- size = this.frame ? this.size :\n- this.layer.getImageSize(this.bounds),\n- ratio = 1;\n- if (this.layer instanceof OpenLayers.Layer.Grid) {\n- ratio = this.layer.getServerResolution() / this.layer.map.getResolution();\n- }\n- style.left = this.position.x + \"px\";\n- style.top = this.position.y + \"px\";\n- style.width = Math.round(ratio * size.w) + \"px\";\n- style.height = Math.round(ratio * size.h) + \"px\";\n- },\n-\n- /** \n- * Method: clear\n- * Remove the tile from the DOM, clear it of any image related data so that\n- * it can be reused in a new location.\n+ * APIProperty: externalProjection\n+ * {} When passed a externalProjection and\n+ * internalProjection, the format will reproject the geometries it\n+ * reads or writes. The externalProjection is the projection used by\n+ * the content which is passed into read or which comes out of write.\n+ * In order to reproject, a projection transformation function for the\n+ * specified projections must be available. This support may be \n+ * provided via proj4js or via a custom transformation function. See\n+ * {} for more information on\n+ * custom transformations.\n */\n- clear: function() {\n- OpenLayers.Tile.prototype.clear.apply(this, arguments);\n- var img = this.imgDiv;\n- if (img) {\n- var tile = this.getTile();\n- if (tile.parentNode === this.layer.div) {\n- this.layer.div.removeChild(tile);\n- }\n- this.setImgSrc();\n- if (this.layerAlphaHack === true) {\n- img.style.filter = \"\";\n- }\n- OpenLayers.Element.removeClass(img, \"olImageLoadError\");\n- }\n- this.canvasContext = null;\n- },\n+ externalProjection: null,\n \n /**\n- * Method: getImage\n- * Returns or creates and returns the tile image.\n+ * APIProperty: internalProjection\n+ * {} When passed a externalProjection and\n+ * internalProjection, the format will reproject the geometries it\n+ * reads or writes. The internalProjection is the projection used by\n+ * the geometries which are returned by read or which are passed into\n+ * write. In order to reproject, a projection transformation function\n+ * for the specified projections must be available. This support may be\n+ * provided via proj4js or via a custom transformation function. See\n+ * {} for more information on\n+ * custom transformations.\n */\n- getImage: function() {\n- if (!this.imgDiv) {\n- this.imgDiv = OpenLayers.Tile.Image.IMAGE.cloneNode(false);\n-\n- var style = this.imgDiv.style;\n- if (this.frame) {\n- var left = 0,\n- top = 0;\n- if (this.layer.gutter) {\n- left = this.layer.gutter / this.layer.tileSize.w * 100;\n- top = this.layer.gutter / this.layer.tileSize.h * 100;\n- }\n- style.left = -left + \"%\";\n- style.top = -top + \"%\";\n- style.width = (2 * left + 100) + \"%\";\n- style.height = (2 * top + 100) + \"%\";\n- }\n- style.visibility = \"hidden\";\n- style.opacity = 0;\n- if (this.layer.opacity < 1) {\n- style.filter = 'alpha(opacity=' +\n- (this.layer.opacity * 100) +\n- ')';\n- }\n- style.position = \"absolute\";\n- if (this.layerAlphaHack) {\n- // move the image out of sight\n- style.paddingTop = style.height;\n- style.height = \"0\";\n- style.width = \"100%\";\n- }\n- if (this.frame) {\n- this.frame.appendChild(this.imgDiv);\n- }\n- }\n-\n- return this.imgDiv;\n- },\n+ internalProjection: null,\n \n /**\n- * APIMethod: setImage\n- * Sets the image element for this tile. This method should only be called\n- * from beforeload listeners.\n- *\n- * Parameters\n- * img - {HTMLImageElement} The image to use for this tile.\n+ * APIProperty: data\n+ * {Object} When is true, this is the parsed string sent to\n+ * .\n */\n- setImage: function(img) {\n- this.imgDiv = img;\n- },\n+ data: null,\n \n /**\n- * Method: initImage\n- * Creates the content for the frame on the tile.\n+ * APIProperty: keepData\n+ * {Object} Maintain a reference () to the most recently read data.\n+ * Default is false.\n */\n- initImage: function() {\n- if (!this.url && !this.imgDiv) {\n- // fast path out - if there is no tile url and no previous image\n- this.isLoading = false;\n- return;\n- }\n- this.events.triggerEvent('beforeload');\n- this.layer.div.appendChild(this.getTile());\n- this.events.triggerEvent(this._loadEvent);\n- var img = this.getImage();\n- var src = img.getAttribute('src') || '';\n- if (this.url && OpenLayers.Util.isEquivalentUrl(src, this.url)) {\n- this._loadTimeout = window.setTimeout(\n- OpenLayers.Function.bind(this.onImageLoad, this), 0\n- );\n- } else {\n- this.stopLoading();\n- if (this.crossOriginKeyword) {\n- img.removeAttribute(\"crossorigin\");\n- }\n- OpenLayers.Event.observe(img, \"load\",\n- OpenLayers.Function.bind(this.onImageLoad, this)\n- );\n- OpenLayers.Event.observe(img, \"error\",\n- OpenLayers.Function.bind(this.onImageError, this)\n- );\n- this.imageReloadAttempts = 0;\n- this.setImgSrc(this.url);\n- }\n- },\n+ keepData: false,\n \n /**\n- * Method: setImgSrc\n- * Sets the source for the tile image\n+ * Constructor: OpenLayers.Format\n+ * Instances of this class are not useful. See one of the subclasses.\n *\n * Parameters:\n- * url - {String} or undefined to hide the image\n- */\n- setImgSrc: function(url) {\n- var img = this.imgDiv;\n- if (url) {\n- img.style.visibility = 'hidden';\n- img.style.opacity = 0;\n- // don't set crossOrigin if the url is a data URL\n- if (this.crossOriginKeyword) {\n- if (url.substr(0, 5) !== 'data:') {\n- img.setAttribute(\"crossorigin\", this.crossOriginKeyword);\n- } else {\n- img.removeAttribute(\"crossorigin\");\n- }\n- }\n- img.src = url;\n- } else {\n- // Remove reference to the image, and leave it to the browser's\n- // caching and garbage collection.\n- this.stopLoading();\n- this.imgDiv = null;\n- if (img.parentNode) {\n- img.parentNode.removeChild(img);\n- }\n- }\n- },\n-\n- /**\n- * Method: getTile\n- * Get the tile's markup.\n+ * options - {Object} An optional object with properties to set on the\n+ * format\n *\n- * Returns:\n- * {DOMElement} The tile's markup\n- */\n- getTile: function() {\n- return this.frame ? this.frame : this.getImage();\n- },\n-\n- /**\n- * Method: createBackBuffer\n- * Create a backbuffer for this tile. A backbuffer isn't exactly a clone\n- * of the tile's markup, because we want to avoid the reloading of the\n- * image. So we clone the frame, and steal the image from the tile.\n+ * Valid options:\n+ * keepData - {Boolean} If true, upon , the data property will be\n+ * set to the parsed object (e.g. the json or xml object).\n *\n * Returns:\n- * {DOMElement} The markup, or undefined if the tile has no image\n- * or if it's currently loading.\n- */\n- createBackBuffer: function() {\n- if (!this.imgDiv || this.isLoading) {\n- return;\n- }\n- var backBuffer;\n- if (this.frame) {\n- backBuffer = this.frame.cloneNode(false);\n- backBuffer.appendChild(this.imgDiv);\n- } else {\n- backBuffer = this.imgDiv;\n- }\n- this.imgDiv = null;\n- return backBuffer;\n- },\n-\n- /**\n- * Method: onImageLoad\n- * Handler for the image onload event\n+ * An instance of OpenLayers.Format\n */\n- onImageLoad: function() {\n- var img = this.imgDiv;\n- this.stopLoading();\n- img.style.visibility = 'inherit';\n- img.style.opacity = this.layer.opacity;\n- this.isLoading = false;\n- this.canvasContext = null;\n- this.events.triggerEvent(\"loadend\");\n-\n- if (this.layerAlphaHack === true) {\n- img.style.filter =\n- \"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='\" +\n- img.src + \"', sizingMethod='scale')\";\n- }\n+ initialize: function(options) {\n+ OpenLayers.Util.extend(this, options);\n+ this.options = options;\n },\n \n /**\n- * Method: onImageError\n- * Handler for the image onerror event\n+ * APIMethod: destroy\n+ * Clean up.\n */\n- onImageError: function() {\n- var img = this.imgDiv;\n- if (img.src != null) {\n- this.imageReloadAttempts++;\n- if (this.imageReloadAttempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) {\n- this.setImgSrc(this.layer.getURL(this.bounds));\n- } else {\n- OpenLayers.Element.addClass(img, \"olImageLoadError\");\n- this.events.triggerEvent(\"loaderror\");\n- this.onImageLoad();\n- }\n- }\n- },\n+ destroy: function() {},\n \n /**\n- * Method: stopLoading\n- * Stops a loading sequence so won't be executed.\n+ * Method: read\n+ * Read data from a string, and return an object whose type depends on the\n+ * subclass. \n+ * \n+ * Parameters:\n+ * data - {string} Data to read/parse.\n+ *\n+ * Returns:\n+ * Depends on the subclass\n */\n- stopLoading: function() {\n- OpenLayers.Event.stopObservingElement(this.imgDiv);\n- window.clearTimeout(this._loadTimeout);\n- delete this._loadTimeout;\n+ read: function(data) {\n+ throw new Error('Read not implemented.');\n },\n \n /**\n- * APIMethod: getCanvasContext\n- * Returns a canvas context associated with the tile image (with\n- * the image drawn on it).\n- * Returns undefined if the browser does not support canvas, if\n- * the tile has no image or if it's currently loading.\n+ * Method: write\n+ * Accept an object, and return a string. \n *\n- * The function returns a canvas context instance but the\n- * underlying canvas is still available in the 'canvas' property:\n- * (code)\n- * var context = tile.getCanvasContext();\n- * if (context) {\n- * var data = context.canvas.toDataURL('image/jpeg');\n- * }\n- * (end)\n+ * Parameters:\n+ * object - {Object} Object to be serialized\n *\n * Returns:\n- * {Boolean}\n+ * {String} A string representation of the object.\n */\n- getCanvasContext: function() {\n- if (OpenLayers.CANVAS_SUPPORTED && this.imgDiv && !this.isLoading) {\n- if (!this.canvasContext) {\n- var canvas = document.createElement(\"canvas\");\n- canvas.width = this.size.w;\n- canvas.height = this.size.h;\n- this.canvasContext = canvas.getContext(\"2d\");\n- this.canvasContext.drawImage(this.imgDiv, 0, 0);\n- }\n- return this.canvasContext;\n- }\n+ write: function(object) {\n+ throw new Error('Write not implemented.');\n },\n \n- CLASS_NAME: \"OpenLayers.Tile.Image\"\n-\n+ CLASS_NAME: \"OpenLayers.Format\"\n });\n-\n-/** \n- * Constant: OpenLayers.Tile.Image.IMAGE\n- * {HTMLImageElement} The image for a tile.\n- */\n-OpenLayers.Tile.Image.IMAGE = (function() {\n- var img = new Image();\n- img.className = \"olTileImage\";\n- // avoid image gallery menu in IE6\n- img.galleryImg = \"no\";\n- return img;\n-}());\n-\n /* ======================================================================\n- OpenLayers/Layer/Grid.js\n+ OpenLayers/Popup.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n-\n /**\n- * @requires OpenLayers/Layer/HTTPRequest.js\n- * @requires OpenLayers/Tile/Image.js\n+ * @requires OpenLayers/BaseTypes/Class.js\n */\n \n+\n /**\n- * Class: OpenLayers.Layer.Grid\n- * Base class for layers that use a lattice of tiles. Create a new grid\n- * layer with the constructor.\n+ * Class: OpenLayers.Popup\n+ * A popup is a small div that can opened and closed on the map.\n+ * Typically opened in response to clicking on a marker. \n+ * See . Popup's don't require their own\n+ * layer and are added the the map using the \n+ * method.\n *\n- * Inherits from:\n- * - \n+ * Example:\n+ * (code)\n+ * popup = new OpenLayers.Popup(\"chicken\", \n+ * new OpenLayers.LonLat(5,40),\n+ * new OpenLayers.Size(200,200),\n+ * \"example popup\",\n+ * true);\n+ * \n+ * map.addPopup(popup);\n+ * (end)\n */\n-OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {\n+OpenLayers.Popup = OpenLayers.Class({\n \n- /**\n- * APIProperty: tileSize\n- * {}\n+ /** \n+ * Property: events \n+ * {} custom event manager \n */\n- tileSize: null,\n+ events: null,\n \n- /**\n- * Property: tileOriginCorner\n- * {String} If the property is not provided, the tile origin \n- * will be derived from the layer's . The corner of the \n- * used is determined by this property. Acceptable values\n- * are \"tl\" (top left), \"tr\" (top right), \"bl\" (bottom left), and \"br\"\n- * (bottom right). Default is \"bl\".\n+ /** Property: id\n+ * {String} the unique identifier assigned to this popup.\n */\n- tileOriginCorner: \"bl\",\n+ id: \"\",\n \n- /**\n- * APIProperty: tileOrigin\n- * {} Optional origin for aligning the grid of tiles.\n- * If provided, requests for tiles at all resolutions will be aligned\n- * with this location (no tiles shall overlap this location). If\n- * not provided, the grid of tiles will be aligned with the layer's\n- * . Default is ``null``.\n+ /** \n+ * Property: lonlat \n+ * {} the position of this popup on the map\n */\n- tileOrigin: null,\n+ lonlat: null,\n \n- /** APIProperty: tileOptions\n- * {Object} optional configuration options for instances\n- * created by this Layer, if supported by the tile class.\n+ /** \n+ * Property: div \n+ * {DOMElement} the div that contains this popup.\n */\n- tileOptions: null,\n+ div: null,\n \n- /**\n- * APIProperty: tileClass\n- * {} The tile class to use for this layer.\n- * Defaults is OpenLayers.Tile.Image.\n+ /** \n+ * Property: contentSize \n+ * {} the width and height of the content.\n */\n- tileClass: OpenLayers.Tile.Image,\n+ contentSize: null,\n \n- /**\n- * Property: grid\n- * {Array(Array())} This is an array of rows, each row is \n- * an array of tiles.\n+ /** \n+ * Property: size \n+ * {} the width and height of the popup.\n */\n- grid: null,\n+ size: null,\n \n- /**\n- * APIProperty: singleTile\n- * {Boolean} Moves the layer into single-tile mode, meaning that one tile \n- * will be loaded. The tile's size will be determined by the 'ratio'\n- * property. When the tile is dragged such that it does not cover the \n- * entire viewport, it is reloaded.\n+ /** \n+ * Property: contentHTML \n+ * {String} An HTML string for this popup to display.\n */\n- singleTile: false,\n+ contentHTML: null,\n \n- /** APIProperty: ratio\n- * {Float} Used only when in single-tile mode, this specifies the \n- * ratio of the size of the single tile to the size of the map.\n- * Default value is 1.5.\n+ /** \n+ * Property: backgroundColor \n+ * {String} the background color used by the popup.\n */\n- ratio: 1.5,\n+ backgroundColor: \"\",\n \n- /**\n- * APIProperty: buffer\n- * {Integer} Used only when in gridded mode, this specifies the number of \n- * extra rows and colums of tiles on each side which will\n- * surround the minimum grid tiles to cover the map.\n- * For very slow loading layers, a larger value may increase\n- * performance somewhat when dragging, but will increase bandwidth\n- * use significantly. \n+ /** \n+ * Property: opacity \n+ * {float} the opacity of this popup (between 0.0 and 1.0)\n */\n- buffer: 0,\n+ opacity: \"\",\n \n- /**\n- * APIProperty: transitionEffect\n- * {String} The transition effect to use when the map is zoomed.\n- * Two posible values:\n- *\n- * \"resize\" - Existing tiles are resized on zoom to provide a visual\n- * effect of the zoom having taken place immediately. As the\n- * new tiles become available, they are drawn on top of the\n- * resized tiles (this is the default setting).\n- * \"map-resize\" - Existing tiles are resized on zoom and placed below the\n- * base layer. New tiles for the base layer will cover existing tiles.\n- * This setting is recommended when having an overlay duplicated during\n- * the transition is undesirable (e.g. street labels or big transparent\n- * fills). \n- * null - No transition effect.\n- *\n- * Using \"resize\" on non-opaque layers can cause undesired visual\n- * effects. Set transitionEffect to null in this case.\n+ /** \n+ * Property: border \n+ * {String} the border size of the popup. (eg 2px)\n */\n- transitionEffect: \"resize\",\n+ border: \"\",\n \n- /**\n- * APIProperty: numLoadingTiles\n- * {Integer} How many tiles are still loading?\n+ /** \n+ * Property: contentDiv \n+ * {DOMElement} a reference to the element that holds the content of\n+ * the div.\n */\n- numLoadingTiles: 0,\n+ contentDiv: null,\n \n- /**\n- * Property: serverResolutions\n- * {Array(Number}} This property is documented in subclasses as\n- * an API property.\n+ /** \n+ * Property: groupDiv \n+ * {DOMElement} First and only child of 'div'. The group Div contains the\n+ * 'contentDiv' and the 'closeDiv'.\n */\n- serverResolutions: null,\n+ groupDiv: null,\n \n- /**\n- * Property: loading\n- * {Boolean} Indicates if tiles are being loaded.\n+ /** \n+ * Property: closeDiv\n+ * {DOMElement} the optional closer image\n */\n- loading: false,\n+ closeDiv: null,\n \n- /**\n- * Property: backBuffer\n- * {DOMElement} The back buffer.\n+ /** \n+ * APIProperty: autoSize\n+ * {Boolean} Resize the popup to auto-fit the contents.\n+ * Default is false.\n */\n- backBuffer: null,\n+ autoSize: false,\n \n /**\n- * Property: gridResolution\n- * {Number} The resolution of the current grid. Used for backbuffer and\n- * client zoom. This property is updated every time the grid is\n- * initialized.\n+ * APIProperty: minSize\n+ * {} Minimum size allowed for the popup's contents.\n */\n- gridResolution: null,\n+ minSize: null,\n \n /**\n- * Property: backBufferResolution\n- * {Number} The resolution of the current back buffer. This property is\n- * updated each time a back buffer is created.\n+ * APIProperty: maxSize\n+ * {} Maximum size allowed for the popup's contents.\n */\n- backBufferResolution: null,\n+ maxSize: null,\n \n- /**\n- * Property: backBufferLonLat\n- * {Object} The top-left corner of the current back buffer. Includes lon\n- * and lat properties. This object is updated each time a back buffer\n- * is created.\n+ /** \n+ * Property: displayClass\n+ * {String} The CSS class of the popup.\n */\n- backBufferLonLat: null,\n+ displayClass: \"olPopup\",\n \n- /**\n- * Property: backBufferTimerId\n- * {Number} The id of the back buffer timer. This timer is used to\n- * delay the removal of the back buffer, thereby preventing\n- * flash effects caused by tile animation.\n+ /** \n+ * Property: contentDisplayClass\n+ * {String} The CSS class of the popup content div.\n */\n- backBufferTimerId: null,\n+ contentDisplayClass: \"olPopupContent\",\n \n- /**\n- * APIProperty: removeBackBufferDelay\n- * {Number} Delay for removing the backbuffer when all tiles have finished\n- * loading. Can be set to 0 when no css opacity transitions for the\n- * olTileImage class are used. Default is 0 for layers,\n- * 2500 for tiled layers. See for more information on\n- * tile animation.\n+ /** \n+ * Property: padding \n+ * {int or } An extra opportunity to specify internal \n+ * padding of the content div inside the popup. This was originally\n+ * confused with the css padding as specified in style.css's \n+ * 'olPopupContent' class. We would like to get rid of this altogether,\n+ * except that it does come in handy for the framed and anchoredbubble\n+ * popups, who need to maintain yet another barrier between their \n+ * content and the outer border of the popup itself. \n+ * \n+ * Note that in order to not break API, we must continue to support \n+ * this property being set as an integer. Really, though, we'd like to \n+ * have this specified as a Bounds object so that user can specify\n+ * distinct left, top, right, bottom paddings. With the 3.0 release\n+ * we can make this only a bounds.\n */\n- removeBackBufferDelay: null,\n+ padding: 0,\n \n- /**\n- * APIProperty: className\n- * {String} Name of the class added to the layer div. If not set in the\n- * options passed to the constructor then className defaults to\n- * \"olLayerGridSingleTile\" for single tile layers (see ),\n- * and \"olLayerGrid\" for non single tile layers.\n- *\n- * Note:\n- *\n- * The displaying of tiles is not animated by default for single tile\n- * layers - OpenLayers' default theme (style.css) includes this:\n- * (code)\n- * .olLayerGrid .olTileImage {\n- * -webkit-transition: opacity 0.2s linear;\n- * -moz-transition: opacity 0.2s linear;\n- * -o-transition: opacity 0.2s linear;\n- * transition: opacity 0.2s linear;\n- * }\n- * (end)\n- * To animate tile displaying for any grid layer the following\n- * CSS rule can be used:\n- * (code)\n- * .olTileImage {\n- * -webkit-transition: opacity 0.2s linear;\n- * -moz-transition: opacity 0.2s linear;\n- * -o-transition: opacity 0.2s linear;\n- * transition: opacity 0.2s linear;\n- * }\n- * (end)\n- * In that case, to avoid flash effects, \n- * should not be zero.\n+ /** \n+ * Property: disableFirefoxOverflowHack\n+ * {Boolean} The hack for overflow in Firefox causes all elements \n+ * to be re-drawn, which causes Flash elements to be \n+ * re-initialized, which is troublesome.\n+ * With this property the hack can be disabled.\n */\n- className: null,\n+ disableFirefoxOverflowHack: false,\n \n /**\n- * Register a listener for a particular event with the following syntax:\n- * (code)\n- * layer.events.register(type, obj, listener);\n- * (end)\n- *\n- * Listeners will be called with a reference to an event object. The\n- * properties of this event depends on exactly what happened.\n- *\n- * All event objects have at least the following properties:\n- * object - {Object} A reference to layer.events.object.\n- * element - {DOMElement} A reference to layer.events.element.\n- *\n- * Supported event types:\n- * addtile - Triggered when a tile is added to this layer. Listeners receive\n- * an object as first argument, which has a tile property that\n- * references the tile that has been added.\n- * tileloadstart - Triggered when a tile starts loading. Listeners receive\n- * an object as first argument, which has a tile property that\n- * references the tile that starts loading.\n- * tileloaded - Triggered when each new tile is\n- * loaded, as a means of progress update to listeners.\n- * listeners can access 'numLoadingTiles' if they wish to keep\n- * track of the loading progress. Listeners are called with an object\n- * with a 'tile' property as first argument, making the loaded tile\n- * available to the listener, and an 'aborted' property, which will be\n- * true when loading was aborted and no tile data is available.\n- * tileerror - Triggered before the tileloaded event (i.e. when the tile is\n- * still hidden) if a tile failed to load. Listeners receive an object\n- * as first argument, which has a tile property that references the\n- * tile that could not be loaded.\n- * retile - Triggered when the layer recreates its tile grid.\n+ * Method: fixPadding\n+ * To be removed in 3.0, this function merely helps us to deal with the \n+ * case where the user may have set an integer value for padding, \n+ * instead of an object.\n */\n+ fixPadding: function() {\n+ if (typeof this.padding == \"number\") {\n+ this.padding = new OpenLayers.Bounds(\n+ this.padding, this.padding, this.padding, this.padding\n+ );\n+ }\n+ },\n \n /**\n- * Property: gridLayout\n- * {Object} Object containing properties tilelon, tilelat, startcol,\n- * startrow\n+ * APIProperty: panMapIfOutOfView\n+ * {Boolean} When drawn, pan map such that the entire popup is visible in\n+ * the current viewport (if necessary).\n+ * Default is false.\n */\n- gridLayout: null,\n+ panMapIfOutOfView: false,\n \n /**\n- * Property: rowSign\n- * {Number} 1 for grids starting at the top, -1 for grids starting at the\n- * bottom. This is used for several grid index and offset calculations.\n+ * APIProperty: keepInMap \n+ * {Boolean} If panMapIfOutOfView is false, and this property is true, \n+ * contrain the popup such that it always fits in the available map\n+ * space. By default, this is not set on the base class. If you are\n+ * creating popups that are near map edges and not allowing pannning,\n+ * and especially if you have a popup which has a\n+ * fixedRelativePosition, setting this to false may be a smart thing to\n+ * do. Subclasses may want to override this setting.\n+ * \n+ * Default is false.\n */\n- rowSign: null,\n+ keepInMap: false,\n \n /**\n- * Property: transitionendEvents\n- * {Array} Event names for transitionend\n+ * APIProperty: closeOnMove\n+ * {Boolean} When map pans, close the popup.\n+ * Default is false.\n */\n- transitionendEvents: [\n- 'transitionend', 'webkitTransitionEnd', 'otransitionend',\n- 'oTransitionEnd'\n- ],\n+ closeOnMove: false,\n \n- /**\n- * Constructor: OpenLayers.Layer.Grid\n- * Create a new grid layer\n- *\n- * Parameters:\n- * name - {String}\n- * url - {String}\n- * params - {Object}\n- * options - {Object} Hashtable of extra options to tag onto the layer\n+ /** \n+ * Property: map \n+ * {} this gets set in Map.js when the popup is added to the map\n */\n- initialize: function(name, url, params, options) {\n- OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,\n- arguments);\n- this.grid = [];\n- this._removeBackBuffer = OpenLayers.Function.bind(this.removeBackBuffer, this);\n-\n- this.initProperties();\n-\n- this.rowSign = this.tileOriginCorner.substr(0, 1) === \"t\" ? 1 : -1;\n- },\n+ map: null,\n \n- /**\n- * Method: initProperties\n- * Set any properties that depend on the value of singleTile.\n- * Currently sets removeBackBufferDelay and className\n+ /** \n+ * Constructor: OpenLayers.Popup\n+ * Create a popup.\n+ * \n+ * Parameters: \n+ * id - {String} a unqiue identifier for this popup. If null is passed\n+ * an identifier will be automatically generated. \n+ * lonlat - {} The position on the map the popup will\n+ * be shown.\n+ * contentSize - {} The size of the content.\n+ * contentHTML - {String} An HTML string to display inside the \n+ * popup.\n+ * closeBox - {Boolean} Whether to display a close box inside\n+ * the popup.\n+ * closeBoxCallback - {Function} Function to be called on closeBox click.\n */\n- initProperties: function() {\n- if (this.options.removeBackBufferDelay === undefined) {\n- this.removeBackBufferDelay = this.singleTile ? 0 : 2500;\n+ initialize: function(id, lonlat, contentSize, contentHTML, closeBox, closeBoxCallback) {\n+ if (id == null) {\n+ id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n }\n \n- if (this.options.className === undefined) {\n- this.className = this.singleTile ? 'olLayerGridSingleTile' :\n- 'olLayerGrid';\n+ this.id = id;\n+ this.lonlat = lonlat;\n+\n+ this.contentSize = (contentSize != null) ? contentSize :\n+ new OpenLayers.Size(\n+ OpenLayers.Popup.WIDTH,\n+ OpenLayers.Popup.HEIGHT);\n+ if (contentHTML != null) {\n+ this.contentHTML = contentHTML;\n }\n- },\n+ this.backgroundColor = OpenLayers.Popup.COLOR;\n+ this.opacity = OpenLayers.Popup.OPACITY;\n+ this.border = OpenLayers.Popup.BORDER;\n \n- /**\n- * Method: setMap\n- *\n- * Parameters:\n- * map - {} The map.\n- */\n- setMap: function(map) {\n- OpenLayers.Layer.HTTPRequest.prototype.setMap.call(this, map);\n- OpenLayers.Element.addClass(this.div, this.className);\n- },\n+ this.div = OpenLayers.Util.createDiv(this.id, null, null,\n+ null, null, null, \"hidden\");\n+ this.div.className = this.displayClass;\n \n- /**\n- * Method: removeMap\n- * Called when the layer is removed from the map.\n- *\n- * Parameters:\n- * map - {} The map.\n- */\n- removeMap: function(map) {\n- this.removeBackBuffer();\n+ var groupDivId = this.id + \"_GroupDiv\";\n+ this.groupDiv = OpenLayers.Util.createDiv(groupDivId, null, null,\n+ null, \"relative\", null,\n+ \"hidden\");\n+\n+ var id = this.div.id + \"_contentDiv\";\n+ this.contentDiv = OpenLayers.Util.createDiv(id, null, this.contentSize.clone(),\n+ null, \"relative\");\n+ this.contentDiv.className = this.contentDisplayClass;\n+ this.groupDiv.appendChild(this.contentDiv);\n+ this.div.appendChild(this.groupDiv);\n+\n+ if (closeBox) {\n+ this.addCloseBox(closeBoxCallback);\n+ }\n+\n+ this.registerEvents();\n },\n \n- /**\n- * APIMethod: destroy\n- * Deconstruct the layer and clear the grid.\n+ /** \n+ * Method: destroy\n+ * nullify references to prevent circular references and memory leaks\n */\n destroy: function() {\n- this.removeBackBuffer();\n- this.clearGrid();\n \n- this.grid = null;\n- this.tileSize = null;\n- OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments);\n+ this.id = null;\n+ this.lonlat = null;\n+ this.size = null;\n+ this.contentHTML = null;\n+\n+ this.backgroundColor = null;\n+ this.opacity = null;\n+ this.border = null;\n+\n+ if (this.closeOnMove && this.map) {\n+ this.map.events.unregister(\"movestart\", this, this.hide);\n+ }\n+\n+ this.events.destroy();\n+ this.events = null;\n+\n+ if (this.closeDiv) {\n+ OpenLayers.Event.stopObservingElement(this.closeDiv);\n+ this.groupDiv.removeChild(this.closeDiv);\n+ }\n+ this.closeDiv = null;\n+\n+ this.div.removeChild(this.groupDiv);\n+ this.groupDiv = null;\n+\n+ if (this.map != null) {\n+ this.map.removePopup(this);\n+ }\n+ this.map = null;\n+ this.div = null;\n+\n+ this.autoSize = null;\n+ this.minSize = null;\n+ this.maxSize = null;\n+ this.padding = null;\n+ this.panMapIfOutOfView = null;\n },\n \n- /**\n- * APIMethod: mergeNewParams\n- * Refetches tiles with new params merged, keeping a backbuffer. Each\n- * loading new tile will have a css class of '.olTileReplacing'. If a\n- * stylesheet applies a 'display: none' style to that class, any fade-in\n- * transition will not apply, and backbuffers for each tile will be removed\n- * as soon as the tile is loaded.\n- * \n- * Parameters:\n- * newParams - {Object}\n+ /** \n+ * Method: draw\n+ * Constructs the elements that make up the popup.\n *\n+ * Parameters:\n+ * px - {} the position the popup in pixels.\n+ * \n * Returns:\n- * redrawn: {Boolean} whether the layer was actually redrawn.\n+ * {DOMElement} Reference to a div that contains the drawn popup\n */\n+ draw: function(px) {\n+ if (px == null) {\n+ if ((this.lonlat != null) && (this.map != null)) {\n+ px = this.map.getLayerPxFromLonLat(this.lonlat);\n+ }\n+ }\n \n- /**\n- * Method: clearGrid\n- * Go through and remove all tiles from the grid, calling\n- * destroy() on each of them to kill circular references\n- */\n- clearGrid: function() {\n- if (this.grid) {\n- for (var iRow = 0, len = this.grid.length; iRow < len; iRow++) {\n- var row = this.grid[iRow];\n- for (var iCol = 0, clen = row.length; iCol < clen; iCol++) {\n- var tile = row[iCol];\n- this.destroyTile(tile);\n+ // this assumes that this.map already exists, which is okay because \n+ // this.draw is only called once the popup has been added to the map.\n+ if (this.closeOnMove) {\n+ this.map.events.register(\"movestart\", this, this.hide);\n+ }\n+\n+ //listen to movestart, moveend to disable overflow (FF bug)\n+ if (!this.disableFirefoxOverflowHack && OpenLayers.BROWSER_NAME == 'firefox') {\n+ this.map.events.register(\"movestart\", this, function() {\n+ var style = document.defaultView.getComputedStyle(\n+ this.contentDiv, null\n+ );\n+ var currentOverflow = style.getPropertyValue(\"overflow\");\n+ if (currentOverflow != \"hidden\") {\n+ this.contentDiv._oldOverflow = currentOverflow;\n+ this.contentDiv.style.overflow = \"hidden\";\n+ }\n+ });\n+ this.map.events.register(\"moveend\", this, function() {\n+ var oldOverflow = this.contentDiv._oldOverflow;\n+ if (oldOverflow) {\n+ this.contentDiv.style.overflow = oldOverflow;\n+ this.contentDiv._oldOverflow = null;\n }\n+ });\n+ }\n+\n+ this.moveTo(px);\n+ if (!this.autoSize && !this.size) {\n+ this.setSize(this.contentSize);\n+ }\n+ this.setBackgroundColor();\n+ this.setOpacity();\n+ this.setBorder();\n+ this.setContentHTML();\n+\n+ if (this.panMapIfOutOfView) {\n+ this.panIntoView();\n+ }\n+\n+ return this.div;\n+ },\n+\n+ /** \n+ * Method: updatePosition\n+ * if the popup has a lonlat and its map members set, \n+ * then have it move itself to its proper position\n+ */\n+ updatePosition: function() {\n+ if ((this.lonlat) && (this.map)) {\n+ var px = this.map.getLayerPxFromLonLat(this.lonlat);\n+ if (px) {\n+ this.moveTo(px);\n }\n- this.grid = [];\n- this.gridResolution = null;\n- this.gridLayout = null;\n }\n },\n \n /**\n- * APIMethod: addOptions\n+ * Method: moveTo\n * \n * Parameters:\n- * newOptions - {Object}\n- * reinitialize - {Boolean} If set to true, and if resolution options of the\n- * current baseLayer were changed, the map will be recentered to make\n- * sure that it is displayed with a valid resolution, and a\n- * changebaselayer event will be triggered.\n+ * px - {} the top and left position of the popup div. \n */\n- addOptions: function(newOptions, reinitialize) {\n- var singleTileChanged = newOptions.singleTile !== undefined &&\n- newOptions.singleTile !== this.singleTile;\n- OpenLayers.Layer.HTTPRequest.prototype.addOptions.apply(this, arguments);\n- if (this.map && singleTileChanged) {\n- this.initProperties();\n- this.clearGrid();\n- this.tileSize = this.options.tileSize;\n- this.setTileSize();\n- this.moveTo(null, true);\n+ moveTo: function(px) {\n+ if ((px != null) && (this.div != null)) {\n+ this.div.style.left = px.x + \"px\";\n+ this.div.style.top = px.y + \"px\";\n }\n },\n \n /**\n- * APIMethod: clone\n- * Create a clone of this layer\n+ * Method: visible\n *\n- * Parameters:\n- * obj - {Object} Is this ever used?\n- * \n- * Returns:\n- * {} An exact clone of this OpenLayers.Layer.Grid\n+ * Returns: \n+ * {Boolean} Boolean indicating whether or not the popup is visible\n */\n- clone: function(obj) {\n+ visible: function() {\n+ return OpenLayers.Element.visible(this.div);\n+ },\n \n- if (obj == null) {\n- obj = new OpenLayers.Layer.Grid(this.name,\n- this.url,\n- this.params,\n- this.getOptions());\n+ /**\n+ * Method: toggle\n+ * Toggles visibility of the popup.\n+ */\n+ toggle: function() {\n+ if (this.visible()) {\n+ this.hide();\n+ } else {\n+ this.show();\n }\n+ },\n \n- //get all additions from superclasses\n- obj = OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this, [obj]);\n+ /**\n+ * Method: show\n+ * Makes the popup visible.\n+ */\n+ show: function() {\n+ this.div.style.display = '';\n \n- // copy/set any non-init, non-simple values here\n- if (this.tileSize != null) {\n- obj.tileSize = this.tileSize.clone();\n+ if (this.panMapIfOutOfView) {\n+ this.panIntoView();\n }\n+ },\n \n- // we do not want to copy reference to grid, so we make a new array\n- obj.grid = [];\n- obj.gridResolution = null;\n- // same for backbuffer\n- obj.backBuffer = null;\n- obj.backBufferTimerId = null;\n- obj.loading = false;\n- obj.numLoadingTiles = 0;\n-\n- return obj;\n+ /**\n+ * Method: hide\n+ * Makes the popup invisible.\n+ */\n+ hide: function() {\n+ this.div.style.display = 'none';\n },\n \n /**\n- * Method: moveTo\n- * This function is called whenever the map is moved. All the moving\n- * of actual 'tiles' is done by the map, but moveTo's role is to accept\n- * a bounds and make sure the data that that bounds requires is pre-loaded.\n+ * Method: setSize\n+ * Used to adjust the size of the popup. \n *\n * Parameters:\n- * bounds - {}\n- * zoomChanged - {Boolean}\n- * dragging - {Boolean}\n+ * contentSize - {} the new size for the popup's \n+ * contents div (in pixels).\n */\n- moveTo: function(bounds, zoomChanged, dragging) {\n+ setSize: function(contentSize) {\n+ this.size = contentSize.clone();\n \n- OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this, arguments);\n+ // if our contentDiv has a css 'padding' set on it by a stylesheet, we \n+ // must add that to the desired \"size\". \n+ var contentDivPadding = this.getContentDivPadding();\n+ var wPadding = contentDivPadding.left + contentDivPadding.right;\n+ var hPadding = contentDivPadding.top + contentDivPadding.bottom;\n \n- bounds = bounds || this.map.getExtent();\n+ // take into account the popup's 'padding' property\n+ this.fixPadding();\n+ wPadding += this.padding.left + this.padding.right;\n+ hPadding += this.padding.top + this.padding.bottom;\n \n- if (bounds != null) {\n+ // make extra space for the close div\n+ if (this.closeDiv) {\n+ var closeDivWidth = parseInt(this.closeDiv.style.width);\n+ wPadding += closeDivWidth + contentDivPadding.right;\n+ }\n \n- // if grid is empty or zoom has changed, we *must* re-tile\n- var forceReTile = !this.grid.length || zoomChanged;\n+ //increase size of the main popup div to take into account the \n+ // users's desired padding and close div. \n+ this.size.w += wPadding;\n+ this.size.h += hPadding;\n \n- // total bounds of the tiles\n- var tilesBounds = this.getTilesBounds();\n+ //now if our browser is IE, we need to actually make the contents \n+ // div itself bigger to take its own padding into effect. this makes \n+ // me want to shoot someone, but so it goes.\n+ if (OpenLayers.BROWSER_NAME == \"msie\") {\n+ this.contentSize.w +=\n+ contentDivPadding.left + contentDivPadding.right;\n+ this.contentSize.h +=\n+ contentDivPadding.bottom + contentDivPadding.top;\n+ }\n \n- // the new map resolution\n- var resolution = this.map.getResolution();\n+ if (this.div != null) {\n+ this.div.style.width = this.size.w + \"px\";\n+ this.div.style.height = this.size.h + \"px\";\n+ }\n+ if (this.contentDiv != null) {\n+ this.contentDiv.style.width = contentSize.w + \"px\";\n+ this.contentDiv.style.height = contentSize.h + \"px\";\n+ }\n+ },\n \n- // the server-supported resolution for the new map resolution\n- var serverResolution = this.getServerResolution(resolution);\n+ /**\n+ * APIMethod: updateSize\n+ * Auto size the popup so that it precisely fits its contents (as \n+ * determined by this.contentDiv.innerHTML). Popup size will, of\n+ * course, be limited by the available space on the current map\n+ */\n+ updateSize: function() {\n \n- if (this.singleTile) {\n+ // determine actual render dimensions of the contents by putting its\n+ // contents into a fake contentDiv (for the CSS) and then measuring it\n+ var preparedHTML = \"
\" +\n+ this.contentDiv.innerHTML +\n+ \"
\";\n \n- // We want to redraw whenever even the slightest part of the \n- // current bounds is not contained by our tile.\n- // (thus, we do not specify partial -- its default is false)\n+ var containerElement = (this.map) ? this.map.div : document.body;\n+ var realSize = OpenLayers.Util.getRenderedDimensions(\n+ preparedHTML, null, {\n+ displayClass: this.displayClass,\n+ containerElement: containerElement\n+ }\n+ );\n \n- if (forceReTile ||\n- (!dragging && !tilesBounds.containsBounds(bounds))) {\n+ // is the \"real\" size of the div is safe to display in our map?\n+ var safeSize = this.getSafeContentSize(realSize);\n \n- // In single tile mode with no transition effect, we insert\n- // a non-scaled backbuffer when the layer is moved. But if\n- // a zoom occurs right after a move, i.e. before the new\n- // image is received, we need to remove the backbuffer, or\n- // an ill-positioned image will be visible during the zoom\n- // transition.\n+ var newSize = null;\n+ if (safeSize.equals(realSize)) {\n+ //real size of content is small enough to fit on the map, \n+ // so we use real size.\n+ newSize = realSize;\n \n- if (zoomChanged && this.transitionEffect !== 'resize') {\n- this.removeBackBuffer();\n- }\n+ } else {\n \n- if (!zoomChanged || this.transitionEffect === 'resize') {\n- this.applyBackBuffer(resolution);\n- }\n+ // make a new 'size' object with the clipped dimensions \n+ // set or null if not clipped.\n+ var fixedSize = {\n+ w: (safeSize.w < realSize.w) ? safeSize.w : null,\n+ h: (safeSize.h < realSize.h) ? safeSize.h : null\n+ };\n \n- this.initSingleTile(bounds);\n- }\n+ if (fixedSize.w && fixedSize.h) {\n+ //content is too big in both directions, so we will use \n+ // max popup size (safeSize), knowing well that it will \n+ // overflow both ways. \n+ newSize = safeSize;\n } else {\n+ //content is clipped in only one direction, so we need to \n+ // run getRenderedDimensions() again with a fixed dimension\n+ var clippedSize = OpenLayers.Util.getRenderedDimensions(\n+ preparedHTML, fixedSize, {\n+ displayClass: this.contentDisplayClass,\n+ containerElement: containerElement\n+ }\n+ );\n \n- // if the bounds have changed such that they are not even \n- // *partially* contained by our tiles (e.g. when user has \n- // programmatically panned to the other side of the earth on\n- // zoom level 18), then moveGriddedTiles could potentially have\n- // to run through thousands of cycles, so we want to reTile\n- // instead (thus, partial true). \n- forceReTile = forceReTile ||\n- !tilesBounds.intersectsBounds(bounds, {\n- worldBounds: this.map.baseLayer.wrapDateLine &&\n- this.map.getMaxExtent()\n- });\n-\n- if (forceReTile) {\n- if (zoomChanged && (this.transitionEffect === 'resize' ||\n- this.gridResolution === resolution)) {\n- this.applyBackBuffer(resolution);\n+ //if the clipped size is still the same as the safeSize, \n+ // that means that our content must be fixed in the \n+ // offending direction. If overflow is 'auto', this means \n+ // we are going to have a scrollbar for sure, so we must \n+ // adjust for that.\n+ //\n+ var currentOverflow = OpenLayers.Element.getStyle(\n+ this.contentDiv, \"overflow\"\n+ );\n+ if ((currentOverflow != \"hidden\") &&\n+ (clippedSize.equals(safeSize))) {\n+ var scrollBar = OpenLayers.Util.getScrollbarWidth();\n+ if (fixedSize.w) {\n+ clippedSize.h += scrollBar;\n+ } else {\n+ clippedSize.w += scrollBar;\n }\n- this.initGriddedTiles(bounds);\n- } else {\n- this.moveGriddedTiles();\n }\n+\n+ newSize = this.getSafeContentSize(clippedSize);\n }\n }\n+ this.setSize(newSize);\n },\n \n /**\n- * Method: getTileData\n- * Given a map location, retrieve a tile and the pixel offset within that\n- * tile corresponding to the location. If there is not an existing \n- * tile in the grid that covers the given location, null will be \n- * returned.\n+ * Method: setBackgroundColor\n+ * Sets the background color of the popup.\n *\n * Parameters:\n- * loc - {} map location\n- *\n- * Returns:\n- * {Object} Object with the following properties: tile ({}),\n- * i ({Number} x-pixel offset from top left), and j ({Integer} y-pixel\n- * offset from top left).\n+ * color - {String} the background color. eg \"#FFBBBB\"\n */\n- getTileData: function(loc) {\n- var data = null,\n- x = loc.lon,\n- y = loc.lat,\n- numRows = this.grid.length;\n+ setBackgroundColor: function(color) {\n+ if (color != undefined) {\n+ this.backgroundColor = color;\n+ }\n \n- if (this.map && numRows) {\n- var res = this.map.getResolution(),\n- tileWidth = this.tileSize.w,\n- tileHeight = this.tileSize.h,\n- bounds = this.grid[0][0].bounds,\n- left = bounds.left,\n- top = bounds.top;\n+ if (this.div != null) {\n+ this.div.style.backgroundColor = this.backgroundColor;\n+ }\n+ },\n \n- if (x < left) {\n- // deal with multiple worlds\n- if (this.map.baseLayer.wrapDateLine) {\n- var worldWidth = this.map.getMaxExtent().getWidth();\n- var worldsAway = Math.ceil((left - x) / worldWidth);\n- x += worldWidth * worldsAway;\n- }\n- }\n- // tile distance to location (fractional number of tiles);\n- var dtx = (x - left) / (res * tileWidth);\n- var dty = (top - y) / (res * tileHeight);\n- // index of tile in grid\n- var col = Math.floor(dtx);\n- var row = Math.floor(dty);\n- if (row >= 0 && row < numRows) {\n- var tile = this.grid[row][col];\n- if (tile) {\n- data = {\n- tile: tile,\n- // pixel index within tile\n- i: Math.floor((dtx - col) * tileWidth),\n- j: Math.floor((dty - row) * tileHeight)\n- };\n- }\n- }\n+ /**\n+ * Method: setOpacity\n+ * Sets the opacity of the popup.\n+ * \n+ * Parameters:\n+ * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid). \n+ */\n+ setOpacity: function(opacity) {\n+ if (opacity != undefined) {\n+ this.opacity = opacity;\n+ }\n+\n+ if (this.div != null) {\n+ // for Mozilla and Safari\n+ this.div.style.opacity = this.opacity;\n+\n+ // for IE\n+ this.div.style.filter = 'alpha(opacity=' + this.opacity * 100 + ')';\n }\n- return data;\n },\n \n /**\n- * Method: destroyTile\n+ * Method: setBorder\n+ * Sets the border style of the popup.\n *\n * Parameters:\n- * tile - {}\n+ * border - {String} The border style value. eg 2px \n */\n- destroyTile: function(tile) {\n- this.removeTileMonitoringHooks(tile);\n- tile.destroy();\n+ setBorder: function(border) {\n+ if (border != undefined) {\n+ this.border = border;\n+ }\n+\n+ if (this.div != null) {\n+ this.div.style.border = this.border;\n+ }\n },\n \n /**\n- * Method: getServerResolution\n- * Return the closest server-supported resolution.\n+ * Method: setContentHTML\n+ * Allows the user to set the HTML content of the popup.\n *\n * Parameters:\n- * resolution - {Number} The base resolution. If undefined the\n- * map resolution is used.\n- *\n- * Returns:\n- * {Number} The closest server resolution value.\n- */\n- getServerResolution: function(resolution) {\n- var distance = Number.POSITIVE_INFINITY;\n- resolution = resolution || this.map.getResolution();\n- if (this.serverResolutions &&\n- OpenLayers.Util.indexOf(this.serverResolutions, resolution) === -1) {\n- var i, newDistance, newResolution, serverResolution;\n- for (i = this.serverResolutions.length - 1; i >= 0; i--) {\n- newResolution = this.serverResolutions[i];\n- newDistance = Math.abs(newResolution - resolution);\n- if (newDistance > distance) {\n- break;\n- }\n- distance = newDistance;\n- serverResolution = newResolution;\n- }\n- resolution = serverResolution;\n- }\n- return resolution;\n- },\n-\n- /**\n- * Method: getServerZoom\n- * Return the zoom value corresponding to the best matching server\n- * resolution, taking into account and .\n- *\n- * Returns:\n- * {Number} The closest server supported zoom. This is not the map zoom\n- * level, but an index of the server's resolutions array.\n- */\n- getServerZoom: function() {\n- var resolution = this.getServerResolution();\n- return this.serverResolutions ?\n- OpenLayers.Util.indexOf(this.serverResolutions, resolution) :\n- this.map.getZoomForResolution(resolution) + (this.zoomOffset || 0);\n- },\n-\n- /**\n- * Method: applyBackBuffer\n- * Create, insert, scale and position a back buffer for the layer.\n- *\n- * Parameters:\n- * resolution - {Number} The resolution to transition to.\n- */\n- applyBackBuffer: function(resolution) {\n- if (this.backBufferTimerId !== null) {\n- this.removeBackBuffer();\n- }\n- var backBuffer = this.backBuffer;\n- if (!backBuffer) {\n- backBuffer = this.createBackBuffer();\n- if (!backBuffer) {\n- return;\n- }\n- if (resolution === this.gridResolution) {\n- this.div.insertBefore(backBuffer, this.div.firstChild);\n- } else {\n- this.map.baseLayer.div.parentNode.insertBefore(backBuffer, this.map.baseLayer.div);\n- }\n- this.backBuffer = backBuffer;\n-\n- // set some information in the instance for subsequent\n- // calls to applyBackBuffer where the same back buffer\n- // is reused\n- var topLeftTileBounds = this.grid[0][0].bounds;\n- this.backBufferLonLat = {\n- lon: topLeftTileBounds.left,\n- lat: topLeftTileBounds.top\n- };\n- this.backBufferResolution = this.gridResolution;\n- }\n-\n- var ratio = this.backBufferResolution / resolution;\n-\n- // scale the tiles inside the back buffer\n- var tiles = backBuffer.childNodes,\n- tile;\n- for (var i = tiles.length - 1; i >= 0; --i) {\n- tile = tiles[i];\n- tile.style.top = ((ratio * tile._i * tile._h) | 0) + 'px';\n- tile.style.left = ((ratio * tile._j * tile._w) | 0) + 'px';\n- tile.style.width = Math.round(ratio * tile._w) + 'px';\n- tile.style.height = Math.round(ratio * tile._h) + 'px';\n- }\n-\n- // and position it (based on the grid's top-left corner)\n- var position = this.getViewPortPxFromLonLat(\n- this.backBufferLonLat, resolution);\n- var leftOffset = this.map.layerContainerOriginPx.x;\n- var topOffset = this.map.layerContainerOriginPx.y;\n- backBuffer.style.left = Math.round(position.x - leftOffset) + 'px';\n- backBuffer.style.top = Math.round(position.y - topOffset) + 'px';\n- },\n-\n- /**\n- * Method: createBackBuffer\n- * Create a back buffer.\n- *\n- * Returns:\n- * {DOMElement} The DOM element for the back buffer, undefined if the\n- * grid isn't initialized yet.\n- */\n- createBackBuffer: function() {\n- var backBuffer;\n- if (this.grid.length > 0) {\n- backBuffer = document.createElement('div');\n- backBuffer.id = this.div.id + '_bb';\n- backBuffer.className = 'olBackBuffer';\n- backBuffer.style.position = 'absolute';\n- var map = this.map;\n- backBuffer.style.zIndex = this.transitionEffect === 'resize' ?\n- this.getZIndex() - 1 :\n- // 'map-resize':\n- map.Z_INDEX_BASE.BaseLayer -\n- (map.getNumLayers() - map.getLayerIndex(this));\n- for (var i = 0, lenI = this.grid.length; i < lenI; i++) {\n- for (var j = 0, lenJ = this.grid[i].length; j < lenJ; j++) {\n- var tile = this.grid[i][j],\n- markup = this.grid[i][j].createBackBuffer();\n- if (markup) {\n- markup._i = i;\n- markup._j = j;\n- markup._w = tile.size.w;\n- markup._h = tile.size.h;\n- markup.id = tile.id + '_bb';\n- backBuffer.appendChild(markup);\n- }\n- }\n- }\n- }\n- return backBuffer;\n- },\n-\n- /**\n- * Method: removeBackBuffer\n- * Remove back buffer from DOM.\n- */\n- removeBackBuffer: function() {\n- if (this._transitionElement) {\n- for (var i = this.transitionendEvents.length - 1; i >= 0; --i) {\n- OpenLayers.Event.stopObserving(this._transitionElement,\n- this.transitionendEvents[i], this._removeBackBuffer);\n- }\n- delete this._transitionElement;\n- }\n- if (this.backBuffer) {\n- if (this.backBuffer.parentNode) {\n- this.backBuffer.parentNode.removeChild(this.backBuffer);\n- }\n- this.backBuffer = null;\n- this.backBufferResolution = null;\n- if (this.backBufferTimerId !== null) {\n- window.clearTimeout(this.backBufferTimerId);\n- this.backBufferTimerId = null;\n- }\n- }\n- },\n-\n- /**\n- * Method: moveByPx\n- * Move the layer based on pixel vector.\n- *\n- * Parameters:\n- * dx - {Number}\n- * dy - {Number}\n- */\n- moveByPx: function(dx, dy) {\n- if (!this.singleTile) {\n- this.moveGriddedTiles();\n- }\n- },\n-\n- /**\n- * APIMethod: setTileSize\n- * Check if we are in singleTile mode and if so, set the size as a ratio\n- * of the map size (as specified by the layer's 'ratio' property).\n- * \n- * Parameters:\n- * size - {}\n- */\n- setTileSize: function(size) {\n- if (this.singleTile) {\n- size = this.map.getSize();\n- size.h = parseInt(size.h * this.ratio, 10);\n- size.w = parseInt(size.w * this.ratio, 10);\n- }\n- OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this, [size]);\n- },\n-\n- /**\n- * APIMethod: getTilesBounds\n- * Return the bounds of the tile grid.\n- *\n- * Returns:\n- * {} A Bounds object representing the bounds of all the\n- * currently loaded tiles (including those partially or not at all seen \n- * onscreen).\n- */\n- getTilesBounds: function() {\n- var bounds = null;\n-\n- var length = this.grid.length;\n- if (length) {\n- var bottomLeftTileBounds = this.grid[length - 1][0].bounds,\n- width = this.grid[0].length * bottomLeftTileBounds.getWidth(),\n- height = this.grid.length * bottomLeftTileBounds.getHeight();\n-\n- bounds = new OpenLayers.Bounds(bottomLeftTileBounds.left,\n- bottomLeftTileBounds.bottom,\n- bottomLeftTileBounds.left + width,\n- bottomLeftTileBounds.bottom + height);\n- }\n- return bounds;\n- },\n-\n- /**\n- * Method: initSingleTile\n- * \n- * Parameters: \n- * bounds - {}\n- */\n- initSingleTile: function(bounds) {\n- this.events.triggerEvent(\"retile\");\n-\n- //determine new tile bounds\n- var center = bounds.getCenterLonLat();\n- var tileWidth = bounds.getWidth() * this.ratio;\n- var tileHeight = bounds.getHeight() * this.ratio;\n-\n- var tileBounds =\n- new OpenLayers.Bounds(center.lon - (tileWidth / 2),\n- center.lat - (tileHeight / 2),\n- center.lon + (tileWidth / 2),\n- center.lat + (tileHeight / 2));\n-\n- var px = this.map.getLayerPxFromLonLat({\n- lon: tileBounds.left,\n- lat: tileBounds.top\n- });\n-\n- if (!this.grid.length) {\n- this.grid[0] = [];\n- }\n-\n- var tile = this.grid[0][0];\n- if (!tile) {\n- tile = this.addTile(tileBounds, px);\n-\n- this.addTileMonitoringHooks(tile);\n- tile.draw();\n- this.grid[0][0] = tile;\n- } else {\n- tile.moveTo(tileBounds, px);\n- }\n-\n- //remove all but our single tile\n- this.removeExcessTiles(1, 1);\n-\n- // store the resolution of the grid\n- this.gridResolution = this.getServerResolution();\n- },\n-\n- /** \n- * Method: calculateGridLayout\n- * Generate parameters for the grid layout.\n- *\n- * Parameters:\n- * bounds - {|Object} OpenLayers.Bounds or an\n- * object with a 'left' and 'top' properties.\n- * origin - {|Object} OpenLayers.LonLat or an\n- * object with a 'lon' and 'lat' properties.\n- * resolution - {Number}\n- *\n- * Returns:\n- * {Object} Object containing properties tilelon, tilelat, startcol,\n- * startrow\n- */\n- calculateGridLayout: function(bounds, origin, resolution) {\n- var tilelon = resolution * this.tileSize.w;\n- var tilelat = resolution * this.tileSize.h;\n-\n- var offsetlon = bounds.left - origin.lon;\n- var tilecol = Math.floor(offsetlon / tilelon) - this.buffer;\n-\n- var rowSign = this.rowSign;\n-\n- var offsetlat = rowSign * (origin.lat - bounds.top + tilelat);\n- var tilerow = Math[~rowSign ? 'floor' : 'ceil'](offsetlat / tilelat) - this.buffer * rowSign;\n-\n- return {\n- tilelon: tilelon,\n- tilelat: tilelat,\n- startcol: tilecol,\n- startrow: tilerow\n- };\n-\n- },\n-\n- /**\n- * Method: getTileOrigin\n- * Determine the origin for aligning the grid of tiles. If a \n- * property is supplied, that will be returned. Otherwise, the origin\n- * will be derived from the layer's property. In this case,\n- * the tile origin will be the corner of the given by the \n- * property.\n- *\n- * Returns:\n- * {} The tile origin.\n- */\n- getTileOrigin: function() {\n- var origin = this.tileOrigin;\n- if (!origin) {\n- var extent = this.getMaxExtent();\n- var edges = ({\n- \"tl\": [\"left\", \"top\"],\n- \"tr\": [\"right\", \"top\"],\n- \"bl\": [\"left\", \"bottom\"],\n- \"br\": [\"right\", \"bottom\"]\n- })[this.tileOriginCorner];\n- origin = new OpenLayers.LonLat(extent[edges[0]], extent[edges[1]]);\n- }\n- return origin;\n- },\n-\n- /**\n- * Method: getTileBoundsForGridIndex\n- *\n- * Parameters:\n- * row - {Number} The row of the grid\n- * col - {Number} The column of the grid\n- *\n- * Returns:\n- * {} The bounds for the tile at (row, col)\n- */\n- getTileBoundsForGridIndex: function(row, col) {\n- var origin = this.getTileOrigin();\n- var tileLayout = this.gridLayout;\n- var tilelon = tileLayout.tilelon;\n- var tilelat = tileLayout.tilelat;\n- var startcol = tileLayout.startcol;\n- var startrow = tileLayout.startrow;\n- var rowSign = this.rowSign;\n- return new OpenLayers.Bounds(\n- origin.lon + (startcol + col) * tilelon,\n- origin.lat - (startrow + row * rowSign) * tilelat * rowSign,\n- origin.lon + (startcol + col + 1) * tilelon,\n- origin.lat - (startrow + (row - 1) * rowSign) * tilelat * rowSign\n- );\n- },\n-\n- /**\n- * Method: initGriddedTiles\n- * \n- * Parameters:\n- * bounds - {}\n- */\n- initGriddedTiles: function(bounds) {\n- this.events.triggerEvent(\"retile\");\n-\n- // work out mininum number of rows and columns; this is the number of\n- // tiles required to cover the viewport plus at least one for panning\n-\n- var viewSize = this.map.getSize();\n-\n- var origin = this.getTileOrigin();\n- var resolution = this.map.getResolution(),\n- serverResolution = this.getServerResolution(),\n- ratio = resolution / serverResolution,\n- tileSize = {\n- w: this.tileSize.w / ratio,\n- h: this.tileSize.h / ratio\n- };\n-\n- var minRows = Math.ceil(viewSize.h / tileSize.h) +\n- 2 * this.buffer + 1;\n- var minCols = Math.ceil(viewSize.w / tileSize.w) +\n- 2 * this.buffer + 1;\n-\n- var tileLayout = this.calculateGridLayout(bounds, origin, serverResolution);\n- this.gridLayout = tileLayout;\n-\n- var tilelon = tileLayout.tilelon;\n- var tilelat = tileLayout.tilelat;\n-\n- var layerContainerDivLeft = this.map.layerContainerOriginPx.x;\n- var layerContainerDivTop = this.map.layerContainerOriginPx.y;\n-\n- var tileBounds = this.getTileBoundsForGridIndex(0, 0);\n- var startPx = this.map.getViewPortPxFromLonLat(\n- new OpenLayers.LonLat(tileBounds.left, tileBounds.top)\n- );\n- startPx.x = Math.round(startPx.x) - layerContainerDivLeft;\n- startPx.y = Math.round(startPx.y) - layerContainerDivTop;\n-\n- var tileData = [],\n- center = this.map.getCenter();\n-\n- var rowidx = 0;\n- do {\n- var row = this.grid[rowidx];\n- if (!row) {\n- row = [];\n- this.grid.push(row);\n- }\n-\n- var colidx = 0;\n- do {\n- tileBounds = this.getTileBoundsForGridIndex(rowidx, colidx);\n- var px = startPx.clone();\n- px.x = px.x + colidx * Math.round(tileSize.w);\n- px.y = px.y + rowidx * Math.round(tileSize.h);\n- var tile = row[colidx];\n- if (!tile) {\n- tile = this.addTile(tileBounds, px);\n- this.addTileMonitoringHooks(tile);\n- row.push(tile);\n- } else {\n- tile.moveTo(tileBounds, px, false);\n- }\n- var tileCenter = tileBounds.getCenterLonLat();\n- tileData.push({\n- tile: tile,\n- distance: Math.pow(tileCenter.lon - center.lon, 2) +\n- Math.pow(tileCenter.lat - center.lat, 2)\n- });\n-\n- colidx += 1;\n- } while ((tileBounds.right <= bounds.right + tilelon * this.buffer) ||\n- colidx < minCols);\n-\n- rowidx += 1;\n- } while ((tileBounds.bottom >= bounds.bottom - tilelat * this.buffer) ||\n- rowidx < minRows);\n-\n- //shave off exceess rows and colums\n- this.removeExcessTiles(rowidx, colidx);\n-\n- var resolution = this.getServerResolution();\n- // store the resolution of the grid\n- this.gridResolution = resolution;\n-\n- //now actually draw the tiles\n- tileData.sort(function(a, b) {\n- return a.distance - b.distance;\n- });\n- for (var i = 0, ii = tileData.length; i < ii; ++i) {\n- tileData[i].tile.draw();\n- }\n- },\n-\n- /**\n- * Method: getMaxExtent\n- * Get this layer's maximum extent. (Implemented as a getter for\n- * potential specific implementations in sub-classes.)\n- *\n- * Returns:\n- * {}\n- */\n- getMaxExtent: function() {\n- return this.maxExtent;\n- },\n-\n- /**\n- * APIMethod: addTile\n- * Create a tile, initialize it, and add it to the layer div. \n- *\n- * Parameters\n- * bounds - {}\n- * position - {}\n- *\n- * Returns:\n- * {} The added OpenLayers.Tile\n- */\n- addTile: function(bounds, position) {\n- var tile = new this.tileClass(\n- this, position, bounds, null, this.tileSize, this.tileOptions\n- );\n- this.events.triggerEvent(\"addtile\", {\n- tile: tile\n- });\n- return tile;\n- },\n-\n- /** \n- * Method: addTileMonitoringHooks\n- * This function takes a tile as input and adds the appropriate hooks to \n- * the tile so that the layer can keep track of the loading tiles.\n- * \n- * Parameters: \n- * tile - {}\n- */\n- addTileMonitoringHooks: function(tile) {\n-\n- var replacingCls = 'olTileReplacing';\n-\n- tile.onLoadStart = function() {\n- //if that was first tile then trigger a 'loadstart' on the layer\n- if (this.loading === false) {\n- this.loading = true;\n- this.events.triggerEvent(\"loadstart\");\n- }\n- this.events.triggerEvent(\"tileloadstart\", {\n- tile: tile\n- });\n- this.numLoadingTiles++;\n- if (!this.singleTile && this.backBuffer && this.gridResolution === this.backBufferResolution) {\n- OpenLayers.Element.addClass(tile.getTile(), replacingCls);\n- }\n- };\n-\n- tile.onLoadEnd = function(evt) {\n- this.numLoadingTiles--;\n- var aborted = evt.type === 'unload';\n- this.events.triggerEvent(\"tileloaded\", {\n- tile: tile,\n- aborted: aborted\n- });\n- if (!this.singleTile && !aborted && this.backBuffer && this.gridResolution === this.backBufferResolution) {\n- var tileDiv = tile.getTile();\n- if (OpenLayers.Element.getStyle(tileDiv, 'display') === 'none') {\n- var bufferTile = document.getElementById(tile.id + '_bb');\n- if (bufferTile) {\n- bufferTile.parentNode.removeChild(bufferTile);\n- }\n- }\n- OpenLayers.Element.removeClass(tileDiv, replacingCls);\n- }\n- //if that was the last tile, then trigger a 'loadend' on the layer\n- if (this.numLoadingTiles === 0) {\n- if (this.backBuffer) {\n- if (this.backBuffer.childNodes.length === 0) {\n- // no tiles transitioning, remove immediately\n- this.removeBackBuffer();\n- } else {\n- // wait until transition has ended or delay has passed\n- this._transitionElement = aborted ?\n- this.div.lastChild : tile.imgDiv;\n- var transitionendEvents = this.transitionendEvents;\n- for (var i = transitionendEvents.length - 1; i >= 0; --i) {\n- OpenLayers.Event.observe(this._transitionElement,\n- transitionendEvents[i],\n- this._removeBackBuffer);\n- }\n- // the removal of the back buffer is delayed to prevent\n- // flash effects due to the animation of tile displaying\n- this.backBufferTimerId = window.setTimeout(\n- this._removeBackBuffer, this.removeBackBufferDelay\n- );\n- }\n- }\n- this.loading = false;\n- this.events.triggerEvent(\"loadend\");\n- }\n- };\n-\n- tile.onLoadError = function() {\n- this.events.triggerEvent(\"tileerror\", {\n- tile: tile\n- });\n- };\n-\n- tile.events.on({\n- \"loadstart\": tile.onLoadStart,\n- \"loadend\": tile.onLoadEnd,\n- \"unload\": tile.onLoadEnd,\n- \"loaderror\": tile.onLoadError,\n- scope: this\n- });\n- },\n-\n- /** \n- * Method: removeTileMonitoringHooks\n- * This function takes a tile as input and removes the tile hooks \n- * that were added in addTileMonitoringHooks()\n- * \n- * Parameters: \n- * tile - {}\n- */\n- removeTileMonitoringHooks: function(tile) {\n- tile.unload();\n- tile.events.un({\n- \"loadstart\": tile.onLoadStart,\n- \"loadend\": tile.onLoadEnd,\n- \"unload\": tile.onLoadEnd,\n- \"loaderror\": tile.onLoadError,\n- scope: this\n- });\n- },\n-\n- /**\n- * Method: moveGriddedTiles\n- */\n- moveGriddedTiles: function() {\n- var buffer = this.buffer + 1;\n- while (true) {\n- var tlTile = this.grid[0][0];\n- var tlViewPort = {\n- x: tlTile.position.x +\n- this.map.layerContainerOriginPx.x,\n- y: tlTile.position.y +\n- this.map.layerContainerOriginPx.y\n- };\n- var ratio = this.getServerResolution() / this.map.getResolution();\n- var tileSize = {\n- w: Math.round(this.tileSize.w * ratio),\n- h: Math.round(this.tileSize.h * ratio)\n- };\n- if (tlViewPort.x > -tileSize.w * (buffer - 1)) {\n- this.shiftColumn(true, tileSize);\n- } else if (tlViewPort.x < -tileSize.w * buffer) {\n- this.shiftColumn(false, tileSize);\n- } else if (tlViewPort.y > -tileSize.h * (buffer - 1)) {\n- this.shiftRow(true, tileSize);\n- } else if (tlViewPort.y < -tileSize.h * buffer) {\n- this.shiftRow(false, tileSize);\n- } else {\n- break;\n- }\n- }\n- },\n-\n- /**\n- * Method: shiftRow\n- * Shifty grid work\n- *\n- * Parameters:\n- * prepend - {Boolean} if true, prepend to beginning.\n- * if false, then append to end\n- * tileSize - {Object} rendered tile size; object with w and h properties\n- */\n- shiftRow: function(prepend, tileSize) {\n- var grid = this.grid;\n- var rowIndex = prepend ? 0 : (grid.length - 1);\n- var sign = prepend ? -1 : 1;\n- var rowSign = this.rowSign;\n- var tileLayout = this.gridLayout;\n- tileLayout.startrow += sign * rowSign;\n-\n- var modelRow = grid[rowIndex];\n- var row = grid[prepend ? 'pop' : 'shift']();\n- for (var i = 0, len = row.length; i < len; i++) {\n- var tile = row[i];\n- var position = modelRow[i].position.clone();\n- position.y += tileSize.h * sign;\n- tile.moveTo(this.getTileBoundsForGridIndex(rowIndex, i), position);\n- }\n- grid[prepend ? 'unshift' : 'push'](row);\n- },\n-\n- /**\n- * Method: shiftColumn\n- * Shift grid work in the other dimension\n- *\n- * Parameters:\n- * prepend - {Boolean} if true, prepend to beginning.\n- * if false, then append to end\n- * tileSize - {Object} rendered tile size; object with w and h properties\n- */\n- shiftColumn: function(prepend, tileSize) {\n- var grid = this.grid;\n- var colIndex = prepend ? 0 : (grid[0].length - 1);\n- var sign = prepend ? -1 : 1;\n- var tileLayout = this.gridLayout;\n- tileLayout.startcol += sign;\n-\n- for (var i = 0, len = grid.length; i < len; i++) {\n- var row = grid[i];\n- var position = row[colIndex].position.clone();\n- var tile = row[prepend ? 'pop' : 'shift']();\n- position.x += tileSize.w * sign;\n- tile.moveTo(this.getTileBoundsForGridIndex(i, colIndex), position);\n- row[prepend ? 'unshift' : 'push'](tile);\n- }\n- },\n-\n- /**\n- * Method: removeExcessTiles\n- * When the size of the map or the buffer changes, we may need to\n- * remove some excess rows and columns.\n- * \n- * Parameters:\n- * rows - {Integer} Maximum number of rows we want our grid to have.\n- * columns - {Integer} Maximum number of columns we want our grid to have.\n- */\n- removeExcessTiles: function(rows, columns) {\n- var i, l;\n-\n- // remove extra rows\n- while (this.grid.length > rows) {\n- var row = this.grid.pop();\n- for (i = 0, l = row.length; i < l; i++) {\n- var tile = row[i];\n- this.destroyTile(tile);\n- }\n- }\n-\n- // remove extra columns\n- for (i = 0, l = this.grid.length; i < l; i++) {\n- while (this.grid[i].length > columns) {\n- var row = this.grid[i];\n- var tile = row.pop();\n- this.destroyTile(tile);\n- }\n- }\n- },\n-\n- /**\n- * Method: onMapResize\n- * For singleTile layers, this will set a new tile size according to the\n- * dimensions of the map pane.\n- */\n- onMapResize: function() {\n- if (this.singleTile) {\n- this.clearGrid();\n- this.setTileSize();\n- }\n- },\n-\n- /**\n- * APIMethod: getTileBounds\n- * Returns The tile bounds for a layer given a pixel location.\n- *\n- * Parameters:\n- * viewPortPx - {} The location in the viewport.\n- *\n- * Returns:\n- * {} Bounds of the tile at the given pixel location.\n- */\n- getTileBounds: function(viewPortPx) {\n- var maxExtent = this.maxExtent;\n- var resolution = this.getResolution();\n- var tileMapWidth = resolution * this.tileSize.w;\n- var tileMapHeight = resolution * this.tileSize.h;\n- var mapPoint = this.getLonLatFromViewPortPx(viewPortPx);\n- var tileLeft = maxExtent.left + (tileMapWidth *\n- Math.floor((mapPoint.lon -\n- maxExtent.left) /\n- tileMapWidth));\n- var tileBottom = maxExtent.bottom + (tileMapHeight *\n- Math.floor((mapPoint.lat -\n- maxExtent.bottom) /\n- tileMapHeight));\n- return new OpenLayers.Bounds(tileLeft, tileBottom,\n- tileLeft + tileMapWidth,\n- tileBottom + tileMapHeight);\n- },\n-\n- CLASS_NAME: \"OpenLayers.Layer.Grid\"\n-});\n-/* ======================================================================\n- OpenLayers/TileManager.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-\n-/**\n- * @requires OpenLayers/Util.js\n- * @requires OpenLayers/BaseTypes.js\n- * @requires OpenLayers/BaseTypes/Element.js\n- * @requires OpenLayers/Layer/Grid.js\n- * @requires OpenLayers/Tile/Image.js\n- */\n-\n-/**\n- * Class: OpenLayers.TileManager\n- * Provides queueing of image requests and caching of image elements.\n- *\n- * Queueing avoids unnecessary image requests while changing zoom levels\n- * quickly, and helps improve dragging performance on mobile devices that show\n- * a lag in dragging when loading of new images starts. and\n- * are the configuration options to control this behavior.\n- *\n- * Caching avoids setting the src on image elements for images that have already\n- * been used. Several maps can share a TileManager instance, in which case each\n- * map gets its own tile queue, but all maps share the same tile cache.\n- */\n-OpenLayers.TileManager = OpenLayers.Class({\n-\n- /**\n- * APIProperty: cacheSize\n- * {Number} Number of image elements to keep referenced in this instance's\n- * cache for fast reuse. Default is 256.\n- */\n- cacheSize: 256,\n-\n- /**\n- * APIProperty: tilesPerFrame\n- * {Number} Number of queued tiles to load per frame (see ).\n- * Default is 2.\n- */\n- tilesPerFrame: 2,\n-\n- /**\n- * APIProperty: frameDelay\n- * {Number} Delay between tile loading frames (see ) in\n- * milliseconds. Default is 16.\n- */\n- frameDelay: 16,\n-\n- /**\n- * APIProperty: moveDelay\n- * {Number} Delay in milliseconds after a map's move event before loading\n- * tiles. Default is 100.\n- */\n- moveDelay: 100,\n-\n- /**\n- * APIProperty: zoomDelay\n- * {Number} Delay in milliseconds after a map's zoomend event before loading\n- * tiles. Default is 200.\n- */\n- zoomDelay: 200,\n-\n- /**\n- * Property: maps\n- * {Array()} The maps to manage tiles on.\n- */\n- maps: null,\n-\n- /**\n- * Property: tileQueueId\n- * {Object} The ids of the loop, keyed by map id.\n- */\n- tileQueueId: null,\n-\n- /**\n- * Property: tileQueue\n- * {Object(Array())} Tiles queued for drawing, keyed by\n- * map id.\n- */\n- tileQueue: null,\n-\n- /**\n- * Property: tileCache\n- * {Object} Cached image elements, keyed by URL.\n- */\n- tileCache: null,\n-\n- /**\n- * Property: tileCacheIndex\n- * {Array(String)} URLs of cached tiles. First entry is the least recently\n- * used.\n- */\n- tileCacheIndex: null,\n-\n- /** \n- * Constructor: OpenLayers.TileManager\n- * Constructor for a new instance.\n- * \n- * Parameters:\n- * options - {Object} Configuration for this instance.\n- */\n- initialize: function(options) {\n- OpenLayers.Util.extend(this, options);\n- this.maps = [];\n- this.tileQueueId = {};\n- this.tileQueue = {};\n- this.tileCache = {};\n- this.tileCacheIndex = [];\n- },\n-\n- /**\n- * Method: addMap\n- * Binds this instance to a map\n- *\n- * Parameters:\n- * map - {}\n- */\n- addMap: function(map) {\n- if (this._destroyed || !OpenLayers.Layer.Grid) {\n- return;\n- }\n- this.maps.push(map);\n- this.tileQueue[map.id] = [];\n- for (var i = 0, ii = map.layers.length; i < ii; ++i) {\n- this.addLayer({\n- layer: map.layers[i]\n- });\n- }\n- map.events.on({\n- move: this.move,\n- zoomend: this.zoomEnd,\n- changelayer: this.changeLayer,\n- addlayer: this.addLayer,\n- preremovelayer: this.removeLayer,\n- scope: this\n- });\n- },\n-\n- /**\n- * Method: removeMap\n- * Unbinds this instance from a map\n- *\n- * Parameters:\n- * map - {}\n- */\n- removeMap: function(map) {\n- if (this._destroyed || !OpenLayers.Layer.Grid) {\n- return;\n- }\n- window.clearTimeout(this.tileQueueId[map.id]);\n- if (map.layers) {\n- for (var i = 0, ii = map.layers.length; i < ii; ++i) {\n- this.removeLayer({\n- layer: map.layers[i]\n- });\n- }\n- }\n- if (map.events) {\n- map.events.un({\n- move: this.move,\n- zoomend: this.zoomEnd,\n- changelayer: this.changeLayer,\n- addlayer: this.addLayer,\n- preremovelayer: this.removeLayer,\n- scope: this\n- });\n- }\n- delete this.tileQueue[map.id];\n- delete this.tileQueueId[map.id];\n- OpenLayers.Util.removeItem(this.maps, map);\n- },\n-\n- /**\n- * Method: move\n- * Handles the map's move event\n- *\n- * Parameters:\n- * evt - {Object} Listener argument\n- */\n- move: function(evt) {\n- this.updateTimeout(evt.object, this.moveDelay, true);\n- },\n-\n- /**\n- * Method: zoomEnd\n- * Handles the map's zoomEnd event\n- *\n- * Parameters:\n- * evt - {Object} Listener argument\n- */\n- zoomEnd: function(evt) {\n- this.updateTimeout(evt.object, this.zoomDelay);\n- },\n-\n- /**\n- * Method: changeLayer\n- * Handles the map's changeLayer event\n- *\n- * Parameters:\n- * evt - {Object} Listener argument\n- */\n- changeLayer: function(evt) {\n- if (evt.property === 'visibility' || evt.property === 'params') {\n- this.updateTimeout(evt.object, 0);\n- }\n- },\n-\n- /**\n- * Method: addLayer\n- * Handles the map's addlayer event\n- *\n- * Parameters:\n- * evt - {Object} The listener argument\n- */\n- addLayer: function(evt) {\n- var layer = evt.layer;\n- if (layer instanceof OpenLayers.Layer.Grid) {\n- layer.events.on({\n- addtile: this.addTile,\n- retile: this.clearTileQueue,\n- scope: this\n- });\n- var i, j, tile;\n- for (i = layer.grid.length - 1; i >= 0; --i) {\n- for (j = layer.grid[i].length - 1; j >= 0; --j) {\n- tile = layer.grid[i][j];\n- this.addTile({\n- tile: tile\n- });\n- if (tile.url && !tile.imgDiv) {\n- this.manageTileCache({\n- object: tile\n- });\n- }\n- }\n- }\n- }\n- },\n-\n- /**\n- * Method: removeLayer\n- * Handles the map's preremovelayer event\n- *\n- * Parameters:\n- * evt - {Object} The listener argument\n- */\n- removeLayer: function(evt) {\n- var layer = evt.layer;\n- if (layer instanceof OpenLayers.Layer.Grid) {\n- this.clearTileQueue({\n- object: layer\n- });\n- if (layer.events) {\n- layer.events.un({\n- addtile: this.addTile,\n- retile: this.clearTileQueue,\n- scope: this\n- });\n- }\n- if (layer.grid) {\n- var i, j, tile;\n- for (i = layer.grid.length - 1; i >= 0; --i) {\n- for (j = layer.grid[i].length - 1; j >= 0; --j) {\n- tile = layer.grid[i][j];\n- this.unloadTile({\n- object: tile\n- });\n- }\n- }\n- }\n- }\n- },\n-\n- /**\n- * Method: updateTimeout\n- * Applies the or to the loop,\n- * and schedules more queue processing after if there are still\n- * tiles in the queue.\n- *\n- * Parameters:\n- * map - {} The map to update the timeout for\n- * delay - {Number} The delay to apply\n- * nice - {Boolean} If true, the timeout function will only be created if\n- * the tilequeue is not empty. This is used by the move handler to\n- * avoid impacts on dragging performance. For other events, the tile\n- * queue may not be populated yet, so we need to set the timer\n- * regardless of the queue size.\n- */\n- updateTimeout: function(map, delay, nice) {\n- window.clearTimeout(this.tileQueueId[map.id]);\n- var tileQueue = this.tileQueue[map.id];\n- if (!nice || tileQueue.length) {\n- this.tileQueueId[map.id] = window.setTimeout(\n- OpenLayers.Function.bind(function() {\n- this.drawTilesFromQueue(map);\n- if (tileQueue.length) {\n- this.updateTimeout(map, this.frameDelay);\n- }\n- }, this), delay\n- );\n- }\n- },\n-\n- /**\n- * Method: addTile\n- * Listener for the layer's addtile event\n- *\n- * Parameters:\n- * evt - {Object} The listener argument\n- */\n- addTile: function(evt) {\n- if (evt.tile instanceof OpenLayers.Tile.Image) {\n- evt.tile.events.on({\n- beforedraw: this.queueTileDraw,\n- beforeload: this.manageTileCache,\n- loadend: this.addToCache,\n- unload: this.unloadTile,\n- scope: this\n- });\n- } else {\n- // Layer has the wrong tile type, so don't handle it any longer\n- this.removeLayer({\n- layer: evt.tile.layer\n- });\n- }\n- },\n-\n- /**\n- * Method: unloadTile\n- * Listener for the tile's unload event\n- *\n- * Parameters:\n- * evt - {Object} The listener argument\n- */\n- unloadTile: function(evt) {\n- var tile = evt.object;\n- tile.events.un({\n- beforedraw: this.queueTileDraw,\n- beforeload: this.manageTileCache,\n- loadend: this.addToCache,\n- unload: this.unloadTile,\n- scope: this\n- });\n- OpenLayers.Util.removeItem(this.tileQueue[tile.layer.map.id], tile);\n- },\n-\n- /**\n- * Method: queueTileDraw\n- * Adds a tile to the queue that will draw it.\n- *\n- * Parameters:\n- * evt - {Object} Listener argument of the tile's beforedraw event\n- */\n- queueTileDraw: function(evt) {\n- var tile = evt.object;\n- var queued = false;\n- var layer = tile.layer;\n- var url = layer.getURL(tile.bounds);\n- var img = this.tileCache[url];\n- if (img && img.className !== 'olTileImage') {\n- // cached image no longer valid, e.g. because we're olTileReplacing\n- delete this.tileCache[url];\n- OpenLayers.Util.removeItem(this.tileCacheIndex, url);\n- img = null;\n- }\n- // queue only if image with same url not cached already\n- if (layer.url && (layer.async || !img)) {\n- // add to queue only if not in queue already\n- var tileQueue = this.tileQueue[layer.map.id];\n- if (!~OpenLayers.Util.indexOf(tileQueue, tile)) {\n- tileQueue.push(tile);\n- }\n- queued = true;\n- }\n- return !queued;\n- },\n-\n- /**\n- * Method: drawTilesFromQueue\n- * Draws tiles from the tileQueue, and unqueues the tiles\n- */\n- drawTilesFromQueue: function(map) {\n- var tileQueue = this.tileQueue[map.id];\n- var limit = this.tilesPerFrame;\n- var animating = map.zoomTween && map.zoomTween.playing;\n- while (!animating && tileQueue.length && limit) {\n- tileQueue.shift().draw(true);\n- --limit;\n- }\n- },\n-\n- /**\n- * Method: manageTileCache\n- * Adds, updates, removes and fetches cache entries.\n- *\n- * Parameters:\n- * evt - {Object} Listener argument of the tile's beforeload event\n- */\n- manageTileCache: function(evt) {\n- var tile = evt.object;\n- var img = this.tileCache[tile.url];\n- if (img) {\n- // if image is on its layer's backbuffer, remove it from backbuffer\n- if (img.parentNode &&\n- OpenLayers.Element.hasClass(img.parentNode, 'olBackBuffer')) {\n- img.parentNode.removeChild(img);\n- img.id = null;\n- }\n- // only use image from cache if it is not on a layer already\n- if (!img.parentNode) {\n- img.style.visibility = 'hidden';\n- img.style.opacity = 0;\n- tile.setImage(img);\n- // LRU - move tile to the end of the array to mark it as the most\n- // recently used\n- OpenLayers.Util.removeItem(this.tileCacheIndex, tile.url);\n- this.tileCacheIndex.push(tile.url);\n- }\n- }\n- },\n-\n- /**\n- * Method: addToCache\n- *\n- * Parameters:\n- * evt - {Object} Listener argument for the tile's loadend event\n- */\n- addToCache: function(evt) {\n- var tile = evt.object;\n- if (!this.tileCache[tile.url]) {\n- if (!OpenLayers.Element.hasClass(tile.imgDiv, 'olImageLoadError')) {\n- if (this.tileCacheIndex.length >= this.cacheSize) {\n- delete this.tileCache[this.tileCacheIndex[0]];\n- this.tileCacheIndex.shift();\n- }\n- this.tileCache[tile.url] = tile.imgDiv;\n- this.tileCacheIndex.push(tile.url);\n- }\n- }\n- },\n-\n- /**\n- * Method: clearTileQueue\n- * Clears the tile queue from tiles of a specific layer\n- *\n- * Parameters:\n- * evt - {Object} Listener argument of the layer's retile event\n- */\n- clearTileQueue: function(evt) {\n- var layer = evt.object;\n- var tileQueue = this.tileQueue[layer.map.id];\n- for (var i = tileQueue.length - 1; i >= 0; --i) {\n- if (tileQueue[i].layer === layer) {\n- tileQueue.splice(i, 1);\n- }\n- }\n- },\n-\n- /**\n- * Method: destroy\n- */\n- destroy: function() {\n- for (var i = this.maps.length - 1; i >= 0; --i) {\n- this.removeMap(this.maps[i]);\n- }\n- this.maps = null;\n- this.tileQueue = null;\n- this.tileQueueId = null;\n- this.tileCache = null;\n- this.tileCacheIndex = null;\n- this._destroyed = true;\n- }\n-\n-});\n-/* ======================================================================\n- OpenLayers/Rule.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Util.js\n- * @requires OpenLayers/Style.js\n- */\n-\n-/**\n- * Class: OpenLayers.Rule\n- * This class represents an SLD Rule, as being used for rule-based SLD styling.\n- */\n-OpenLayers.Rule = OpenLayers.Class({\n-\n- /**\n- * Property: id\n- * {String} A unique id for this session.\n- */\n- id: null,\n-\n- /**\n- * APIProperty: name\n- * {String} name of this rule\n- */\n- name: null,\n-\n- /**\n- * Property: title\n- * {String} Title of this rule (set if included in SLD)\n- */\n- title: null,\n-\n- /**\n- * Property: description\n- * {String} Description of this rule (set if abstract is included in SLD)\n- */\n- description: null,\n-\n- /**\n- * Property: context\n- * {Object} An optional object with properties that the rule should be\n- * evaluated against. If no context is specified, feature.attributes will\n- * be used.\n- */\n- context: null,\n-\n- /**\n- * Property: filter\n- * {} Optional filter for the rule.\n- */\n- filter: null,\n-\n- /**\n- * Property: elseFilter\n- * {Boolean} Determines whether this rule is only to be applied only if\n- * no other rules match (ElseFilter according to the SLD specification). \n- * Default is false. For instances of OpenLayers.Rule, if elseFilter is\n- * false, the rule will always apply. For subclasses, the else property is \n- * ignored.\n- */\n- elseFilter: false,\n-\n- /**\n- * Property: symbolizer\n- * {Object} Symbolizer or hash of symbolizers for this rule. If hash of\n- * symbolizers, keys are one or more of [\"Point\", \"Line\", \"Polygon\"]. The\n- * latter if useful if it is required to style e.g. vertices of a line\n- * with a point symbolizer. Note, however, that this is not implemented\n- * yet in OpenLayers, but it is the way how symbolizers are defined in\n- * SLD.\n- */\n- symbolizer: null,\n-\n- /**\n- * Property: symbolizers\n- * {Array} Collection of symbolizers associated with this rule. If \n- * provided at construction, the symbolizers array has precedence\n- * over the deprecated symbolizer property. Note that multiple \n- * symbolizers are not currently supported by the vector renderers.\n- * Rules with multiple symbolizers are currently only useful for\n- * maintaining elements in an SLD document.\n- */\n- symbolizers: null,\n-\n- /**\n- * APIProperty: minScaleDenominator\n- * {Number} or {String} minimum scale at which to draw the feature.\n- * In the case of a String, this can be a combination of text and\n- * propertyNames in the form \"literal ${propertyName}\"\n- */\n- minScaleDenominator: null,\n-\n- /**\n- * APIProperty: maxScaleDenominator\n- * {Number} or {String} maximum scale at which to draw the feature.\n- * In the case of a String, this can be a combination of text and\n- * propertyNames in the form \"literal ${propertyName}\"\n- */\n- maxScaleDenominator: null,\n-\n- /** \n- * Constructor: OpenLayers.Rule\n- * Creates a Rule.\n- *\n- * Parameters:\n- * options - {Object} An optional object with properties to set on the\n- * rule\n- * \n- * Returns:\n- * {}\n- */\n- initialize: function(options) {\n- this.symbolizer = {};\n- OpenLayers.Util.extend(this, options);\n- if (this.symbolizers) {\n- delete this.symbolizer;\n- }\n- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n- },\n-\n- /** \n- * APIMethod: destroy\n- * nullify references to prevent circular references and memory leaks\n- */\n- destroy: function() {\n- for (var i in this.symbolizer) {\n- this.symbolizer[i] = null;\n- }\n- this.symbolizer = null;\n- delete this.symbolizers;\n- },\n-\n- /**\n- * APIMethod: evaluate\n- * evaluates this rule for a specific feature\n- * \n- * Parameters:\n- * feature - {} feature to apply the rule to.\n- * \n- * Returns:\n- * {Boolean} true if the rule applies, false if it does not.\n- * This rule is the default rule and always returns true.\n- */\n- evaluate: function(feature) {\n- var context = this.getContext(feature);\n- var applies = true;\n-\n- if (this.minScaleDenominator || this.maxScaleDenominator) {\n- var scale = feature.layer.map.getScale();\n- }\n-\n- // check if within minScale/maxScale bounds\n- if (this.minScaleDenominator) {\n- applies = scale >= OpenLayers.Style.createLiteral(\n- this.minScaleDenominator, context);\n- }\n- if (applies && this.maxScaleDenominator) {\n- applies = scale < OpenLayers.Style.createLiteral(\n- this.maxScaleDenominator, context);\n- }\n-\n- // check if optional filter applies\n- if (applies && this.filter) {\n- // feature id filters get the feature, others get the context\n- if (this.filter.CLASS_NAME == \"OpenLayers.Filter.FeatureId\") {\n- applies = this.filter.evaluate(feature);\n- } else {\n- applies = this.filter.evaluate(context);\n- }\n- }\n-\n- return applies;\n- },\n-\n- /**\n- * Method: getContext\n- * Gets the context for evaluating this rule\n- * \n- * Paramters:\n- * feature - {} feature to take the context from if\n- * none is specified.\n- */\n- getContext: function(feature) {\n- var context = this.context;\n- if (!context) {\n- context = feature.attributes || feature.data;\n- }\n- if (typeof this.context == \"function\") {\n- context = this.context(feature);\n- }\n- return context;\n- },\n-\n- /**\n- * APIMethod: clone\n- * Clones this rule.\n- * \n- * Returns:\n- * {} Clone of this rule.\n- */\n- clone: function() {\n- var options = OpenLayers.Util.extend({}, this);\n- if (this.symbolizers) {\n- // clone symbolizers\n- var len = this.symbolizers.length;\n- options.symbolizers = new Array(len);\n- for (var i = 0; i < len; ++i) {\n- options.symbolizers[i] = this.symbolizers[i].clone();\n- }\n- } else {\n- // clone symbolizer\n- options.symbolizer = {};\n- var value, type;\n- for (var key in this.symbolizer) {\n- value = this.symbolizer[key];\n- type = typeof value;\n- if (type === \"object\") {\n- options.symbolizer[key] = OpenLayers.Util.extend({}, value);\n- } else if (type === \"string\") {\n- options.symbolizer[key] = value;\n- }\n- }\n- }\n- // clone filter\n- options.filter = this.filter && this.filter.clone();\n- // clone context\n- options.context = this.context && OpenLayers.Util.extend({}, this.context);\n- return new OpenLayers.Rule(options);\n- },\n-\n- CLASS_NAME: \"OpenLayers.Rule\"\n-});\n-/* ======================================================================\n- OpenLayers/Symbolizer.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- */\n-\n-/**\n- * Class: OpenLayers.Symbolizer\n- * Base class representing a symbolizer used for feature rendering.\n- */\n-OpenLayers.Symbolizer = OpenLayers.Class({\n-\n-\n- /**\n- * APIProperty: zIndex\n- * {Number} The zIndex determines the rendering order for a symbolizer.\n- * Symbolizers with larger zIndex values are rendered over symbolizers\n- * with smaller zIndex values. Default is 0.\n- */\n- zIndex: 0,\n-\n- /**\n- * Constructor: OpenLayers.Symbolizer\n- * Instances of this class are not useful. See one of the subclasses.\n- *\n- * Parameters:\n- * config - {Object} An object containing properties to be set on the \n- * symbolizer. Any documented symbolizer property can be set at \n- * construction.\n- *\n- * Returns:\n- * A new symbolizer.\n- */\n- initialize: function(config) {\n- OpenLayers.Util.extend(this, config);\n- },\n-\n- /** \n- * APIMethod: clone\n- * Create a copy of this symbolizer.\n- *\n- * Returns a symbolizer of the same type with the same properties.\n- */\n- clone: function() {\n- var Type = eval(this.CLASS_NAME);\n- return new Type(OpenLayers.Util.extend({}, this));\n- },\n-\n- CLASS_NAME: \"OpenLayers.Symbolizer\"\n-\n-});\n-\n-/* ======================================================================\n- OpenLayers/Symbolizer/Point.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/Symbolizer.js\n- */\n-\n-/**\n- * Class: OpenLayers.Symbolizer.Point\n- * A symbolizer used to render point features.\n- */\n-OpenLayers.Symbolizer.Point = OpenLayers.Class(OpenLayers.Symbolizer, {\n-\n- /**\n- * APIProperty: strokeColor\n- * {String} Color for line stroke. This is a RGB hex value (e.g. \"#ff0000\"\n- * for red).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeOpacity\n- * {Number} Stroke opacity (0-1).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeWidth\n- * {Number} Pixel stroke width.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeLinecap\n- * {String} Stroke cap type (\"butt\", \"round\", or \"square\").\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * Property: strokeDashstyle\n- * {String} Stroke dash style according to the SLD spec. Note that the\n- * OpenLayers values for strokeDashstyle (\"dot\", \"dash\", \"dashdot\",\n- * \"longdash\", \"longdashdot\", or \"solid\") will not work in SLD, but\n- * most SLD patterns will render correctly in OpenLayers.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: fillColor\n- * {String} RGB hex fill color (e.g. \"#ff0000\" for red).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: fillOpacity\n- * {Number} Fill opacity (0-1).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: pointRadius\n- * {Number} Pixel point radius.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: externalGraphic\n- * {String} Url to an external graphic that will be used for rendering \n- * points.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: graphicWidth\n- * {Number} Pixel width for sizing an external graphic.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: graphicHeight\n- * {Number} Pixel height for sizing an external graphic.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: graphicOpacity\n- * {Number} Opacity (0-1) for an external graphic.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: graphicXOffset\n- * {Number} Pixel offset along the positive x axis for displacing an \n- * external graphic.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: graphicYOffset\n- * {Number} Pixel offset along the positive y axis for displacing an \n- * external graphic.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: rotation\n- * {Number} The rotation of a graphic in the clockwise direction about its \n- * center point (or any point off center as specified by \n- * and ).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: graphicName\n- * {String} Named graphic to use when rendering points. Supported values \n- * include \"circle\", \"square\", \"star\", \"x\", \"cross\", and \"triangle\".\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * Constructor: OpenLayers.Symbolizer.Point\n- * Create a symbolizer for rendering points.\n- *\n- * Parameters:\n- * config - {Object} An object containing properties to be set on the \n- * symbolizer. Any documented symbolizer property can be set at \n- * construction.\n- *\n- * Returns:\n- * A new point symbolizer.\n- */\n- initialize: function(config) {\n- OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);\n- },\n-\n- CLASS_NAME: \"OpenLayers.Symbolizer.Point\"\n-\n-});\n-\n-/* ======================================================================\n- OpenLayers/Symbolizer/Line.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/Symbolizer.js\n- */\n-\n-/**\n- * Class: OpenLayers.Symbolizer.Line\n- * A symbolizer used to render line features.\n- */\n-OpenLayers.Symbolizer.Line = OpenLayers.Class(OpenLayers.Symbolizer, {\n-\n- /**\n- * APIProperty: strokeColor\n- * {String} Color for line stroke. This is a RGB hex value (e.g. \"#ff0000\"\n- * for red). \n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeOpacity\n- * {Number} Stroke opacity (0-1).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeWidth\n- * {Number} Pixel stroke width.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeLinecap\n- * {String} Stroke cap type (\"butt\", \"round\", or \"square\").\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * Property: strokeDashstyle\n- * {String} Stroke dash style according to the SLD spec. Note that the\n- * OpenLayers values for strokeDashstyle (\"dot\", \"dash\", \"dashdot\",\n- * \"longdash\", \"longdashdot\", or \"solid\") will not work in SLD, but\n- * most SLD patterns will render correctly in OpenLayers.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * Constructor: OpenLayers.Symbolizer.Line\n- * Create a symbolizer for rendering lines.\n- *\n- * Parameters:\n- * config - {Object} An object containing properties to be set on the \n- * symbolizer. Any documented symbolizer property can be set at \n- * construction.\n- *\n- * Returns:\n- * A new line symbolizer.\n- */\n- initialize: function(config) {\n- OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);\n- },\n-\n- CLASS_NAME: \"OpenLayers.Symbolizer.Line\"\n-\n-});\n-\n-/* ======================================================================\n- OpenLayers/Symbolizer/Polygon.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/Symbolizer.js\n- */\n-\n-/**\n- * Class: OpenLayers.Symbolizer.Polygon\n- * A symbolizer used to render line features.\n- */\n-OpenLayers.Symbolizer.Polygon = OpenLayers.Class(OpenLayers.Symbolizer, {\n-\n- /**\n- * APIProperty: strokeColor\n- * {String} Color for line stroke. This is a RGB hex value (e.g. \"#ff0000\"\n- * for red).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeOpacity\n- * {Number} Stroke opacity (0-1).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeWidth\n- * {Number} Pixel stroke width.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: strokeLinecap\n- * {String} Stroke cap type (\"butt\", \"round\", or \"square\").\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * Property: strokeDashstyle\n- * {String} Stroke dash style according to the SLD spec. Note that the\n- * OpenLayers values for strokeDashstyle (\"dot\", \"dash\", \"dashdot\",\n- * \"longdash\", \"longdashdot\", or \"solid\") will not work in SLD, but\n- * most SLD patterns will render correctly in OpenLayers.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: fillColor\n- * {String} RGB hex fill color (e.g. \"#ff0000\" for red).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * APIProperty: fillOpacity\n- * {Number} Fill opacity (0-1).\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * Constructor: OpenLayers.Symbolizer.Polygon\n- * Create a symbolizer for rendering polygons.\n- *\n- * Parameters:\n- * config - {Object} An object containing properties to be set on the \n- * symbolizer. Any documented symbolizer property can be set at \n- * construction.\n- *\n- * Returns:\n- * A new polygon symbolizer.\n- */\n- initialize: function(config) {\n- OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);\n- },\n-\n- CLASS_NAME: \"OpenLayers.Symbolizer.Polygon\"\n-\n-});\n-\n-/* ======================================================================\n- OpenLayers/Symbolizer/Text.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/Symbolizer.js\n- */\n-\n-/**\n- * Class: OpenLayers.Symbolizer.Text\n- * A symbolizer used to render text labels for features.\n- */\n-OpenLayers.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, {\n-\n- /** \n- * APIProperty: label\n- * {String} The text for the label.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /** \n- * APIProperty: fontFamily\n- * {String} The font family for the label.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /** \n- * APIProperty: fontSize\n- * {String} The font size for the label.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /** \n- * APIProperty: fontWeight\n- * {String} The font weight for the label.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * Property: fontStyle\n- * {String} The font style for the label.\n- * \n- * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.\n- */\n-\n- /**\n- * Constructor: OpenLayers.Symbolizer.Text\n- * Create a symbolizer for rendering text labels.\n- *\n- * Parameters:\n- * config - {Object} An object containing properties to be set on the \n- * symbolizer. Any documented symbolizer property can be set at \n- * construction.\n- *\n- * Returns:\n- * A new text symbolizer.\n- */\n- initialize: function(config) {\n- OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);\n- },\n-\n- CLASS_NAME: \"OpenLayers.Symbolizer.Text\"\n-\n-});\n-\n-/* ======================================================================\n- OpenLayers/Symbolizer/Raster.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/Symbolizer.js\n- */\n-\n-/**\n- * Class: OpenLayers.Symbolizer.Raster\n- * A symbolizer used to render raster images.\n- */\n-OpenLayers.Symbolizer.Raster = OpenLayers.Class(OpenLayers.Symbolizer, {\n-\n- /**\n- * Constructor: OpenLayers.Symbolizer.Raster\n- * Create a symbolizer for rendering rasters.\n- *\n- * Parameters:\n- * config - {Object} An object containing properties to be set on the \n- * symbolizer. Any documented symbolizer property can be set at \n- * construction.\n- *\n- * Returns:\n- * A new raster symbolizer.\n- */\n- initialize: function(config) {\n- OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);\n- },\n-\n- CLASS_NAME: \"OpenLayers.Symbolizer.Raster\"\n-\n-});\n-/* ======================================================================\n- OpenLayers/Style2.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Rule.js\n- * @requires OpenLayers/Symbolizer/Point.js\n- * @requires OpenLayers/Symbolizer/Line.js\n- * @requires OpenLayers/Symbolizer/Polygon.js\n- * @requires OpenLayers/Symbolizer/Text.js\n- * @requires OpenLayers/Symbolizer/Raster.js\n- */\n-\n-/**\n- * Class: OpenLayers.Style2\n- * This class represents a collection of rules for rendering features.\n- */\n-OpenLayers.Style2 = OpenLayers.Class({\n-\n- /**\n- * Property: id\n- * {String} A unique id for this session.\n- */\n- id: null,\n-\n- /**\n- * APIProperty: name\n- * {String} Style identifier.\n- */\n- name: null,\n-\n- /**\n- * APIProperty: title\n- * {String} Title of this style.\n- */\n- title: null,\n-\n- /**\n- * APIProperty: description\n- * {String} Description of this style.\n- */\n- description: null,\n-\n- /**\n- * APIProperty: layerName\n- * {} Name of the layer that this style belongs to, usually\n- * according to the NamedLayer attribute of an SLD document.\n- */\n- layerName: null,\n-\n- /**\n- * APIProperty: isDefault\n- * {Boolean}\n- */\n- isDefault: false,\n-\n- /** \n- * APIProperty: rules \n- * {Array()} Collection of rendering rules.\n- */\n- rules: null,\n-\n- /** \n- * Constructor: OpenLayers.Style2\n- * Creates a style representing a collection of rendering rules.\n- *\n- * Parameters:\n- * config - {Object} An object containing properties to be set on the \n- * style. Any documented properties may be set at construction.\n- *\n- * Returns:\n- * {} A new style object.\n- */\n- initialize: function(config) {\n- OpenLayers.Util.extend(this, config);\n- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n- },\n-\n- /** \n- * APIMethod: destroy\n- * nullify references to prevent circular references and memory leaks\n- */\n- destroy: function() {\n- for (var i = 0, len = this.rules.length; i < len; i++) {\n- this.rules[i].destroy();\n- }\n- delete this.rules;\n- },\n-\n- /**\n- * APIMethod: clone\n- * Clones this style.\n- * \n- * Returns:\n- * {} Clone of this style.\n- */\n- clone: function() {\n- var config = OpenLayers.Util.extend({}, this);\n- // clone rules\n- if (this.rules) {\n- config.rules = [];\n- for (var i = 0, len = this.rules.length; i < len; ++i) {\n- config.rules.push(this.rules[i].clone());\n- }\n- }\n- return new OpenLayers.Style2(config);\n- },\n-\n- CLASS_NAME: \"OpenLayers.Style2\"\n-});\n-/* ======================================================================\n- OpenLayers/Spherical.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/SingleFile.js\n- */\n-\n-/**\n- * Namespace: Spherical\n- * The OpenLayers.Spherical namespace includes utility functions for\n- * calculations on the basis of a spherical earth (ignoring ellipsoidal\n- * effects), which is accurate enough for most purposes.\n- *\n- * Relevant links:\n- * * http://www.movable-type.co.uk/scripts/latlong.html\n- * * http://code.google.com/apis/maps/documentation/javascript/reference.html#spherical\n- */\n-\n-OpenLayers.Spherical = OpenLayers.Spherical || {};\n-\n-OpenLayers.Spherical.DEFAULT_RADIUS = 6378137;\n-\n-/**\n- * APIFunction: computeDistanceBetween\n- * Computes the distance between two LonLats.\n- *\n- * Parameters:\n- * from - {} or {Object} Starting point. A LonLat or\n- * a JavaScript literal with lon lat properties.\n- * to - {} or {Object} Ending point. A LonLat or a\n- * JavaScript literal with lon lat properties.\n- * radius - {Float} The radius. Optional. Defaults to 6378137 meters.\n- *\n- * Returns:\n- * {Float} The distance in meters.\n- */\n-OpenLayers.Spherical.computeDistanceBetween = function(from, to, radius) {\n- var R = radius || OpenLayers.Spherical.DEFAULT_RADIUS;\n- var sinHalfDeltaLon = Math.sin(Math.PI * (to.lon - from.lon) / 360);\n- var sinHalfDeltaLat = Math.sin(Math.PI * (to.lat - from.lat) / 360);\n- var a = sinHalfDeltaLat * sinHalfDeltaLat +\n- sinHalfDeltaLon * sinHalfDeltaLon * Math.cos(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180);\n- return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n-};\n-\n-\n-/**\n- * APIFunction: computeHeading\n- * Computes the heading from one LonLat to another LonLat.\n- *\n- * Parameters:\n- * from - {} or {Object} Starting point. A LonLat or\n- * a JavaScript literal with lon lat properties.\n- * to - {} or {Object} Ending point. A LonLat or a\n- * JavaScript literal with lon lat properties.\n- *\n- * Returns:\n- * {Float} The heading in degrees.\n- */\n-OpenLayers.Spherical.computeHeading = function(from, to) {\n- var y = Math.sin(Math.PI * (from.lon - to.lon) / 180) * Math.cos(Math.PI * to.lat / 180);\n- var x = Math.cos(Math.PI * from.lat / 180) * Math.sin(Math.PI * to.lat / 180) -\n- Math.sin(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180) * Math.cos(Math.PI * (from.lon - to.lon) / 180);\n- return 180 * Math.atan2(y, x) / Math.PI;\n-};\n-/* ======================================================================\n- OpenLayers/Popup.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- */\n-\n-\n-/**\n- * Class: OpenLayers.Popup\n- * A popup is a small div that can opened and closed on the map.\n- * Typically opened in response to clicking on a marker. \n- * See . Popup's don't require their own\n- * layer and are added the the map using the \n- * method.\n- *\n- * Example:\n- * (code)\n- * popup = new OpenLayers.Popup(\"chicken\", \n- * new OpenLayers.LonLat(5,40),\n- * new OpenLayers.Size(200,200),\n- * \"example popup\",\n- * true);\n- * \n- * map.addPopup(popup);\n- * (end)\n- */\n-OpenLayers.Popup = OpenLayers.Class({\n-\n- /** \n- * Property: events \n- * {} custom event manager \n- */\n- events: null,\n-\n- /** Property: id\n- * {String} the unique identifier assigned to this popup.\n- */\n- id: \"\",\n-\n- /** \n- * Property: lonlat \n- * {} the position of this popup on the map\n- */\n- lonlat: null,\n-\n- /** \n- * Property: div \n- * {DOMElement} the div that contains this popup.\n- */\n- div: null,\n-\n- /** \n- * Property: contentSize \n- * {} the width and height of the content.\n- */\n- contentSize: null,\n-\n- /** \n- * Property: size \n- * {} the width and height of the popup.\n- */\n- size: null,\n-\n- /** \n- * Property: contentHTML \n- * {String} An HTML string for this popup to display.\n- */\n- contentHTML: null,\n-\n- /** \n- * Property: backgroundColor \n- * {String} the background color used by the popup.\n- */\n- backgroundColor: \"\",\n-\n- /** \n- * Property: opacity \n- * {float} the opacity of this popup (between 0.0 and 1.0)\n- */\n- opacity: \"\",\n-\n- /** \n- * Property: border \n- * {String} the border size of the popup. (eg 2px)\n- */\n- border: \"\",\n-\n- /** \n- * Property: contentDiv \n- * {DOMElement} a reference to the element that holds the content of\n- * the div.\n- */\n- contentDiv: null,\n-\n- /** \n- * Property: groupDiv \n- * {DOMElement} First and only child of 'div'. The group Div contains the\n- * 'contentDiv' and the 'closeDiv'.\n- */\n- groupDiv: null,\n-\n- /** \n- * Property: closeDiv\n- * {DOMElement} the optional closer image\n- */\n- closeDiv: null,\n-\n- /** \n- * APIProperty: autoSize\n- * {Boolean} Resize the popup to auto-fit the contents.\n- * Default is false.\n- */\n- autoSize: false,\n-\n- /**\n- * APIProperty: minSize\n- * {} Minimum size allowed for the popup's contents.\n- */\n- minSize: null,\n-\n- /**\n- * APIProperty: maxSize\n- * {} Maximum size allowed for the popup's contents.\n- */\n- maxSize: null,\n-\n- /** \n- * Property: displayClass\n- * {String} The CSS class of the popup.\n- */\n- displayClass: \"olPopup\",\n-\n- /** \n- * Property: contentDisplayClass\n- * {String} The CSS class of the popup content div.\n- */\n- contentDisplayClass: \"olPopupContent\",\n-\n- /** \n- * Property: padding \n- * {int or } An extra opportunity to specify internal \n- * padding of the content div inside the popup. This was originally\n- * confused with the css padding as specified in style.css's \n- * 'olPopupContent' class. We would like to get rid of this altogether,\n- * except that it does come in handy for the framed and anchoredbubble\n- * popups, who need to maintain yet another barrier between their \n- * content and the outer border of the popup itself. \n- * \n- * Note that in order to not break API, we must continue to support \n- * this property being set as an integer. Really, though, we'd like to \n- * have this specified as a Bounds object so that user can specify\n- * distinct left, top, right, bottom paddings. With the 3.0 release\n- * we can make this only a bounds.\n- */\n- padding: 0,\n-\n- /** \n- * Property: disableFirefoxOverflowHack\n- * {Boolean} The hack for overflow in Firefox causes all elements \n- * to be re-drawn, which causes Flash elements to be \n- * re-initialized, which is troublesome.\n- * With this property the hack can be disabled.\n- */\n- disableFirefoxOverflowHack: false,\n-\n- /**\n- * Method: fixPadding\n- * To be removed in 3.0, this function merely helps us to deal with the \n- * case where the user may have set an integer value for padding, \n- * instead of an object.\n- */\n- fixPadding: function() {\n- if (typeof this.padding == \"number\") {\n- this.padding = new OpenLayers.Bounds(\n- this.padding, this.padding, this.padding, this.padding\n- );\n- }\n- },\n-\n- /**\n- * APIProperty: panMapIfOutOfView\n- * {Boolean} When drawn, pan map such that the entire popup is visible in\n- * the current viewport (if necessary).\n- * Default is false.\n- */\n- panMapIfOutOfView: false,\n-\n- /**\n- * APIProperty: keepInMap \n- * {Boolean} If panMapIfOutOfView is false, and this property is true, \n- * contrain the popup such that it always fits in the available map\n- * space. By default, this is not set on the base class. If you are\n- * creating popups that are near map edges and not allowing pannning,\n- * and especially if you have a popup which has a\n- * fixedRelativePosition, setting this to false may be a smart thing to\n- * do. Subclasses may want to override this setting.\n- * \n- * Default is false.\n- */\n- keepInMap: false,\n-\n- /**\n- * APIProperty: closeOnMove\n- * {Boolean} When map pans, close the popup.\n- * Default is false.\n- */\n- closeOnMove: false,\n-\n- /** \n- * Property: map \n- * {} this gets set in Map.js when the popup is added to the map\n- */\n- map: null,\n-\n- /** \n- * Constructor: OpenLayers.Popup\n- * Create a popup.\n- * \n- * Parameters: \n- * id - {String} a unqiue identifier for this popup. If null is passed\n- * an identifier will be automatically generated. \n- * lonlat - {} The position on the map the popup will\n- * be shown.\n- * contentSize - {} The size of the content.\n- * contentHTML - {String} An HTML string to display inside the \n- * popup.\n- * closeBox - {Boolean} Whether to display a close box inside\n- * the popup.\n- * closeBoxCallback - {Function} Function to be called on closeBox click.\n- */\n- initialize: function(id, lonlat, contentSize, contentHTML, closeBox, closeBoxCallback) {\n- if (id == null) {\n- id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n- }\n-\n- this.id = id;\n- this.lonlat = lonlat;\n-\n- this.contentSize = (contentSize != null) ? contentSize :\n- new OpenLayers.Size(\n- OpenLayers.Popup.WIDTH,\n- OpenLayers.Popup.HEIGHT);\n- if (contentHTML != null) {\n- this.contentHTML = contentHTML;\n- }\n- this.backgroundColor = OpenLayers.Popup.COLOR;\n- this.opacity = OpenLayers.Popup.OPACITY;\n- this.border = OpenLayers.Popup.BORDER;\n-\n- this.div = OpenLayers.Util.createDiv(this.id, null, null,\n- null, null, null, \"hidden\");\n- this.div.className = this.displayClass;\n-\n- var groupDivId = this.id + \"_GroupDiv\";\n- this.groupDiv = OpenLayers.Util.createDiv(groupDivId, null, null,\n- null, \"relative\", null,\n- \"hidden\");\n-\n- var id = this.div.id + \"_contentDiv\";\n- this.contentDiv = OpenLayers.Util.createDiv(id, null, this.contentSize.clone(),\n- null, \"relative\");\n- this.contentDiv.className = this.contentDisplayClass;\n- this.groupDiv.appendChild(this.contentDiv);\n- this.div.appendChild(this.groupDiv);\n-\n- if (closeBox) {\n- this.addCloseBox(closeBoxCallback);\n- }\n-\n- this.registerEvents();\n- },\n-\n- /** \n- * Method: destroy\n- * nullify references to prevent circular references and memory leaks\n- */\n- destroy: function() {\n-\n- this.id = null;\n- this.lonlat = null;\n- this.size = null;\n- this.contentHTML = null;\n-\n- this.backgroundColor = null;\n- this.opacity = null;\n- this.border = null;\n-\n- if (this.closeOnMove && this.map) {\n- this.map.events.unregister(\"movestart\", this, this.hide);\n- }\n-\n- this.events.destroy();\n- this.events = null;\n-\n- if (this.closeDiv) {\n- OpenLayers.Event.stopObservingElement(this.closeDiv);\n- this.groupDiv.removeChild(this.closeDiv);\n- }\n- this.closeDiv = null;\n-\n- this.div.removeChild(this.groupDiv);\n- this.groupDiv = null;\n-\n- if (this.map != null) {\n- this.map.removePopup(this);\n- }\n- this.map = null;\n- this.div = null;\n-\n- this.autoSize = null;\n- this.minSize = null;\n- this.maxSize = null;\n- this.padding = null;\n- this.panMapIfOutOfView = null;\n- },\n-\n- /** \n- * Method: draw\n- * Constructs the elements that make up the popup.\n- *\n- * Parameters:\n- * px - {} the position the popup in pixels.\n- * \n- * Returns:\n- * {DOMElement} Reference to a div that contains the drawn popup\n- */\n- draw: function(px) {\n- if (px == null) {\n- if ((this.lonlat != null) && (this.map != null)) {\n- px = this.map.getLayerPxFromLonLat(this.lonlat);\n- }\n- }\n-\n- // this assumes that this.map already exists, which is okay because \n- // this.draw is only called once the popup has been added to the map.\n- if (this.closeOnMove) {\n- this.map.events.register(\"movestart\", this, this.hide);\n- }\n-\n- //listen to movestart, moveend to disable overflow (FF bug)\n- if (!this.disableFirefoxOverflowHack && OpenLayers.BROWSER_NAME == 'firefox') {\n- this.map.events.register(\"movestart\", this, function() {\n- var style = document.defaultView.getComputedStyle(\n- this.contentDiv, null\n- );\n- var currentOverflow = style.getPropertyValue(\"overflow\");\n- if (currentOverflow != \"hidden\") {\n- this.contentDiv._oldOverflow = currentOverflow;\n- this.contentDiv.style.overflow = \"hidden\";\n- }\n- });\n- this.map.events.register(\"moveend\", this, function() {\n- var oldOverflow = this.contentDiv._oldOverflow;\n- if (oldOverflow) {\n- this.contentDiv.style.overflow = oldOverflow;\n- this.contentDiv._oldOverflow = null;\n- }\n- });\n- }\n-\n- this.moveTo(px);\n- if (!this.autoSize && !this.size) {\n- this.setSize(this.contentSize);\n- }\n- this.setBackgroundColor();\n- this.setOpacity();\n- this.setBorder();\n- this.setContentHTML();\n-\n- if (this.panMapIfOutOfView) {\n- this.panIntoView();\n- }\n-\n- return this.div;\n- },\n-\n- /** \n- * Method: updatePosition\n- * if the popup has a lonlat and its map members set, \n- * then have it move itself to its proper position\n- */\n- updatePosition: function() {\n- if ((this.lonlat) && (this.map)) {\n- var px = this.map.getLayerPxFromLonLat(this.lonlat);\n- if (px) {\n- this.moveTo(px);\n- }\n- }\n- },\n-\n- /**\n- * Method: moveTo\n- * \n- * Parameters:\n- * px - {} the top and left position of the popup div. \n- */\n- moveTo: function(px) {\n- if ((px != null) && (this.div != null)) {\n- this.div.style.left = px.x + \"px\";\n- this.div.style.top = px.y + \"px\";\n- }\n- },\n-\n- /**\n- * Method: visible\n- *\n- * Returns: \n- * {Boolean} Boolean indicating whether or not the popup is visible\n- */\n- visible: function() {\n- return OpenLayers.Element.visible(this.div);\n- },\n-\n- /**\n- * Method: toggle\n- * Toggles visibility of the popup.\n- */\n- toggle: function() {\n- if (this.visible()) {\n- this.hide();\n- } else {\n- this.show();\n- }\n- },\n-\n- /**\n- * Method: show\n- * Makes the popup visible.\n- */\n- show: function() {\n- this.div.style.display = '';\n-\n- if (this.panMapIfOutOfView) {\n- this.panIntoView();\n- }\n- },\n-\n- /**\n- * Method: hide\n- * Makes the popup invisible.\n- */\n- hide: function() {\n- this.div.style.display = 'none';\n- },\n-\n- /**\n- * Method: setSize\n- * Used to adjust the size of the popup. \n- *\n- * Parameters:\n- * contentSize - {} the new size for the popup's \n- * contents div (in pixels).\n- */\n- setSize: function(contentSize) {\n- this.size = contentSize.clone();\n-\n- // if our contentDiv has a css 'padding' set on it by a stylesheet, we \n- // must add that to the desired \"size\". \n- var contentDivPadding = this.getContentDivPadding();\n- var wPadding = contentDivPadding.left + contentDivPadding.right;\n- var hPadding = contentDivPadding.top + contentDivPadding.bottom;\n-\n- // take into account the popup's 'padding' property\n- this.fixPadding();\n- wPadding += this.padding.left + this.padding.right;\n- hPadding += this.padding.top + this.padding.bottom;\n-\n- // make extra space for the close div\n- if (this.closeDiv) {\n- var closeDivWidth = parseInt(this.closeDiv.style.width);\n- wPadding += closeDivWidth + contentDivPadding.right;\n- }\n-\n- //increase size of the main popup div to take into account the \n- // users's desired padding and close div. \n- this.size.w += wPadding;\n- this.size.h += hPadding;\n-\n- //now if our browser is IE, we need to actually make the contents \n- // div itself bigger to take its own padding into effect. this makes \n- // me want to shoot someone, but so it goes.\n- if (OpenLayers.BROWSER_NAME == \"msie\") {\n- this.contentSize.w +=\n- contentDivPadding.left + contentDivPadding.right;\n- this.contentSize.h +=\n- contentDivPadding.bottom + contentDivPadding.top;\n- }\n-\n- if (this.div != null) {\n- this.div.style.width = this.size.w + \"px\";\n- this.div.style.height = this.size.h + \"px\";\n- }\n- if (this.contentDiv != null) {\n- this.contentDiv.style.width = contentSize.w + \"px\";\n- this.contentDiv.style.height = contentSize.h + \"px\";\n- }\n- },\n-\n- /**\n- * APIMethod: updateSize\n- * Auto size the popup so that it precisely fits its contents (as \n- * determined by this.contentDiv.innerHTML). Popup size will, of\n- * course, be limited by the available space on the current map\n- */\n- updateSize: function() {\n-\n- // determine actual render dimensions of the contents by putting its\n- // contents into a fake contentDiv (for the CSS) and then measuring it\n- var preparedHTML = \"
\" +\n- this.contentDiv.innerHTML +\n- \"
\";\n-\n- var containerElement = (this.map) ? this.map.div : document.body;\n- var realSize = OpenLayers.Util.getRenderedDimensions(\n- preparedHTML, null, {\n- displayClass: this.displayClass,\n- containerElement: containerElement\n- }\n- );\n-\n- // is the \"real\" size of the div is safe to display in our map?\n- var safeSize = this.getSafeContentSize(realSize);\n-\n- var newSize = null;\n- if (safeSize.equals(realSize)) {\n- //real size of content is small enough to fit on the map, \n- // so we use real size.\n- newSize = realSize;\n-\n- } else {\n-\n- // make a new 'size' object with the clipped dimensions \n- // set or null if not clipped.\n- var fixedSize = {\n- w: (safeSize.w < realSize.w) ? safeSize.w : null,\n- h: (safeSize.h < realSize.h) ? safeSize.h : null\n- };\n-\n- if (fixedSize.w && fixedSize.h) {\n- //content is too big in both directions, so we will use \n- // max popup size (safeSize), knowing well that it will \n- // overflow both ways. \n- newSize = safeSize;\n- } else {\n- //content is clipped in only one direction, so we need to \n- // run getRenderedDimensions() again with a fixed dimension\n- var clippedSize = OpenLayers.Util.getRenderedDimensions(\n- preparedHTML, fixedSize, {\n- displayClass: this.contentDisplayClass,\n- containerElement: containerElement\n- }\n- );\n-\n- //if the clipped size is still the same as the safeSize, \n- // that means that our content must be fixed in the \n- // offending direction. If overflow is 'auto', this means \n- // we are going to have a scrollbar for sure, so we must \n- // adjust for that.\n- //\n- var currentOverflow = OpenLayers.Element.getStyle(\n- this.contentDiv, \"overflow\"\n- );\n- if ((currentOverflow != \"hidden\") &&\n- (clippedSize.equals(safeSize))) {\n- var scrollBar = OpenLayers.Util.getScrollbarWidth();\n- if (fixedSize.w) {\n- clippedSize.h += scrollBar;\n- } else {\n- clippedSize.w += scrollBar;\n- }\n- }\n-\n- newSize = this.getSafeContentSize(clippedSize);\n- }\n- }\n- this.setSize(newSize);\n- },\n-\n- /**\n- * Method: setBackgroundColor\n- * Sets the background color of the popup.\n- *\n- * Parameters:\n- * color - {String} the background color. eg \"#FFBBBB\"\n- */\n- setBackgroundColor: function(color) {\n- if (color != undefined) {\n- this.backgroundColor = color;\n- }\n-\n- if (this.div != null) {\n- this.div.style.backgroundColor = this.backgroundColor;\n- }\n- },\n-\n- /**\n- * Method: setOpacity\n- * Sets the opacity of the popup.\n- * \n- * Parameters:\n- * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid). \n- */\n- setOpacity: function(opacity) {\n- if (opacity != undefined) {\n- this.opacity = opacity;\n- }\n-\n- if (this.div != null) {\n- // for Mozilla and Safari\n- this.div.style.opacity = this.opacity;\n-\n- // for IE\n- this.div.style.filter = 'alpha(opacity=' + this.opacity * 100 + ')';\n- }\n- },\n-\n- /**\n- * Method: setBorder\n- * Sets the border style of the popup.\n- *\n- * Parameters:\n- * border - {String} The border style value. eg 2px \n- */\n- setBorder: function(border) {\n- if (border != undefined) {\n- this.border = border;\n- }\n-\n- if (this.div != null) {\n- this.div.style.border = this.border;\n- }\n- },\n-\n- /**\n- * Method: setContentHTML\n- * Allows the user to set the HTML content of the popup.\n- *\n- * Parameters:\n- * contentHTML - {String} HTML for the div.\n+ * contentHTML - {String} HTML for the div.\n */\n setContentHTML: function(contentHTML) {\n \n if (contentHTML != null) {\n this.contentHTML = contentHTML;\n }\n \n@@ -19386,830 +12758,103 @@\n \n OpenLayers.Popup.WIDTH = 200;\n OpenLayers.Popup.HEIGHT = 200;\n OpenLayers.Popup.COLOR = \"white\";\n OpenLayers.Popup.OPACITY = 1;\n OpenLayers.Popup.BORDER = \"0px\";\n /* ======================================================================\n- OpenLayers/Renderer.js\n+ OpenLayers/Filter.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n+\n /**\n * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Util.js\n+ * @requires OpenLayers/Style.js\n */\n \n /**\n- * Class: OpenLayers.Renderer \n- * This is the base class for all renderers.\n- *\n- * This is based on a merger code written by Paul Spencer and Bertil Chapuis.\n- * It is largely composed of virtual functions that are to be implemented\n- * in technology-specific subclasses, but there is some generic code too.\n- * \n- * The functions that *are* implemented here merely deal with the maintenance\n- * of the size and extent variables, as well as the cached 'resolution' \n- * value. \n- * \n- * A note to the user that all subclasses should use getResolution() instead\n- * of directly accessing this.resolution in order to correctly use the \n- * cacheing system.\n- *\n+ * Class: OpenLayers.Filter\n+ * This class represents an OGC Filter.\n */\n-OpenLayers.Renderer = OpenLayers.Class({\n-\n- /** \n- * Property: container\n- * {DOMElement} \n- */\n- container: null,\n-\n- /**\n- * Property: root\n- * {DOMElement}\n- */\n- root: null,\n-\n- /** \n- * Property: extent\n- * {}\n- */\n- extent: null,\n-\n- /**\n- * Property: locked\n- * {Boolean} If the renderer is currently in a state where many things\n- * are changing, the 'locked' property is set to true. This means \n- * that renderers can expect at least one more drawFeature event to be\n- * called with the 'locked' property set to 'true': In some renderers,\n- * this might make sense to use as a 'only update local information'\n- * flag. \n- */\n- locked: false,\n-\n- /** \n- * Property: size\n- * {} \n- */\n- size: null,\n-\n- /**\n- * Property: resolution\n- * {Float} cache of current map resolution\n- */\n- resolution: null,\n-\n- /**\n- * Property: map \n- * {} Reference to the map -- this is set in Vector's setMap()\n- */\n- map: null,\n-\n- /**\n- * Property: featureDx\n- * {Number} Feature offset in x direction. Will be calculated for and\n- * applied to the current feature while rendering (see\n- * ).\n- */\n- featureDx: 0,\n-\n- /**\n- * Constructor: OpenLayers.Renderer \n- *\n- * Parameters:\n- * containerID - {} \n- * options - {Object} options for this renderer. See sublcasses for\n- * supported options.\n- */\n- initialize: function(containerID, options) {\n- this.container = OpenLayers.Util.getElement(containerID);\n- OpenLayers.Util.extend(this, options);\n- },\n-\n- /**\n- * APIMethod: destroy\n- */\n- destroy: function() {\n- this.container = null;\n- this.extent = null;\n- this.size = null;\n- this.resolution = null;\n- this.map = null;\n- },\n-\n- /**\n- * APIMethod: supported\n- * This should be overridden by specific subclasses\n- * \n- * Returns:\n- * {Boolean} Whether or not the browser supports the renderer class\n- */\n- supported: function() {\n- return false;\n- },\n-\n- /**\n- * Method: setExtent\n- * Set the visible part of the layer.\n- *\n- * Resolution has probably changed, so we nullify the resolution \n- * cache (this.resolution) -- this way it will be re-computed when \n- * next it is needed.\n- * We nullify the resolution cache (this.resolution) if resolutionChanged\n- * is set to true - this way it will be re-computed on the next\n- * getResolution() request.\n- *\n- * Parameters:\n- * extent - {}\n- * resolutionChanged - {Boolean}\n- *\n- * Returns:\n- * {Boolean} true to notify the layer that the new extent does not exceed\n- * the coordinate range, and the features will not need to be redrawn.\n- * False otherwise.\n- */\n- setExtent: function(extent, resolutionChanged) {\n- this.extent = extent.clone();\n- if (this.map.baseLayer && this.map.baseLayer.wrapDateLine) {\n- var ratio = extent.getWidth() / this.map.getExtent().getWidth(),\n- extent = extent.scale(1 / ratio);\n- this.extent = extent.wrapDateLine(this.map.getMaxExtent()).scale(ratio);\n- }\n- if (resolutionChanged) {\n- this.resolution = null;\n- }\n- return true;\n- },\n-\n- /**\n- * Method: setSize\n- * Sets the size of the drawing surface.\n- * \n- * Resolution has probably changed, so we nullify the resolution \n- * cache (this.resolution) -- this way it will be re-computed when \n- * next it is needed.\n- *\n- * Parameters:\n- * size - {} \n- */\n- setSize: function(size) {\n- this.size = size.clone();\n- this.resolution = null;\n- },\n+OpenLayers.Filter = OpenLayers.Class({\n \n /** \n- * Method: getResolution\n- * Uses cached copy of resolution if available to minimize computing\n- * \n- * Returns:\n- * {Float} The current map's resolution\n- */\n- getResolution: function() {\n- this.resolution = this.resolution || this.map.getResolution();\n- return this.resolution;\n- },\n-\n- /**\n- * Method: drawFeature\n- * Draw the feature. The optional style argument can be used\n- * to override the feature's own style. This method should only\n- * be called from layer.drawFeature().\n+ * Constructor: OpenLayers.Filter\n+ * This class represents a generic filter.\n *\n * Parameters:\n- * feature - {} \n- * style - {}\n+ * options - {Object} Optional object whose properties will be set on the\n+ * instance.\n * \n * Returns:\n- * {Boolean} true if the feature has been drawn completely, false if not,\n- * undefined if the feature had no geometry\n- */\n- drawFeature: function(feature, style) {\n- if (style == null) {\n- style = feature.style;\n- }\n- if (feature.geometry) {\n- var bounds = feature.geometry.getBounds();\n- if (bounds) {\n- var worldBounds;\n- if (this.map.baseLayer && this.map.baseLayer.wrapDateLine) {\n- worldBounds = this.map.getMaxExtent();\n- }\n- if (!bounds.intersectsBounds(this.extent, {\n- worldBounds: worldBounds\n- })) {\n- style = {\n- display: \"none\"\n- };\n- } else {\n- this.calculateFeatureDx(bounds, worldBounds);\n- }\n- var rendered = this.drawGeometry(feature.geometry, style, feature.id);\n- if (style.display != \"none\" && style.label && rendered !== false) {\n-\n- var location = feature.geometry.getCentroid();\n- if (style.labelXOffset || style.labelYOffset) {\n- var xOffset = isNaN(style.labelXOffset) ? 0 : style.labelXOffset;\n- var yOffset = isNaN(style.labelYOffset) ? 0 : style.labelYOffset;\n- var res = this.getResolution();\n- location.move(xOffset * res, yOffset * res);\n- }\n- this.drawText(feature.id, style, location);\n- } else {\n- this.removeText(feature.id);\n- }\n- return rendered;\n- }\n- }\n- },\n-\n- /**\n- * Method: calculateFeatureDx\n- * {Number} Calculates the feature offset in x direction. Looking at the\n- * center of the feature bounds and the renderer extent, we calculate how\n- * many world widths the two are away from each other. This distance is\n- * used to shift the feature as close as possible to the center of the\n- * current enderer extent, which ensures that the feature is visible in the\n- * current viewport.\n- *\n- * Parameters:\n- * bounds - {} Bounds of the feature\n- * worldBounds - {} Bounds of the world\n+ * {}\n */\n- calculateFeatureDx: function(bounds, worldBounds) {\n- this.featureDx = 0;\n- if (worldBounds) {\n- var worldWidth = worldBounds.getWidth(),\n- rendererCenterX = (this.extent.left + this.extent.right) / 2,\n- featureCenterX = (bounds.left + bounds.right) / 2,\n- worldsAway = Math.round((featureCenterX - rendererCenterX) / worldWidth);\n- this.featureDx = worldsAway * worldWidth;\n- }\n+ initialize: function(options) {\n+ OpenLayers.Util.extend(this, options);\n },\n \n /** \n- * Method: drawGeometry\n- * \n- * Draw a geometry. This should only be called from the renderer itself.\n- * Use layer.drawFeature() from outside the renderer.\n- * virtual function\n- *\n- * Parameters:\n- * geometry - {} \n- * style - {Object} \n- * featureId - {} \n- */\n- drawGeometry: function(geometry, style, featureId) {},\n-\n- /**\n- * Method: drawText\n- * Function for drawing text labels.\n- * This method is only called by the renderer itself.\n- * \n- * Parameters: \n- * featureId - {String}\n- * style -\n- * location - {}\n- */\n- drawText: function(featureId, style, location) {},\n-\n- /**\n- * Method: removeText\n- * Function for removing text labels.\n- * This method is only called by the renderer itself.\n- * \n- * Parameters: \n- * featureId - {String}\n- */\n- removeText: function(featureId) {},\n-\n- /**\n- * Method: clear\n- * Clear all vectors from the renderer.\n- * virtual function.\n- */\n- clear: function() {},\n-\n- /**\n- * Method: getFeatureIdFromEvent\n- * Returns a feature id from an event on the renderer. \n- * How this happens is specific to the renderer. This should be\n- * called from layer.getFeatureFromEvent().\n- * Virtual function.\n- * \n- * Parameters:\n- * evt - {} \n- *\n- * Returns:\n- * {String} A feature id or undefined.\n- */\n- getFeatureIdFromEvent: function(evt) {},\n-\n- /**\n- * Method: eraseFeatures \n- * This is called by the layer to erase features\n- * \n- * Parameters:\n- * features - {Array()} \n- */\n- eraseFeatures: function(features) {\n- if (!(OpenLayers.Util.isArray(features))) {\n- features = [features];\n- }\n- for (var i = 0, len = features.length; i < len; ++i) {\n- var feature = features[i];\n- this.eraseGeometry(feature.geometry, feature.id);\n- this.removeText(feature.id);\n- }\n- },\n-\n- /**\n- * Method: eraseGeometry\n- * Remove a geometry from the renderer (by id).\n- * virtual function.\n- * \n- * Parameters:\n- * geometry - {} \n- * featureId - {String}\n- */\n- eraseGeometry: function(geometry, featureId) {},\n-\n- /**\n- * Method: moveRoot\n- * moves this renderer's root to a (different) renderer.\n- * To be implemented by subclasses that require a common renderer root for\n- * feature selection.\n- * \n- * Parameters:\n- * renderer - {} target renderer for the moved root\n- */\n- moveRoot: function(renderer) {},\n-\n- /**\n- * Method: getRenderLayerId\n- * Gets the layer that this renderer's output appears on. If moveRoot was\n- * used, this will be different from the id of the layer containing the\n- * features rendered by this renderer.\n- * \n- * Returns:\n- * {String} the id of the output layer.\n+ * APIMethod: destroy\n+ * Remove reference to anything added.\n */\n- getRenderLayerId: function() {\n- return this.container.id;\n- },\n+ destroy: function() {},\n \n /**\n- * Method: applyDefaultSymbolizer\n+ * APIMethod: evaluate\n+ * Evaluates this filter in a specific context. Instances or subclasses\n+ * are supposed to override this method.\n * \n * Parameters:\n- * symbolizer - {Object}\n+ * context - {Object} Context to use in evaluating the filter. If a vector\n+ * feature is provided, the feature.attributes will be used as context.\n * \n * Returns:\n- * {Object}\n+ * {Boolean} The filter applies.\n */\n- applyDefaultSymbolizer: function(symbolizer) {\n- var result = OpenLayers.Util.extend({},\n- OpenLayers.Renderer.defaultSymbolizer);\n- if (symbolizer.stroke === false) {\n- delete result.strokeWidth;\n- delete result.strokeColor;\n- }\n- if (symbolizer.fill === false) {\n- delete result.fillColor;\n- }\n- OpenLayers.Util.extend(result, symbolizer);\n- return result;\n+ evaluate: function(context) {\n+ return true;\n },\n \n- CLASS_NAME: \"OpenLayers.Renderer\"\n-});\n-\n-/**\n- * Constant: OpenLayers.Renderer.defaultSymbolizer\n- * {Object} Properties from this symbolizer will be applied to symbolizers\n- * with missing properties. This can also be used to set a global\n- * symbolizer default in OpenLayers. To be SLD 1.x compliant, add the\n- * following code before rendering any vector features:\n- * (code)\n- * OpenLayers.Renderer.defaultSymbolizer = {\n- * fillColor: \"#808080\",\n- * fillOpacity: 1,\n- * strokeColor: \"#000000\",\n- * strokeOpacity: 1,\n- * strokeWidth: 1,\n- * pointRadius: 3,\n- * graphicName: \"square\"\n- * };\n- * (end)\n- */\n-OpenLayers.Renderer.defaultSymbolizer = {\n- fillColor: \"#000000\",\n- strokeColor: \"#000000\",\n- strokeWidth: 2,\n- fillOpacity: 1,\n- strokeOpacity: 1,\n- pointRadius: 0,\n- labelAlign: 'cm'\n-};\n-\n-\n-\n-/**\n- * Constant: OpenLayers.Renderer.symbol\n- * Coordinate arrays for well known (named) symbols.\n- */\n-OpenLayers.Renderer.symbol = {\n- \"star\": [350, 75, 379, 161, 469, 161, 397, 215, 423, 301, 350, 250, 277, 301,\n- 303, 215, 231, 161, 321, 161, 350, 75\n- ],\n- \"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,\n- 4, 0\n- ],\n- \"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],\n- \"square\": [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],\n- \"triangle\": [0, 10, 10, 10, 5, 0, 0, 10]\n-};\n-/* ======================================================================\n- OpenLayers/Control.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- */\n-\n-/**\n- * Class: OpenLayers.Control\n- * Controls affect the display or behavior of the map. They allow everything\n- * from panning and zooming to displaying a scale indicator. Controls by \n- * default are added to the map they are contained within however it is\n- * possible to add a control to an external div by passing the div in the\n- * options parameter.\n- * \n- * Example:\n- * The following example shows how to add many of the common controls\n- * to a map.\n- * \n- * > var map = new OpenLayers.Map('map', { controls: [] });\n- * >\n- * > map.addControl(new OpenLayers.Control.PanZoomBar());\n- * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));\n- * > map.addControl(new OpenLayers.Control.Permalink());\n- * > map.addControl(new OpenLayers.Control.Permalink('permalink'));\n- * > map.addControl(new OpenLayers.Control.MousePosition());\n- * > map.addControl(new OpenLayers.Control.OverviewMap());\n- * > map.addControl(new OpenLayers.Control.KeyboardDefaults());\n- *\n- * The next code fragment is a quick example of how to intercept \n- * shift-mouse click to display the extent of the bounding box\n- * dragged out by the user. Usually controls are not created\n- * in exactly this manner. See the source for a more complete \n- * example:\n- *\n- * > var control = new OpenLayers.Control();\n- * > OpenLayers.Util.extend(control, {\n- * > draw: function () {\n- * > // this Handler.Box will intercept the shift-mousedown\n- * > // before Control.MouseDefault gets to see it\n- * > this.box = new OpenLayers.Handler.Box( control, \n- * > {\"done\": this.notice},\n- * > {keyMask: OpenLayers.Handler.MOD_SHIFT});\n- * > this.box.activate();\n- * > },\n- * >\n- * > notice: function (bounds) {\n- * > OpenLayers.Console.userError(bounds);\n- * > }\n- * > }); \n- * > map.addControl(control);\n- * \n- */\n-OpenLayers.Control = OpenLayers.Class({\n-\n- /** \n- * Property: id \n- * {String} \n- */\n- id: null,\n-\n- /** \n- * Property: map \n- * {} this gets set in the addControl() function in\n- * OpenLayers.Map \n- */\n- map: null,\n-\n- /** \n- * APIProperty: div \n- * {DOMElement} The element that contains the control, if not present the \n- * control is placed inside the map.\n- */\n- div: null,\n-\n- /** \n- * APIProperty: type \n- * {Number} Controls can have a 'type'. The type determines the type of\n- * interactions which are possible with them when they are placed in an\n- * . \n- */\n- type: null,\n-\n- /** \n- * Property: allowSelection\n- * {Boolean} By default, controls do not allow selection, because\n- * it may interfere with map dragging. If this is true, OpenLayers\n- * will not prevent selection of the control.\n- * Default is false.\n- */\n- allowSelection: false,\n-\n- /** \n- * Property: displayClass \n- * {string} This property is used for CSS related to the drawing of the\n- * Control. \n- */\n- displayClass: \"\",\n-\n- /**\n- * APIProperty: title \n- * {string} This property is used for showing a tooltip over the \n- * Control. \n- */\n- title: \"\",\n-\n- /**\n- * APIProperty: autoActivate\n- * {Boolean} Activate the control when it is added to a map. Default is\n- * false.\n- */\n- autoActivate: false,\n-\n- /** \n- * APIProperty: active \n- * {Boolean} The control is active (read-only). Use and \n- * to change control state.\n- */\n- active: null,\n-\n- /**\n- * Property: handlerOptions\n- * {Object} Used to set non-default properties on the control's handler\n- */\n- handlerOptions: null,\n-\n- /** \n- * Property: handler \n- * {} null\n- */\n- handler: null,\n-\n- /**\n- * APIProperty: eventListeners\n- * {Object} If set as an option at construction, the eventListeners\n- * object will be registered with . Object\n- * structure must be a listeners object as shown in the example for\n- * the events.on method.\n- */\n- eventListeners: null,\n-\n- /** \n- * APIProperty: events\n- * {} Events instance for listeners and triggering\n- * control specific events.\n- *\n- * Register a listener for a particular event with the following syntax:\n- * (code)\n- * control.events.register(type, obj, listener);\n- * (end)\n- *\n- * Listeners will be called with a reference to an event object. The\n- * properties of this event depends on exactly what happened.\n- *\n- * All event objects have at least the following properties:\n- * object - {Object} A reference to control.events.object (a reference\n- * to the control).\n- * element - {DOMElement} A reference to control.events.element (which\n- * will be null unless documented otherwise).\n- *\n- * Supported map event types:\n- * activate - Triggered when activated.\n- * deactivate - Triggered when deactivated.\n- */\n- events: null,\n-\n /**\n- * Constructor: OpenLayers.Control\n- * Create an OpenLayers Control. The options passed as a parameter\n- * directly extend the control. For example passing the following:\n- * \n- * > var control = new OpenLayers.Control({div: myDiv});\n- *\n- * Overrides the default div attribute value of null.\n+ * APIMethod: clone\n+ * Clones this filter. Should be implemented by subclasses.\n * \n- * Parameters:\n- * options - {Object} \n- */\n- initialize: function(options) {\n- // We do this before the extend so that instances can override\n- // className in options.\n- this.displayClass =\n- this.CLASS_NAME.replace(\"OpenLayers.\", \"ol\").replace(/\\./g, \"\");\n-\n- OpenLayers.Util.extend(this, options);\n-\n- this.events = new OpenLayers.Events(this);\n- if (this.eventListeners instanceof Object) {\n- this.events.on(this.eventListeners);\n- }\n- if (this.id == null) {\n- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n- }\n- },\n-\n- /**\n- * Method: destroy\n- * The destroy method is used to perform any clean up before the control\n- * is dereferenced. Typically this is where event listeners are removed\n- * to prevent memory leaks.\n- */\n- destroy: function() {\n- if (this.events) {\n- if (this.eventListeners) {\n- this.events.un(this.eventListeners);\n- }\n- this.events.destroy();\n- this.events = null;\n- }\n- this.eventListeners = null;\n-\n- // eliminate circular references\n- if (this.handler) {\n- this.handler.destroy();\n- this.handler = null;\n- }\n- if (this.handlers) {\n- for (var key in this.handlers) {\n- if (this.handlers.hasOwnProperty(key) &&\n- typeof this.handlers[key].destroy == \"function\") {\n- this.handlers[key].destroy();\n- }\n- }\n- this.handlers = null;\n- }\n- if (this.map) {\n- this.map.removeControl(this);\n- this.map = null;\n- }\n- this.div = null;\n- },\n-\n- /** \n- * Method: setMap\n- * Set the map property for the control. This is done through an accessor\n- * so that subclasses can override this and take special action once \n- * they have their map variable set. \n- *\n- * Parameters:\n- * map - {} \n- */\n- setMap: function(map) {\n- this.map = map;\n- if (this.handler) {\n- this.handler.setMap(map);\n- }\n- },\n-\n- /**\n- * Method: draw\n- * The draw method is called when the control is ready to be displayed\n- * on the page. If a div has not been created one is created. Controls\n- * with a visual component will almost always want to override this method \n- * to customize the look of control. \n- *\n- * Parameters:\n- * px - {} The top-left pixel position of the control\n- * or null.\n- *\n * Returns:\n- * {DOMElement} A reference to the DIV DOMElement containing the control\n+ * {} Clone of this filter.\n */\n- draw: function(px) {\n- if (this.div == null) {\n- this.div = OpenLayers.Util.createDiv(this.id);\n- this.div.className = this.displayClass;\n- if (!this.allowSelection) {\n- this.div.className += \" olControlNoSelect\";\n- this.div.setAttribute(\"unselectable\", \"on\", 0);\n- this.div.onselectstart = OpenLayers.Function.False;\n- }\n- if (this.title != \"\") {\n- this.div.title = this.title;\n- }\n- }\n- if (px != null) {\n- this.position = px.clone();\n- }\n- this.moveTo(this.position);\n- return this.div;\n+ clone: function() {\n+ return null;\n },\n \n /**\n- * Method: moveTo\n- * Sets the left and top style attributes to the passed in pixel \n- * coordinates.\n+ * APIMethod: toString\n *\n- * Parameters:\n- * px - {}\n- */\n- moveTo: function(px) {\n- if ((px != null) && (this.div != null)) {\n- this.div.style.left = px.x + \"px\";\n- this.div.style.top = px.y + \"px\";\n- }\n- },\n-\n- /**\n- * APIMethod: activate\n- * Explicitly activates a control and it's associated\n- * handler if one has been set. Controls can be\n- * deactivated by calling the deactivate() method.\n- * \n- * Returns:\n- * {Boolean} True if the control was successfully activated or\n- * false if the control was already active.\n- */\n- activate: function() {\n- if (this.active) {\n- return false;\n- }\n- if (this.handler) {\n- this.handler.activate();\n- }\n- this.active = true;\n- if (this.map) {\n- OpenLayers.Element.addClass(\n- this.map.viewPortDiv,\n- this.displayClass.replace(/ /g, \"\") + \"Active\"\n- );\n- }\n- this.events.triggerEvent(\"activate\");\n- return true;\n- },\n-\n- /**\n- * APIMethod: deactivate\n- * Deactivates a control and it's associated handler if any. The exact\n- * effect of this depends on the control itself.\n- * \n * Returns:\n- * {Boolean} True if the control was effectively deactivated or false\n- * if the control was already inactive.\n+ * {String} Include in your build to get a CQL\n+ * representation of the filter returned. Otherwise \"[Object object]\"\n+ * will be returned.\n */\n- deactivate: function() {\n- if (this.active) {\n- if (this.handler) {\n- this.handler.deactivate();\n- }\n- this.active = false;\n- if (this.map) {\n- OpenLayers.Element.removeClass(\n- this.map.viewPortDiv,\n- this.displayClass.replace(/ /g, \"\") + \"Active\"\n- );\n- }\n- this.events.triggerEvent(\"deactivate\");\n- return true;\n+ toString: function() {\n+ var string;\n+ if (OpenLayers.Format && OpenLayers.Format.CQL) {\n+ string = OpenLayers.Format.CQL.prototype.write(this);\n+ } else {\n+ string = Object.prototype.toString.call(this);\n }\n- return false;\n+ return string;\n },\n \n- CLASS_NAME: \"OpenLayers.Control\"\n+ CLASS_NAME: \"OpenLayers.Filter\"\n });\n-\n-/**\n- * Constant: OpenLayers.Control.TYPE_BUTTON\n- */\n-OpenLayers.Control.TYPE_BUTTON = 1;\n-\n-/**\n- * Constant: OpenLayers.Control.TYPE_TOGGLE\n- */\n-OpenLayers.Control.TYPE_TOGGLE = 2;\n-\n-/**\n- * Constant: OpenLayers.Control.TYPE_TOOL\n- */\n-OpenLayers.Control.TYPE_TOOL = 3;\n /* ======================================================================\n OpenLayers/Geometry.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n@@ -26951,104 +19596,14 @@\n * Constant: OpenLayers.Format.WFST.DEFAULTS\n * {Object} Default properties for the WFST format.\n */\n OpenLayers.Format.WFST.DEFAULTS = {\n \"version\": \"1.0.0\"\n };\n /* ======================================================================\n- OpenLayers/Filter.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-\n-/**\n- * @requires OpenLayers/BaseTypes/Class.js\n- * @requires OpenLayers/Util.js\n- * @requires OpenLayers/Style.js\n- */\n-\n-/**\n- * Class: OpenLayers.Filter\n- * This class represents an OGC Filter.\n- */\n-OpenLayers.Filter = OpenLayers.Class({\n-\n- /** \n- * Constructor: OpenLayers.Filter\n- * This class represents a generic filter.\n- *\n- * Parameters:\n- * options - {Object} Optional object whose properties will be set on the\n- * instance.\n- * \n- * Returns:\n- * {}\n- */\n- initialize: function(options) {\n- OpenLayers.Util.extend(this, options);\n- },\n-\n- /** \n- * APIMethod: destroy\n- * Remove reference to anything added.\n- */\n- destroy: function() {},\n-\n- /**\n- * APIMethod: evaluate\n- * Evaluates this filter in a specific context. Instances or subclasses\n- * are supposed to override this method.\n- * \n- * Parameters:\n- * context - {Object} Context to use in evaluating the filter. If a vector\n- * feature is provided, the feature.attributes will be used as context.\n- * \n- * Returns:\n- * {Boolean} The filter applies.\n- */\n- evaluate: function(context) {\n- return true;\n- },\n-\n- /**\n- * APIMethod: clone\n- * Clones this filter. Should be implemented by subclasses.\n- * \n- * Returns:\n- * {} Clone of this filter.\n- */\n- clone: function() {\n- return null;\n- },\n-\n- /**\n- * APIMethod: toString\n- *\n- * Returns:\n- * {String} Include in your build to get a CQL\n- * representation of the filter returned. Otherwise \"[Object object]\"\n- * will be returned.\n- */\n- toString: function() {\n- var string;\n- if (OpenLayers.Format && OpenLayers.Format.CQL) {\n- string = OpenLayers.Format.CQL.prototype.write(this);\n- } else {\n- string = Object.prototype.toString.call(this);\n- }\n- return string;\n- },\n-\n- CLASS_NAME: \"OpenLayers.Filter\"\n-});\n-/* ======================================================================\n OpenLayers/Filter/Spatial.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n@@ -31847,332 +24402,1255 @@\n \"ows\": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers[\"ows\"]\n },\n \n CLASS_NAME: \"OpenLayers.Format.WPSExecute\"\n \n });\n /* ======================================================================\n- OpenLayers/WPSProcess.js\n+ OpenLayers/Request/XMLHttpRequest.js\n ====================================================================== */\n \n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-/**\n- * @requires OpenLayers/SingleFile.js\n- */\n+// XMLHttpRequest.js Copyright (C) 2010 Sergey Ilinsky (http://www.ilinsky.com)\n+//\n+// Licensed under the Apache License, Version 2.0 (the \"License\");\n+// you may not use this file except in compliance with the License.\n+// You may obtain a copy of the License at\n+//\n+// http://www.apache.org/licenses/LICENSE-2.0\n+//\n+// Unless required by applicable law or agreed to in writing, software\n+// distributed under the License is distributed on an \"AS IS\" BASIS,\n+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+// See the License for the specific language governing permissions and\n+// limitations under the License.\n \n /**\n- * @requires OpenLayers/Geometry.js\n- * @requires OpenLayers/Feature/Vector.js\n- * @requires OpenLayers/Format/WKT.js\n- * @requires OpenLayers/Format/GeoJSON.js\n- * @requires OpenLayers/Format/WPSExecute.js\n * @requires OpenLayers/Request.js\n */\n \n-/**\n- * Class: OpenLayers.WPSProcess\n- * Representation of a WPS process. Usually instances of\n- * are created by calling 'getProcess' on an\n- * instance.\n- *\n- * Currently supports processes that have geometries\n- * or features as output, using WKT or GeoJSON as output format. It also\n- * supports chaining of processes by using the method to create a\n- * handle that is used as process input instead of a static value.\n- */\n-OpenLayers.WPSProcess = OpenLayers.Class({\n+(function() {\n \n- /**\n- * Property: client\n- * {} The client that manages this process.\n- */\n- client: null,\n+ // Save reference to earlier defined object implementation (if any)\n+ var oXMLHttpRequest = window.XMLHttpRequest;\n \n- /**\n- * Property: server\n- * {String} Local client identifier for this process's server.\n- */\n- server: null,\n+ // Define on browser type\n+ var bGecko = !!window.controllers,\n+ bIE = window.document.all && !window.opera,\n+ bIE7 = bIE && window.navigator.userAgent.match(/MSIE 7.0/);\n \n- /**\n- * Property: identifier\n- * {String} Process identifier known to the server.\n- */\n- identifier: null,\n+ // Enables \"XMLHttpRequest()\" call next to \"new XMLHttpReques()\"\n+ function fXMLHttpRequest() {\n+ this._object = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject(\"Microsoft.XMLHTTP\");\n+ this._listeners = [];\n+ };\n \n- /**\n- * Property: description\n- * {Object} DescribeProcess response for this process.\n- */\n- description: null,\n+ // Constructor\n+ function cXMLHttpRequest() {\n+ return new fXMLHttpRequest;\n+ };\n+ cXMLHttpRequest.prototype = fXMLHttpRequest.prototype;\n \n- /**\n- * APIProperty: localWPS\n- * {String} Service endpoint for locally chained WPS processes. Default is\n- * 'http://geoserver/wps'.\n- */\n- localWPS: 'http://geoserver/wps',\n+ // BUGFIX: Firefox with Firebug installed would break pages if not executed\n+ if (bGecko && oXMLHttpRequest.wrapped)\n+ cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped;\n \n- /**\n- * Property: formats\n- * {Object} OpenLayers.Format instances keyed by mimetype.\n- */\n- formats: null,\n+ // Constants\n+ cXMLHttpRequest.UNSENT = 0;\n+ cXMLHttpRequest.OPENED = 1;\n+ cXMLHttpRequest.HEADERS_RECEIVED = 2;\n+ cXMLHttpRequest.LOADING = 3;\n+ cXMLHttpRequest.DONE = 4;\n \n- /**\n- * Property: chained\n- * {Integer} Number of chained processes for pending execute requests that\n- * don't have a full configuration yet.\n- */\n- chained: 0,\n+ // Public Properties\n+ cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT;\n+ cXMLHttpRequest.prototype.responseText = '';\n+ cXMLHttpRequest.prototype.responseXML = null;\n+ cXMLHttpRequest.prototype.status = 0;\n+ cXMLHttpRequest.prototype.statusText = '';\n \n- /**\n- * Property: executeCallbacks\n- * {Array} Callbacks waiting to be executed until all chained processes\n- * are configured;\n- */\n- executeCallbacks: null,\n+ // Priority proposal\n+ cXMLHttpRequest.prototype.priority = \"NORMAL\";\n \n- /**\n- * Constructor: OpenLayers.WPSProcess\n- *\n- * Parameters:\n- * options - {Object} Object whose properties will be set on the instance.\n- *\n- * Avaliable options:\n- * client - {} Mandatory. Client that manages this\n- * process.\n- * server - {String} Mandatory. Local client identifier of this process's\n- * server.\n- * identifier - {String} Mandatory. Process identifier known to the server.\n- */\n- initialize: function(options) {\n- OpenLayers.Util.extend(this, options);\n- this.executeCallbacks = [];\n- this.formats = {\n- 'application/wkt': new OpenLayers.Format.WKT(),\n- 'application/json': new OpenLayers.Format.GeoJSON()\n- };\n- },\n+ // Instance-level Events Handlers\n+ cXMLHttpRequest.prototype.onreadystatechange = null;\n \n- /**\n- * Method: describe\n- * Makes the client issue a DescribeProcess request asynchronously.\n- *\n- * Parameters:\n- * options - {Object} Configuration for the method call\n- *\n- * Available options:\n- * callback - {Function} Callback to execute when the description is\n- * available. Will be called with the parsed description as argument.\n- * Optional.\n- * scope - {Object} The scope in which the callback will be executed.\n- * Default is the global object.\n- */\n- describe: function(options) {\n- options = options || {};\n- if (!this.description) {\n- this.client.describeProcess(this.server, this.identifier, function(description) {\n- if (!this.description) {\n- this.parseDescription(description);\n- }\n- if (options.callback) {\n- options.callback.call(options.scope, this.description);\n+ // Class-level Events Handlers\n+ cXMLHttpRequest.onreadystatechange = null;\n+ cXMLHttpRequest.onopen = null;\n+ cXMLHttpRequest.onsend = null;\n+ cXMLHttpRequest.onabort = null;\n+\n+ // Public Methods\n+ cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) {\n+ // Delete headers, required when object is reused\n+ delete this._headers;\n+\n+ // When bAsync parameter value is omitted, use true as default\n+ if (arguments.length < 3)\n+ bAsync = true;\n+\n+ // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests\n+ this._async = bAsync;\n+\n+ // Set the onreadystatechange handler\n+ var oRequest = this,\n+ nState = this.readyState,\n+ fOnUnload;\n+\n+ // BUGFIX: IE - memory leak on page unload (inter-page leak)\n+ if (bIE && bAsync) {\n+ fOnUnload = function() {\n+ if (nState != cXMLHttpRequest.DONE) {\n+ fCleanTransport(oRequest);\n+ // Safe to abort here since onreadystatechange handler removed\n+ oRequest.abort();\n }\n- }, this);\n- } else if (options.callback) {\n- var description = this.description;\n- window.setTimeout(function() {\n- options.callback.call(options.scope, description);\n- }, 0);\n+ };\n+ window.attachEvent(\"onunload\", fOnUnload);\n }\n- },\n \n- /**\n- * APIMethod: configure\n- * Configure the process, but do not execute it. Use this for processes\n- * that are chained as input of a different process by means of the\n- * method.\n- *\n- * Parameters:\n- * options - {Object}\n- *\n- * Returns:\n- * {} this process.\n- *\n- * Available options:\n- * inputs - {Object} The inputs for the process, keyed by input identifier.\n- * For spatial data inputs, the value of an input is usually an\n- * , an or an array of\n- * geometries or features.\n- * callback - {Function} Callback to call when the configuration is\n- * complete. Optional.\n- * scope - {Object} Optional scope for the callback.\n- */\n- configure: function(options) {\n- this.describe({\n- callback: function() {\n- var description = this.description,\n- inputs = options.inputs,\n- input, i, ii;\n- for (i = 0, ii = description.dataInputs.length; i < ii; ++i) {\n- input = description.dataInputs[i];\n- this.setInputData(input, inputs[input.identifier]);\n- }\n- if (options.callback) {\n- options.callback.call(options.scope);\n- }\n- },\n- scope: this\n- });\n- return this;\n- },\n+ // Add method sniffer\n+ if (cXMLHttpRequest.onopen)\n+ cXMLHttpRequest.onopen.apply(this, arguments);\n \n- /**\n- * APIMethod: execute\n- * Configures and executes the process\n- *\n- * Parameters:\n- * options - {Object}\n- *\n- * Available options:\n- * inputs - {Object} The inputs for the process, keyed by input identifier.\n- * For spatial data inputs, the value of an input is usually an\n- * , an or an array of\n- * geometries or features.\n- * output - {String} The identifier of the output to request and parse.\n- * Optional. If not provided, the first output will be requested.\n- * success - {Function} Callback to call when the process is complete.\n- * This function is called with an outputs object as argument, which\n- * will have a property with the identifier of the requested output\n- * (or 'result' if output was not configured). For processes that\n- * generate spatial output, the value will be an array of\n- * instances.\n- * scope - {Object} Optional scope for the success callback.\n- */\n- execute: function(options) {\n- this.configure({\n- inputs: options.inputs,\n- callback: function() {\n- var me = this;\n- //TODO For now we only deal with a single output\n- var outputIndex = this.getOutputIndex(\n- me.description.processOutputs, options.output\n- );\n- me.setResponseForm({\n- outputIndex: outputIndex\n- });\n- (function callback() {\n- OpenLayers.Util.removeItem(me.executeCallbacks, callback);\n- if (me.chained !== 0) {\n- // need to wait until chained processes have a\n- // description and configuration - see chainProcess\n- me.executeCallbacks.push(callback);\n- return;\n- }\n- // all chained processes are added as references now, so\n- // let's proceed.\n- OpenLayers.Request.POST({\n- url: me.client.servers[me.server].url,\n- data: new OpenLayers.Format.WPSExecute().write(me.description),\n- success: function(response) {\n- var output = me.description.processOutputs[outputIndex];\n- var mimeType = me.findMimeType(\n- output.complexOutput.supported.formats\n- );\n- //TODO For now we assume a spatial output\n- var features = me.formats[mimeType].read(response.responseText);\n- if (features instanceof OpenLayers.Feature.Vector) {\n- features = [features];\n- }\n- if (options.success) {\n- var outputs = {};\n- outputs[options.output || 'result'] = features;\n- options.success.call(options.scope, outputs);\n- }\n- },\n- scope: me\n- });\n- })();\n- },\n- scope: this\n- });\n- },\n+ if (arguments.length > 4)\n+ this._object.open(sMethod, sUrl, bAsync, sUser, sPassword);\n+ else\n+ if (arguments.length > 3)\n+ this._object.open(sMethod, sUrl, bAsync, sUser);\n+ else\n+ this._object.open(sMethod, sUrl, bAsync);\n \n- /**\n- * APIMethod: output\n- * Chain an output of a configured process (see ) as input to\n- * another process.\n- *\n- * (code)\n- * intersect = client.getProcess('opengeo', 'JTS:intersection'); \n- * intersect.configure({\n- * // ...\n- * });\n- * buffer = client.getProcess('opengeo', 'JTS:buffer');\n- * buffer.execute({\n- * inputs: {\n- * geom: intersect.output('result'), // <-- here we're chaining\n- * distance: 1\n- * },\n- * // ...\n- * });\n- * (end)\n- *\n- * Parameters:\n- * identifier - {String} Identifier of the output that we're chaining. If\n- * not provided, the first output will be used.\n- */\n- output: function(identifier) {\n- return new OpenLayers.WPSProcess.ChainLink({\n- process: this,\n- output: identifier\n- });\n- },\n+ this.readyState = cXMLHttpRequest.OPENED;\n+ fReadyStateChange(this);\n \n- /**\n- * Method: parseDescription\n- * Parses the DescribeProcess response\n- *\n- * Parameters:\n- * description - {Object}\n- */\n- parseDescription: function(description) {\n- var server = this.client.servers[this.server];\n- this.description = new OpenLayers.Format.WPSDescribeProcess()\n- .read(server.processDescription[this.identifier])\n- .processDescriptions[this.identifier];\n- },\n+ this._object.onreadystatechange = function() {\n+ if (bGecko && !bAsync)\n+ return;\n \n- /**\n- * Method: setInputData\n- * Sets the data for a single input\n- *\n- * Parameters:\n- * input - {Object} An entry from the dataInputs array of the process\n- * description.\n- * data - {Mixed} For spatial data inputs, this is usually an\n- * , an or an array of\n- * geometries or features.\n- */\n- setInputData: function(input, data) {\n- // clear any previous data\n- delete input.data;\n- delete input.reference;\n- if (data instanceof OpenLayers.WPSProcess.ChainLink) {\n- ++this.chained;\n- input.reference = {\n- method: 'POST',\n- href: data.process.server === this.server ?\n- this.localWPS : this.client.servers[data.process.server].url\n- };\n+ // Synchronize state\n+ oRequest.readyState = oRequest._object.readyState;\n+\n+ //\n+ fSynchronizeValues(oRequest);\n+\n+ // BUGFIX: Firefox fires unnecessary DONE when aborting\n+ if (oRequest._aborted) {\n+ // Reset readyState to UNSENT\n+ oRequest.readyState = cXMLHttpRequest.UNSENT;\n+\n+ // Return now\n+ return;\n+ }\n+\n+ if (oRequest.readyState == cXMLHttpRequest.DONE) {\n+ // Free up queue\n+ delete oRequest._data;\n+ /* if (bAsync)\n+ fQueue_remove(oRequest);*/\n+ //\n+ fCleanTransport(oRequest);\n+ // Uncomment this block if you need a fix for IE cache\n+ /*\n+ // BUGFIX: IE - cache issue\n+ if (!oRequest._object.getResponseHeader(\"Date\")) {\n+ // Save object to cache\n+ oRequest._cached = oRequest._object;\n+\n+ // Instantiate a new transport object\n+ cXMLHttpRequest.call(oRequest);\n+\n+ // Re-send request\n+ if (sUser) {\n+ if (sPassword)\n+ oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword);\n+ else\n+ oRequest._object.open(sMethod, sUrl, bAsync, sUser);\n+ }\n+ else\n+ oRequest._object.open(sMethod, sUrl, bAsync);\n+ oRequest._object.setRequestHeader(\"If-Modified-Since\", oRequest._cached.getResponseHeader(\"Last-Modified\") || new window.Date(0));\n+ // Copy headers set\n+ if (oRequest._headers)\n+ for (var sHeader in oRequest._headers)\n+ if (typeof oRequest._headers[sHeader] == \"string\") // Some frameworks prototype objects with functions\n+ oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]);\n+\n+ oRequest._object.onreadystatechange = function() {\n+ // Synchronize state\n+ oRequest.readyState = oRequest._object.readyState;\n+\n+ if (oRequest._aborted) {\n+ //\n+ oRequest.readyState = cXMLHttpRequest.UNSENT;\n+\n+ // Return\n+ return;\n+ }\n+\n+ if (oRequest.readyState == cXMLHttpRequest.DONE) {\n+ // Clean Object\n+ fCleanTransport(oRequest);\n+\n+ // get cached request\n+ if (oRequest.status == 304)\n+ oRequest._object = oRequest._cached;\n+\n+ //\n+ delete oRequest._cached;\n+\n+ //\n+ fSynchronizeValues(oRequest);\n+\n+ //\n+ fReadyStateChange(oRequest);\n+\n+ // BUGFIX: IE - memory leak in interrupted\n+ if (bIE && bAsync)\n+ window.detachEvent(\"onunload\", fOnUnload);\n+ }\n+ };\n+ oRequest._object.send(null);\n+\n+ // Return now - wait until re-sent request is finished\n+ return;\n+ };\n+ */\n+ // BUGFIX: IE - memory leak in interrupted\n+ if (bIE && bAsync)\n+ window.detachEvent(\"onunload\", fOnUnload);\n+ }\n+\n+ // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice\n+ if (nState != oRequest.readyState)\n+ fReadyStateChange(oRequest);\n+\n+ nState = oRequest.readyState;\n+ }\n+ };\n+\n+ function fXMLHttpRequest_send(oRequest) {\n+ oRequest._object.send(oRequest._data);\n+\n+ // BUGFIX: Gecko - missing readystatechange calls in synchronous requests\n+ if (bGecko && !oRequest._async) {\n+ oRequest.readyState = cXMLHttpRequest.OPENED;\n+\n+ // Synchronize state\n+ fSynchronizeValues(oRequest);\n+\n+ // Simulate missing states\n+ while (oRequest.readyState < cXMLHttpRequest.DONE) {\n+ oRequest.readyState++;\n+ fReadyStateChange(oRequest);\n+ // Check if we are aborted\n+ if (oRequest._aborted)\n+ return;\n+ }\n+ }\n+ };\n+ cXMLHttpRequest.prototype.send = function(vData) {\n+ // Add method sniffer\n+ if (cXMLHttpRequest.onsend)\n+ cXMLHttpRequest.onsend.apply(this, arguments);\n+\n+ if (!arguments.length)\n+ vData = null;\n+\n+ // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required\n+ // BUGFIX: IE - rewrites any custom mime-type to \"text/xml\" in case an XMLNode is sent\n+ // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard)\n+ if (vData && vData.nodeType) {\n+ vData = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml;\n+ if (!this._headers[\"Content-Type\"])\n+ this._object.setRequestHeader(\"Content-Type\", \"application/xml\");\n+ }\n+\n+ this._data = vData;\n+ /*\n+ // Add to queue\n+ if (this._async)\n+ fQueue_add(this);\n+ else*/\n+ fXMLHttpRequest_send(this);\n+ };\n+ cXMLHttpRequest.prototype.abort = function() {\n+ // Add method sniffer\n+ if (cXMLHttpRequest.onabort)\n+ cXMLHttpRequest.onabort.apply(this, arguments);\n+\n+ // BUGFIX: Gecko - unnecessary DONE when aborting\n+ if (this.readyState > cXMLHttpRequest.UNSENT)\n+ this._aborted = true;\n+\n+ this._object.abort();\n+\n+ // BUGFIX: IE - memory leak\n+ fCleanTransport(this);\n+\n+ this.readyState = cXMLHttpRequest.UNSENT;\n+\n+ delete this._data;\n+ /* if (this._async)\n+ fQueue_remove(this);*/\n+ };\n+ cXMLHttpRequest.prototype.getAllResponseHeaders = function() {\n+ return this._object.getAllResponseHeaders();\n+ };\n+ cXMLHttpRequest.prototype.getResponseHeader = function(sName) {\n+ return this._object.getResponseHeader(sName);\n+ };\n+ cXMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) {\n+ // BUGFIX: IE - cache issue\n+ if (!this._headers)\n+ this._headers = {};\n+ this._headers[sName] = sValue;\n+\n+ return this._object.setRequestHeader(sName, sValue);\n+ };\n+\n+ // EventTarget interface implementation\n+ cXMLHttpRequest.prototype.addEventListener = function(sName, fHandler, bUseCapture) {\n+ for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)\n+ if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)\n+ return;\n+ // Add listener\n+ this._listeners.push([sName, fHandler, bUseCapture]);\n+ };\n+\n+ cXMLHttpRequest.prototype.removeEventListener = function(sName, fHandler, bUseCapture) {\n+ for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)\n+ if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)\n+ break;\n+ // Remove listener\n+ if (oListener)\n+ this._listeners.splice(nIndex, 1);\n+ };\n+\n+ cXMLHttpRequest.prototype.dispatchEvent = function(oEvent) {\n+ var oEventPseudo = {\n+ 'type': oEvent.type,\n+ 'target': this,\n+ 'currentTarget': this,\n+ 'eventPhase': 2,\n+ 'bubbles': oEvent.bubbles,\n+ 'cancelable': oEvent.cancelable,\n+ 'timeStamp': oEvent.timeStamp,\n+ 'stopPropagation': function() {}, // There is no flow\n+ 'preventDefault': function() {}, // There is no default action\n+ 'initEvent': function() {} // Original event object should be initialized\n+ };\n+\n+ // Execute onreadystatechange\n+ if (oEventPseudo.type == \"readystatechange\" && this.onreadystatechange)\n+ (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]);\n+\n+ // Execute listeners\n+ for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)\n+ if (oListener[0] == oEventPseudo.type && !oListener[2])\n+ (oListener[1].handleEvent || oListener[1]).apply(this, [oEventPseudo]);\n+ };\n+\n+ //\n+ cXMLHttpRequest.prototype.toString = function() {\n+ return '[' + \"object\" + ' ' + \"XMLHttpRequest\" + ']';\n+ };\n+\n+ cXMLHttpRequest.toString = function() {\n+ return '[' + \"XMLHttpRequest\" + ']';\n+ };\n+\n+ // Helper function\n+ function fReadyStateChange(oRequest) {\n+ // Sniffing code\n+ if (cXMLHttpRequest.onreadystatechange)\n+ cXMLHttpRequest.onreadystatechange.apply(oRequest);\n+\n+ // Fake event\n+ oRequest.dispatchEvent({\n+ 'type': \"readystatechange\",\n+ 'bubbles': false,\n+ 'cancelable': false,\n+ 'timeStamp': new Date + 0\n+ });\n+ };\n+\n+ function fGetDocument(oRequest) {\n+ var oDocument = oRequest.responseXML,\n+ sResponse = oRequest.responseText;\n+ // Try parsing responseText\n+ if (bIE && sResponse && oDocument && !oDocument.documentElement && oRequest.getResponseHeader(\"Content-Type\").match(/[^\\/]+\\/[^\\+]+\\+xml/)) {\n+ oDocument = new window.ActiveXObject(\"Microsoft.XMLDOM\");\n+ oDocument.async = false;\n+ oDocument.validateOnParse = false;\n+ oDocument.loadXML(sResponse);\n+ }\n+ // Check if there is no error in document\n+ if (oDocument)\n+ if ((bIE && oDocument.parseError != 0) || !oDocument.documentElement || (oDocument.documentElement && oDocument.documentElement.tagName == \"parsererror\"))\n+ return null;\n+ return oDocument;\n+ };\n+\n+ function fSynchronizeValues(oRequest) {\n+ try {\n+ oRequest.responseText = oRequest._object.responseText;\n+ } catch (e) {}\n+ try {\n+ oRequest.responseXML = fGetDocument(oRequest._object);\n+ } catch (e) {}\n+ try {\n+ oRequest.status = oRequest._object.status;\n+ } catch (e) {}\n+ try {\n+ oRequest.statusText = oRequest._object.statusText;\n+ } catch (e) {}\n+ };\n+\n+ function fCleanTransport(oRequest) {\n+ // BUGFIX: IE - memory leak (on-page leak)\n+ oRequest._object.onreadystatechange = new window.Function;\n+ };\n+ /*\n+ // Queue manager\n+ var oQueuePending = {\"CRITICAL\":[],\"HIGH\":[],\"NORMAL\":[],\"LOW\":[],\"LOWEST\":[]},\n+ aQueueRunning = [];\n+ function fQueue_add(oRequest) {\n+ oQueuePending[oRequest.priority in oQueuePending ? oRequest.priority : \"NORMAL\"].push(oRequest);\n+ //\n+ setTimeout(fQueue_process);\n+ };\n+\n+ function fQueue_remove(oRequest) {\n+ for (var nIndex = 0, bFound = false; nIndex < aQueueRunning.length; nIndex++)\n+ if (bFound)\n+ aQueueRunning[nIndex - 1] = aQueueRunning[nIndex];\n+ else\n+ if (aQueueRunning[nIndex] == oRequest)\n+ bFound = true;\n+ if (bFound)\n+ aQueueRunning.length--;\n+ //\n+ setTimeout(fQueue_process);\n+ };\n+\n+ function fQueue_process() {\n+ if (aQueueRunning.length < 6) {\n+ for (var sPriority in oQueuePending) {\n+ if (oQueuePending[sPriority].length) {\n+ var oRequest = oQueuePending[sPriority][0];\n+ oQueuePending[sPriority] = oQueuePending[sPriority].slice(1);\n+ //\n+ aQueueRunning.push(oRequest);\n+ // Send request\n+ fXMLHttpRequest_send(oRequest);\n+ break;\n+ }\n+ }\n+ }\n+ };\n+ */\n+ // Internet Explorer 5.0 (missing apply)\n+ if (!window.Function.prototype.apply) {\n+ window.Function.prototype.apply = function(oRequest, oArguments) {\n+ if (!oArguments)\n+ oArguments = [];\n+ oRequest.__func = this;\n+ oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]);\n+ delete oRequest.__func;\n+ };\n+ };\n+\n+ // Register new object with window\n+ /**\n+ * Class: OpenLayers.Request.XMLHttpRequest\n+ * Standard-compliant (W3C) cross-browser implementation of the\n+ * XMLHttpRequest object. From\n+ * http://code.google.com/p/xmlhttprequest/.\n+ */\n+ if (!OpenLayers.Request) {\n+ /**\n+ * This allows for OpenLayers/Request.js to be included\n+ * before or after this script.\n+ */\n+ OpenLayers.Request = {};\n+ }\n+ OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest;\n+})();\n+/* ======================================================================\n+ OpenLayers/Request.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/Events.js\n+ * @requires OpenLayers/Request/XMLHttpRequest.js\n+ */\n+\n+/**\n+ * TODO: deprecate me\n+ * Use OpenLayers.Request.proxy instead.\n+ */\n+OpenLayers.ProxyHost = \"\";\n+\n+/**\n+ * Namespace: OpenLayers.Request\n+ * The OpenLayers.Request namespace contains convenience methods for working\n+ * with XMLHttpRequests. These methods work with a cross-browser\n+ * W3C compliant class.\n+ */\n+if (!OpenLayers.Request) {\n+ /**\n+ * This allows for OpenLayers/Request/XMLHttpRequest.js to be included\n+ * before or after this script.\n+ */\n+ OpenLayers.Request = {};\n+}\n+OpenLayers.Util.extend(OpenLayers.Request, {\n+\n+ /**\n+ * Constant: DEFAULT_CONFIG\n+ * {Object} Default configuration for all requests.\n+ */\n+ DEFAULT_CONFIG: {\n+ method: \"GET\",\n+ url: window.location.href,\n+ async: true,\n+ user: undefined,\n+ password: undefined,\n+ params: null,\n+ proxy: OpenLayers.ProxyHost,\n+ headers: {},\n+ data: null,\n+ callback: function() {},\n+ success: null,\n+ failure: null,\n+ scope: null\n+ },\n+\n+ /**\n+ * Constant: URL_SPLIT_REGEX\n+ */\n+ URL_SPLIT_REGEX: /([^:]*:)\\/\\/([^:]*:?[^@]*@)?([^:\\/\\?]*):?([^\\/\\?]*)/,\n+\n+ /**\n+ * APIProperty: events\n+ * {} An events object that handles all \n+ * events on the {} object.\n+ *\n+ * All event listeners will receive an event object with three properties:\n+ * request - {} The request object.\n+ * config - {Object} The config object sent to the specific request method.\n+ * requestUrl - {String} The request url.\n+ * \n+ * Supported event types:\n+ * complete - Triggered when we have a response from the request, if a\n+ * listener returns false, no further response processing will take\n+ * place.\n+ * success - Triggered when the HTTP response has a success code (200-299).\n+ * failure - Triggered when the HTTP response does not have a success code.\n+ */\n+ events: new OpenLayers.Events(this),\n+\n+ /**\n+ * Method: makeSameOrigin\n+ * Using the specified proxy, returns a same origin url of the provided url.\n+ *\n+ * Parameters:\n+ * url - {String} An arbitrary url\n+ * proxy {String|Function} The proxy to use to make the provided url a\n+ * same origin url.\n+ *\n+ * Returns\n+ * {String} the same origin url. If no proxy is provided, the returned url\n+ * will be the same as the provided url.\n+ */\n+ makeSameOrigin: function(url, proxy) {\n+ var sameOrigin = url.indexOf(\"http\") !== 0;\n+ var urlParts = !sameOrigin && url.match(this.URL_SPLIT_REGEX);\n+ if (urlParts) {\n+ var location = window.location;\n+ sameOrigin =\n+ urlParts[1] == location.protocol &&\n+ urlParts[3] == location.hostname;\n+ var uPort = urlParts[4],\n+ lPort = location.port;\n+ if (uPort != 80 && uPort != \"\" || lPort != \"80\" && lPort != \"\") {\n+ sameOrigin = sameOrigin && uPort == lPort;\n+ }\n+ }\n+ if (!sameOrigin) {\n+ if (proxy) {\n+ if (typeof proxy == \"function\") {\n+ url = proxy(url);\n+ } else {\n+ url = proxy + encodeURIComponent(url);\n+ }\n+ }\n+ }\n+ return url;\n+ },\n+\n+ /**\n+ * APIMethod: issue\n+ * Create a new XMLHttpRequest object, open it, set any headers, bind\n+ * a callback to done state, and send any data. It is recommended that\n+ * you use one , , , , , or .\n+ * This method is only documented to provide detail on the configuration\n+ * options available to all request methods.\n+ *\n+ * Parameters:\n+ * config - {Object} Object containing properties for configuring the\n+ * request. Allowed configuration properties are described below.\n+ * This object is modified and should not be reused.\n+ *\n+ * Allowed config properties:\n+ * method - {String} One of GET, POST, PUT, DELETE, HEAD, or\n+ * OPTIONS. Default is GET.\n+ * url - {String} URL for the request.\n+ * async - {Boolean} Open an asynchronous request. Default is true.\n+ * user - {String} User for relevant authentication scheme. Set\n+ * to null to clear current user.\n+ * password - {String} Password for relevant authentication scheme.\n+ * Set to null to clear current password.\n+ * proxy - {String} Optional proxy. Defaults to\n+ * .\n+ * params - {Object} Any key:value pairs to be appended to the\n+ * url as a query string. Assumes url doesn't already include a query\n+ * string or hash. Typically, this is only appropriate for \n+ * requests where the query string will be appended to the url.\n+ * Parameter values that are arrays will be\n+ * concatenated with a comma (note that this goes against form-encoding)\n+ * as is done with .\n+ * headers - {Object} Object with header:value pairs to be set on\n+ * the request.\n+ * data - {String | Document} Optional data to send with the request.\n+ * Typically, this is only used with and requests.\n+ * Make sure to provide the appropriate \"Content-Type\" header for your\n+ * data. For and requests, the content type defaults to\n+ * \"application-xml\". If your data is a different content type, or\n+ * if you are using a different HTTP method, set the \"Content-Type\"\n+ * header to match your data type.\n+ * callback - {Function} Function to call when request is done.\n+ * To determine if the request failed, check request.status (200\n+ * indicates success).\n+ * success - {Function} Optional function to call if request status is in\n+ * the 200s. This will be called in addition to callback above and\n+ * would typically only be used as an alternative.\n+ * failure - {Function} Optional function to call if request status is not\n+ * in the 200s. This will be called in addition to callback above and\n+ * would typically only be used as an alternative.\n+ * scope - {Object} If callback is a public method on some object,\n+ * set the scope to that object.\n+ *\n+ * Returns:\n+ * {XMLHttpRequest} Request object. To abort the request before a response\n+ * is received, call abort() on the request object.\n+ */\n+ issue: function(config) {\n+ // apply default config - proxy host may have changed\n+ var defaultConfig = OpenLayers.Util.extend(\n+ this.DEFAULT_CONFIG, {\n+ proxy: OpenLayers.ProxyHost\n+ }\n+ );\n+ config = config || {};\n+ config.headers = config.headers || {};\n+ config = OpenLayers.Util.applyDefaults(config, defaultConfig);\n+ config.headers = OpenLayers.Util.applyDefaults(config.headers, defaultConfig.headers);\n+ // Always set the \"X-Requested-With\" header to signal that this request\n+ // was issued through the XHR-object. Since header keys are case \n+ // insensitive and we want to allow overriding of the \"X-Requested-With\"\n+ // header through the user we cannot use applyDefaults, but have to \n+ // check manually whether we were called with a \"X-Requested-With\"\n+ // header.\n+ var customRequestedWithHeader = false,\n+ headerKey;\n+ for (headerKey in config.headers) {\n+ if (config.headers.hasOwnProperty(headerKey)) {\n+ if (headerKey.toLowerCase() === 'x-requested-with') {\n+ customRequestedWithHeader = true;\n+ }\n+ }\n+ }\n+ if (customRequestedWithHeader === false) {\n+ // we did not have a custom \"X-Requested-With\" header\n+ config.headers['X-Requested-With'] = 'XMLHttpRequest';\n+ }\n+\n+ // create request, open, and set headers\n+ var request = new OpenLayers.Request.XMLHttpRequest();\n+ var url = OpenLayers.Util.urlAppend(config.url,\n+ OpenLayers.Util.getParameterString(config.params || {}));\n+ url = OpenLayers.Request.makeSameOrigin(url, config.proxy);\n+ request.open(\n+ config.method, url, config.async, config.user, config.password\n+ );\n+ for (var header in config.headers) {\n+ request.setRequestHeader(header, config.headers[header]);\n+ }\n+\n+ var events = this.events;\n+\n+ // we want to execute runCallbacks with \"this\" as the\n+ // execution scope\n+ var self = this;\n+\n+ request.onreadystatechange = function() {\n+ if (request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {\n+ var proceed = events.triggerEvent(\n+ \"complete\", {\n+ request: request,\n+ config: config,\n+ requestUrl: url\n+ }\n+ );\n+ if (proceed !== false) {\n+ self.runCallbacks({\n+ request: request,\n+ config: config,\n+ requestUrl: url\n+ });\n+ }\n+ }\n+ };\n+\n+ // send request (optionally with data) and return\n+ // call in a timeout for asynchronous requests so the return is\n+ // available before readyState == 4 for cached docs\n+ if (config.async === false) {\n+ request.send(config.data);\n+ } else {\n+ window.setTimeout(function() {\n+ if (request.readyState !== 0) { // W3C: 0-UNSENT\n+ request.send(config.data);\n+ }\n+ }, 0);\n+ }\n+ return request;\n+ },\n+\n+ /**\n+ * Method: runCallbacks\n+ * Calls the complete, success and failure callbacks. Application\n+ * can listen to the \"complete\" event, have the listener \n+ * display a confirm window and always return false, and\n+ * execute OpenLayers.Request.runCallbacks if the user\n+ * hits \"yes\" in the confirm window.\n+ *\n+ * Parameters:\n+ * options - {Object} Hash containing request, config and requestUrl keys\n+ */\n+ runCallbacks: function(options) {\n+ var request = options.request;\n+ var config = options.config;\n+\n+ // bind callbacks to readyState 4 (done)\n+ var complete = (config.scope) ?\n+ OpenLayers.Function.bind(config.callback, config.scope) :\n+ config.callback;\n+\n+ // optional success callback\n+ var success;\n+ if (config.success) {\n+ success = (config.scope) ?\n+ OpenLayers.Function.bind(config.success, config.scope) :\n+ config.success;\n+ }\n+\n+ // optional failure callback\n+ var failure;\n+ if (config.failure) {\n+ failure = (config.scope) ?\n+ OpenLayers.Function.bind(config.failure, config.scope) :\n+ config.failure;\n+ }\n+\n+ if (OpenLayers.Util.createUrlObject(config.url).protocol == \"file:\" &&\n+ request.responseText) {\n+ request.status = 200;\n+ }\n+ complete(request);\n+\n+ if (!request.status || (request.status >= 200 && request.status < 300)) {\n+ this.events.triggerEvent(\"success\", options);\n+ if (success) {\n+ success(request);\n+ }\n+ }\n+ if (request.status && (request.status < 200 || request.status >= 300)) {\n+ this.events.triggerEvent(\"failure\", options);\n+ if (failure) {\n+ failure(request);\n+ }\n+ }\n+ },\n+\n+ /**\n+ * APIMethod: GET\n+ * Send an HTTP GET request. Additional configuration properties are\n+ * documented in the method, with the method property set\n+ * to GET.\n+ *\n+ * Parameters:\n+ * config - {Object} Object with properties for configuring the request.\n+ * See the method for documentation of allowed properties.\n+ * This object is modified and should not be reused.\n+ * \n+ * Returns:\n+ * {XMLHttpRequest} Request object.\n+ */\n+ GET: function(config) {\n+ config = OpenLayers.Util.extend(config, {\n+ method: \"GET\"\n+ });\n+ return OpenLayers.Request.issue(config);\n+ },\n+\n+ /**\n+ * APIMethod: POST\n+ * Send a POST request. Additional configuration properties are\n+ * documented in the method, with the method property set\n+ * to POST and \"Content-Type\" header set to \"application/xml\".\n+ *\n+ * Parameters:\n+ * config - {Object} Object with properties for configuring the request.\n+ * See the method for documentation of allowed properties. The\n+ * default \"Content-Type\" header will be set to \"application-xml\" if\n+ * none is provided. This object is modified and should not be reused.\n+ * \n+ * Returns:\n+ * {XMLHttpRequest} Request object.\n+ */\n+ POST: function(config) {\n+ config = OpenLayers.Util.extend(config, {\n+ method: \"POST\"\n+ });\n+ // set content type to application/xml if it isn't already set\n+ config.headers = config.headers ? config.headers : {};\n+ if (!(\"CONTENT-TYPE\" in OpenLayers.Util.upperCaseObject(config.headers))) {\n+ config.headers[\"Content-Type\"] = \"application/xml\";\n+ }\n+ return OpenLayers.Request.issue(config);\n+ },\n+\n+ /**\n+ * APIMethod: PUT\n+ * Send an HTTP PUT request. Additional configuration properties are\n+ * documented in the method, with the method property set\n+ * to PUT and \"Content-Type\" header set to \"application/xml\".\n+ *\n+ * Parameters:\n+ * config - {Object} Object with properties for configuring the request.\n+ * See the method for documentation of allowed properties. The\n+ * default \"Content-Type\" header will be set to \"application-xml\" if\n+ * none is provided. This object is modified and should not be reused.\n+ * \n+ * Returns:\n+ * {XMLHttpRequest} Request object.\n+ */\n+ PUT: function(config) {\n+ config = OpenLayers.Util.extend(config, {\n+ method: \"PUT\"\n+ });\n+ // set content type to application/xml if it isn't already set\n+ config.headers = config.headers ? config.headers : {};\n+ if (!(\"CONTENT-TYPE\" in OpenLayers.Util.upperCaseObject(config.headers))) {\n+ config.headers[\"Content-Type\"] = \"application/xml\";\n+ }\n+ return OpenLayers.Request.issue(config);\n+ },\n+\n+ /**\n+ * APIMethod: DELETE\n+ * Send an HTTP DELETE request. Additional configuration properties are\n+ * documented in the method, with the method property set\n+ * to DELETE.\n+ *\n+ * Parameters:\n+ * config - {Object} Object with properties for configuring the request.\n+ * See the method for documentation of allowed properties.\n+ * This object is modified and should not be reused.\n+ * \n+ * Returns:\n+ * {XMLHttpRequest} Request object.\n+ */\n+ DELETE: function(config) {\n+ config = OpenLayers.Util.extend(config, {\n+ method: \"DELETE\"\n+ });\n+ return OpenLayers.Request.issue(config);\n+ },\n+\n+ /**\n+ * APIMethod: HEAD\n+ * Send an HTTP HEAD request. Additional configuration properties are\n+ * documented in the method, with the method property set\n+ * to HEAD.\n+ *\n+ * Parameters:\n+ * config - {Object} Object with properties for configuring the request.\n+ * See the method for documentation of allowed properties.\n+ * This object is modified and should not be reused.\n+ * \n+ * Returns:\n+ * {XMLHttpRequest} Request object.\n+ */\n+ HEAD: function(config) {\n+ config = OpenLayers.Util.extend(config, {\n+ method: \"HEAD\"\n+ });\n+ return OpenLayers.Request.issue(config);\n+ },\n+\n+ /**\n+ * APIMethod: OPTIONS\n+ * Send an HTTP OPTIONS request. Additional configuration properties are\n+ * documented in the method, with the method property set\n+ * to OPTIONS.\n+ *\n+ * Parameters:\n+ * config - {Object} Object with properties for configuring the request.\n+ * See the method for documentation of allowed properties.\n+ * This object is modified and should not be reused.\n+ * \n+ * Returns:\n+ * {XMLHttpRequest} Request object.\n+ */\n+ OPTIONS: function(config) {\n+ config = OpenLayers.Util.extend(config, {\n+ method: \"OPTIONS\"\n+ });\n+ return OpenLayers.Request.issue(config);\n+ }\n+\n+});\n+/* ======================================================================\n+ OpenLayers/WPSProcess.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/SingleFile.js\n+ */\n+\n+/**\n+ * @requires OpenLayers/Geometry.js\n+ * @requires OpenLayers/Feature/Vector.js\n+ * @requires OpenLayers/Format/WKT.js\n+ * @requires OpenLayers/Format/GeoJSON.js\n+ * @requires OpenLayers/Format/WPSExecute.js\n+ * @requires OpenLayers/Request.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.WPSProcess\n+ * Representation of a WPS process. Usually instances of\n+ * are created by calling 'getProcess' on an\n+ * instance.\n+ *\n+ * Currently supports processes that have geometries\n+ * or features as output, using WKT or GeoJSON as output format. It also\n+ * supports chaining of processes by using the method to create a\n+ * handle that is used as process input instead of a static value.\n+ */\n+OpenLayers.WPSProcess = OpenLayers.Class({\n+\n+ /**\n+ * Property: client\n+ * {} The client that manages this process.\n+ */\n+ client: null,\n+\n+ /**\n+ * Property: server\n+ * {String} Local client identifier for this process's server.\n+ */\n+ server: null,\n+\n+ /**\n+ * Property: identifier\n+ * {String} Process identifier known to the server.\n+ */\n+ identifier: null,\n+\n+ /**\n+ * Property: description\n+ * {Object} DescribeProcess response for this process.\n+ */\n+ description: null,\n+\n+ /**\n+ * APIProperty: localWPS\n+ * {String} Service endpoint for locally chained WPS processes. Default is\n+ * 'http://geoserver/wps'.\n+ */\n+ localWPS: 'http://geoserver/wps',\n+\n+ /**\n+ * Property: formats\n+ * {Object} OpenLayers.Format instances keyed by mimetype.\n+ */\n+ formats: null,\n+\n+ /**\n+ * Property: chained\n+ * {Integer} Number of chained processes for pending execute requests that\n+ * don't have a full configuration yet.\n+ */\n+ chained: 0,\n+\n+ /**\n+ * Property: executeCallbacks\n+ * {Array} Callbacks waiting to be executed until all chained processes\n+ * are configured;\n+ */\n+ executeCallbacks: null,\n+\n+ /**\n+ * Constructor: OpenLayers.WPSProcess\n+ *\n+ * Parameters:\n+ * options - {Object} Object whose properties will be set on the instance.\n+ *\n+ * Avaliable options:\n+ * client - {} Mandatory. Client that manages this\n+ * process.\n+ * server - {String} Mandatory. Local client identifier of this process's\n+ * server.\n+ * identifier - {String} Mandatory. Process identifier known to the server.\n+ */\n+ initialize: function(options) {\n+ OpenLayers.Util.extend(this, options);\n+ this.executeCallbacks = [];\n+ this.formats = {\n+ 'application/wkt': new OpenLayers.Format.WKT(),\n+ 'application/json': new OpenLayers.Format.GeoJSON()\n+ };\n+ },\n+\n+ /**\n+ * Method: describe\n+ * Makes the client issue a DescribeProcess request asynchronously.\n+ *\n+ * Parameters:\n+ * options - {Object} Configuration for the method call\n+ *\n+ * Available options:\n+ * callback - {Function} Callback to execute when the description is\n+ * available. Will be called with the parsed description as argument.\n+ * Optional.\n+ * scope - {Object} The scope in which the callback will be executed.\n+ * Default is the global object.\n+ */\n+ describe: function(options) {\n+ options = options || {};\n+ if (!this.description) {\n+ this.client.describeProcess(this.server, this.identifier, function(description) {\n+ if (!this.description) {\n+ this.parseDescription(description);\n+ }\n+ if (options.callback) {\n+ options.callback.call(options.scope, this.description);\n+ }\n+ }, this);\n+ } else if (options.callback) {\n+ var description = this.description;\n+ window.setTimeout(function() {\n+ options.callback.call(options.scope, description);\n+ }, 0);\n+ }\n+ },\n+\n+ /**\n+ * APIMethod: configure\n+ * Configure the process, but do not execute it. Use this for processes\n+ * that are chained as input of a different process by means of the\n+ * method.\n+ *\n+ * Parameters:\n+ * options - {Object}\n+ *\n+ * Returns:\n+ * {} this process.\n+ *\n+ * Available options:\n+ * inputs - {Object} The inputs for the process, keyed by input identifier.\n+ * For spatial data inputs, the value of an input is usually an\n+ * , an or an array of\n+ * geometries or features.\n+ * callback - {Function} Callback to call when the configuration is\n+ * complete. Optional.\n+ * scope - {Object} Optional scope for the callback.\n+ */\n+ configure: function(options) {\n+ this.describe({\n+ callback: function() {\n+ var description = this.description,\n+ inputs = options.inputs,\n+ input, i, ii;\n+ for (i = 0, ii = description.dataInputs.length; i < ii; ++i) {\n+ input = description.dataInputs[i];\n+ this.setInputData(input, inputs[input.identifier]);\n+ }\n+ if (options.callback) {\n+ options.callback.call(options.scope);\n+ }\n+ },\n+ scope: this\n+ });\n+ return this;\n+ },\n+\n+ /**\n+ * APIMethod: execute\n+ * Configures and executes the process\n+ *\n+ * Parameters:\n+ * options - {Object}\n+ *\n+ * Available options:\n+ * inputs - {Object} The inputs for the process, keyed by input identifier.\n+ * For spatial data inputs, the value of an input is usually an\n+ * , an or an array of\n+ * geometries or features.\n+ * output - {String} The identifier of the output to request and parse.\n+ * Optional. If not provided, the first output will be requested.\n+ * success - {Function} Callback to call when the process is complete.\n+ * This function is called with an outputs object as argument, which\n+ * will have a property with the identifier of the requested output\n+ * (or 'result' if output was not configured). For processes that\n+ * generate spatial output, the value will be an array of\n+ * instances.\n+ * scope - {Object} Optional scope for the success callback.\n+ */\n+ execute: function(options) {\n+ this.configure({\n+ inputs: options.inputs,\n+ callback: function() {\n+ var me = this;\n+ //TODO For now we only deal with a single output\n+ var outputIndex = this.getOutputIndex(\n+ me.description.processOutputs, options.output\n+ );\n+ me.setResponseForm({\n+ outputIndex: outputIndex\n+ });\n+ (function callback() {\n+ OpenLayers.Util.removeItem(me.executeCallbacks, callback);\n+ if (me.chained !== 0) {\n+ // need to wait until chained processes have a\n+ // description and configuration - see chainProcess\n+ me.executeCallbacks.push(callback);\n+ return;\n+ }\n+ // all chained processes are added as references now, so\n+ // let's proceed.\n+ OpenLayers.Request.POST({\n+ url: me.client.servers[me.server].url,\n+ data: new OpenLayers.Format.WPSExecute().write(me.description),\n+ success: function(response) {\n+ var output = me.description.processOutputs[outputIndex];\n+ var mimeType = me.findMimeType(\n+ output.complexOutput.supported.formats\n+ );\n+ //TODO For now we assume a spatial output\n+ var features = me.formats[mimeType].read(response.responseText);\n+ if (features instanceof OpenLayers.Feature.Vector) {\n+ features = [features];\n+ }\n+ if (options.success) {\n+ var outputs = {};\n+ outputs[options.output || 'result'] = features;\n+ options.success.call(options.scope, outputs);\n+ }\n+ },\n+ scope: me\n+ });\n+ })();\n+ },\n+ scope: this\n+ });\n+ },\n+\n+ /**\n+ * APIMethod: output\n+ * Chain an output of a configured process (see ) as input to\n+ * another process.\n+ *\n+ * (code)\n+ * intersect = client.getProcess('opengeo', 'JTS:intersection'); \n+ * intersect.configure({\n+ * // ...\n+ * });\n+ * buffer = client.getProcess('opengeo', 'JTS:buffer');\n+ * buffer.execute({\n+ * inputs: {\n+ * geom: intersect.output('result'), // <-- here we're chaining\n+ * distance: 1\n+ * },\n+ * // ...\n+ * });\n+ * (end)\n+ *\n+ * Parameters:\n+ * identifier - {String} Identifier of the output that we're chaining. If\n+ * not provided, the first output will be used.\n+ */\n+ output: function(identifier) {\n+ return new OpenLayers.WPSProcess.ChainLink({\n+ process: this,\n+ output: identifier\n+ });\n+ },\n+\n+ /**\n+ * Method: parseDescription\n+ * Parses the DescribeProcess response\n+ *\n+ * Parameters:\n+ * description - {Object}\n+ */\n+ parseDescription: function(description) {\n+ var server = this.client.servers[this.server];\n+ this.description = new OpenLayers.Format.WPSDescribeProcess()\n+ .read(server.processDescription[this.identifier])\n+ .processDescriptions[this.identifier];\n+ },\n+\n+ /**\n+ * Method: setInputData\n+ * Sets the data for a single input\n+ *\n+ * Parameters:\n+ * input - {Object} An entry from the dataInputs array of the process\n+ * description.\n+ * data - {Mixed} For spatial data inputs, this is usually an\n+ * , an or an array of\n+ * geometries or features.\n+ */\n+ setInputData: function(input, data) {\n+ // clear any previous data\n+ delete input.data;\n+ delete input.reference;\n+ if (data instanceof OpenLayers.WPSProcess.ChainLink) {\n+ ++this.chained;\n+ input.reference = {\n+ method: 'POST',\n+ href: data.process.server === this.server ?\n+ this.localWPS : this.client.servers[data.process.server].url\n+ };\n data.process.describe({\n callback: function() {\n --this.chained;\n this.chainProcess(input, data);\n },\n scope: this\n });\n@@ -32354,428 +25832,640 @@\n OpenLayers.Util.extend(this, options);\n },\n \n CLASS_NAME: \"OpenLayers.WPSProcess.ChainLink\"\n \n });\n /* ======================================================================\n- OpenLayers/Format/WPSDescribeProcess.js\n+ OpenLayers/Icon.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n /**\n- * @requires OpenLayers/Format/XML.js\n- * @requires OpenLayers/Format/OWSCommon/v1_1_0.js\n+ * @requires OpenLayers/BaseTypes/Class.js\n */\n \n /**\n- * Class: OpenLayers.Format.WPSDescribeProcess\n- * Read WPS DescribeProcess responses. \n+ * Class: OpenLayers.Icon\n+ * \n+ * The icon represents a graphical icon on the screen. Typically used in\n+ * conjunction with a to represent markers on a screen.\n *\n- * Inherits from:\n- * - \n+ * An icon has a url, size and position. It also contains an offset which \n+ * allows the center point to be represented correctly. This can be\n+ * provided either as a fixed offset or a function provided to calculate\n+ * the desired offset. \n+ * \n */\n-OpenLayers.Format.WPSDescribeProcess = OpenLayers.Class(\n- OpenLayers.Format.XML, {\n+OpenLayers.Icon = OpenLayers.Class({\n \n- /**\n- * Constant: VERSION\n- * {String} 1.0.0\n- */\n- VERSION: \"1.0.0\",\n+ /** \n+ * Property: url \n+ * {String} image url\n+ */\n+ url: null,\n \n- /**\n- * Property: namespaces\n- * {Object} Mapping of namespace aliases to namespace URIs.\n- */\n- namespaces: {\n- wps: \"http://www.opengis.net/wps/1.0.0\",\n- ows: \"http://www.opengis.net/ows/1.1\",\n- xsi: \"http://www.w3.org/2001/XMLSchema-instance\"\n- },\n+ /** \n+ * Property: size \n+ * {|Object} An OpenLayers.Size or\n+ * an object with a 'w' and 'h' properties.\n+ */\n+ size: null,\n \n- /**\n- * Property: schemaLocation\n- * {String} Schema location\n- */\n- schemaLocation: \"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd\",\n+ /** \n+ * Property: offset \n+ * {|Object} distance in pixels to offset the\n+ * image when being rendered. An OpenLayers.Pixel or an object\n+ * with a 'x' and 'y' properties.\n+ */\n+ offset: null,\n \n- /**\n- * Property: defaultPrefix\n- */\n- defaultPrefix: \"wps\",\n+ /** \n+ * Property: calculateOffset \n+ * {Function} Function to calculate the offset (based on the size)\n+ */\n+ calculateOffset: null,\n \n- /**\n- * Property: regExes\n- * Compiled regular expressions for manipulating strings.\n- */\n- regExes: {\n- trimSpace: (/^\\s*|\\s*$/g),\n- removeSpace: (/\\s*/g),\n- splitSpace: (/\\s+/),\n- trimComma: (/\\s*,\\s*/g)\n- },\n+ /** \n+ * Property: imageDiv \n+ * {DOMElement} \n+ */\n+ imageDiv: null,\n \n- /**\n- * Constructor: OpenLayers.Format.WPSDescribeProcess\n- *\n- * Parameters:\n- * options - {Object} An optional object whose properties will be set on\n- * this instance.\n- */\n+ /** \n+ * Property: px \n+ * {|Object} An OpenLayers.Pixel or an object\n+ * with a 'x' and 'y' properties.\n+ */\n+ px: null,\n \n- /**\n- * APIMethod: read\n- * Parse a WPS DescribeProcess and return an object with its information.\n- * \n- * Parameters: \n- * data - {String} or {DOMElement} data to read/parse.\n- *\n- * Returns:\n- * {Object}\n- */\n- read: function(data) {\n- if (typeof data == \"string\") {\n- data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);\n- }\n- if (data && data.nodeType == 9) {\n- data = data.documentElement;\n- }\n- var info = {};\n- this.readNode(data, info);\n- return info;\n- },\n+ /** \n+ * Constructor: OpenLayers.Icon\n+ * Creates an icon, which is an image tag in a div. \n+ *\n+ * url - {String} \n+ * size - {|Object} An OpenLayers.Size or an\n+ * object with a 'w' and 'h'\n+ * properties.\n+ * offset - {|Object} An OpenLayers.Pixel or an\n+ * object with a 'x' and 'y'\n+ * properties.\n+ * calculateOffset - {Function} \n+ */\n+ initialize: function(url, size, offset, calculateOffset) {\n+ this.url = url;\n+ this.size = size || {\n+ w: 20,\n+ h: 20\n+ };\n+ this.offset = offset || {\n+ x: -(this.size.w / 2),\n+ y: -(this.size.h / 2)\n+ };\n+ this.calculateOffset = calculateOffset;\n \n- /**\n- * Property: readers\n- * Contains public functions, grouped by namespace prefix, that will\n- * be applied when a namespaced node is found matching the function\n- * name. The function will be applied in the scope of this parser\n- * with two arguments: the node being read and a context object passed\n- * from the parent.\n- */\n- readers: {\n- \"wps\": {\n- \"ProcessDescriptions\": function(node, obj) {\n- obj.processDescriptions = {};\n- this.readChildNodes(node, obj.processDescriptions);\n- },\n- \"ProcessDescription\": function(node, processDescriptions) {\n- var processVersion = this.getAttributeNS(node, this.namespaces.wps, \"processVersion\");\n- var processDescription = {\n- processVersion: processVersion,\n- statusSupported: (node.getAttribute(\"statusSupported\") === \"true\"),\n- storeSupported: (node.getAttribute(\"storeSupported\") === \"true\")\n- };\n- this.readChildNodes(node, processDescription);\n- processDescriptions[processDescription.identifier] = processDescription;\n- },\n- \"DataInputs\": function(node, processDescription) {\n- processDescription.dataInputs = [];\n- this.readChildNodes(node, processDescription.dataInputs);\n- },\n- \"ProcessOutputs\": function(node, processDescription) {\n- processDescription.processOutputs = [];\n- this.readChildNodes(node, processDescription.processOutputs);\n- },\n- \"Output\": function(node, processOutputs) {\n- var output = {};\n- this.readChildNodes(node, output);\n- processOutputs.push(output);\n- },\n- \"ComplexOutput\": function(node, output) {\n- output.complexOutput = {};\n- this.readChildNodes(node, output.complexOutput);\n- },\n- \"LiteralOutput\": function(node, output) {\n- output.literalOutput = {};\n- this.readChildNodes(node, output.literalOutput);\n- },\n- \"Input\": function(node, dataInputs) {\n- var input = {\n- maxOccurs: parseInt(node.getAttribute(\"maxOccurs\")),\n- minOccurs: parseInt(node.getAttribute(\"minOccurs\"))\n- };\n- this.readChildNodes(node, input);\n- dataInputs.push(input);\n- },\n- \"BoundingBoxData\": function(node, input) {\n- input.boundingBoxData = {};\n- this.readChildNodes(node, input.boundingBoxData);\n- },\n- \"CRS\": function(node, obj) {\n- if (!obj.CRSs) {\n- obj.CRSs = {};\n- }\n- obj.CRSs[this.getChildValue(node)] = true;\n- },\n- \"LiteralData\": function(node, input) {\n- input.literalData = {};\n- this.readChildNodes(node, input.literalData);\n- },\n- \"ComplexData\": function(node, input) {\n- input.complexData = {};\n- this.readChildNodes(node, input.complexData);\n- },\n- \"Default\": function(node, complexData) {\n- complexData[\"default\"] = {};\n- this.readChildNodes(node, complexData[\"default\"]);\n- },\n- \"Supported\": function(node, complexData) {\n- complexData[\"supported\"] = {};\n- this.readChildNodes(node, complexData[\"supported\"]);\n- },\n- \"Format\": function(node, obj) {\n- var format = {};\n- this.readChildNodes(node, format);\n- if (!obj.formats) {\n- obj.formats = {};\n- }\n- obj.formats[format.mimeType] = true;\n- },\n- \"MimeType\": function(node, format) {\n- format.mimeType = this.getChildValue(node);\n+ var id = OpenLayers.Util.createUniqueID(\"OL_Icon_\");\n+ this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);\n+ },\n+\n+ /** \n+ * Method: destroy\n+ * Nullify references and remove event listeners to prevent circular \n+ * references and memory leaks\n+ */\n+ destroy: function() {\n+ // erase any drawn elements\n+ this.erase();\n+\n+ OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);\n+ this.imageDiv.innerHTML = \"\";\n+ this.imageDiv = null;\n+ },\n+\n+ /** \n+ * Method: clone\n+ * \n+ * Returns:\n+ * {} A fresh copy of the icon.\n+ */\n+ clone: function() {\n+ return new OpenLayers.Icon(this.url,\n+ this.size,\n+ this.offset,\n+ this.calculateOffset);\n+ },\n+\n+ /**\n+ * Method: setSize\n+ * \n+ * Parameters:\n+ * size - {|Object} An OpenLayers.Size or\n+ * an object with a 'w' and 'h' properties.\n+ */\n+ setSize: function(size) {\n+ if (size != null) {\n+ this.size = size;\n+ }\n+ this.draw();\n+ },\n+\n+ /**\n+ * Method: setUrl\n+ * \n+ * Parameters:\n+ * url - {String} \n+ */\n+ setUrl: function(url) {\n+ if (url != null) {\n+ this.url = url;\n+ }\n+ this.draw();\n+ },\n+\n+ /** \n+ * Method: draw\n+ * Move the div to the given pixel.\n+ * \n+ * Parameters:\n+ * px - {|Object} An OpenLayers.Pixel or an\n+ * object with a 'x' and 'y' properties.\n+ * \n+ * Returns:\n+ * {DOMElement} A new DOM Image of this icon set at the location passed-in\n+ */\n+ draw: function(px) {\n+ OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,\n+ null,\n+ null,\n+ this.size,\n+ this.url,\n+ \"absolute\");\n+ this.moveTo(px);\n+ return this.imageDiv;\n+ },\n+\n+ /** \n+ * Method: erase\n+ * Erase the underlying image element.\n+ */\n+ erase: function() {\n+ if (this.imageDiv != null && this.imageDiv.parentNode != null) {\n+ OpenLayers.Element.remove(this.imageDiv);\n+ }\n+ },\n+\n+ /** \n+ * Method: setOpacity\n+ * Change the icon's opacity\n+ *\n+ * Parameters:\n+ * opacity - {float} \n+ */\n+ setOpacity: function(opacity) {\n+ OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null,\n+ null, null, null, null, opacity);\n+\n+ },\n+\n+ /**\n+ * Method: moveTo\n+ * move icon to passed in px.\n+ *\n+ * Parameters:\n+ * px - {|Object} the pixel position to move to.\n+ * An OpenLayers.Pixel or an object with a 'x' and 'y' properties.\n+ */\n+ moveTo: function(px) {\n+ //if no px passed in, use stored location\n+ if (px != null) {\n+ this.px = px;\n+ }\n+\n+ if (this.imageDiv != null) {\n+ if (this.px == null) {\n+ this.display(false);\n+ } else {\n+ if (this.calculateOffset) {\n+ this.offset = this.calculateOffset(this.size);\n }\n- },\n- \"ows\": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers[\"ows\"]\n- },\n+ OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, {\n+ x: this.px.x + this.offset.x,\n+ y: this.px.y + this.offset.y\n+ });\n+ }\n+ }\n+ },\n \n- CLASS_NAME: \"OpenLayers.Format.WPSDescribeProcess\"\n+ /** \n+ * Method: display\n+ * Hide or show the icon\n+ *\n+ * Parameters:\n+ * display - {Boolean} \n+ */\n+ display: function(display) {\n+ this.imageDiv.style.display = (display) ? \"\" : \"none\";\n+ },\n \n- });\n+\n+ /**\n+ * APIMethod: isDrawn\n+ * \n+ * Returns:\n+ * {Boolean} Whether or not the icon is drawn.\n+ */\n+ isDrawn: function() {\n+ // nodeType 11 for ie, whose nodes *always* have a parentNode\n+ // (of type document fragment)\n+ var isDrawn = (this.imageDiv && this.imageDiv.parentNode &&\n+ (this.imageDiv.parentNode.nodeType != 11));\n+\n+ return isDrawn;\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Icon\"\n+});\n /* ======================================================================\n- OpenLayers/WPSClient.js\n+ OpenLayers/Marker.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n-/**\n- * @requires OpenLayers/SingleFile.js\n- */\n \n /**\n+ * @requires OpenLayers/BaseTypes/Class.js\n * @requires OpenLayers/Events.js\n- * @requires OpenLayers/WPSProcess.js\n- * @requires OpenLayers/Format/WPSDescribeProcess.js\n- * @requires OpenLayers/Request.js\n+ * @requires OpenLayers/Icon.js\n */\n \n /**\n- * Class: OpenLayers.WPSClient\n- * High level API for interaction with Web Processing Services (WPS).\n- * An instance is used to create \n- * instances for servers known to the WPSClient. The WPSClient also caches\n- * DescribeProcess responses to reduce the number of requests sent to servers\n- * when processes are created.\n+ * Class: OpenLayers.Marker\n+ * Instances of OpenLayers.Marker are a combination of a \n+ * and an . \n+ *\n+ * Markers are generally added to a special layer called\n+ * .\n+ *\n+ * Example:\n+ * (code)\n+ * var markers = new OpenLayers.Layer.Markers( \"Markers\" );\n+ * map.addLayer(markers);\n+ *\n+ * var size = new OpenLayers.Size(21,25);\n+ * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);\n+ * var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset);\n+ * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon));\n+ * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone()));\n+ *\n+ * (end)\n+ *\n+ * Note that if you pass an icon into the Marker constructor, it will take\n+ * that icon and use it. This means that you should not share icons between\n+ * markers -- you use them once, but you should clone() for any additional\n+ * markers using that same icon.\n */\n-OpenLayers.WPSClient = OpenLayers.Class({\n+OpenLayers.Marker = OpenLayers.Class({\n \n- /**\n- * Property: servers\n- * {Object} Service metadata, keyed by a local identifier.\n+ /** \n+ * Property: icon \n+ * {} The icon used by this marker.\n+ */\n+ icon: null,\n+\n+ /** \n+ * Property: lonlat \n+ * {} location of object\n+ */\n+ lonlat: null,\n+\n+ /** \n+ * Property: events \n+ * {} the event handler.\n+ */\n+ events: null,\n+\n+ /** \n+ * Property: map \n+ * {} the map this marker is attached to\n+ */\n+ map: null,\n+\n+ /** \n+ * Constructor: OpenLayers.Marker\n *\n- * Properties:\n- * url - {String} the url of the server\n- * version - {String} WPS version of the server\n- * processDescription - {Object} Cache of raw DescribeProcess\n- * responses, keyed by process identifier.\n+ * Parameters:\n+ * lonlat - {} the position of this marker\n+ * icon - {} the icon for this marker\n */\n- servers: null,\n+ initialize: function(lonlat, icon) {\n+ this.lonlat = lonlat;\n+\n+ var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon();\n+ if (this.icon == null) {\n+ this.icon = newIcon;\n+ } else {\n+ this.icon.url = newIcon.url;\n+ this.icon.size = newIcon.size;\n+ this.icon.offset = newIcon.offset;\n+ this.icon.calculateOffset = newIcon.calculateOffset;\n+ }\n+ this.events = new OpenLayers.Events(this, this.icon.imageDiv);\n+ },\n \n /**\n- * Property: version\n- * {String} The default WPS version to use if none is configured. Default\n- * is '1.0.0'.\n+ * APIMethod: destroy\n+ * Destroy the marker. You must first remove the marker from any \n+ * layer which it has been added to, or you will get buggy behavior.\n+ * (This can not be done within the marker since the marker does not\n+ * know which layer it is attached to.)\n */\n- version: '1.0.0',\n+ destroy: function() {\n+ // erase any drawn features\n+ this.erase();\n+\n+ this.map = null;\n+\n+ this.events.destroy();\n+ this.events = null;\n+\n+ if (this.icon != null) {\n+ this.icon.destroy();\n+ this.icon = null;\n+ }\n+ },\n+\n+ /** \n+ * Method: draw\n+ * Calls draw on the icon, and returns that output.\n+ * \n+ * Parameters:\n+ * px - {}\n+ * \n+ * Returns:\n+ * {DOMElement} A new DOM Image with this marker's icon set at the \n+ * location passed-in\n+ */\n+ draw: function(px) {\n+ return this.icon.draw(px);\n+ },\n+\n+ /** \n+ * Method: erase\n+ * Erases any drawn elements for this marker.\n+ */\n+ erase: function() {\n+ if (this.icon != null) {\n+ this.icon.erase();\n+ }\n+ },\n \n /**\n- * Property: lazy\n- * {Boolean} Should the DescribeProcess be deferred until a process is\n- * fully configured? Default is false.\n+ * Method: moveTo\n+ * Move the marker to the new location.\n+ *\n+ * Parameters:\n+ * px - {|Object} the pixel position to move to.\n+ * An OpenLayers.Pixel or an object with a 'x' and 'y' properties.\n */\n- lazy: false,\n+ moveTo: function(px) {\n+ if ((px != null) && (this.icon != null)) {\n+ this.icon.moveTo(px);\n+ }\n+ this.lonlat = this.map.getLonLatFromLayerPx(px);\n+ },\n \n /**\n- * Property: events\n- * {}\n+ * APIMethod: isDrawn\n+ * \n+ * Returns:\n+ * {Boolean} Whether or not the marker is drawn.\n+ */\n+ isDrawn: function() {\n+ var isDrawn = (this.icon && this.icon.isDrawn());\n+ return isDrawn;\n+ },\n+\n+ /**\n+ * Method: onScreen\n *\n- * Supported event types:\n- * describeprocess - Fires when the process description is available.\n- * Listeners receive an object with a 'raw' property holding the raw\n- * DescribeProcess response, and an 'identifier' property holding the\n- * process identifier of the described process.\n+ * Returns:\n+ * {Boolean} Whether or not the marker is currently visible on screen.\n */\n- events: null,\n+ onScreen: function() {\n+\n+ var onScreen = false;\n+ if (this.map) {\n+ var screenBounds = this.map.getExtent();\n+ onScreen = screenBounds.containsLonLat(this.lonlat);\n+ }\n+ return onScreen;\n+ },\n \n /**\n- * Constructor: OpenLayers.WPSClient\n+ * Method: inflate\n+ * Englarges the markers icon by the specified ratio.\n *\n * Parameters:\n- * options - {Object} Object whose properties will be set on the instance.\n- *\n- * Avaliable options:\n- * servers - {Object} Mandatory. Service metadata, keyed by a local\n- * identifier. Can either be a string with the service url or an\n- * object literal with additional metadata:\n- *\n- * (code)\n- * servers: {\n- * local: '/geoserver/wps'\n- * }, {\n- * opengeo: {\n- * url: 'http://demo.opengeo.org/geoserver/wps',\n- * version: '1.0.0'\n- * }\n- * }\n- * (end)\n- *\n- * lazy - {Boolean} Optional. Set to true if DescribeProcess should not be\n- * requested until a process is fully configured. Default is false.\n+ * inflate - {float} the ratio to enlarge the marker by (passing 2\n+ * will double the size).\n */\n- initialize: function(options) {\n- OpenLayers.Util.extend(this, options);\n- this.events = new OpenLayers.Events(this);\n- this.servers = {};\n- for (var s in options.servers) {\n- this.servers[s] = typeof options.servers[s] == 'string' ? {\n- url: options.servers[s],\n- version: this.version,\n- processDescription: {}\n- } : options.servers[s];\n+ inflate: function(inflate) {\n+ if (this.icon) {\n+ this.icon.setSize({\n+ w: this.icon.size.w * inflate,\n+ h: this.icon.size.h * inflate\n+ });\n }\n },\n \n+ /** \n+ * Method: setOpacity\n+ * Change the opacity of the marker by changin the opacity of \n+ * its icon\n+ * \n+ * Parameters:\n+ * opacity - {float} Specified as fraction (0.4, etc)\n+ */\n+ setOpacity: function(opacity) {\n+ this.icon.setOpacity(opacity);\n+ },\n+\n /**\n- * APIMethod: execute\n- * Shortcut to execute a process with a single function call. This is\n- * equivalent to using and then calling execute on the\n- * process.\n+ * Method: setUrl\n+ * Change URL of the Icon Image.\n+ * \n+ * url - {String} \n+ */\n+ setUrl: function(url) {\n+ this.icon.setUrl(url);\n+ },\n+\n+ /** \n+ * Method: display\n+ * Hide or show the icon\n+ * \n+ * display - {Boolean} \n+ */\n+ display: function(display) {\n+ this.icon.display(display);\n+ },\n+\n+ CLASS_NAME: \"OpenLayers.Marker\"\n+});\n+\n+\n+/**\n+ * Function: defaultIcon\n+ * Creates a default .\n+ * \n+ * Returns:\n+ * {} A default OpenLayers.Icon to use for a marker\n+ */\n+OpenLayers.Marker.defaultIcon = function() {\n+ return new OpenLayers.Icon(OpenLayers.Util.getImageLocation(\"marker.png\"), {\n+ w: 21,\n+ h: 25\n+ }, {\n+ x: -10.5,\n+ y: -25\n+ });\n+};\n+\n+\n+/* ======================================================================\n+ OpenLayers/Strategy.js\n+ ====================================================================== */\n+\n+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n+ * full list of contributors). Published under the 2-clause BSD license.\n+ * See license.txt in the OpenLayers distribution or repository for the\n+ * full text of the license. */\n+\n+/**\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ */\n+\n+/**\n+ * Class: OpenLayers.Strategy\n+ * Abstract vector layer strategy class. Not to be instantiated directly. Use\n+ * one of the strategy subclasses instead.\n+ */\n+OpenLayers.Strategy = OpenLayers.Class({\n+\n+ /**\n+ * Property: layer\n+ * {} The layer this strategy belongs to.\n+ */\n+ layer: null,\n+\n+ /**\n+ * Property: options\n+ * {Object} Any options sent to the constructor.\n+ */\n+ options: null,\n+\n+ /** \n+ * Property: active \n+ * {Boolean} The control is active.\n+ */\n+ active: null,\n+\n+ /**\n+ * Property: autoActivate\n+ * {Boolean} The creator of the strategy can set autoActivate to false\n+ * to fully control when the protocol is activated and deactivated.\n+ * Defaults to true.\n+ */\n+ autoActivate: true,\n+\n+ /**\n+ * Property: autoDestroy\n+ * {Boolean} The creator of the strategy can set autoDestroy to false\n+ * to fully control when the strategy is destroyed. Defaults to\n+ * true.\n+ */\n+ autoDestroy: true,\n+\n+ /**\n+ * Constructor: OpenLayers.Strategy\n+ * Abstract class for vector strategies. Create instances of a subclass.\n *\n * Parameters:\n- * options - {Object} Options for the execute operation.\n- *\n- * Available options:\n- * server - {String} Mandatory. One of the local identifiers of the\n- * configured servers.\n- * process - {String} Mandatory. A process identifier known to the\n- * server.\n- * inputs - {Object} The inputs for the process, keyed by input identifier.\n- * For spatial data inputs, the value of an input is usually an\n- * , an or an array of\n- * geometries or features.\n- * output - {String} The identifier of an output to parse. Optional. If not\n- * provided, the first output will be parsed.\n- * success - {Function} Callback to call when the process is complete.\n- * This function is called with an outputs object as argument, which\n- * will have a property with the identifier of the requested output\n- * (e.g. 'result'). For processes that generate spatial output, the\n- * value will either be a single or an\n- * array of features.\n- * scope - {Object} Optional scope for the success callback.\n+ * options - {Object} Optional object whose properties will be set on the\n+ * instance.\n */\n- execute: function(options) {\n- var process = this.getProcess(options.server, options.process);\n- process.execute({\n- inputs: options.inputs,\n- success: options.success,\n- scope: options.scope\n- });\n+ initialize: function(options) {\n+ OpenLayers.Util.extend(this, options);\n+ this.options = options;\n+ // set the active property here, so that user cannot override it\n+ this.active = false;\n },\n \n /**\n- * APIMethod: getProcess\n- * Creates an .\n+ * APIMethod: destroy\n+ * Clean up the strategy.\n+ */\n+ destroy: function() {\n+ this.deactivate();\n+ this.layer = null;\n+ this.options = null;\n+ },\n+\n+ /**\n+ * Method: setLayer\n+ * Called to set the property.\n *\n * Parameters:\n- * serverID - {String} Local identifier from the servers that this instance\n- * was constructed with.\n- * processID - {String} Process identifier known to the server.\n- *\n- * Returns:\n- * {}\n+ * layer - {}\n */\n- getProcess: function(serverID, processID) {\n- var process = new OpenLayers.WPSProcess({\n- client: this,\n- server: serverID,\n- identifier: processID\n- });\n- if (!this.lazy) {\n- process.describe();\n- }\n- return process;\n+ setLayer: function(layer) {\n+ this.layer = layer;\n },\n \n /**\n- * Method: describeProcess\n+ * Method: activate\n+ * Activate the strategy. Register any listeners, do appropriate setup.\n *\n- * Parameters:\n- * serverID - {String} Identifier of the server\n- * processID - {String} Identifier of the requested process\n- * callback - {Function} Callback to call when the description is available\n- * scope - {Object} Optional execution scope for the callback function\n+ * Returns:\n+ * {Boolean} True if the strategy was successfully activated or false if\n+ * the strategy was already active.\n */\n- describeProcess: function(serverID, processID, callback, scope) {\n- var server = this.servers[serverID];\n- if (!server.processDescription[processID]) {\n- if (!(processID in server.processDescription)) {\n- // set to null so we know a describeFeature request is pending\n- server.processDescription[processID] = null;\n- OpenLayers.Request.GET({\n- url: server.url,\n- params: {\n- SERVICE: 'WPS',\n- VERSION: server.version,\n- REQUEST: 'DescribeProcess',\n- IDENTIFIER: processID\n- },\n- success: function(response) {\n- server.processDescription[processID] = response.responseText;\n- this.events.triggerEvent('describeprocess', {\n- identifier: processID,\n- raw: response.responseText\n- });\n- },\n- scope: this\n- });\n- } else {\n- // pending request\n- this.events.register('describeprocess', this, function describe(evt) {\n- if (evt.identifier === processID) {\n- this.events.unregister('describeprocess', this, describe);\n- callback.call(scope, evt.raw);\n- }\n- });\n- }\n- } else {\n- window.setTimeout(function() {\n- callback.call(scope, server.processDescription[processID]);\n- }, 0);\n+ activate: function() {\n+ if (!this.active) {\n+ this.active = true;\n+ return true;\n }\n+ return false;\n },\n \n /**\n- * Method: destroy\n+ * Method: deactivate\n+ * Deactivate the strategy. Unregister any listeners, do appropriate\n+ * tear-down.\n+ *\n+ * Returns:\n+ * {Boolean} True if the strategy was successfully deactivated or false if\n+ * the strategy was already inactive.\n */\n- destroy: function() {\n- this.events.destroy();\n- this.events = null;\n- this.servers = null;\n+ deactivate: function() {\n+ if (this.active) {\n+ this.active = false;\n+ return true;\n+ }\n+ return false;\n },\n \n- CLASS_NAME: 'OpenLayers.WPSClient'\n-\n+ CLASS_NAME: \"OpenLayers.Strategy\"\n });\n /* ======================================================================\n OpenLayers/Kinetic.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n@@ -32958,4851 +26648,6323 @@\n OpenLayers.Function.bind(timerCallback, this)\n );\n },\n \n CLASS_NAME: \"OpenLayers.Kinetic\"\n });\n /* ======================================================================\n- OpenLayers/Strategy/Save.js\n+ OpenLayers/Layer.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n+\n /**\n- * @requires OpenLayers/Strategy.js\n+ * @requires OpenLayers/BaseTypes/Class.js\n+ * @requires OpenLayers/Map.js\n+ * @requires OpenLayers/Projection.js\n */\n \n /**\n- * Class: OpenLayers.Strategy.Save\n- * A strategy that commits newly created or modified features. By default\n- * the strategy waits for a call to before persisting changes. By\n- * configuring the strategy with the option, changes can be saved\n- * automatically.\n- *\n- * Inherits from:\n- * - \n+ * Class: OpenLayers.Layer\n */\n-OpenLayers.Strategy.Save = OpenLayers.Class(OpenLayers.Strategy, {\n+OpenLayers.Layer = OpenLayers.Class({\n+\n+ /**\n+ * APIProperty: id\n+ * {String}\n+ */\n+ id: null,\n+\n+ /** \n+ * APIProperty: name\n+ * {String}\n+ */\n+ name: null,\n+\n+ /** \n+ * APIProperty: div\n+ * {DOMElement}\n+ */\n+ div: null,\n+\n+ /**\n+ * APIProperty: opacity\n+ * {Float} The layer's opacity. Float number between 0.0 and 1.0. Default\n+ * is 1.\n+ */\n+ opacity: 1,\n+\n+ /**\n+ * APIProperty: alwaysInRange\n+ * {Boolean} If a layer's display should not be scale-based, this should \n+ * be set to true. This will cause the layer, as an overlay, to always \n+ * be 'active', by always returning true from the calculateInRange() \n+ * function. \n+ * \n+ * If not explicitly specified for a layer, its value will be \n+ * determined on startup in initResolutions() based on whether or not \n+ * any scale-specific properties have been set as options on the \n+ * layer. If no scale-specific options have been set on the layer, we \n+ * assume that it should always be in range.\n+ * \n+ * See #987 for more info.\n+ */\n+ alwaysInRange: null,\n+\n+ /**\n+ * Constant: RESOLUTION_PROPERTIES\n+ * {Array} The properties that are used for calculating resolutions\n+ * information.\n+ */\n+ RESOLUTION_PROPERTIES: [\n+ 'scales', 'resolutions',\n+ 'maxScale', 'minScale',\n+ 'maxResolution', 'minResolution',\n+ 'numZoomLevels', 'maxZoomLevel'\n+ ],\n \n /**\n * APIProperty: events\n- * {} An events object that handles all \n- * events on the strategy object.\n+ * {}\n *\n * Register a listener for a particular event with the following syntax:\n * (code)\n- * strategy.events.register(type, obj, listener);\n+ * layer.events.register(type, obj, listener);\n * (end)\n *\n- * Supported event types:\n- * start - Triggered before saving\n- * success - Triggered after a successful transaction\n- * fail - Triggered after a failed transaction\n- * \n+ * Listeners will be called with a reference to an event object. The\n+ * properties of this event depends on exactly what happened.\n+ *\n+ * All event objects have at least the following properties:\n+ * object - {Object} A reference to layer.events.object.\n+ * element - {DOMElement} A reference to layer.events.element.\n+ *\n+ * Supported map event types:\n+ * loadstart - Triggered when layer loading starts. When using a Vector \n+ * layer with a Fixed or BBOX strategy, the event object includes \n+ * a *filter* property holding the OpenLayers.Filter used when \n+ * calling read on the protocol.\n+ * loadend - Triggered when layer loading ends. When using a Vector layer\n+ * with a Fixed or BBOX strategy, the event object includes a \n+ * *response* property holding an OpenLayers.Protocol.Response object.\n+ * visibilitychanged - Triggered when the layer's visibility property is\n+ * changed, e.g. by turning the layer on or off in the layer switcher.\n+ * Note that the actual visibility of the layer can also change if it\n+ * gets out of range (see ). If you also want to catch\n+ * these cases, register for the map's 'changelayer' event instead.\n+ * move - Triggered when layer moves (triggered with every mousemove\n+ * during a drag).\n+ * moveend - Triggered when layer is done moving, object passed as\n+ * argument has a zoomChanged boolean property which tells that the\n+ * zoom has changed.\n+ * added - Triggered after the layer is added to a map. Listeners will\n+ * receive an object with a *map* property referencing the map and a\n+ * *layer* property referencing the layer.\n+ * removed - Triggered after the layer is removed from the map. Listeners\n+ * will receive an object with a *map* property referencing the map and\n+ * a *layer* property referencing the layer.\n+ */\n+ events: null,\n+\n+ /**\n+ * APIProperty: map\n+ * {} This variable is set when the layer is added to \n+ * the map, via the accessor function setMap().\n+ */\n+ map: null,\n+\n+ /**\n+ * APIProperty: isBaseLayer\n+ * {Boolean} Whether or not the layer is a base layer. This should be set \n+ * individually by all subclasses. Default is false\n+ */\n+ isBaseLayer: false,\n+\n+ /**\n+ * Property: alpha\n+ * {Boolean} The layer's images have an alpha channel. Default is false.\n */\n+ alpha: false,\n \n /** \n- * Property: events\n- * {} Events instance for triggering this protocol\n- * events.\n+ * APIProperty: displayInLayerSwitcher\n+ * {Boolean} Display the layer's name in the layer switcher. Default is\n+ * true.\n */\n- events: null,\n+ displayInLayerSwitcher: true,\n \n /**\n- * APIProperty: auto\n- * {Boolean | Number} Auto-save. Default is false. If true, features will be\n- * saved immediately after being added to the layer and with each\n- * modification or deletion. If auto is a number, features will be\n- * saved on an interval provided by the value (in seconds).\n+ * APIProperty: visibility\n+ * {Boolean} The layer should be displayed in the map. Default is true.\n */\n- auto: false,\n+ visibility: true,\n \n /**\n- * Property: timer\n- * {Number} The id of the timer.\n+ * APIProperty: attribution\n+ * {String} Attribution string, displayed when an \n+ * has been added to the map.\n */\n- timer: null,\n+ attribution: null,\n+\n+ /** \n+ * Property: inRange\n+ * {Boolean} The current map resolution is within the layer's min/max \n+ * range. This is set in whenever the zoom \n+ * changes.\n+ */\n+ inRange: false,\n \n /**\n- * Constructor: OpenLayers.Strategy.Save\n- * Create a new Save strategy.\n- *\n- * Parameters:\n- * options - {Object} Optional object whose properties will be set on the\n- * instance.\n+ * Propery: imageSize\n+ * {} For layers with a gutter, the image is larger than \n+ * the tile by twice the gutter in each dimension.\n */\n- initialize: function(options) {\n- OpenLayers.Strategy.prototype.initialize.apply(this, [options]);\n- this.events = new OpenLayers.Events(this);\n- },\n+ imageSize: null,\n+\n+ // OPTIONS\n+\n+ /** \n+ * Property: options\n+ * {Object} An optional object whose properties will be set on the layer.\n+ * Any of the layer properties can be set as a property of the options\n+ * object and sent to the constructor when the layer is created.\n+ */\n+ options: null,\n \n /**\n- * APIMethod: activate\n- * Activate the strategy. Register any listeners, do appropriate setup.\n- * \n- * Returns:\n- * {Boolean} The strategy was successfully activated.\n+ * APIProperty: eventListeners\n+ * {Object} If set as an option at construction, the eventListeners\n+ * object will be registered with . Object\n+ * structure must be a listeners object as shown in the example for\n+ * the events.on method.\n */\n- activate: function() {\n- var activated = OpenLayers.Strategy.prototype.activate.call(this);\n- if (activated) {\n- if (this.auto) {\n- if (typeof this.auto === \"number\") {\n- this.timer = window.setInterval(\n- OpenLayers.Function.bind(this.save, this),\n- this.auto * 1000\n- );\n- } else {\n- this.layer.events.on({\n- \"featureadded\": this.triggerSave,\n- \"afterfeaturemodified\": this.triggerSave,\n- scope: this\n- });\n- }\n- }\n- }\n- return activated;\n- },\n+ eventListeners: null,\n \n /**\n- * APIMethod: deactivate\n- * Deactivate the strategy. Unregister any listeners, do appropriate\n- * tear-down.\n+ * APIProperty: gutter\n+ * {Integer} Determines the width (in pixels) of the gutter around image\n+ * tiles to ignore. By setting this property to a non-zero value,\n+ * images will be requested that are wider and taller than the tile\n+ * size by a value of 2 x gutter. This allows artifacts of rendering\n+ * at tile edges to be ignored. Set a gutter value that is equal to\n+ * half the size of the widest symbol that needs to be displayed.\n+ * Defaults to zero. Non-tiled layers always have zero gutter.\n+ */\n+ gutter: 0,\n+\n+ /**\n+ * APIProperty: projection\n+ * {} or {} Specifies the projection of the layer.\n+ * Can be set in the layer options. If not specified in the layer options,\n+ * it is set to the default projection specified in the map,\n+ * when the layer is added to the map.\n+ * Projection along with default maxExtent and resolutions\n+ * are set automatically with commercial baselayers in EPSG:3857,\n+ * such as Google, Bing and OpenStreetMap, and do not need to be specified.\n+ * Otherwise, if specifying projection, also set maxExtent,\n+ * maxResolution or resolutions as appropriate.\n+ * When using vector layers with strategies, layer projection should be set\n+ * to the projection of the source data if that is different from the map default.\n+ * \n+ * Can be either a string or an object;\n+ * if a string is passed, will be converted to an object when\n+ * the layer is added to the map.\n * \n- * Returns:\n- * {Boolean} The strategy was successfully deactivated.\n */\n- deactivate: function() {\n- var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);\n- if (deactivated) {\n- if (this.auto) {\n- if (typeof this.auto === \"number\") {\n- window.clearInterval(this.timer);\n- } else {\n- this.layer.events.un({\n- \"featureadded\": this.triggerSave,\n- \"afterfeaturemodified\": this.triggerSave,\n- scope: this\n- });\n- }\n- }\n- }\n- return deactivated;\n- },\n+ projection: null,\n \n /**\n- * Method: triggerSave\n- * Registered as a listener. Calls save if a feature has insert, update,\n- * or delete state.\n- *\n- * Parameters:\n- * event - {Object} The event this function is listening for.\n+ * APIProperty: units\n+ * {String} The layer map units. Defaults to null. Possible values\n+ * are 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.\n+ * Normally taken from the projection.\n+ * Only required if both map and layers do not define a projection,\n+ * or if they define a projection which does not define units.\n */\n- triggerSave: function(event) {\n- var feature = event.feature;\n- if (feature.state === OpenLayers.State.INSERT ||\n- feature.state === OpenLayers.State.UPDATE ||\n- feature.state === OpenLayers.State.DELETE) {\n- this.save([event.feature]);\n- }\n- },\n+ units: null,\n \n /**\n- * APIMethod: save\n- * Tell the layer protocol to commit unsaved features. If the layer\n- * projection differs from the map projection, features will be\n- * transformed into the layer projection before being committed.\n- *\n- * Parameters:\n- * features - {Array} Features to be saved. If null, then default is all\n- * features in the layer. Features are assumed to be in the map\n- * projection.\n+ * APIProperty: scales\n+ * {Array} An array of map scales in descending order. The values in the\n+ * array correspond to the map scale denominator. Note that these\n+ * values only make sense if the display (monitor) resolution of the\n+ * client is correctly guessed by whomever is configuring the\n+ * application. In addition, the units property must also be set.\n+ * Use instead wherever possible.\n */\n- save: function(features) {\n- if (!features) {\n- features = this.layer.features;\n- }\n- this.events.triggerEvent(\"start\", {\n- features: features\n- });\n- var remote = this.layer.projection;\n- var local = this.layer.map.getProjectionObject();\n- if (!local.equals(remote)) {\n- var len = features.length;\n- var clones = new Array(len);\n- var orig, clone;\n- for (var i = 0; i < len; ++i) {\n- orig = features[i];\n- clone = orig.clone();\n- clone.fid = orig.fid;\n- clone.state = orig.state;\n- if (orig.url) {\n- clone.url = orig.url;\n- }\n- clone._original = orig;\n- clone.geometry.transform(local, remote);\n- clones[i] = clone;\n- }\n- features = clones;\n- }\n- this.layer.protocol.commit(features, {\n- callback: this.onCommit,\n- scope: this\n- });\n- },\n+ scales: null,\n \n /**\n- * Method: onCommit\n- * Called after protocol commit.\n- *\n- * Parameters:\n- * response - {} A response object.\n+ * APIProperty: resolutions\n+ * {Array} A list of map resolutions (map units per pixel) in descending\n+ * order. If this is not set in the layer constructor, it will be set\n+ * based on other resolution related properties (maxExtent,\n+ * maxResolution, maxScale, etc.).\n */\n- onCommit: function(response) {\n- var evt = {\n- \"response\": response\n- };\n- if (response.success()) {\n- var features = response.reqFeatures;\n- // deal with inserts, updates, and deletes\n- var state, feature;\n- var destroys = [];\n- var insertIds = response.insertIds || [];\n- var j = 0;\n- for (var i = 0, len = features.length; i < len; ++i) {\n- feature = features[i];\n- // if projection was different, we may be dealing with clones\n- feature = feature._original || feature;\n- state = feature.state;\n- if (state) {\n- if (state == OpenLayers.State.DELETE) {\n- destroys.push(feature);\n- } else if (state == OpenLayers.State.INSERT) {\n- feature.fid = insertIds[j];\n- ++j;\n- }\n- feature.state = null;\n- }\n- }\n+ resolutions: null,\n \n- if (destroys.length > 0) {\n- this.layer.destroyFeatures(destroys);\n- }\n+ /**\n+ * APIProperty: maxExtent\n+ * {|Array} If provided as an array, the array\n+ * should consist of four values (left, bottom, right, top).\n+ * The maximum extent for the layer. Defaults to null.\n+ * \n+ * The center of these bounds will not stray outside\n+ * of the viewport extent during panning. In addition, if\n+ * is set to false, data will not be\n+ * requested that falls completely outside of these bounds.\n+ */\n+ maxExtent: null,\n \n- this.events.triggerEvent(\"success\", evt);\n+ /**\n+ * APIProperty: minExtent\n+ * {|Array} If provided as an array, the array\n+ * should consist of four values (left, bottom, right, top).\n+ * The minimum extent for the layer. Defaults to null.\n+ */\n+ minExtent: null,\n \n- } else {\n- this.events.triggerEvent(\"fail\", evt);\n- }\n- },\n+ /**\n+ * APIProperty: maxResolution\n+ * {Float} Default max is 360 deg / 256 px, which corresponds to\n+ * zoom level 0 on gmaps. Specify a different value in the layer \n+ * options if you are not using the default \n+ * and displaying the whole world.\n+ */\n+ maxResolution: null,\n \n- CLASS_NAME: \"OpenLayers.Strategy.Save\"\n-});\n-/* ======================================================================\n- OpenLayers/Strategy/Refresh.js\n- ====================================================================== */\n+ /**\n+ * APIProperty: minResolution\n+ * {Float}\n+ */\n+ minResolution: null,\n \n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n+ /**\n+ * APIProperty: numZoomLevels\n+ * {Integer}\n+ */\n+ numZoomLevels: null,\n \n-/**\n- * @requires OpenLayers/Strategy.js\n- */\n+ /**\n+ * APIProperty: minScale\n+ * {Float}\n+ */\n+ minScale: null,\n \n-/**\n- * Class: OpenLayers.Strategy.Refresh\n- * A strategy that refreshes the layer. By default the strategy waits for a\n- * call to before refreshing. By configuring the strategy with \n- * the option, refreshing can take place automatically.\n- *\n- * Inherits from:\n- * - \n- */\n-OpenLayers.Strategy.Refresh = OpenLayers.Class(OpenLayers.Strategy, {\n+ /**\n+ * APIProperty: maxScale\n+ * {Float}\n+ */\n+ maxScale: null,\n \n /**\n- * Property: force\n- * {Boolean} Force a refresh on the layer. Default is false.\n+ * APIProperty: displayOutsideMaxExtent\n+ * {Boolean} Request map tiles that are completely outside of the max \n+ * extent for this layer. Defaults to false.\n */\n- force: false,\n+ displayOutsideMaxExtent: false,\n \n /**\n- * Property: interval\n- * {Number} Auto-refresh. Default is 0. If > 0, layer will be refreshed \n- * every N milliseconds.\n+ * APIProperty: wrapDateLine\n+ * {Boolean} Wraps the world at the international dateline, so the map can\n+ * be panned infinitely in longitudinal direction. Only use this on the\n+ * base layer, and only if the layer's maxExtent equals the world bounds.\n+ * #487 for more info. \n */\n- interval: 0,\n+ wrapDateLine: false,\n \n /**\n- * Property: timer\n- * {Number} The id of the timer.\n+ * Property: metadata\n+ * {Object} This object can be used to store additional information on a\n+ * layer object.\n */\n- timer: null,\n+ metadata: null,\n \n /**\n- * Constructor: OpenLayers.Strategy.Refresh\n- * Create a new Refresh strategy.\n+ * Constructor: OpenLayers.Layer\n *\n * Parameters:\n- * options - {Object} Optional object whose properties will be set on the\n- * instance.\n+ * name - {String} The layer name\n+ * options - {Object} Hashtable of extra options to tag onto the layer\n */\n+ initialize: function(name, options) {\n+\n+ this.metadata = {};\n+\n+ options = OpenLayers.Util.extend({}, options);\n+ // make sure we respect alwaysInRange if set on the prototype\n+ if (this.alwaysInRange != null) {\n+ options.alwaysInRange = this.alwaysInRange;\n+ }\n+ this.addOptions(options);\n+\n+ this.name = name;\n+\n+ if (this.id == null) {\n+\n+ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + \"_\");\n+\n+ this.div = OpenLayers.Util.createDiv(this.id);\n+ this.div.style.width = \"100%\";\n+ this.div.style.height = \"100%\";\n+ this.div.dir = \"ltr\";\n+\n+ this.events = new OpenLayers.Events(this, this.div);\n+ if (this.eventListeners instanceof Object) {\n+ this.events.on(this.eventListeners);\n+ }\n+\n+ }\n+ },\n \n /**\n- * APIMethod: activate\n- * Activate the strategy. Register any listeners, do appropriate setup.\n- * \n- * Returns:\n- * {Boolean} True if the strategy was successfully activated.\n+ * Method: destroy\n+ * Destroy is a destructor: this is to alleviate cyclic references which\n+ * the Javascript garbage cleaner can not take care of on its own.\n+ *\n+ * Parameters:\n+ * setNewBaseLayer - {Boolean} Set a new base layer when this layer has\n+ * been destroyed. Default is true.\n */\n- activate: function() {\n- var activated = OpenLayers.Strategy.prototype.activate.call(this);\n- if (activated) {\n- if (this.layer.visibility === true) {\n- this.start();\n+ destroy: function(setNewBaseLayer) {\n+ if (setNewBaseLayer == null) {\n+ setNewBaseLayer = true;\n+ }\n+ if (this.map != null) {\n+ this.map.removeLayer(this, setNewBaseLayer);\n+ }\n+ this.projection = null;\n+ this.map = null;\n+ this.name = null;\n+ this.div = null;\n+ this.options = null;\n+\n+ if (this.events) {\n+ if (this.eventListeners) {\n+ this.events.un(this.eventListeners);\n }\n- this.layer.events.on({\n- \"visibilitychanged\": this.reset,\n- scope: this\n- });\n+ this.events.destroy();\n }\n- return activated;\n+ this.eventListeners = null;\n+ this.events = null;\n },\n \n /**\n- * APIMethod: deactivate\n- * Deactivate the strategy. Unregister any listeners, do appropriate\n- * tear-down.\n- * \n+ * Method: clone\n+ *\n+ * Parameters:\n+ * obj - {} The layer to be cloned\n+ *\n * Returns:\n- * {Boolean} True if the strategy was successfully deactivated.\n+ * {} An exact clone of this \n */\n- deactivate: function() {\n- var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);\n- if (deactivated) {\n- this.stop();\n- this.layer.events.un({\n- \"visibilitychanged\": this.reset,\n- scope: this\n- });\n+ clone: function(obj) {\n+\n+ if (obj == null) {\n+ obj = new OpenLayers.Layer(this.name, this.getOptions());\n }\n- return deactivated;\n+\n+ // catch any randomly tagged-on properties\n+ OpenLayers.Util.applyDefaults(obj, this);\n+\n+ // a cloned layer should never have its map property set\n+ // because it has not been added to a map yet. \n+ obj.map = null;\n+\n+ return obj;\n },\n \n /**\n- * Method: reset\n- * Start or cancel the refresh interval depending on the visibility of \n- * the layer.\n+ * Method: getOptions\n+ * Extracts an object from the layer with the properties that were set as\n+ * options, but updates them with the values currently set on the\n+ * instance.\n+ * \n+ * Returns:\n+ * {Object} the of the layer, representing the current state.\n */\n- reset: function() {\n- if (this.layer.visibility === true) {\n- this.start();\n- } else {\n- this.stop();\n+ getOptions: function() {\n+ var options = {};\n+ for (var o in this.options) {\n+ options[o] = this[o];\n }\n+ return options;\n },\n \n- /**\n- * Method: start\n- * Start the refresh interval. \n+ /** \n+ * APIMethod: setName\n+ * Sets the new layer name for this layer. Can trigger a changelayer event\n+ * on the map.\n+ *\n+ * Parameters:\n+ * newName - {String} The new name.\n */\n- start: function() {\n- if (this.interval && typeof this.interval === \"number\" &&\n- this.interval > 0) {\n-\n- this.timer = window.setInterval(\n- OpenLayers.Function.bind(this.refresh, this),\n- this.interval);\n+ setName: function(newName) {\n+ if (newName != this.name) {\n+ this.name = newName;\n+ if (this.map != null) {\n+ this.map.events.triggerEvent(\"changelayer\", {\n+ layer: this,\n+ property: \"name\"\n+ });\n+ }\n }\n },\n \n /**\n- * APIMethod: refresh\n- * Tell the strategy to refresh which will refresh the layer.\n+ * APIMethod: addOptions\n+ * \n+ * Parameters:\n+ * newOptions - {Object}\n+ * reinitialize - {Boolean} If set to true, and if resolution options of the\n+ * current baseLayer were changed, the map will be recentered to make\n+ * sure that it is displayed with a valid resolution, and a\n+ * changebaselayer event will be triggered.\n */\n- refresh: function() {\n- if (this.layer && this.layer.refresh &&\n- typeof this.layer.refresh == \"function\") {\n+ addOptions: function(newOptions, reinitialize) {\n \n- this.layer.refresh({\n- force: this.force\n- });\n+ if (this.options == null) {\n+ this.options = {};\n }\n- },\n \n- /**\n- * Method: stop\n- * Cancels the refresh interval. \n- */\n- stop: function() {\n- if (this.timer !== null) {\n- window.clearInterval(this.timer);\n- this.timer = null;\n+ if (newOptions) {\n+ // make sure this.projection references a projection object\n+ if (typeof newOptions.projection == \"string\") {\n+ newOptions.projection = new OpenLayers.Projection(newOptions.projection);\n+ }\n+ if (newOptions.projection) {\n+ // get maxResolution, units and maxExtent from projection defaults if\n+ // they are not defined already\n+ OpenLayers.Util.applyDefaults(newOptions,\n+ OpenLayers.Projection.defaults[newOptions.projection.getCode()]);\n+ }\n+ // allow array for extents\n+ if (newOptions.maxExtent && !(newOptions.maxExtent instanceof OpenLayers.Bounds)) {\n+ newOptions.maxExtent = new OpenLayers.Bounds(newOptions.maxExtent);\n+ }\n+ if (newOptions.minExtent && !(newOptions.minExtent instanceof OpenLayers.Bounds)) {\n+ newOptions.minExtent = new OpenLayers.Bounds(newOptions.minExtent);\n+ }\n }\n- },\n \n- CLASS_NAME: \"OpenLayers.Strategy.Refresh\"\n-});\n-/* ======================================================================\n- OpenLayers/Strategy/Paging.js\n- ====================================================================== */\n+ // update our copy for clone\n+ OpenLayers.Util.extend(this.options, newOptions);\n \n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n+ // add new options to this\n+ OpenLayers.Util.extend(this, newOptions);\n \n-/**\n- * @requires OpenLayers/Strategy.js\n- */\n+ // get the units from the projection, if we have a projection\n+ // and it it has units\n+ if (this.projection && this.projection.getUnits()) {\n+ this.units = this.projection.getUnits();\n+ }\n \n-/**\n- * Class: OpenLayers.Strategy.Paging\n- * Strategy for vector feature paging\n- *\n- * Inherits from:\n- * - \n- */\n-OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, {\n+ // re-initialize resolutions if necessary, i.e. if any of the\n+ // properties of the \"properties\" array defined below is set\n+ // in the new options\n+ if (this.map) {\n+ // store current resolution so we can try to restore it later\n+ var resolution = this.map.getResolution();\n+ var properties = this.RESOLUTION_PROPERTIES.concat(\n+ [\"projection\", \"units\", \"minExtent\", \"maxExtent\"]\n+ );\n+ for (var o in newOptions) {\n+ if (newOptions.hasOwnProperty(o) &&\n+ OpenLayers.Util.indexOf(properties, o) >= 0) {\n \n- /**\n- * Property: features\n- * {Array()} Cached features.\n- */\n- features: null,\n+ this.initResolutions();\n+ if (reinitialize && this.map.baseLayer === this) {\n+ // update map position, and restore previous resolution\n+ this.map.setCenter(this.map.getCenter(),\n+ this.map.getZoomForResolution(resolution),\n+ false, true\n+ );\n+ // trigger a changebaselayer event to make sure that\n+ // all controls (especially\n+ // OpenLayers.Control.PanZoomBar) get notified of the\n+ // new options\n+ this.map.events.triggerEvent(\"changebaselayer\", {\n+ layer: this\n+ });\n+ }\n+ break;\n+ }\n+ }\n+ }\n+ },\n \n /**\n- * Property: length\n- * {Integer} Number of features per page. Default is 10.\n+ * APIMethod: onMapResize\n+ * This function can be implemented by subclasses\n */\n- length: 10,\n+ onMapResize: function() {\n+ //this function can be implemented by subclasses \n+ },\n \n /**\n- * Property: num\n- * {Integer} The currently displayed page number.\n+ * APIMethod: redraw\n+ * Redraws the layer. Returns true if the layer was redrawn, false if not.\n+ *\n+ * Returns:\n+ * {Boolean} The layer was redrawn.\n */\n- num: null,\n+ redraw: function() {\n+ var redrawn = false;\n+ if (this.map) {\n+\n+ // min/max Range may have changed\n+ this.inRange = this.calculateInRange();\n+\n+ // map's center might not yet be set\n+ var extent = this.getExtent();\n+\n+ if (extent && this.inRange && this.visibility) {\n+ var zoomChanged = true;\n+ this.moveTo(extent, zoomChanged, false);\n+ this.events.triggerEvent(\"moveend\", {\n+ \"zoomChanged\": zoomChanged\n+ });\n+ redrawn = true;\n+ }\n+ }\n+ return redrawn;\n+ },\n \n /**\n- * Property: paging\n- * {Boolean} The strategy is currently changing pages.\n+ * Method: moveTo\n+ * \n+ * Parameters:\n+ * bounds - {}\n+ * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to\n+ * do some init work in that case.\n+ * dragging - {Boolean}\n */\n- paging: false,\n+ moveTo: function(bounds, zoomChanged, dragging) {\n+ var display = this.visibility;\n+ if (!this.isBaseLayer) {\n+ display = display && this.inRange;\n+ }\n+ this.display(display);\n+ },\n \n /**\n- * Constructor: OpenLayers.Strategy.Paging\n- * Create a new paging strategy.\n+ * Method: moveByPx\n+ * Move the layer based on pixel vector. To be implemented by subclasses.\n *\n * Parameters:\n- * options - {Object} Optional object whose properties will be set on the\n- * instance.\n+ * dx - {Number} The x coord of the displacement vector.\n+ * dy - {Number} The y coord of the displacement vector.\n */\n+ moveByPx: function(dx, dy) {},\n \n /**\n- * APIMethod: activate\n- * Activate the strategy. Register any listeners, do appropriate setup.\n+ * Method: setMap\n+ * Set the map property for the layer. This is done through an accessor\n+ * so that subclasses can override this and take special action once \n+ * they have their map variable set. \n * \n- * Returns:\n- * {Boolean} The strategy was successfully activated.\n+ * Here we take care to bring over any of the necessary default \n+ * properties from the map. \n+ * \n+ * Parameters:\n+ * map - {}\n */\n- activate: function() {\n- var activated = OpenLayers.Strategy.prototype.activate.call(this);\n- if (activated) {\n- this.layer.events.on({\n- \"beforefeaturesadded\": this.cacheFeatures,\n- scope: this\n- });\n+ setMap: function(map) {\n+ if (this.map == null) {\n+\n+ this.map = map;\n+\n+ // grab some essential layer data from the map if it hasn't already\n+ // been set\n+ this.maxExtent = this.maxExtent || this.map.maxExtent;\n+ this.minExtent = this.minExtent || this.map.minExtent;\n+\n+ this.projection = this.projection || this.map.projection;\n+ if (typeof this.projection == \"string\") {\n+ this.projection = new OpenLayers.Projection(this.projection);\n+ }\n+\n+ // Check the projection to see if we can get units -- if not, refer\n+ // to properties.\n+ this.units = this.projection.getUnits() ||\n+ this.units || this.map.units;\n+\n+ this.initResolutions();\n+\n+ if (!this.isBaseLayer) {\n+ this.inRange = this.calculateInRange();\n+ var show = ((this.visibility) && (this.inRange));\n+ this.div.style.display = show ? \"\" : \"none\";\n+ }\n+\n+ // deal with gutters\n+ this.setTileSize();\n }\n- return activated;\n },\n \n /**\n- * APIMethod: deactivate\n- * Deactivate the strategy. Unregister any listeners, do appropriate\n- * tear-down.\n+ * Method: afterAdd\n+ * Called at the end of the map.addLayer sequence. At this point, the map\n+ * will have a base layer. To be overridden by subclasses.\n+ */\n+ afterAdd: function() {},\n+\n+ /**\n+ * APIMethod: removeMap\n+ * Just as setMap() allows each layer the possibility to take a \n+ * personalized action on being added to the map, removeMap() allows\n+ * each layer to take a personalized action on being removed from it. \n+ * For now, this will be mostly unused, except for the EventPane layer,\n+ * which needs this hook so that it can remove the special invisible\n+ * pane. \n * \n- * Returns:\n- * {Boolean} The strategy was successfully deactivated.\n+ * Parameters:\n+ * map - {}\n */\n- deactivate: function() {\n- var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);\n- if (deactivated) {\n- this.clearCache();\n- this.layer.events.un({\n- \"beforefeaturesadded\": this.cacheFeatures,\n- scope: this\n- });\n- }\n- return deactivated;\n+ removeMap: function(map) {\n+ //to be overridden by subclasses\n },\n \n /**\n- * Method: cacheFeatures\n- * Cache features before they are added to the layer.\n+ * APIMethod: getImageSize\n *\n * Parameters:\n- * event - {Object} The event that this was listening for. This will come\n- * with a batch of features to be paged.\n+ * bounds - {} optional tile bounds, can be used\n+ * by subclasses that have to deal with different tile sizes at the\n+ * layer extent edges (e.g. Zoomify)\n+ * \n+ * Returns:\n+ * {} The size that the image should be, taking into \n+ * account gutters.\n */\n- cacheFeatures: function(event) {\n- if (!this.paging) {\n- this.clearCache();\n- this.features = event.features;\n- this.pageNext(event);\n- }\n+ getImageSize: function(bounds) {\n+ return (this.imageSize || this.tileSize);\n },\n \n /**\n- * Method: clearCache\n- * Clear out the cached features. This destroys features, assuming\n- * nothing else has a reference.\n+ * APIMethod: setTileSize\n+ * Set the tile size based on the map size. This also sets layer.imageSize\n+ * or use by Tile.Image.\n+ * \n+ * Parameters:\n+ * size - {}\n */\n- clearCache: function() {\n- if (this.features) {\n- for (var i = 0; i < this.features.length; ++i) {\n- this.features[i].destroy();\n- }\n+ setTileSize: function(size) {\n+ var tileSize = (size) ? size :\n+ ((this.tileSize) ? this.tileSize :\n+ this.map.getTileSize());\n+ this.tileSize = tileSize;\n+ if (this.gutter) {\n+ // layers with gutters need non-null tile sizes\n+ //if(tileSize == null) {\n+ // OpenLayers.console.error(\"Error in layer.setMap() for \" +\n+ // this.name + \": layers with \" +\n+ // \"gutters need non-null tile sizes\");\n+ //}\n+ this.imageSize = new OpenLayers.Size(tileSize.w + (2 * this.gutter),\n+ tileSize.h + (2 * this.gutter));\n }\n- this.features = null;\n- this.num = null;\n },\n \n /**\n- * APIMethod: pageCount\n- * Get the total count of pages given the current cache of features.\n- *\n+ * APIMethod: getVisibility\n+ * \n * Returns:\n- * {Integer} The page count.\n+ * {Boolean} The layer should be displayed (if in range).\n */\n- pageCount: function() {\n- var numFeatures = this.features ? this.features.length : 0;\n- return Math.ceil(numFeatures / this.length);\n+ getVisibility: function() {\n+ return this.visibility;\n },\n \n- /**\n- * APIMethod: pageNum\n- * Get the zero based page number.\n- *\n- * Returns:\n- * {Integer} The current page number being displayed.\n+ /** \n+ * APIMethod: setVisibility\n+ * Set the visibility flag for the layer and hide/show & redraw \n+ * accordingly. Fire event unless otherwise specified\n+ * \n+ * Note that visibility is no longer simply whether or not the layer's\n+ * style.display is set to \"block\". Now we store a 'visibility' state \n+ * property on the layer class, this allows us to remember whether or \n+ * not we *desire* for a layer to be visible. In the case where the \n+ * map's resolution is out of the layer's range, this desire may be \n+ * subverted.\n+ * \n+ * Parameters:\n+ * visibility - {Boolean} Whether or not to display the layer (if in range)\n */\n- pageNum: function() {\n- return this.num;\n+ setVisibility: function(visibility) {\n+ if (visibility != this.visibility) {\n+ this.visibility = visibility;\n+ this.display(visibility);\n+ this.redraw();\n+ if (this.map != null) {\n+ this.map.events.triggerEvent(\"changelayer\", {\n+ layer: this,\n+ property: \"visibility\"\n+ });\n+ }\n+ this.events.triggerEvent(\"visibilitychanged\");\n+ }\n },\n \n- /**\n- * APIMethod: pageLength\n- * Gets or sets page length.\n- *\n+ /** \n+ * APIMethod: display\n+ * Hide or show the Layer. This is designed to be used internally, and \n+ * is not generally the way to enable or disable the layer. For that,\n+ * use the setVisibility function instead..\n+ * \n * Parameters:\n- * newLength - {Integer} Optional length to be set.\n- *\n- * Returns:\n- * {Integer} The length of a page (number of features per page).\n+ * display - {Boolean}\n */\n- pageLength: function(newLength) {\n- if (newLength && newLength > 0) {\n- this.length = newLength;\n+ display: function(display) {\n+ if (display != (this.div.style.display != \"none\")) {\n+ this.div.style.display = (display && this.calculateInRange()) ? \"block\" : \"none\";\n }\n- return this.length;\n },\n \n /**\n- * APIMethod: pageNext\n- * Display the next page of features.\n- *\n+ * APIMethod: calculateInRange\n+ * \n * Returns:\n- * {Boolean} A new page was displayed.\n+ * {Boolean} The layer is displayable at the current map's current\n+ * resolution. Note that if 'alwaysInRange' is true for the layer, \n+ * this function will always return true.\n */\n- pageNext: function(event) {\n- var changed = false;\n- if (this.features) {\n- if (this.num === null) {\n- this.num = -1;\n+ calculateInRange: function() {\n+ var inRange = false;\n+\n+ if (this.alwaysInRange) {\n+ inRange = true;\n+ } else {\n+ if (this.map) {\n+ var resolution = this.map.getResolution();\n+ inRange = ((resolution >= this.minResolution) &&\n+ (resolution <= this.maxResolution));\n }\n- var start = (this.num + 1) * this.length;\n- changed = this.page(start, event);\n }\n- return changed;\n+ return inRange;\n },\n \n- /**\n- * APIMethod: pagePrevious\n- * Display the previous page of features.\n- *\n- * Returns:\n- * {Boolean} A new page was displayed.\n+ /** \n+ * APIMethod: setIsBaseLayer\n+ * \n+ * Parameters:\n+ * isBaseLayer - {Boolean}\n */\n- pagePrevious: function() {\n- var changed = false;\n- if (this.features) {\n- if (this.num === null) {\n- this.num = this.pageCount();\n+ setIsBaseLayer: function(isBaseLayer) {\n+ if (isBaseLayer != this.isBaseLayer) {\n+ this.isBaseLayer = isBaseLayer;\n+ if (this.map != null) {\n+ this.map.events.triggerEvent(\"changebaselayer\", {\n+ layer: this\n+ });\n }\n- var start = (this.num - 1) * this.length;\n- changed = this.page(start);\n }\n- return changed;\n },\n \n- /**\n- * Method: page\n- * Display the page starting at the given index from the cache.\n- *\n- * Returns:\n- * {Boolean} A new page was displayed.\n+ /********************************************************/\n+ /* */\n+ /* Baselayer Functions */\n+ /* */\n+ /********************************************************/\n+\n+ /** \n+ * Method: initResolutions\n+ * This method's responsibility is to set up the 'resolutions' array \n+ * for the layer -- this array is what the layer will use to interface\n+ * between the zoom levels of the map and the resolution display \n+ * of the layer.\n+ * \n+ * The user has several options that determine how the array is set up.\n+ * \n+ * For a detailed explanation, see the following wiki from the \n+ * openlayers.org homepage:\n+ * http://trac.openlayers.org/wiki/SettingZoomLevels\n */\n- page: function(start, event) {\n- var changed = false;\n- if (this.features) {\n- if (start >= 0 && start < this.features.length) {\n- var num = Math.floor(start / this.length);\n- if (num != this.num) {\n- this.paging = true;\n- var features = this.features.slice(start, start + this.length);\n- this.layer.removeFeatures(this.layer.features);\n- this.num = num;\n- // modify the event if any\n- if (event && event.features) {\n- // this.was called by an event listener\n- event.features = features;\n- } else {\n- // this was called directly on the strategy\n- this.layer.addFeatures(features);\n- }\n- this.paging = false;\n- changed = true;\n- }\n+ initResolutions: function() {\n+\n+ // ok we want resolutions, here's our strategy:\n+ //\n+ // 1. if resolutions are defined in the layer config, use them\n+ // 2. else, if scales are defined in the layer config then derive\n+ // resolutions from these scales\n+ // 3. else, attempt to calculate resolutions from maxResolution,\n+ // minResolution, numZoomLevels, maxZoomLevel set in the\n+ // layer config\n+ // 4. if we still don't have resolutions, and if resolutions\n+ // are defined in the same, use them\n+ // 5. else, if scales are defined in the map then derive\n+ // resolutions from these scales\n+ // 6. else, attempt to calculate resolutions from maxResolution,\n+ // minResolution, numZoomLevels, maxZoomLevel set in the\n+ // map\n+ // 7. hope for the best!\n+\n+ var i, len, p;\n+ var props = {},\n+ alwaysInRange = true;\n+\n+ // get resolution data from layer config\n+ // (we also set alwaysInRange in the layer as appropriate)\n+ for (i = 0, len = this.RESOLUTION_PROPERTIES.length; i < len; i++) {\n+ p = this.RESOLUTION_PROPERTIES[i];\n+ props[p] = this.options[p];\n+ if (alwaysInRange && this.options[p]) {\n+ alwaysInRange = false;\n }\n }\n- return changed;\n- },\n+ if (this.options.alwaysInRange == null) {\n+ this.alwaysInRange = alwaysInRange;\n+ }\n \n- CLASS_NAME: \"OpenLayers.Strategy.Paging\"\n-});\n-/* ======================================================================\n- OpenLayers/Strategy/Fixed.js\n- ====================================================================== */\n+ // if we don't have resolutions then attempt to derive them from scales\n+ if (props.resolutions == null) {\n+ props.resolutions = this.resolutionsFromScales(props.scales);\n+ }\n \n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n+ // if we still don't have resolutions then attempt to calculate them\n+ if (props.resolutions == null) {\n+ props.resolutions = this.calculateResolutions(props);\n+ }\n \n-/**\n- * @requires OpenLayers/Strategy.js\n- */\n+ // if we couldn't calculate resolutions then we look at we have\n+ // in the map\n+ if (props.resolutions == null) {\n+ for (i = 0, len = this.RESOLUTION_PROPERTIES.length; i < len; i++) {\n+ p = this.RESOLUTION_PROPERTIES[i];\n+ props[p] = this.options[p] != null ?\n+ this.options[p] : this.map[p];\n+ }\n+ if (props.resolutions == null) {\n+ props.resolutions = this.resolutionsFromScales(props.scales);\n+ }\n+ if (props.resolutions == null) {\n+ props.resolutions = this.calculateResolutions(props);\n+ }\n+ }\n \n-/**\n- * Class: OpenLayers.Strategy.Fixed\n- * A simple strategy that requests features once and never requests new data.\n- *\n- * Inherits from:\n- * - \n- */\n-OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, {\n+ // ok, we new need to set properties in the instance\n \n- /**\n- * APIProperty: preload\n- * {Boolean} Load data before layer made visible. Enabling this may result\n- * in considerable overhead if your application loads many data layers\n- * that are not visible by default. Default is false.\n- */\n- preload: false,\n+ // get maxResolution from the config if it's defined there\n+ var maxResolution;\n+ if (this.options.maxResolution &&\n+ this.options.maxResolution !== \"auto\") {\n+ maxResolution = this.options.maxResolution;\n+ }\n+ if (this.options.minScale) {\n+ maxResolution = OpenLayers.Util.getResolutionFromScale(\n+ this.options.minScale, this.units);\n+ }\n \n- /**\n- * Constructor: OpenLayers.Strategy.Fixed\n- * Create a new Fixed strategy.\n- *\n- * Parameters:\n- * options - {Object} Optional object whose properties will be set on the\n- * instance.\n- */\n+ // get minResolution from the config if it's defined there\n+ var minResolution;\n+ if (this.options.minResolution &&\n+ this.options.minResolution !== \"auto\") {\n+ minResolution = this.options.minResolution;\n+ }\n+ if (this.options.maxScale) {\n+ minResolution = OpenLayers.Util.getResolutionFromScale(\n+ this.options.maxScale, this.units);\n+ }\n \n- /**\n- * Method: activate\n- * Activate the strategy: load data or add listener to load when visible\n- *\n- * Returns:\n- * {Boolean} True if the strategy was successfully activated or false if\n- * the strategy was already active.\n- */\n- activate: function() {\n- var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments);\n- if (activated) {\n- this.layer.events.on({\n- \"refresh\": this.load,\n- scope: this\n+ if (props.resolutions) {\n+\n+ //sort resolutions array descendingly\n+ props.resolutions.sort(function(a, b) {\n+ return (b - a);\n });\n- if (this.layer.visibility == true || this.preload) {\n- this.load();\n- } else {\n- this.layer.events.on({\n- \"visibilitychanged\": this.load,\n- scope: this\n- });\n+\n+ // if we still don't have a maxResolution get it from the\n+ // resolutions array\n+ if (!maxResolution) {\n+ maxResolution = props.resolutions[0];\n+ }\n+\n+ // if we still don't have a minResolution get it from the\n+ // resolutions array\n+ if (!minResolution) {\n+ var lastIdx = props.resolutions.length - 1;\n+ minResolution = props.resolutions[lastIdx];\n }\n }\n- return activated;\n- },\n \n- /**\n- * Method: deactivate\n- * Deactivate the strategy. Undo what is done in .\n- * \n- * Returns:\n- * {Boolean} The strategy was successfully deactivated.\n- */\n- deactivate: function() {\n- var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);\n- if (deactivated) {\n- this.layer.events.un({\n- \"refresh\": this.load,\n- \"visibilitychanged\": this.load,\n- scope: this\n- });\n+ this.resolutions = props.resolutions;\n+ if (this.resolutions) {\n+ len = this.resolutions.length;\n+ this.scales = new Array(len);\n+ for (i = 0; i < len; i++) {\n+ this.scales[i] = OpenLayers.Util.getScaleFromResolution(\n+ this.resolutions[i], this.units);\n+ }\n+ this.numZoomLevels = len;\n+ }\n+ this.minResolution = minResolution;\n+ if (minResolution) {\n+ this.maxScale = OpenLayers.Util.getScaleFromResolution(\n+ minResolution, this.units);\n+ }\n+ this.maxResolution = maxResolution;\n+ if (maxResolution) {\n+ this.minScale = OpenLayers.Util.getScaleFromResolution(\n+ maxResolution, this.units);\n }\n- return deactivated;\n },\n \n /**\n- * Method: load\n- * Tells protocol to load data and unhooks the visibilitychanged event\n+ * Method: resolutionsFromScales\n+ * Derive resolutions from scales.\n *\n * Parameters:\n- * options - {Object} options to pass to protocol read.\n+ * scales - {Array(Number)} Scales\n+ *\n+ * Returns\n+ * {Array(Number)} Resolutions\n */\n- load: function(options) {\n- var layer = this.layer;\n- layer.events.triggerEvent(\"loadstart\", {\n- filter: layer.filter\n- });\n- layer.protocol.read(OpenLayers.Util.applyDefaults({\n- callback: this.merge,\n- filter: layer.filter,\n- scope: this\n- }, options));\n- layer.events.un({\n- \"visibilitychanged\": this.load,\n- scope: this\n- });\n+ resolutionsFromScales: function(scales) {\n+ if (scales == null) {\n+ return;\n+ }\n+ var resolutions, i, len;\n+ len = scales.length;\n+ resolutions = new Array(len);\n+ for (i = 0; i < len; i++) {\n+ resolutions[i] = OpenLayers.Util.getResolutionFromScale(\n+ scales[i], this.units);\n+ }\n+ return resolutions;\n },\n \n /**\n- * Method: merge\n- * Add all features to the layer.\n- * If the layer projection differs from the map projection, features\n- * will be transformed from the layer projection to the map projection.\n+ * Method: calculateResolutions\n+ * Calculate resolutions based on the provided properties.\n *\n * Parameters:\n- * resp - {} The response object passed\n- * by the protocol.\n+ * props - {Object} Properties\n+ *\n+ * Returns:\n+ * {Array({Number})} Array of resolutions.\n */\n- merge: function(resp) {\n- var layer = this.layer;\n- layer.destroyFeatures();\n- var features = resp.features;\n- if (features && features.length > 0) {\n- var remote = layer.projection;\n- var local = layer.map.getProjectionObject();\n- if (!local.equals(remote)) {\n- var geom;\n- for (var i = 0, len = features.length; i < len; ++i) {\n- geom = features[i].geometry;\n- if (geom) {\n- geom.transform(remote, local);\n- }\n- }\n- }\n- layer.addFeatures(features);\n+ calculateResolutions: function(props) {\n+\n+ var viewSize, wRes, hRes;\n+\n+ // determine maxResolution\n+ var maxResolution = props.maxResolution;\n+ if (props.minScale != null) {\n+ maxResolution =\n+ OpenLayers.Util.getResolutionFromScale(props.minScale,\n+ this.units);\n+ } else if (maxResolution == \"auto\" && this.maxExtent != null) {\n+ viewSize = this.map.getSize();\n+ wRes = this.maxExtent.getWidth() / viewSize.w;\n+ hRes = this.maxExtent.getHeight() / viewSize.h;\n+ maxResolution = Math.max(wRes, hRes);\n }\n- layer.events.triggerEvent(\"loadend\", {\n- response: resp\n- });\n- },\n \n- CLASS_NAME: \"OpenLayers.Strategy.Fixed\"\n-});\n-/* ======================================================================\n- OpenLayers/Strategy/Cluster.js\n- ====================================================================== */\n+ // determine minResolution\n+ var minResolution = props.minResolution;\n+ if (props.maxScale != null) {\n+ minResolution =\n+ OpenLayers.Util.getResolutionFromScale(props.maxScale,\n+ this.units);\n+ } else if (props.minResolution == \"auto\" && this.minExtent != null) {\n+ viewSize = this.map.getSize();\n+ wRes = this.minExtent.getWidth() / viewSize.w;\n+ hRes = this.minExtent.getHeight() / viewSize.h;\n+ minResolution = Math.max(wRes, hRes);\n+ }\n \n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n+ if (typeof maxResolution !== \"number\" &&\n+ typeof minResolution !== \"number\" &&\n+ this.maxExtent != null) {\n+ // maxResolution for default grid sets assumes that at zoom\n+ // level zero, the whole world fits on one tile.\n+ var tileSize = this.map.getTileSize();\n+ maxResolution = Math.max(\n+ this.maxExtent.getWidth() / tileSize.w,\n+ this.maxExtent.getHeight() / tileSize.h\n+ );\n+ }\n \n-/**\n- * @requires OpenLayers/Strategy.js\n- */\n+ // determine numZoomLevels\n+ var maxZoomLevel = props.maxZoomLevel;\n+ var numZoomLevels = props.numZoomLevels;\n+ if (typeof minResolution === \"number\" &&\n+ typeof maxResolution === \"number\" && numZoomLevels === undefined) {\n+ var ratio = maxResolution / minResolution;\n+ numZoomLevels = Math.floor(Math.log(ratio) / Math.log(2)) + 1;\n+ } else if (numZoomLevels === undefined && maxZoomLevel != null) {\n+ numZoomLevels = maxZoomLevel + 1;\n+ }\n \n-/**\n- * Class: OpenLayers.Strategy.Cluster\n- * Strategy for vector feature clustering.\n- *\n- * Inherits from:\n- * - \n- */\n-OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, {\n+ // are we able to calculate resolutions?\n+ if (typeof numZoomLevels !== \"number\" || numZoomLevels <= 0 ||\n+ (typeof maxResolution !== \"number\" &&\n+ typeof minResolution !== \"number\")) {\n+ return;\n+ }\n \n- /**\n- * APIProperty: distance\n- * {Integer} Pixel distance between features that should be considered a\n- * single cluster. Default is 20 pixels.\n- */\n- distance: 20,\n+ // now we have numZoomLevels and at least one of maxResolution\n+ // or minResolution, we can populate the resolutions array\n \n- /**\n- * APIProperty: threshold\n- * {Integer} Optional threshold below which original features will be\n- * added to the layer instead of clusters. For example, a threshold\n- * of 3 would mean that any time there are 2 or fewer features in\n- * a cluster, those features will be added directly to the layer instead\n- * of a cluster representing those features. Default is null (which is\n- * equivalent to 1 - meaning that clusters may contain just one feature).\n- */\n- threshold: null,\n+ var resolutions = new Array(numZoomLevels);\n+ var base = 2;\n+ if (typeof minResolution == \"number\" &&\n+ typeof maxResolution == \"number\") {\n+ // if maxResolution and minResolution are set, we calculate\n+ // the base for exponential scaling that starts at\n+ // maxResolution and ends at minResolution in numZoomLevels\n+ // steps.\n+ base = Math.pow(\n+ (maxResolution / minResolution),\n+ (1 / (numZoomLevels - 1))\n+ );\n+ }\n \n- /**\n- * Property: features\n- * {Array()} Cached features.\n- */\n- features: null,\n+ var i;\n+ if (typeof maxResolution === \"number\") {\n+ for (i = 0; i < numZoomLevels; i++) {\n+ resolutions[i] = maxResolution / Math.pow(base, i);\n+ }\n+ } else {\n+ for (i = 0; i < numZoomLevels; i++) {\n+ resolutions[numZoomLevels - 1 - i] =\n+ minResolution * Math.pow(base, i);\n+ }\n+ }\n \n- /**\n- * Property: clusters\n- * {Array()} Calculated clusters.\n- */\n- clusters: null,\n+ return resolutions;\n+ },\n \n /**\n- * Property: clustering\n- * {Boolean} The strategy is currently clustering features.\n+ * APIMethod: getResolution\n+ * \n+ * Returns:\n+ * {Float} The currently selected resolution of the map, taken from the\n+ * resolutions array, indexed by current zoom level.\n */\n- clustering: false,\n+ getResolution: function() {\n+ var zoom = this.map.getZoom();\n+ return this.getResolutionForZoom(zoom);\n+ },\n \n- /**\n- * Property: resolution\n- * {Float} The resolution (map units per pixel) of the current cluster set.\n+ /** \n+ * APIMethod: getExtent\n+ * \n+ * Returns:\n+ * {} A Bounds object which represents the lon/lat \n+ * bounds of the current viewPort.\n */\n- resolution: null,\n+ getExtent: function() {\n+ // just use stock map calculateBounds function -- passing no arguments\n+ // means it will user map's current center & resolution\n+ //\n+ return this.map.calculateBounds();\n+ },\n \n /**\n- * Constructor: OpenLayers.Strategy.Cluster\n- * Create a new clustering strategy.\n- *\n+ * APIMethod: getZoomForExtent\n+ * \n * Parameters:\n- * options - {Object} Optional object whose properties will be set on the\n- * instance.\n+ * extent - {}\n+ * closest - {Boolean} Find the zoom level that most closely fits the \n+ * specified bounds. Note that this may result in a zoom that does \n+ * not exactly contain the entire extent.\n+ * Default is false.\n+ *\n+ * Returns:\n+ * {Integer} The index of the zoomLevel (entry in the resolutions array) \n+ * for the passed-in extent. We do this by calculating the ideal \n+ * resolution for the given extent (based on the map size) and then \n+ * calling getZoomForResolution(), passing along the 'closest'\n+ * parameter.\n */\n+ getZoomForExtent: function(extent, closest) {\n+ var viewSize = this.map.getSize();\n+ var idealResolution = Math.max(extent.getWidth() / viewSize.w,\n+ extent.getHeight() / viewSize.h);\n \n- /**\n- * APIMethod: activate\n- * Activate the strategy. Register any listeners, do appropriate setup.\n+ return this.getZoomForResolution(idealResolution, closest);\n+ },\n+\n+ /** \n+ * Method: getDataExtent\n+ * Calculates the max extent which includes all of the data for the layer.\n+ * This function is to be implemented by subclasses.\n * \n * Returns:\n- * {Boolean} The strategy was successfully activated.\n+ * {}\n */\n- activate: function() {\n- var activated = OpenLayers.Strategy.prototype.activate.call(this);\n- if (activated) {\n- this.layer.events.on({\n- \"beforefeaturesadded\": this.cacheFeatures,\n- \"featuresremoved\": this.clearCache,\n- \"moveend\": this.cluster,\n- scope: this\n- });\n- }\n- return activated;\n+ getDataExtent: function() {\n+ //to be implemented by subclasses\n },\n \n /**\n- * APIMethod: deactivate\n- * Deactivate the strategy. Unregister any listeners, do appropriate\n- * tear-down.\n+ * APIMethod: getResolutionForZoom\n+ * \n+ * Parameters:\n+ * zoom - {Float}\n * \n * Returns:\n- * {Boolean} The strategy was successfully deactivated.\n+ * {Float} A suitable resolution for the specified zoom.\n */\n- deactivate: function() {\n- var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);\n- if (deactivated) {\n- this.clearCache();\n- this.layer.events.un({\n- \"beforefeaturesadded\": this.cacheFeatures,\n- \"featuresremoved\": this.clearCache,\n- \"moveend\": this.cluster,\n- scope: this\n- });\n+ getResolutionForZoom: function(zoom) {\n+ zoom = Math.max(0, Math.min(zoom, this.resolutions.length - 1));\n+ var resolution;\n+ if (this.map.fractionalZoom) {\n+ var low = Math.floor(zoom);\n+ var high = Math.ceil(zoom);\n+ resolution = this.resolutions[low] -\n+ ((zoom - low) * (this.resolutions[low] - this.resolutions[high]));\n+ } else {\n+ resolution = this.resolutions[Math.round(zoom)];\n }\n- return deactivated;\n+ return resolution;\n },\n \n /**\n- * Method: cacheFeatures\n- * Cache features before they are added to the layer.\n- *\n+ * APIMethod: getZoomForResolution\n+ * \n * Parameters:\n- * event - {Object} The event that this was listening for. This will come\n- * with a batch of features to be clustered.\n- * \n+ * resolution - {Float}\n+ * closest - {Boolean} Find the zoom level that corresponds to the absolute \n+ * closest resolution, which may result in a zoom whose corresponding\n+ * resolution is actually smaller than we would have desired (if this\n+ * is being called from a getZoomForExtent() call, then this means that\n+ * the returned zoom index might not actually contain the entire \n+ * extent specified... but it'll be close).\n+ * Default is false.\n+ * \n * Returns:\n- * {Boolean} False to stop features from being added to the layer.\n+ * {Integer} The index of the zoomLevel (entry in the resolutions array) \n+ * that corresponds to the best fit resolution given the passed in \n+ * value and the 'closest' specification.\n */\n- cacheFeatures: function(event) {\n- var propagate = true;\n- if (!this.clustering) {\n- this.clearCache();\n- this.features = event.features;\n- this.cluster();\n- propagate = false;\n+ getZoomForResolution: function(resolution, closest) {\n+ var zoom, i, len;\n+ if (this.map.fractionalZoom) {\n+ var lowZoom = 0;\n+ var highZoom = this.resolutions.length - 1;\n+ var highRes = this.resolutions[lowZoom];\n+ var lowRes = this.resolutions[highZoom];\n+ var res;\n+ for (i = 0, len = this.resolutions.length; i < len; ++i) {\n+ res = this.resolutions[i];\n+ if (res >= resolution) {\n+ highRes = res;\n+ lowZoom = i;\n+ }\n+ if (res <= resolution) {\n+ lowRes = res;\n+ highZoom = i;\n+ break;\n+ }\n+ }\n+ var dRes = highRes - lowRes;\n+ if (dRes > 0) {\n+ zoom = lowZoom + ((highRes - resolution) / dRes);\n+ } else {\n+ zoom = lowZoom;\n+ }\n+ } else {\n+ var diff;\n+ var minDiff = Number.POSITIVE_INFINITY;\n+ for (i = 0, len = this.resolutions.length; i < len; i++) {\n+ if (closest) {\n+ diff = Math.abs(this.resolutions[i] - resolution);\n+ if (diff > minDiff) {\n+ break;\n+ }\n+ minDiff = diff;\n+ } else {\n+ if (this.resolutions[i] < resolution) {\n+ break;\n+ }\n+ }\n+ }\n+ zoom = Math.max(0, i - 1);\n }\n- return propagate;\n+ return zoom;\n },\n \n /**\n- * Method: clearCache\n- * Clear out the cached features.\n+ * APIMethod: getLonLatFromViewPortPx\n+ * \n+ * Parameters:\n+ * viewPortPx - {|Object} An OpenLayers.Pixel or\n+ * an object with a 'x'\n+ * and 'y' properties.\n+ *\n+ * Returns:\n+ * {} An OpenLayers.LonLat which is the passed-in \n+ * view port , translated into lon/lat by the layer.\n */\n- clearCache: function() {\n- if (!this.clustering) {\n- this.features = null;\n+ getLonLatFromViewPortPx: function(viewPortPx) {\n+ var lonlat = null;\n+ var map = this.map;\n+ if (viewPortPx != null && map.minPx) {\n+ var res = map.getResolution();\n+ var maxExtent = map.getMaxExtent({\n+ restricted: true\n+ });\n+ var lon = (viewPortPx.x - map.minPx.x) * res + maxExtent.left;\n+ var lat = (map.minPx.y - viewPortPx.y) * res + maxExtent.top;\n+ lonlat = new OpenLayers.LonLat(lon, lat);\n+\n+ if (this.wrapDateLine) {\n+ lonlat = lonlat.wrapDateLine(this.maxExtent);\n+ }\n }\n+ return lonlat;\n },\n \n /**\n- * Method: cluster\n- * Cluster features based on some threshold distance.\n- *\n+ * APIMethod: getViewPortPxFromLonLat\n+ * Returns a pixel location given a map location. This method will return\n+ * fractional pixel values.\n+ * \n * Parameters:\n- * event - {Object} The event received when cluster is called as a\n- * result of a moveend event.\n+ * lonlat - {|Object} An OpenLayers.LonLat or\n+ * an object with a 'lon'\n+ * and 'lat' properties.\n+ *\n+ * Returns: \n+ * {} An which is the passed-in \n+ * lonlat translated into view port pixels.\n */\n- cluster: function(event) {\n- if ((!event || event.zoomChanged) && this.features) {\n- var resolution = this.layer.map.getResolution();\n- if (resolution != this.resolution || !this.clustersExist()) {\n- this.resolution = resolution;\n- var clusters = [];\n- var feature, clustered, cluster;\n- for (var i = 0; i < this.features.length; ++i) {\n- feature = this.features[i];\n- if (feature.geometry) {\n- clustered = false;\n- for (var j = clusters.length - 1; j >= 0; --j) {\n- cluster = clusters[j];\n- if (this.shouldCluster(cluster, feature)) {\n- this.addToCluster(cluster, feature);\n- clustered = true;\n- break;\n- }\n- }\n- if (!clustered) {\n- clusters.push(this.createCluster(this.features[i]));\n- }\n- }\n- }\n- this.clustering = true;\n- this.layer.removeAllFeatures();\n- this.clustering = false;\n- if (clusters.length > 0) {\n- if (this.threshold > 1) {\n- var clone = clusters.slice();\n- clusters = [];\n- var candidate;\n- for (var i = 0, len = clone.length; i < len; ++i) {\n- candidate = clone[i];\n- if (candidate.attributes.count < this.threshold) {\n- Array.prototype.push.apply(clusters, candidate.cluster);\n- } else {\n- clusters.push(candidate);\n- }\n- }\n- }\n- this.clustering = true;\n- // A legitimate feature addition could occur during this\n- // addFeatures call. For clustering to behave well, features\n- // should be removed from a layer before requesting a new batch.\n- this.layer.addFeatures(clusters);\n- this.clustering = false;\n- }\n- this.clusters = clusters;\n- }\n+ getViewPortPxFromLonLat: function(lonlat, resolution) {\n+ var px = null;\n+ if (lonlat != null) {\n+ resolution = resolution || this.map.getResolution();\n+ var extent = this.map.calculateBounds(null, resolution);\n+ px = new OpenLayers.Pixel(\n+ (1 / resolution * (lonlat.lon - extent.left)),\n+ (1 / resolution * (extent.top - lonlat.lat))\n+ );\n }\n+ return px;\n },\n \n /**\n- * Method: clustersExist\n- * Determine whether calculated clusters are already on the layer.\n- *\n- * Returns:\n- * {Boolean} The calculated clusters are already on the layer.\n+ * APIMethod: setOpacity\n+ * Sets the opacity for the entire layer (all images)\n+ * \n+ * Parameters:\n+ * opacity - {Float}\n */\n- clustersExist: function() {\n- var exist = false;\n- if (this.clusters && this.clusters.length > 0 &&\n- this.clusters.length == this.layer.features.length) {\n- exist = true;\n- for (var i = 0; i < this.clusters.length; ++i) {\n- if (this.clusters[i] != this.layer.features[i]) {\n- exist = false;\n- break;\n+ setOpacity: function(opacity) {\n+ if (opacity != this.opacity) {\n+ this.opacity = opacity;\n+ var childNodes = this.div.childNodes;\n+ for (var i = 0, len = childNodes.length; i < len; ++i) {\n+ var element = childNodes[i].firstChild || childNodes[i];\n+ var lastChild = childNodes[i].lastChild;\n+ //TODO de-uglify this\n+ if (lastChild && lastChild.nodeName.toLowerCase() === \"iframe\") {\n+ element = lastChild.parentNode;\n }\n+ OpenLayers.Util.modifyDOMElement(element, null, null, null,\n+ null, null, null, opacity);\n+ }\n+ if (this.map != null) {\n+ this.map.events.triggerEvent(\"changelayer\", {\n+ layer: this,\n+ property: \"opacity\"\n+ });\n }\n }\n- return exist;\n },\n \n /**\n- * Method: shouldCluster\n- * Determine whether to include a feature in a given cluster.\n- *\n- * Parameters:\n- * cluster - {} A cluster.\n- * feature - {} A feature.\n- *\n- * Returns:\n- * {Boolean} The feature should be included in the cluster.\n+ * Method: getZIndex\n+ * \n+ * Returns: \n+ * {Integer} the z-index of this layer\n */\n- shouldCluster: function(cluster, feature) {\n- var cc = cluster.geometry.getBounds().getCenterLonLat();\n- var fc = feature.geometry.getBounds().getCenterLonLat();\n- var distance = (\n- Math.sqrt(\n- Math.pow((cc.lon - fc.lon), 2) + Math.pow((cc.lat - fc.lat), 2)\n- ) / this.resolution\n- );\n- return (distance <= this.distance);\n+ getZIndex: function() {\n+ return this.div.style.zIndex;\n },\n \n /**\n- * Method: addToCluster\n- * Add a feature to a cluster.\n- *\n- * Parameters:\n- * cluster - {} A cluster.\n- * feature - {} A feature.\n+ * Method: setZIndex\n+ * \n+ * Parameters: \n+ * zIndex - {Integer}\n */\n- addToCluster: function(cluster, feature) {\n- cluster.cluster.push(feature);\n- cluster.attributes.count += 1;\n+ setZIndex: function(zIndex) {\n+ this.div.style.zIndex = zIndex;\n },\n \n /**\n- * Method: createCluster\n- * Given a feature, create a cluster.\n- *\n+ * Method: adjustBounds\n+ * This function will take a bounds, and if wrapDateLine option is set\n+ * on the layer, it will return a bounds which is wrapped around the \n+ * world. We do not wrap for bounds which *cross* the \n+ * maxExtent.left/right, only bounds which are entirely to the left \n+ * or entirely to the right.\n+ * \n * Parameters:\n- * feature - {}\n- *\n- * Returns:\n- * {} A cluster.\n+ * bounds - {}\n */\n- createCluster: function(feature) {\n- var center = feature.geometry.getBounds().getCenterLonLat();\n- var cluster = new OpenLayers.Feature.Vector(\n- new OpenLayers.Geometry.Point(center.lon, center.lat), {\n- count: 1\n- }\n- );\n- cluster.cluster = [feature];\n- return cluster;\n+ adjustBounds: function(bounds) {\n+\n+ if (this.gutter) {\n+ // Adjust the extent of a bounds in map units by the \n+ // layer's gutter in pixels.\n+ var mapGutter = this.gutter * this.map.getResolution();\n+ bounds = new OpenLayers.Bounds(bounds.left - mapGutter,\n+ bounds.bottom - mapGutter,\n+ bounds.right + mapGutter,\n+ bounds.top + mapGutter);\n+ }\n+\n+ if (this.wrapDateLine) {\n+ // wrap around the date line, within the limits of rounding error\n+ var wrappingOptions = {\n+ 'rightTolerance': this.getResolution(),\n+ 'leftTolerance': this.getResolution()\n+ };\n+ bounds = bounds.wrapDateLine(this.maxExtent, wrappingOptions);\n+\n+ }\n+ return bounds;\n },\n \n- CLASS_NAME: \"OpenLayers.Strategy.Cluster\"\n+ CLASS_NAME: \"OpenLayers.Layer\"\n });\n /* ======================================================================\n- OpenLayers/Strategy/BBOX.js\n+ OpenLayers/Layer/HTTPRequest.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n+\n /**\n- * @requires OpenLayers/Strategy.js\n- * @requires OpenLayers/Filter/Spatial.js\n+ * @requires OpenLayers/Layer.js\n */\n \n /**\n- * Class: OpenLayers.Strategy.BBOX\n- * A simple strategy that reads new features when the viewport invalidates\n- * some bounds.\n- *\n- * Inherits from:\n- * - \n+ * Class: OpenLayers.Layer.HTTPRequest\n+ * \n+ * Inherits from: \n+ * - \n */\n-OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, {\n+OpenLayers.Layer.HTTPRequest = OpenLayers.Class(OpenLayers.Layer, {\n \n- /**\n- * Property: bounds\n- * {} The current data bounds (in the same projection\n- * as the layer - not always the same projection as the map).\n+ /** \n+ * Constant: URL_HASH_FACTOR\n+ * {Float} Used to hash URL param strings for multi-WMS server selection.\n+ * Set to the Golden Ratio per Knuth's recommendation.\n */\n- bounds: null,\n+ URL_HASH_FACTOR: (Math.sqrt(5) - 1) / 2,\n \n /** \n- * Property: resolution \n- * {Float} The current data resolution. \n+ * Property: url\n+ * {Array(String) or String} This is either an array of url strings or \n+ * a single url string. \n */\n- resolution: null,\n+ url: null,\n \n- /**\n- * APIProperty: ratio\n- * {Float} The ratio of the data bounds to the viewport bounds (in each\n- * dimension). Default is 2.\n+ /** \n+ * Property: params\n+ * {Object} Hashtable of key/value parameters\n */\n- ratio: 2,\n+ params: null,\n \n /** \n- * Property: resFactor \n- * {Float} Optional factor used to determine when previously requested \n- * features are invalid. If set, the resFactor will be compared to the\n- * resolution of the previous request to the current map resolution.\n- * If resFactor > (old / new) and 1/resFactor < (old / new). If you\n- * set a resFactor of 1, data will be requested every time the\n- * resolution changes. If you set a resFactor of 3, data will be\n- * requested if the old resolution is 3 times the new, or if the new is\n- * 3 times the old. If the old bounds do not contain the new bounds\n- * new data will always be requested (with or without considering\n- * resFactor). \n+ * APIProperty: reproject\n+ * *Deprecated*. See http://docs.openlayers.org/library/spherical_mercator.html\n+ * for information on the replacement for this functionality. \n+ * {Boolean} Whether layer should reproject itself based on base layer \n+ * locations. This allows reprojection onto commercial layers. \n+ * Default is false: Most layers can't reproject, but layers \n+ * which can create non-square geographic pixels can, like WMS.\n+ * \n */\n- resFactor: null,\n+ reproject: false,\n \n /**\n- * Property: response\n- * {} The protocol response object returned\n- * by the layer protocol.\n+ * Constructor: OpenLayers.Layer.HTTPRequest\n+ * \n+ * Parameters:\n+ * name - {String}\n+ * url - {Array(String) or String}\n+ * params - {Object}\n+ * options - {Object} Hashtable of extra options to tag onto the layer\n */\n- response: null,\n+ initialize: function(name, url, params, options) {\n+ OpenLayers.Layer.prototype.initialize.apply(this, [name, options]);\n+ this.url = url;\n+ if (!this.params) {\n+ this.params = OpenLayers.Util.extend({}, params);\n+ }\n+ },\n \n /**\n- * Constructor: OpenLayers.Strategy.BBOX\n- * Create a new BBOX strategy.\n- *\n- * Parameters:\n- * options - {Object} Optional object whose properties will be set on the\n- * instance.\n+ * APIMethod: destroy\n */\n+ destroy: function() {\n+ this.url = null;\n+ this.params = null;\n+ OpenLayers.Layer.prototype.destroy.apply(this, arguments);\n+ },\n \n /**\n- * Method: activate\n- * Set up strategy with regard to reading new batches of remote data.\n+ * APIMethod: clone\n+ * \n+ * Parameters:\n+ * obj - {Object}\n * \n * Returns:\n- * {Boolean} The strategy was successfully activated.\n+ * {} An exact clone of this \n+ * \n */\n- activate: function() {\n- var activated = OpenLayers.Strategy.prototype.activate.call(this);\n- if (activated) {\n- this.layer.events.on({\n- \"moveend\": this.update,\n- \"refresh\": this.update,\n- \"visibilitychanged\": this.update,\n- scope: this\n- });\n- this.update();\n+ clone: function(obj) {\n+\n+ if (obj == null) {\n+ obj = new OpenLayers.Layer.HTTPRequest(this.name,\n+ this.url,\n+ this.params,\n+ this.getOptions());\n }\n- return activated;\n+\n+ //get all additions from superclasses\n+ obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]);\n+\n+ // copy/set any non-init, non-simple values here\n+\n+ return obj;\n },\n \n- /**\n- * Method: deactivate\n- * Tear down strategy with regard to reading new batches of remote data.\n+ /** \n+ * APIMethod: setUrl\n * \n- * Returns:\n- * {Boolean} The strategy was successfully deactivated.\n+ * Parameters:\n+ * newUrl - {String}\n */\n- deactivate: function() {\n- var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);\n- if (deactivated) {\n- this.layer.events.un({\n- \"moveend\": this.update,\n- \"refresh\": this.update,\n- \"visibilitychanged\": this.update,\n- scope: this\n- });\n- }\n- return deactivated;\n+ setUrl: function(newUrl) {\n+ this.url = newUrl;\n },\n \n /**\n- * Method: update\n- * Callback function called on \"moveend\" or \"refresh\" layer events.\n- *\n+ * APIMethod: mergeNewParams\n+ * \n * Parameters:\n- * options - {Object} Optional object whose properties will determine\n- * the behaviour of this Strategy\n+ * newParams - {Object}\n *\n- * Valid options include:\n- * force - {Boolean} if true, new data must be unconditionally read.\n- * noAbort - {Boolean} if true, do not abort previous requests.\n+ * Returns:\n+ * redrawn: {Boolean} whether the layer was actually redrawn.\n */\n- update: function(options) {\n- var mapBounds = this.getMapBounds();\n- if (mapBounds !== null && ((options && options.force) ||\n- (this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds)))) {\n- this.calculateBounds(mapBounds);\n- this.resolution = this.layer.map.getResolution();\n- this.triggerRead(options);\n+ mergeNewParams: function(newParams) {\n+ this.params = OpenLayers.Util.extend(this.params, newParams);\n+ var ret = this.redraw();\n+ if (this.map != null) {\n+ this.map.events.triggerEvent(\"changelayer\", {\n+ layer: this,\n+ property: \"params\"\n+ });\n }\n+ return ret;\n },\n \n /**\n- * Method: getMapBounds\n- * Get the map bounds expressed in the same projection as this layer.\n+ * APIMethod: redraw\n+ * Redraws the layer. Returns true if the layer was redrawn, false if not.\n+ *\n+ * Parameters:\n+ * force - {Boolean} Force redraw by adding random parameter.\n *\n * Returns:\n- * {} Map bounds in the projection of the layer.\n+ * {Boolean} The layer was redrawn.\n */\n- getMapBounds: function() {\n- if (this.layer.map === null) {\n- return null;\n- }\n- var bounds = this.layer.map.getExtent();\n- if (bounds && !this.layer.projection.equals(\n- this.layer.map.getProjectionObject())) {\n- bounds = bounds.clone().transform(\n- this.layer.map.getProjectionObject(), this.layer.projection\n- );\n+ redraw: function(force) {\n+ if (force) {\n+ return this.mergeNewParams({\n+ \"_olSalt\": Math.random()\n+ });\n+ } else {\n+ return OpenLayers.Layer.prototype.redraw.apply(this, []);\n }\n- return bounds;\n },\n \n /**\n- * Method: invalidBounds\n- * Determine whether the previously requested set of features is invalid. \n- * This occurs when the new map bounds do not contain the previously \n- * requested bounds. In addition, if is set, it will be \n- * considered.\n+ * Method: selectUrl\n+ * selectUrl() implements the standard floating-point multiplicative\n+ * hash function described by Knuth, and hashes the contents of the \n+ * given param string into a float between 0 and 1. This float is then\n+ * scaled to the size of the provided urls array, and used to select\n+ * a URL.\n *\n * Parameters:\n- * mapBounds - {} the current map extent, will be\n- * retrieved from the map object if not provided\n- *\n+ * paramString - {String}\n+ * urls - {Array(String)}\n+ * \n * Returns:\n- * {Boolean} \n+ * {String} An entry from the urls array, deterministically selected based\n+ * on the paramString.\n */\n- invalidBounds: function(mapBounds) {\n- if (!mapBounds) {\n- mapBounds = this.getMapBounds();\n- }\n- var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds);\n- if (!invalid && this.resFactor) {\n- var ratio = this.resolution / this.layer.map.getResolution();\n- invalid = (ratio >= this.resFactor || ratio <= (1 / this.resFactor));\n+ selectUrl: function(paramString, urls) {\n+ var product = 1;\n+ for (var i = 0, len = paramString.length; i < len; i++) {\n+ product *= paramString.charCodeAt(i) * this.URL_HASH_FACTOR;\n+ product -= Math.floor(product);\n }\n- return invalid;\n+ return urls[Math.floor(product * urls.length)];\n },\n \n- /**\n- * Method: calculateBounds\n+ /** \n+ * Method: getFullRequestString\n+ * Combine url with layer's params and these newParams. \n+ * \n+ * does checking on the serverPath variable, allowing for cases when it \n+ * is supplied with trailing ? or &, as well as cases where not. \n *\n- * Parameters:\n- * mapBounds - {} the current map extent, will be\n- * retrieved from the map object if not provided\n- */\n- calculateBounds: function(mapBounds) {\n- if (!mapBounds) {\n- mapBounds = this.getMapBounds();\n- }\n- var center = mapBounds.getCenterLonLat();\n- var dataWidth = mapBounds.getWidth() * this.ratio;\n- var dataHeight = mapBounds.getHeight() * this.ratio;\n- this.bounds = new OpenLayers.Bounds(\n- center.lon - (dataWidth / 2),\n- center.lat - (dataHeight / 2),\n- center.lon + (dataWidth / 2),\n- center.lat + (dataHeight / 2)\n- );\n- },\n-\n- /**\n- * Method: triggerRead\n+ * return in formatted string like this:\n+ * \"server?key1=value1&key2=value2&key3=value3\"\n+ * \n+ * WARNING: The altUrl parameter is deprecated and will be removed in 3.0.\n *\n * Parameters:\n- * options - {Object} Additional options for the protocol's read method \n- * (optional)\n- *\n- * Returns:\n- * {} The protocol response object\n- * returned by the layer protocol.\n+ * newParams - {Object}\n+ * altUrl - {String} Use this as the url instead of the layer's url\n+ * \n+ * Returns: \n+ * {String}\n */\n- triggerRead: function(options) {\n- if (this.response && !(options && options.noAbort === true)) {\n- this.layer.protocol.abort(this.response);\n- this.layer.events.triggerEvent(\"loadend\");\n- }\n- var evt = {\n- filter: this.createFilter()\n- };\n- this.layer.events.triggerEvent(\"loadstart\", evt);\n- this.response = this.layer.protocol.read(\n- OpenLayers.Util.applyDefaults({\n- filter: evt.filter,\n- callback: this.merge,\n- scope: this\n- }, options));\n- },\n+ getFullRequestString: function(newParams, altUrl) {\n \n- /**\n- * Method: createFilter\n- * Creates a spatial BBOX filter. If the layer that this strategy belongs\n- * to has a filter property, this filter will be combined with the BBOX \n- * filter.\n- * \n- * Returns\n- * {} The filter object.\n- */\n- createFilter: function() {\n- var filter = new OpenLayers.Filter.Spatial({\n- type: OpenLayers.Filter.Spatial.BBOX,\n- value: this.bounds,\n- projection: this.layer.projection\n- });\n- if (this.layer.filter) {\n- filter = new OpenLayers.Filter.Logical({\n- type: OpenLayers.Filter.Logical.AND,\n- filters: [this.layer.filter, filter]\n- });\n+ // if not altUrl passed in, use layer's url\n+ var url = altUrl || this.url;\n+\n+ // create a new params hashtable with all the layer params and the \n+ // new params together. then convert to string\n+ var allParams = OpenLayers.Util.extend({}, this.params);\n+ allParams = OpenLayers.Util.extend(allParams, newParams);\n+ var paramsString = OpenLayers.Util.getParameterString(allParams);\n+\n+ // if url is not a string, it should be an array of strings, \n+ // in which case we will deterministically select one of them in \n+ // order to evenly distribute requests to different urls.\n+ //\n+ if (OpenLayers.Util.isArray(url)) {\n+ url = this.selectUrl(paramsString, url);\n }\n- return filter;\n- },\n \n- /**\n- * Method: merge\n- * Given a list of features, determine which ones to add to the layer.\n- * If the layer projection differs from the map projection, features\n- * will be transformed from the layer projection to the map projection.\n- *\n- * Parameters:\n- * resp - {} The response object passed\n- * by the protocol.\n- */\n- merge: function(resp) {\n- this.layer.destroyFeatures();\n- if (resp.success()) {\n- var features = resp.features;\n- if (features && features.length > 0) {\n- var remote = this.layer.projection;\n- var local = this.layer.map.getProjectionObject();\n- if (!local.equals(remote)) {\n- var geom;\n- for (var i = 0, len = features.length; i < len; ++i) {\n- geom = features[i].geometry;\n- if (geom) {\n- geom.transform(remote, local);\n- }\n- }\n- }\n- this.layer.addFeatures(features);\n+ // ignore parameters that are already in the url search string\n+ var urlParams =\n+ OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));\n+ for (var key in allParams) {\n+ if (key.toUpperCase() in urlParams) {\n+ delete allParams[key];\n }\n- } else {\n- this.bounds = null;\n }\n- this.response = null;\n- this.layer.events.triggerEvent(\"loadend\", {\n- response: resp\n- });\n+ paramsString = OpenLayers.Util.getParameterString(allParams);\n+\n+ return OpenLayers.Util.urlAppend(url, paramsString);\n },\n \n- CLASS_NAME: \"OpenLayers.Strategy.BBOX\"\n+ CLASS_NAME: \"OpenLayers.Layer.HTTPRequest\"\n });\n /* ======================================================================\n- OpenLayers/Strategy/Filter.js\n+ OpenLayers/Tile/Image.js\n ====================================================================== */\n \n /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n * full list of contributors). Published under the 2-clause BSD license.\n * See license.txt in the OpenLayers distribution or repository for the\n * full text of the license. */\n \n+\n /**\n- * @requires OpenLayers/Strategy.js\n- * @requires OpenLayers/Filter.js\n+ * @requires OpenLayers/Tile.js\n+ * @requires OpenLayers/Animation.js\n+ * @requires OpenLayers/Util.js\n */\n \n /**\n- * Class: OpenLayers.Strategy.Filter\n- * Strategy for limiting features that get added to a layer by \n- * evaluating a filter. The strategy maintains a cache of\n- * all features until removeFeatures is called on the layer.\n+ * Class: OpenLayers.Tile.Image\n+ * Instances of OpenLayers.Tile.Image are used to manage the image tiles\n+ * used by various layers. Create a new image tile with the\n+ * constructor.\n *\n * Inherits from:\n- * - \n+ * - \n */\n-OpenLayers.Strategy.Filter = OpenLayers.Class(OpenLayers.Strategy, {\n+OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {\n \n /**\n- * APIProperty: filter\n- * {} Filter for limiting features sent to the layer.\n- * Use the method to update this filter after construction.\n+ * APIProperty: events\n+ * {} An events object that handles all \n+ * events on the tile.\n+ *\n+ * Register a listener for a particular event with the following syntax:\n+ * (code)\n+ * tile.events.register(type, obj, listener);\n+ * (end)\n+ *\n+ * Supported event types (in addition to the events):\n+ * beforeload - Triggered before an image is prepared for loading, when the\n+ * url for the image is known already. Listeners may call on\n+ * the tile instance. If they do so, that image will be used and no new\n+ * one will be created.\n */\n- filter: null,\n \n- /**\n- * Property: cache\n- * {Array()} List of currently cached\n- * features.\n+ /** \n+ * APIProperty: url\n+ * {String} The URL of the image being requested. No default. Filled in by\n+ * layer.getURL() function. May be modified by loadstart listeners.\n */\n- cache: null,\n+ url: null,\n \n- /**\n- * Property: caching\n- * {Boolean} The filter is currently caching features.\n+ /** \n+ * Property: imgDiv\n+ * {HTMLImageElement} The image for this tile.\n */\n- caching: false,\n+ imgDiv: null,\n \n /**\n- * Constructor: OpenLayers.Strategy.Filter\n- * Create a new filter strategy.\n- *\n- * Parameters:\n- * options - {Object} Optional object whose properties will be set on the\n- * instance.\n+ * Property: frame\n+ * {DOMElement} The image element is appended to the frame. Any gutter on\n+ * the image will be hidden behind the frame. If no gutter is set,\n+ * this will be null.\n */\n+ frame: null,\n \n- /**\n- * APIMethod: activate\n- * Activate the strategy. Register any listeners, do appropriate setup.\n- * By default, this strategy automatically activates itself when a layer\n- * is added to a map.\n- *\n- * Returns:\n- * {Boolean} True if the strategy was successfully activated or false if\n- * the strategy was already active.\n+ /** \n+ * Property: imageReloadAttempts\n+ * {Integer} Attempts to load the image.\n */\n- activate: function() {\n- var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments);\n- if (activated) {\n- this.cache = [];\n- this.layer.events.on({\n- \"beforefeaturesadded\": this.handleAdd,\n- \"beforefeaturesremoved\": this.handleRemove,\n- scope: this\n- });\n- }\n- return activated;\n- },\n+ imageReloadAttempts: null,\n \n /**\n- * APIMethod: deactivate\n- * Deactivate the strategy. Clear the feature cache.\n- *\n- * Returns:\n- * {Boolean} True if the strategy was successfully deactivated or false if\n- * the strategy was already inactive.\n+ * Property: layerAlphaHack\n+ * {Boolean} True if the png alpha hack needs to be applied on the layer's div.\n */\n- deactivate: function() {\n- this.cache = null;\n- if (this.layer && this.layer.events) {\n- this.layer.events.un({\n- \"beforefeaturesadded\": this.handleAdd,\n- \"beforefeaturesremoved\": this.handleRemove,\n- scope: this\n- });\n- }\n- return OpenLayers.Strategy.prototype.deactivate.apply(this, arguments);\n- },\n+ layerAlphaHack: null,\n \n /**\n- * Method: handleAdd\n+ * Property: asyncRequestId\n+ * {Integer} ID of an request to see if request is still valid. This is a\n+ * number which increments by 1 for each asynchronous request.\n */\n- handleAdd: function(event) {\n- if (!this.caching && this.filter) {\n- var features = event.features;\n- event.features = [];\n- var feature;\n- for (var i = 0, ii = features.length; i < ii; ++i) {\n- feature = features[i];\n- if (this.filter.evaluate(feature)) {\n- event.features.push(feature);\n- } else {\n- this.cache.push(feature);\n- }\n- }\n- }\n- },\n+ asyncRequestId: null,\n \n /**\n- * Method: handleRemove\n- */\n- handleRemove: function(event) {\n- if (!this.caching) {\n- this.cache = [];\n- }\n- },\n-\n- /** \n- * APIMethod: setFilter\n- * Update the filter for this strategy. This will re-evaluate\n- * any features on the layer and in the cache. Only features\n- * for which filter.evalute(feature) returns true will be\n- * added to the layer. Others will be cached by the strategy.\n+ * APIProperty: maxGetUrlLength\n+ * {Number} If set, requests that would result in GET urls with more\n+ * characters than the number provided will be made using form-encoded\n+ * HTTP POST. It is good practice to avoid urls that are longer than 2048\n+ * characters.\n *\n- * Parameters:\n- * filter - {} A filter for evaluating features.\n- */\n- setFilter: function(filter) {\n- this.filter = filter;\n- var previousCache = this.cache;\n- this.cache = [];\n- // look through layer for features to remove from layer\n- this.handleAdd({\n- features: this.layer.features\n- });\n- // cache now contains features to remove from layer\n- if (this.cache.length > 0) {\n- this.caching = true;\n- this.layer.removeFeatures(this.cache.slice());\n- this.caching = false;\n- }\n- // now look through previous cache for features to add to layer\n- if (previousCache.length > 0) {\n- var event = {\n- features: previousCache\n- };\n- this.handleAdd(event);\n- if (event.features.length > 0) {\n- // event has features to add to layer\n- this.caching = true;\n- this.layer.addFeatures(event.features);\n- this.caching = false;\n- }\n- }\n- },\n-\n- CLASS_NAME: \"OpenLayers.Strategy.Filter\"\n-\n-});\n-/* ======================================================================\n- OpenLayers/Tile/UTFGrid.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-\n-/**\n- * @requires OpenLayers/Tile.js\n- * @requires OpenLayers/Format/JSON.js\n- * @requires OpenLayers/Request.js\n- */\n-\n-/**\n- * Class: OpenLayers.Tile.UTFGrid\n- * Instances of OpenLayers.Tile.UTFGrid are used to manage \n- * UTFGrids. This is an unusual tile type in that it doesn't have a\n- * rendered image; only a 'hit grid' that can be used to \n- * look up feature attributes.\n- *\n- * See the constructor for details on constructing a\n- * new instance.\n- *\n- * Inherits from:\n- * - \n- */\n-OpenLayers.Tile.UTFGrid = OpenLayers.Class(OpenLayers.Tile, {\n-\n- /** \n- * Property: url\n- * {String}\n- * The URL of the UTFGrid file being requested. Provided by the \n- * method. \n+ * Caution:\n+ * Older versions of Gecko based browsers (e.g. Firefox < 3.5) and most\n+ * Opera versions do not fully support this option. On all browsers,\n+ * transition effects are not supported if POST requests are used.\n */\n- url: null,\n+ maxGetUrlLength: null,\n \n /**\n- * Property: utfgridResolution\n- * {Number}\n- * Ratio of the pixel width to the width of a UTFGrid data point. If an \n- * entry in the grid represents a 4x4 block of pixels, the \n- * utfgridResolution would be 4. Default is 2.\n+ * Property: canvasContext\n+ * {CanvasRenderingContext2D} A canvas context associated with\n+ * the tile image.\n */\n- utfgridResolution: 2,\n+ canvasContext: null,\n \n- /** \n- * Property: json\n- * {Object}\n- * Stores the parsed JSON tile data structure. \n+ /**\n+ * APIProperty: crossOriginKeyword\n+ * The value of the crossorigin keyword to use when loading images. This is\n+ * only relevant when using for tiles from remote\n+ * origins and should be set to either 'anonymous' or 'use-credentials'\n+ * for servers that send Access-Control-Allow-Origin headers with their\n+ * tiles.\n */\n- json: null,\n+ crossOriginKeyword: null,\n \n- /** \n- * Property: format\n- * {OpenLayers.Format.JSON}\n- * Parser instance used to parse JSON for cross browser support. The native\n- * JSON.parse method will be used where available (all except IE<8).\n+ /** TBD 3.0 - reorder the parameters to the init function to remove \n+ * URL. the getUrl() function on the layer gets called on \n+ * each draw(), so no need to specify it here.\n */\n- format: null,\n \n /** \n- * Constructor: OpenLayers.Tile.UTFGrid\n- * Constructor for a new instance.\n+ * Constructor: OpenLayers.Tile.Image\n+ * Constructor for a new instance.\n * \n * Parameters:\n * layer - {} layer that the tile will go in.\n * position - {}\n * bounds - {}\n * url - {} Deprecated. Remove me in 3.0.\n * size - {}\n * options - {Object}\n */\n+ initialize: function(layer, position, bounds, url, size, options) {\n+ OpenLayers.Tile.prototype.initialize.apply(this, arguments);\n+\n+ this.url = url; //deprecated remove me\n+\n+ this.layerAlphaHack = this.layer.alpha && OpenLayers.Util.alphaHack();\n+\n+ if (this.maxGetUrlLength != null || this.layer.gutter || this.layerAlphaHack) {\n+ // only create frame if it's needed\n+ this.frame = document.createElement(\"div\");\n+ this.frame.style.position = \"absolute\";\n+ this.frame.style.overflow = \"hidden\";\n+ }\n+ if (this.maxGetUrlLength != null) {\n+ OpenLayers.Util.extend(this, OpenLayers.Tile.Image.IFrame);\n+ }\n+ },\n \n /** \n * APIMethod: destroy\n- * Clean up.\n+ * nullify references to prevent circular references and memory leaks\n */\n destroy: function() {\n- this.clear();\n+ if (this.imgDiv) {\n+ this.clear();\n+ this.imgDiv = null;\n+ this.frame = null;\n+ }\n+ // don't handle async requests any more\n+ this.asyncRequestId = null;\n OpenLayers.Tile.prototype.destroy.apply(this, arguments);\n },\n \n /**\n * Method: draw\n * Check that a tile should be drawn, and draw it.\n- * In the case of UTFGrids, \"drawing\" it means fetching and\n- * parsing the json. \n * \n * Returns:\n- * {Boolean} Was a tile drawn?\n+ * {Boolean} Was a tile drawn? Or null if a beforedraw listener returned\n+ * false.\n */\n draw: function() {\n- var drawn = OpenLayers.Tile.prototype.draw.apply(this, arguments);\n- if (drawn) {\n+ var shouldDraw = OpenLayers.Tile.prototype.draw.apply(this, arguments);\n+ if (shouldDraw) {\n+ // The layer's reproject option is deprecated.\n+ if (this.layer != this.layer.map.baseLayer && this.layer.reproject) {\n+ // getBoundsFromBaseLayer is defined in deprecated.js.\n+ this.bounds = this.getBoundsFromBaseLayer(this.position);\n+ }\n if (this.isLoading) {\n- this.abortLoading();\n //if we're already loading, send 'reload' instead of 'loadstart'.\n- this.events.triggerEvent(\"reload\");\n+ this._loadEvent = \"reload\";\n } else {\n this.isLoading = true;\n- this.events.triggerEvent(\"loadstart\");\n- }\n- this.url = this.layer.getURL(this.bounds);\n-\n- if (this.layer.useJSONP) {\n- // Use JSONP method to avoid xbrowser policy\n- var ols = new OpenLayers.Protocol.Script({\n- url: this.url,\n- callback: function(response) {\n- this.isLoading = false;\n- this.events.triggerEvent(\"loadend\");\n- this.json = response.data;\n- },\n- scope: this\n- });\n- ols.read();\n- this.request = ols;\n- } else {\n- // Use standard XHR\n- this.request = OpenLayers.Request.GET({\n- url: this.url,\n- callback: function(response) {\n- this.isLoading = false;\n- this.events.triggerEvent(\"loadend\");\n- if (response.status === 200) {\n- this.parseData(response.responseText);\n- }\n- },\n- scope: this\n- });\n+ this._loadEvent = \"loadstart\";\n }\n- } else {\n+ this.renderTile();\n+ this.positionTile();\n+ } else if (shouldDraw === false) {\n this.unload();\n }\n- return drawn;\n- },\n-\n- /**\n- * Method: abortLoading\n- * Cancel a pending request.\n- */\n- abortLoading: function() {\n- if (this.request) {\n- this.request.abort();\n- delete this.request;\n- }\n- this.isLoading = false;\n- },\n-\n- /**\n- * Method: getFeatureInfo\n- * Get feature information associated with a pixel offset. If the pixel\n- * offset corresponds to a feature, the returned object will have id\n- * and data properties. Otherwise, null will be returned.\n- * \n- *\n- * Parameters:\n- * i - {Number} X-axis pixel offset (from top left of tile)\n- * j - {Number} Y-axis pixel offset (from top left of tile)\n- *\n- * Returns:\n- * {Object} Object with feature id and data properties corresponding to the \n- * given pixel offset.\n- */\n- getFeatureInfo: function(i, j) {\n- var info = null;\n- if (this.json) {\n- var id = this.getFeatureId(i, j);\n- if (id !== null) {\n- info = {\n- id: id,\n- data: this.json.data[id]\n- };\n- }\n- }\n- return info;\n- },\n-\n- /**\n- * Method: getFeatureId\n- * Get the identifier for the feature associated with a pixel offset.\n- *\n- * Parameters:\n- * i - {Number} X-axis pixel offset (from top left of tile)\n- * j - {Number} Y-axis pixel offset (from top left of tile)\n- *\n- * Returns:\n- * {Object} The feature identifier corresponding to the given pixel offset.\n- * Returns null if pixel doesn't correspond to a feature.\n- */\n- getFeatureId: function(i, j) {\n- var id = null;\n- if (this.json) {\n- var resolution = this.utfgridResolution;\n- var row = Math.floor(j / resolution);\n- var col = Math.floor(i / resolution);\n- var charCode = this.json.grid[row].charCodeAt(col);\n- var index = this.indexFromCharCode(charCode);\n- var keys = this.json.keys;\n- if (!isNaN(index) && (index in keys)) {\n- id = keys[index];\n- }\n- }\n- return id;\n+ return shouldDraw;\n },\n \n /**\n- * Method: indexFromCharCode\n- * Given a character code for one of the UTFGrid \"grid\" characters, \n- * resolve the integer index for the feature id in the UTFGrid \"keys\"\n- * array.\n- *\n- * Parameters:\n- * charCode - {Integer}\n- *\n- * Returns:\n- * {Integer} Index for the feature id from the keys array.\n+ * Method: renderTile\n+ * Internal function to actually initialize the image tile,\n+ * position it correctly, and set its url.\n */\n- indexFromCharCode: function(charCode) {\n- if (charCode >= 93) {\n- charCode--;\n- }\n- if (charCode >= 35) {\n- charCode--;\n+ renderTile: function() {\n+ if (this.layer.async) {\n+ // Asynchronous image requests call the asynchronous getURL method\n+ // on the layer to fetch an image that covers 'this.bounds'.\n+ var id = this.asyncRequestId = (this.asyncRequestId || 0) + 1;\n+ this.layer.getURLasync(this.bounds, function(url) {\n+ if (id == this.asyncRequestId) {\n+ this.url = url;\n+ this.initImage();\n+ }\n+ }, this);\n+ } else {\n+ // synchronous image requests get the url immediately.\n+ this.url = this.layer.getURL(this.bounds);\n+ this.initImage();\n }\n- return charCode - 32;\n },\n \n /**\n- * Method: parseData\n- * Parse the JSON from a request\n- *\n- * Parameters:\n- * str - {String} UTFGrid as a JSON string. \n- * \n- * Returns:\n- * {Object} parsed javascript data\n+ * Method: positionTile\n+ * Using the properties currenty set on the layer, position the tile correctly.\n+ * This method is used both by the async and non-async versions of the Tile.Image\n+ * code.\n */\n- parseData: function(str) {\n- if (!this.format) {\n- this.format = new OpenLayers.Format.JSON();\n+ positionTile: function() {\n+ var style = this.getTile().style,\n+ size = this.frame ? this.size :\n+ this.layer.getImageSize(this.bounds),\n+ ratio = 1;\n+ if (this.layer instanceof OpenLayers.Layer.Grid) {\n+ ratio = this.layer.getServerResolution() / this.layer.map.getResolution();\n }\n- this.json = this.format.read(str);\n+ style.left = this.position.x + \"px\";\n+ style.top = this.position.y + \"px\";\n+ style.width = Math.round(ratio * size.w) + \"px\";\n+ style.height = Math.round(ratio * size.h) + \"px\";\n },\n \n /** \n * Method: clear\n- * Delete data stored with this tile.\n+ * Remove the tile from the DOM, clear it of any image related data so that\n+ * it can be reused in a new location.\n */\n clear: function() {\n- this.json = null;\n- },\n-\n- CLASS_NAME: \"OpenLayers.Tile.UTFGrid\"\n-\n-});\n-/* ======================================================================\n- OpenLayers/Tile/Image/IFrame.js\n- ====================================================================== */\n-\n-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for\n- * full list of contributors). Published under the 2-clause BSD license.\n- * See license.txt in the OpenLayers distribution or repository for the\n- * full text of the license. */\n-\n-\n-/**\n- * @requires OpenLayers/Tile/Image.js\n- */\n-\n-/**\n- * Constant: OpenLayers.Tile.Image.IFrame\n- * Mixin for tiles that use form-encoded POST requests to get images from\n- * remote services. Images will be loaded using HTTP-POST into an IFrame.\n- *\n- * This mixin will be applied to instances\n- * configured with set.\n- */\n-OpenLayers.Tile.Image.IFrame = {\n-\n- /**\n- * Property: useIFrame\n- * {Boolean} true if we are currently using an IFrame to render POST\n- * responses, false if we are using an img element to render GET responses.\n- */\n- useIFrame: null,\n-\n- /**\n- * Property: blankImageUrl\n- * {String} Using a data scheme url is not supported by all browsers, but\n- * we don't care because we either set it as css backgroundImage, or the\n- * image's display style is set to \"none\" when we use it.\n- */\n- blankImageUrl: \"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7\",\n-\n- /**\n- * Method: draw\n- * Set useIFrame in the instance, and operate the image/iframe switch.\n- * Then call Tile.Image.draw.\n- *\n- * Returns:\n- * {Boolean}\n- */\n- draw: function() {\n- var draw = OpenLayers.Tile.Image.prototype.shouldDraw.call(this);\n- if (draw) {\n-\n- // this.url isn't set to the currect value yet, so we call getURL\n- // on the layer and store the result in a local variable\n- var url = this.layer.getURL(this.bounds);\n-\n- var usedIFrame = this.useIFrame;\n- this.useIFrame = this.maxGetUrlLength !== null &&\n- !this.layer.async &&\n- url.length > this.maxGetUrlLength;\n-\n- var fromIFrame = usedIFrame && !this.useIFrame;\n- var toIFrame = !usedIFrame && this.useIFrame;\n-\n- if (fromIFrame || toIFrame) {\n-\n- // Switching between GET (image) and POST (iframe).\n-\n- // We remove the imgDiv (really either an image or an iframe)\n- // from the frame and set it to null to make sure initImage\n- // will call getImage.\n-\n- if (this.imgDiv && this.imgDiv.parentNode === this.frame) {\n- this.frame.removeChild(this.imgDiv);\n- }\n- this.imgDiv = null;\n-\n- // And if we had an iframe we also remove the event pane.\n-\n- if (fromIFrame) {\n- this.frame.removeChild(this.frame.firstChild);\n- }\n+ OpenLayers.Tile.prototype.clear.apply(this, arguments);\n+ var img = this.imgDiv;\n+ if (img) {\n+ var tile = this.getTile();\n+ if (tile.parentNode === this.layer.div) {\n+ this.layer.div.removeChild(tile);\n+ }\n+ this.setImgSrc();\n+ if (this.layerAlphaHack === true) {\n+ img.style.filter = \"\";\n }\n+ OpenLayers.Element.removeClass(img, \"olImageLoadError\");\n }\n- return OpenLayers.Tile.Image.prototype.draw.apply(this, arguments);\n+ this.canvasContext = null;\n },\n \n /**\n * Method: getImage\n- * Creates the content for the frame on the tile.\n+ * Returns or creates and returns the tile image.\n */\n getImage: function() {\n- if (this.useIFrame === true) {\n- if (!this.frame.childNodes.length) {\n- var eventPane = document.createElement(\"div\"),\n- style = eventPane.style;\n- style.position = \"absolute\";\n- style.width = \"100%\";\n- style.height = \"100%\";\n- style.zIndex = 1;\n- style.backgroundImage = \"url(\" + this.blankImageUrl + \")\";\n- this.frame.appendChild(eventPane);\n- }\n-\n- var id = this.id + '_iFrame',\n- iframe;\n- if (parseFloat(navigator.appVersion.split(\"MSIE\")[1]) < 9) {\n- // Older IE versions do not set the name attribute of an iFrame \n- // properly via DOM manipulation, so we need to do it on our own with\n- // this hack.\n- iframe = document.createElement('