--- /srv/reproducible-results/rbuild-debian/r-b-build.23FnhKPr/b1/openlayers_2.13.1+ds2-10_armhf.changes +++ /srv/reproducible-results/rbuild-debian/r-b-build.23FnhKPr/b2/openlayers_2.13.1+ds2-10_armhf.changes ├── Files │ @@ -1,2 +1,2 @@ │ │ - c5b7e5c200b9cd4991cea7757a73d3c3 715764 javascript optional libjs-openlayers_2.13.1+ds2-10_all.deb │ + 3965f4e677fd5a8b4d1b9cbc6222579e 730016 javascript optional libjs-openlayers_2.13.1+ds2-10_all.deb ├── libjs-openlayers_2.13.1+ds2-10_all.deb │ ├── file list │ │ @@ -1,3 +1,3 @@ │ │ -rw-r--r-- 0 0 0 4 2023-01-14 13:27:41.000000 debian-binary │ │ -rw-r--r-- 0 0 0 3680 2023-01-14 13:27:41.000000 control.tar.xz │ │ --rw-r--r-- 0 0 0 711892 2023-01-14 13:27:41.000000 data.tar.xz │ │ +-rw-r--r-- 0 0 0 726144 2023-01-14 13:27:41.000000 data.tar.xz │ ├── control.tar.xz │ │ ├── control.tar │ │ │ ├── ./md5sums │ │ │ │ ├── ./md5sums │ │ │ │ │┄ Files differ │ ├── data.tar.xz │ │ ├── data.tar │ │ │ ├── ./usr/share/javascript/openlayers/OpenLayers.js │ │ │ │ ├── js-beautify {} │ │ │ │ │ @@ -52,14 +52,37 @@ │ │ │ │ │ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS │ │ │ │ │ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN │ │ │ │ │ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) │ │ │ │ │ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE │ │ │ │ │ * POSSIBILITY OF SUCH DAMAGE. │ │ │ │ │ */ │ │ │ │ │ /* ====================================================================== │ │ │ │ │ + Rico/license.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @license Apache 2 │ │ │ │ │ + * │ │ │ │ │ + * Contains portions of Rico │ │ │ │ │ + * │ │ │ │ │ + * Copyright 2005 Sabre Airline Solutions │ │ │ │ │ + * │ │ │ │ │ + * Licensed under the Apache License, Version 2.0 (the "License"); you │ │ │ │ │ + * may not use this file except in compliance with the License. You │ │ │ │ │ + * may obtain a copy of the License at │ │ │ │ │ + * │ │ │ │ │ + * http://www.apache.org/licenses/LICENSE-2.0 │ │ │ │ │ + * │ │ │ │ │ + * Unless required by applicable law or agreed to in writing, software │ │ │ │ │ + * distributed under the License is distributed on an "AS IS" BASIS, │ │ │ │ │ + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or │ │ │ │ │ + * implied. See the License for the specific language governing │ │ │ │ │ + * permissions and limitations under the License. │ │ │ │ │ + */ │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ OpenLayers/SingleFile.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ @@ -136,14 +159,395 @@ │ │ │ │ │ * (code) │ │ │ │ │ * │ │ │ │ │ * (end code) │ │ │ │ │ */ │ │ │ │ │ ImgPath: '' │ │ │ │ │ }; │ │ │ │ │ /* ====================================================================== │ │ │ │ │ + OpenLayers/BaseTypes/Class.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/SingleFile.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Constructor: OpenLayers.Class │ │ │ │ │ + * Base class used to construct all other classes. Includes support for │ │ │ │ │ + * multiple inheritance. │ │ │ │ │ + * │ │ │ │ │ + * This constructor is new in OpenLayers 2.5. At OpenLayers 3.0, the old │ │ │ │ │ + * syntax for creating classes and dealing with inheritance │ │ │ │ │ + * will be removed. │ │ │ │ │ + * │ │ │ │ │ + * To create a new OpenLayers-style class, use the following syntax: │ │ │ │ │ + * (code) │ │ │ │ │ + * var MyClass = OpenLayers.Class(prototype); │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * To create a new OpenLayers-style class with multiple inheritance, use the │ │ │ │ │ + * following syntax: │ │ │ │ │ + * (code) │ │ │ │ │ + * var MyClass = OpenLayers.Class(Class1, Class2, prototype); │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Note that instanceof reflection will only reveal Class1 as superclass. │ │ │ │ │ + * │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Class = function() { │ │ │ │ │ + var len = arguments.length; │ │ │ │ │ + var P = arguments[0]; │ │ │ │ │ + var F = arguments[len - 1]; │ │ │ │ │ + │ │ │ │ │ + var C = typeof F.initialize == "function" ? │ │ │ │ │ + F.initialize : │ │ │ │ │ + function() { │ │ │ │ │ + P.prototype.initialize.apply(this, arguments); │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ + if (len > 1) { │ │ │ │ │ + var newArgs = [C, P].concat( │ │ │ │ │ + Array.prototype.slice.call(arguments).slice(1, len - 1), F); │ │ │ │ │ + OpenLayers.inherit.apply(null, newArgs); │ │ │ │ │ + } else { │ │ │ │ │ + C.prototype = F; │ │ │ │ │ + } │ │ │ │ │ + return C; │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Function: OpenLayers.inherit │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * C - {Object} the class that inherits │ │ │ │ │ + * P - {Object} the superclass to inherit from │ │ │ │ │ + * │ │ │ │ │ + * In addition to the mandatory C and P parameters, an arbitrary number of │ │ │ │ │ + * objects can be passed, which will extend C. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.inherit = function(C, P) { │ │ │ │ │ + var F = function() {}; │ │ │ │ │ + F.prototype = P.prototype; │ │ │ │ │ + C.prototype = new F; │ │ │ │ │ + var i, l, o; │ │ │ │ │ + for (i = 2, l = arguments.length; i < l; i++) { │ │ │ │ │ + o = arguments[i]; │ │ │ │ │ + if (typeof o === "function") { │ │ │ │ │ + o = o.prototype; │ │ │ │ │ + } │ │ │ │ │ + OpenLayers.Util.extend(C.prototype, o); │ │ │ │ │ + } │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * APIFunction: extend │ │ │ │ │ + * Copy all properties of a source object to a destination object. Modifies │ │ │ │ │ + * the passed in destination object. Any properties on the source object │ │ │ │ │ + * that are set to undefined will not be (re)set on the destination object. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * destination - {Object} The object that will be modified │ │ │ │ │ + * source - {Object} The object with properties to be set on the destination │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Object} The destination object. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Util = OpenLayers.Util || {}; │ │ │ │ │ +OpenLayers.Util.extend = function(destination, source) { │ │ │ │ │ + destination = destination || {}; │ │ │ │ │ + if (source) { │ │ │ │ │ + for (var property in source) { │ │ │ │ │ + var value = source[property]; │ │ │ │ │ + if (value !== undefined) { │ │ │ │ │ + destination[property] = value; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * IE doesn't include the toString property when iterating over an object's │ │ │ │ │ + * properties with the for(property in object) syntax. Explicitly check if │ │ │ │ │ + * the source has its own toString property. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /* │ │ │ │ │ + * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative │ │ │ │ │ + * prototype object" when calling hawOwnProperty if the source object │ │ │ │ │ + * is an instance of window.Event. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + var sourceIsEvt = typeof window.Event == "function" && │ │ │ │ │ + source instanceof window.Event; │ │ │ │ │ + │ │ │ │ │ + if (!sourceIsEvt && │ │ │ │ │ + source.hasOwnProperty && source.hasOwnProperty("toString")) { │ │ │ │ │ + destination.toString = source.toString; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return destination; │ │ │ │ │ +}; │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Console.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Namespace: OpenLayers.Console │ │ │ │ │ + * The OpenLayers.Console namespace is used for debugging and error logging. │ │ │ │ │ + * If the Firebug Lite (../Firebug/firebug.js) is included before this script, │ │ │ │ │ + * calls to OpenLayers.Console methods will get redirected to window.console. │ │ │ │ │ + * This makes use of the Firebug extension where available and allows for │ │ │ │ │ + * cross-browser debugging Firebug style. │ │ │ │ │ + * │ │ │ │ │ + * Note: │ │ │ │ │ + * Note that behavior will differ with the Firebug extention and Firebug Lite. │ │ │ │ │ + * Most notably, the Firebug Lite console does not currently allow for │ │ │ │ │ + * hyperlinks to code or for clicking on object to explore their properties. │ │ │ │ │ + * │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Console = { │ │ │ │ │ + /** │ │ │ │ │ + * Create empty functions for all console methods. The real value of these │ │ │ │ │ + * properties will be set if Firebug Lite (../Firebug/firebug.js script) is │ │ │ │ │ + * included. We explicitly require the Firebug Lite script to trigger │ │ │ │ │ + * functionality of the OpenLayers.Console methods. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: log │ │ │ │ │ + * Log an object in the console. The Firebug Lite console logs string │ │ │ │ │ + * representation of objects. Given multiple arguments, they will │ │ │ │ │ + * be cast to strings and logged with a space delimiter. If the first │ │ │ │ │ + * argument is a string with printf-like formatting, subsequent arguments │ │ │ │ │ + * will be used in string substitution. Any additional arguments (beyond │ │ │ │ │ + * the number substituted in a format string) will be appended in a space- │ │ │ │ │ + * delimited line. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * object - {Object} │ │ │ │ │ + */ │ │ │ │ │ + log: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: debug │ │ │ │ │ + * Writes a message to the console, including a hyperlink to the line │ │ │ │ │ + * where it was called. │ │ │ │ │ + * │ │ │ │ │ + * May be called with multiple arguments as with OpenLayers.Console.log(). │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * object - {Object} │ │ │ │ │ + */ │ │ │ │ │ + debug: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: info │ │ │ │ │ + * Writes a message to the console with the visual "info" icon and color │ │ │ │ │ + * coding and a hyperlink to the line where it was called. │ │ │ │ │ + * │ │ │ │ │ + * May be called with multiple arguments as with OpenLayers.Console.log(). │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * object - {Object} │ │ │ │ │ + */ │ │ │ │ │ + info: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: warn │ │ │ │ │ + * Writes a message to the console with the visual "warning" icon and │ │ │ │ │ + * color coding and a hyperlink to the line where it was called. │ │ │ │ │ + * │ │ │ │ │ + * May be called with multiple arguments as with OpenLayers.Console.log(). │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * object - {Object} │ │ │ │ │ + */ │ │ │ │ │ + warn: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: error │ │ │ │ │ + * Writes a message to the console with the visual "error" icon and color │ │ │ │ │ + * coding and a hyperlink to the line where it was called. │ │ │ │ │ + * │ │ │ │ │ + * May be called with multiple arguments as with OpenLayers.Console.log(). │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * object - {Object} │ │ │ │ │ + */ │ │ │ │ │ + error: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: userError │ │ │ │ │ + * A single interface for showing error messages to the user. The default │ │ │ │ │ + * behavior is a Javascript alert, though this can be overridden by │ │ │ │ │ + * reassigning OpenLayers.Console.userError to a different function. │ │ │ │ │ + * │ │ │ │ │ + * Expects a single error message │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * error - {Object} │ │ │ │ │ + */ │ │ │ │ │ + userError: function(error) { │ │ │ │ │ + alert(error); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: assert │ │ │ │ │ + * Tests that an expression is true. If not, it will write a message to │ │ │ │ │ + * the console and throw an exception. │ │ │ │ │ + * │ │ │ │ │ + * May be called with multiple arguments as with OpenLayers.Console.log(). │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * object - {Object} │ │ │ │ │ + */ │ │ │ │ │ + assert: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: dir │ │ │ │ │ + * Prints an interactive listing of all properties of the object. This │ │ │ │ │ + * looks identical to the view that you would see in the DOM tab. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * object - {Object} │ │ │ │ │ + */ │ │ │ │ │ + dir: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: dirxml │ │ │ │ │ + * Prints the XML source tree of an HTML or XML element. This looks │ │ │ │ │ + * identical to the view that you would see in the HTML tab. You can click │ │ │ │ │ + * on any node to inspect it in the HTML tab. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * object - {Object} │ │ │ │ │ + */ │ │ │ │ │ + dirxml: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: trace │ │ │ │ │ + * Prints an interactive stack trace of JavaScript execution at the point │ │ │ │ │ + * where it is called. The stack trace details the functions on the stack, │ │ │ │ │ + * as well as the values that were passed as arguments to each function. │ │ │ │ │ + * You can click each function to take you to its source in the Script tab, │ │ │ │ │ + * and click each argument value to inspect it in the DOM or HTML tabs. │ │ │ │ │ + * │ │ │ │ │ + */ │ │ │ │ │ + trace: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: group │ │ │ │ │ + * Writes a message to the console and opens a nested block to indent all │ │ │ │ │ + * future messages sent to the console. Call OpenLayers.Console.groupEnd() │ │ │ │ │ + * to close the block. │ │ │ │ │ + * │ │ │ │ │ + * May be called with multiple arguments as with OpenLayers.Console.log(). │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * object - {Object} │ │ │ │ │ + */ │ │ │ │ │ + group: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: groupEnd │ │ │ │ │ + * Closes the most recently opened block created by a call to │ │ │ │ │ + * OpenLayers.Console.group │ │ │ │ │ + */ │ │ │ │ │ + groupEnd: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: time │ │ │ │ │ + * Creates a new timer under the given name. Call │ │ │ │ │ + * OpenLayers.Console.timeEnd(name) │ │ │ │ │ + * with the same name to stop the timer and print the time elapsed. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * name - {String} │ │ │ │ │ + */ │ │ │ │ │ + time: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: timeEnd │ │ │ │ │ + * Stops a timer created by a call to OpenLayers.Console.time(name) and │ │ │ │ │ + * writes the time elapsed. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * name - {String} │ │ │ │ │ + */ │ │ │ │ │ + timeEnd: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: profile │ │ │ │ │ + * Turns on the JavaScript profiler. The optional argument title would │ │ │ │ │ + * contain the text to be printed in the header of the profile report. │ │ │ │ │ + * │ │ │ │ │ + * This function is not currently implemented in Firebug Lite. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * title - {String} Optional title for the profiler │ │ │ │ │ + */ │ │ │ │ │ + profile: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: profileEnd │ │ │ │ │ + * Turns off the JavaScript profiler and prints its report. │ │ │ │ │ + * │ │ │ │ │ + * This function is not currently implemented in Firebug Lite. │ │ │ │ │ + */ │ │ │ │ │ + profileEnd: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: count │ │ │ │ │ + * Writes the number of times that the line of code where count was called │ │ │ │ │ + * was executed. The optional argument title will print a message in │ │ │ │ │ + * addition to the number of the count. │ │ │ │ │ + * │ │ │ │ │ + * This function is not currently implemented in Firebug Lite. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * title - {String} Optional title to be printed with count │ │ │ │ │ + */ │ │ │ │ │ + count: function() {}, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Console" │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Execute an anonymous function to extend the OpenLayers.Console namespace │ │ │ │ │ + * if the firebug.js script is included. This closure is used so that the │ │ │ │ │ + * "scripts" and "i" variables don't pollute the global namespace. │ │ │ │ │ + */ │ │ │ │ │ +(function() { │ │ │ │ │ + /** │ │ │ │ │ + * If Firebug Lite is included (before this script), re-route all │ │ │ │ │ + * OpenLayers.Console calls to the console object. │ │ │ │ │ + */ │ │ │ │ │ + var scripts = document.getElementsByTagName("script"); │ │ │ │ │ + for (var i = 0, len = scripts.length; i < len; ++i) { │ │ │ │ │ + if (scripts[i].src.indexOf("firebug.js") != -1) { │ │ │ │ │ + if (console) { │ │ │ │ │ + OpenLayers.Util.extend(OpenLayers.Console, console); │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ +})(); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ OpenLayers/BaseTypes.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ @@ -603,141 +1007,14 @@ │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ return selected; │ │ │ │ │ } │ │ │ │ │ │ │ │ │ │ }; │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/BaseTypes/Class.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/SingleFile.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Constructor: OpenLayers.Class │ │ │ │ │ - * Base class used to construct all other classes. Includes support for │ │ │ │ │ - * multiple inheritance. │ │ │ │ │ - * │ │ │ │ │ - * This constructor is new in OpenLayers 2.5. At OpenLayers 3.0, the old │ │ │ │ │ - * syntax for creating classes and dealing with inheritance │ │ │ │ │ - * will be removed. │ │ │ │ │ - * │ │ │ │ │ - * To create a new OpenLayers-style class, use the following syntax: │ │ │ │ │ - * (code) │ │ │ │ │ - * var MyClass = OpenLayers.Class(prototype); │ │ │ │ │ - * (end) │ │ │ │ │ - * │ │ │ │ │ - * To create a new OpenLayers-style class with multiple inheritance, use the │ │ │ │ │ - * following syntax: │ │ │ │ │ - * (code) │ │ │ │ │ - * var MyClass = OpenLayers.Class(Class1, Class2, prototype); │ │ │ │ │ - * (end) │ │ │ │ │ - * │ │ │ │ │ - * Note that instanceof reflection will only reveal Class1 as superclass. │ │ │ │ │ - * │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Class = function() { │ │ │ │ │ - var len = arguments.length; │ │ │ │ │ - var P = arguments[0]; │ │ │ │ │ - var F = arguments[len - 1]; │ │ │ │ │ - │ │ │ │ │ - var C = typeof F.initialize == "function" ? │ │ │ │ │ - F.initialize : │ │ │ │ │ - function() { │ │ │ │ │ - P.prototype.initialize.apply(this, arguments); │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - if (len > 1) { │ │ │ │ │ - var newArgs = [C, P].concat( │ │ │ │ │ - Array.prototype.slice.call(arguments).slice(1, len - 1), F); │ │ │ │ │ - OpenLayers.inherit.apply(null, newArgs); │ │ │ │ │ - } else { │ │ │ │ │ - C.prototype = F; │ │ │ │ │ - } │ │ │ │ │ - return C; │ │ │ │ │ -}; │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Function: OpenLayers.inherit │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * C - {Object} the class that inherits │ │ │ │ │ - * P - {Object} the superclass to inherit from │ │ │ │ │ - * │ │ │ │ │ - * In addition to the mandatory C and P parameters, an arbitrary number of │ │ │ │ │ - * objects can be passed, which will extend C. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.inherit = function(C, P) { │ │ │ │ │ - var F = function() {}; │ │ │ │ │ - F.prototype = P.prototype; │ │ │ │ │ - C.prototype = new F; │ │ │ │ │ - var i, l, o; │ │ │ │ │ - for (i = 2, l = arguments.length; i < l; i++) { │ │ │ │ │ - o = arguments[i]; │ │ │ │ │ - if (typeof o === "function") { │ │ │ │ │ - o = o.prototype; │ │ │ │ │ - } │ │ │ │ │ - OpenLayers.Util.extend(C.prototype, o); │ │ │ │ │ - } │ │ │ │ │ -}; │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * APIFunction: extend │ │ │ │ │ - * Copy all properties of a source object to a destination object. Modifies │ │ │ │ │ - * the passed in destination object. Any properties on the source object │ │ │ │ │ - * that are set to undefined will not be (re)set on the destination object. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * destination - {Object} The object that will be modified │ │ │ │ │ - * source - {Object} The object with properties to be set on the destination │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} The destination object. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Util = OpenLayers.Util || {}; │ │ │ │ │ -OpenLayers.Util.extend = function(destination, source) { │ │ │ │ │ - destination = destination || {}; │ │ │ │ │ - if (source) { │ │ │ │ │ - for (var property in source) { │ │ │ │ │ - var value = source[property]; │ │ │ │ │ - if (value !== undefined) { │ │ │ │ │ - destination[property] = value; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * IE doesn't include the toString property when iterating over an object's │ │ │ │ │ - * properties with the for(property in object) syntax. Explicitly check if │ │ │ │ │ - * the source has its own toString property. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /* │ │ │ │ │ - * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative │ │ │ │ │ - * prototype object" when calling hawOwnProperty if the source object │ │ │ │ │ - * is an instance of window.Event. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - var sourceIsEvt = typeof window.Event == "function" && │ │ │ │ │ - source instanceof window.Event; │ │ │ │ │ - │ │ │ │ │ - if (!sourceIsEvt && │ │ │ │ │ - source.hasOwnProperty && source.hasOwnProperty("toString")) { │ │ │ │ │ - destination.toString = source.toString; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - return destination; │ │ │ │ │ -}; │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ OpenLayers/BaseTypes/Bounds.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ @@ -1589,207 +1866,14 @@ │ │ │ │ │ │ │ │ │ │ opp += (quadrant.charAt(0) == 't') ? 'b' : 't'; │ │ │ │ │ opp += (quadrant.charAt(1) == 'l') ? 'r' : 'l'; │ │ │ │ │ │ │ │ │ │ return opp; │ │ │ │ │ }; │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/BaseTypes/Element.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ │ - * @requires OpenLayers/BaseTypes.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Namespace: OpenLayers.Element │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Element = { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: visible │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * element - {DOMElement} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} Is the element visible? │ │ │ │ │ - */ │ │ │ │ │ - visible: function(element) { │ │ │ │ │ - return OpenLayers.Util.getElement(element).style.display != 'none'; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: toggle │ │ │ │ │ - * Toggle the visibility of element(s) passed in │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * element - {DOMElement} Actually user can pass any number of elements │ │ │ │ │ - */ │ │ │ │ │ - toggle: function() { │ │ │ │ │ - for (var i = 0, len = arguments.length; i < len; i++) { │ │ │ │ │ - var element = OpenLayers.Util.getElement(arguments[i]); │ │ │ │ │ - var display = OpenLayers.Element.visible(element) ? 'none' : │ │ │ │ │ - ''; │ │ │ │ │ - element.style.display = display; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: remove │ │ │ │ │ - * Remove the specified element from the DOM. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * element - {DOMElement} │ │ │ │ │ - */ │ │ │ │ │ - remove: function(element) { │ │ │ │ │ - element = OpenLayers.Util.getElement(element); │ │ │ │ │ - element.parentNode.removeChild(element); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: getHeight │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * element - {DOMElement} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Integer} The offset height of the element passed in │ │ │ │ │ - */ │ │ │ │ │ - getHeight: function(element) { │ │ │ │ │ - element = OpenLayers.Util.getElement(element); │ │ │ │ │ - return element.offsetHeight; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Function: hasClass │ │ │ │ │ - * Tests if an element has the given CSS class name. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * element - {DOMElement} A DOM element node. │ │ │ │ │ - * name - {String} The CSS class name to search for. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The element has the given class name. │ │ │ │ │ - */ │ │ │ │ │ - hasClass: function(element, name) { │ │ │ │ │ - var names = element.className; │ │ │ │ │ - return (!!names && new RegExp("(^|\\s)" + name + "(\\s|$)").test(names)); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Function: addClass │ │ │ │ │ - * Add a CSS class name to an element. Safe where element already has │ │ │ │ │ - * the class name. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * element - {DOMElement} A DOM element node. │ │ │ │ │ - * name - {String} The CSS class name to add. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {DOMElement} The element. │ │ │ │ │ - */ │ │ │ │ │ - addClass: function(element, name) { │ │ │ │ │ - if (!OpenLayers.Element.hasClass(element, name)) { │ │ │ │ │ - element.className += (element.className ? " " : "") + name; │ │ │ │ │ - } │ │ │ │ │ - return element; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Function: removeClass │ │ │ │ │ - * Remove a CSS class name from an element. Safe where element does not │ │ │ │ │ - * have the class name. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * element - {DOMElement} A DOM element node. │ │ │ │ │ - * name - {String} The CSS class name to remove. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {DOMElement} The element. │ │ │ │ │ - */ │ │ │ │ │ - removeClass: function(element, name) { │ │ │ │ │ - var names = element.className; │ │ │ │ │ - if (names) { │ │ │ │ │ - element.className = OpenLayers.String.trim( │ │ │ │ │ - names.replace( │ │ │ │ │ - new RegExp("(^|\\s+)" + name + "(\\s+|$)"), " " │ │ │ │ │ - ) │ │ │ │ │ - ); │ │ │ │ │ - } │ │ │ │ │ - return element; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Function: toggleClass │ │ │ │ │ - * Remove a CSS class name from an element if it exists. Add the class name │ │ │ │ │ - * if it doesn't exist. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * element - {DOMElement} A DOM element node. │ │ │ │ │ - * name - {String} The CSS class name to toggle. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {DOMElement} The element. │ │ │ │ │ - */ │ │ │ │ │ - toggleClass: function(element, name) { │ │ │ │ │ - if (OpenLayers.Element.hasClass(element, name)) { │ │ │ │ │ - OpenLayers.Element.removeClass(element, name); │ │ │ │ │ - } else { │ │ │ │ │ - OpenLayers.Element.addClass(element, name); │ │ │ │ │ - } │ │ │ │ │ - return element; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: getStyle │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * element - {DOMElement} │ │ │ │ │ - * style - {?} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {?} │ │ │ │ │ - */ │ │ │ │ │ - getStyle: function(element, style) { │ │ │ │ │ - element = OpenLayers.Util.getElement(element); │ │ │ │ │ - │ │ │ │ │ - var value = null; │ │ │ │ │ - if (element && element.style) { │ │ │ │ │ - value = element.style[OpenLayers.String.camelize(style)]; │ │ │ │ │ - if (!value) { │ │ │ │ │ - if (document.defaultView && │ │ │ │ │ - document.defaultView.getComputedStyle) { │ │ │ │ │ - │ │ │ │ │ - var css = document.defaultView.getComputedStyle(element, null); │ │ │ │ │ - value = css ? css.getPropertyValue(style) : null; │ │ │ │ │ - } else if (element.currentStyle) { │ │ │ │ │ - value = element.currentStyle[OpenLayers.String.camelize(style)]; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - var positions = ['left', 'top', 'right', 'bottom']; │ │ │ │ │ - if (window.opera && │ │ │ │ │ - (OpenLayers.Util.indexOf(positions, style) != -1) && │ │ │ │ │ - (OpenLayers.Element.getStyle(element, 'position') == 'static')) { │ │ │ │ │ - value = 'auto'; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - return value == 'auto' ? null : value; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ -}; │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ OpenLayers/BaseTypes/LonLat.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ @@ -2243,268 +2327,14 @@ │ │ │ │ │ } │ │ │ │ │ return equals; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Size" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Console.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Namespace: OpenLayers.Console │ │ │ │ │ - * The OpenLayers.Console namespace is used for debugging and error logging. │ │ │ │ │ - * If the Firebug Lite (../Firebug/firebug.js) is included before this script, │ │ │ │ │ - * calls to OpenLayers.Console methods will get redirected to window.console. │ │ │ │ │ - * This makes use of the Firebug extension where available and allows for │ │ │ │ │ - * cross-browser debugging Firebug style. │ │ │ │ │ - * │ │ │ │ │ - * Note: │ │ │ │ │ - * Note that behavior will differ with the Firebug extention and Firebug Lite. │ │ │ │ │ - * Most notably, the Firebug Lite console does not currently allow for │ │ │ │ │ - * hyperlinks to code or for clicking on object to explore their properties. │ │ │ │ │ - * │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Console = { │ │ │ │ │ - /** │ │ │ │ │ - * Create empty functions for all console methods. The real value of these │ │ │ │ │ - * properties will be set if Firebug Lite (../Firebug/firebug.js script) is │ │ │ │ │ - * included. We explicitly require the Firebug Lite script to trigger │ │ │ │ │ - * functionality of the OpenLayers.Console methods. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: log │ │ │ │ │ - * Log an object in the console. The Firebug Lite console logs string │ │ │ │ │ - * representation of objects. Given multiple arguments, they will │ │ │ │ │ - * be cast to strings and logged with a space delimiter. If the first │ │ │ │ │ - * argument is a string with printf-like formatting, subsequent arguments │ │ │ │ │ - * will be used in string substitution. Any additional arguments (beyond │ │ │ │ │ - * the number substituted in a format string) will be appended in a space- │ │ │ │ │ - * delimited line. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * object - {Object} │ │ │ │ │ - */ │ │ │ │ │ - log: function() {}, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: debug │ │ │ │ │ - * Writes a message to the console, including a hyperlink to the line │ │ │ │ │ - * where it was called. │ │ │ │ │ - * │ │ │ │ │ - * May be called with multiple arguments as with OpenLayers.Console.log(). │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * object - {Object} │ │ │ │ │ - */ │ │ │ │ │ - debug: function() {}, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: info │ │ │ │ │ - * Writes a message to the console with the visual "info" icon and color │ │ │ │ │ - * coding and a hyperlink to the line where it was called. │ │ │ │ │ - * │ │ │ │ │ - * May be called with multiple arguments as with OpenLayers.Console.log(). │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * object - {Object} │ │ │ │ │ - */ │ │ │ │ │ - info: function() {}, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: warn │ │ │ │ │ - * Writes a message to the console with the visual "warning" icon and │ │ │ │ │ - * color coding and a hyperlink to the line where it was called. │ │ │ │ │ - * │ │ │ │ │ - * May be called with multiple arguments as with OpenLayers.Console.log(). │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * object - {Object} │ │ │ │ │ - */ │ │ │ │ │ - warn: function() {}, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: error │ │ │ │ │ - * Writes a message to the console with the visual "error" icon and color │ │ │ │ │ - * coding and a hyperlink to the line where it was called. │ │ │ │ │ - * │ │ │ │ │ - * May be called with multiple arguments as with OpenLayers.Console.log(). │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * object - {Object} │ │ │ │ │ - */ │ │ │ │ │ - error: function() {}, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: userError │ │ │ │ │ - * A single interface for showing error messages to the user. The default │ │ │ │ │ - * behavior is a Javascript alert, though this can be overridden by │ │ │ │ │ - * reassigning OpenLayers.Console.userError to a different function. │ │ │ │ │ - * │ │ │ │ │ - * Expects a single error message │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * error - {Object} │ │ │ │ │ - */ │ │ │ │ │ - userError: function(error) { │ │ │ │ │ - alert(error); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: assert │ │ │ │ │ - * Tests that an expression is true. If not, it will write a message to │ │ │ │ │ - * the console and throw an exception. │ │ │ │ │ - * │ │ │ │ │ - * May be called with multiple arguments as with OpenLayers.Console.log(). │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * object - {Object} │ │ │ │ │ - */ │ │ │ │ │ - assert: function() {}, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: dir │ │ │ │ │ - * Prints an interactive listing of all properties of the object. This │ │ │ │ │ - * looks identical to the view that you would see in the DOM tab. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * object - {Object} │ │ │ │ │ - */ │ │ │ │ │ - dir: function() {}, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: dirxml │ │ │ │ │ - * Prints the XML source tree of an HTML or XML element. This looks │ │ │ │ │ - * identical to the view that you would see in the HTML tab. You can click │ │ │ │ │ - * on any node to inspect it in the HTML tab. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * object - {Object} │ │ │ │ │ - */ │ │ │ │ │ - dirxml: function() {}, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: trace │ │ │ │ │ - * Prints an interactive stack trace of JavaScript execution at the point │ │ │ │ │ - * where it is called. The stack trace details the functions on the stack, │ │ │ │ │ - * as well as the values that were passed as arguments to each function. │ │ │ │ │ - * You can click each function to take you to its source in the Script tab, │ │ │ │ │ - * and click each argument value to inspect it in the DOM or HTML tabs. │ │ │ │ │ - * │ │ │ │ │ - */ │ │ │ │ │ - trace: function() {}, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: group │ │ │ │ │ - * Writes a message to the console and opens a nested block to indent all │ │ │ │ │ - * future messages sent to the console. Call OpenLayers.Console.groupEnd() │ │ │ │ │ - * to close the block. │ │ │ │ │ - * │ │ │ │ │ - * May be called with multiple arguments as with OpenLayers.Console.log(). │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * object - {Object} │ │ │ │ │ - */ │ │ │ │ │ - group: function() {}, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: groupEnd │ │ │ │ │ - * Closes the most recently opened block created by a call to │ │ │ │ │ - * OpenLayers.Console.group │ │ │ │ │ - */ │ │ │ │ │ - groupEnd: function() {}, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: time │ │ │ │ │ - * Creates a new timer under the given name. Call │ │ │ │ │ - * OpenLayers.Console.timeEnd(name) │ │ │ │ │ - * with the same name to stop the timer and print the time elapsed. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * name - {String} │ │ │ │ │ - */ │ │ │ │ │ - time: function() {}, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: timeEnd │ │ │ │ │ - * Stops a timer created by a call to OpenLayers.Console.time(name) and │ │ │ │ │ - * writes the time elapsed. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * name - {String} │ │ │ │ │ - */ │ │ │ │ │ - timeEnd: function() {}, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: profile │ │ │ │ │ - * Turns on the JavaScript profiler. The optional argument title would │ │ │ │ │ - * contain the text to be printed in the header of the profile report. │ │ │ │ │ - * │ │ │ │ │ - * This function is not currently implemented in Firebug Lite. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * title - {String} Optional title for the profiler │ │ │ │ │ - */ │ │ │ │ │ - profile: function() {}, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: profileEnd │ │ │ │ │ - * Turns off the JavaScript profiler and prints its report. │ │ │ │ │ - * │ │ │ │ │ - * This function is not currently implemented in Firebug Lite. │ │ │ │ │ - */ │ │ │ │ │ - profileEnd: function() {}, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIFunction: count │ │ │ │ │ - * Writes the number of times that the line of code where count was called │ │ │ │ │ - * was executed. The optional argument title will print a message in │ │ │ │ │ - * addition to the number of the count. │ │ │ │ │ - * │ │ │ │ │ - * This function is not currently implemented in Firebug Lite. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * title - {String} Optional title to be printed with count │ │ │ │ │ - */ │ │ │ │ │ - count: function() {}, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Console" │ │ │ │ │ -}; │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Execute an anonymous function to extend the OpenLayers.Console namespace │ │ │ │ │ - * if the firebug.js script is included. This closure is used so that the │ │ │ │ │ - * "scripts" and "i" variables don't pollute the global namespace. │ │ │ │ │ - */ │ │ │ │ │ -(function() { │ │ │ │ │ - /** │ │ │ │ │ - * If Firebug Lite is included (before this script), re-route all │ │ │ │ │ - * OpenLayers.Console calls to the console object. │ │ │ │ │ - */ │ │ │ │ │ - var scripts = document.getElementsByTagName("script"); │ │ │ │ │ - for (var i = 0, len = scripts.length; i < len; ++i) { │ │ │ │ │ - if (scripts[i].src.indexOf("firebug.js") != -1) { │ │ │ │ │ - if (console) { │ │ │ │ │ - OpenLayers.Util.extend(OpenLayers.Console, console); │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ -})(); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ OpenLayers/Lang.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ @@ -4426,812 +4256,839 @@ │ │ │ │ │ } else { │ │ │ │ │ str += coordinate < 0 ? OpenLayers.i18n("S") : OpenLayers.i18n("N"); │ │ │ │ │ } │ │ │ │ │ return str; │ │ │ │ │ }; │ │ │ │ │ │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Util/vendorPrefix.js │ │ │ │ │ + OpenLayers/BaseTypes/Element.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/SingleFile.js │ │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ │ + * @requires OpenLayers/BaseTypes.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ -OpenLayers.Util = OpenLayers.Util || {}; │ │ │ │ │ /** │ │ │ │ │ - * Namespace: OpenLayers.Util.vendorPrefix │ │ │ │ │ - * A collection of utility functions to detect vendor prefixed features │ │ │ │ │ + * Namespace: OpenLayers.Element │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Util.vendorPrefix = (function() { │ │ │ │ │ - "use strict"; │ │ │ │ │ +OpenLayers.Element = { │ │ │ │ │ │ │ │ │ │ - var VENDOR_PREFIXES = ["", "O", "ms", "Moz", "Webkit"], │ │ │ │ │ - divStyle = document.createElement("div").style, │ │ │ │ │ - cssCache = {}, │ │ │ │ │ - jsCache = {}; │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: visible │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * element - {DOMElement} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Is the element visible? │ │ │ │ │ + */ │ │ │ │ │ + visible: function(element) { │ │ │ │ │ + return OpenLayers.Util.getElement(element).style.display != 'none'; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: toggle │ │ │ │ │ + * Toggle the visibility of element(s) passed in │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * element - {DOMElement} Actually user can pass any number of elements │ │ │ │ │ + */ │ │ │ │ │ + toggle: function() { │ │ │ │ │ + for (var i = 0, len = arguments.length; i < len; i++) { │ │ │ │ │ + var element = OpenLayers.Util.getElement(arguments[i]); │ │ │ │ │ + var display = OpenLayers.Element.visible(element) ? 'none' : │ │ │ │ │ + ''; │ │ │ │ │ + element.style.display = display; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Function: domToCss │ │ │ │ │ - * Converts a upper camel case DOM style property name to a CSS property │ │ │ │ │ - * i.e. transformOrigin -> transform-origin │ │ │ │ │ - * or WebkitTransformOrigin -> -webkit-transform-origin │ │ │ │ │ - * │ │ │ │ │ + * APIFunction: remove │ │ │ │ │ + * Remove the specified element from the DOM. │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * prefixedDom - {String} The property to convert │ │ │ │ │ - * │ │ │ │ │ + * element - {DOMElement} │ │ │ │ │ + */ │ │ │ │ │ + remove: function(element) { │ │ │ │ │ + element = OpenLayers.Util.getElement(element); │ │ │ │ │ + element.parentNode.removeChild(element); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIFunction: getHeight │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * element - {DOMElement} │ │ │ │ │ + * │ │ │ │ │ * Returns: │ │ │ │ │ - * {String} The CSS property │ │ │ │ │ + * {Integer} The offset height of the element passed in │ │ │ │ │ */ │ │ │ │ │ - function domToCss(prefixedDom) { │ │ │ │ │ - if (!prefixedDom) { │ │ │ │ │ - return null; │ │ │ │ │ - } │ │ │ │ │ - return prefixedDom. │ │ │ │ │ - replace(/([A-Z])/g, function(c) { │ │ │ │ │ - return "-" + c.toLowerCase(); │ │ │ │ │ - }). │ │ │ │ │ - replace(/^ms-/, "-ms-"); │ │ │ │ │ - } │ │ │ │ │ + getHeight: function(element) { │ │ │ │ │ + element = OpenLayers.Util.getElement(element); │ │ │ │ │ + return element.offsetHeight; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: css │ │ │ │ │ - * Detect which property is used for a CSS property │ │ │ │ │ + * Function: hasClass │ │ │ │ │ + * Tests if an element has the given CSS class name. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * property - {String} The standard (unprefixed) CSS property name │ │ │ │ │ + * element - {DOMElement} A DOM element node. │ │ │ │ │ + * name - {String} The CSS class name to search for. │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {String} The standard CSS property, prefixed property or null if not │ │ │ │ │ - * supported │ │ │ │ │ + * {Boolean} The element has the given class name. │ │ │ │ │ */ │ │ │ │ │ - function css(property) { │ │ │ │ │ - if (cssCache[property] === undefined) { │ │ │ │ │ - var domProperty = property. │ │ │ │ │ - replace(/(-[\s\S])/g, function(c) { │ │ │ │ │ - return c.charAt(1).toUpperCase(); │ │ │ │ │ - }); │ │ │ │ │ - var prefixedDom = style(domProperty); │ │ │ │ │ - cssCache[property] = domToCss(prefixedDom); │ │ │ │ │ - } │ │ │ │ │ - return cssCache[property]; │ │ │ │ │ - } │ │ │ │ │ + hasClass: function(element, name) { │ │ │ │ │ + var names = element.className; │ │ │ │ │ + return (!!names && new RegExp("(^|\\s)" + name + "(\\s|$)").test(names)); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: js │ │ │ │ │ - * Detect which property is used for a JS property/method │ │ │ │ │ + * Function: addClass │ │ │ │ │ + * Add a CSS class name to an element. Safe where element already has │ │ │ │ │ + * the class name. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * obj - {Object} The object to test on │ │ │ │ │ - * property - {String} The standard (unprefixed) JS property name │ │ │ │ │ + * element - {DOMElement} A DOM element node. │ │ │ │ │ + * name - {String} The CSS class name to add. │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {String} The standard JS property, prefixed property or null if not │ │ │ │ │ - * supported │ │ │ │ │ + * {DOMElement} The element. │ │ │ │ │ */ │ │ │ │ │ - function js(obj, property) { │ │ │ │ │ - if (jsCache[property] === undefined) { │ │ │ │ │ - var tmpProp, │ │ │ │ │ - i = 0, │ │ │ │ │ - l = VENDOR_PREFIXES.length, │ │ │ │ │ - prefix, │ │ │ │ │ - isStyleObj = (typeof obj.cssText !== "undefined"); │ │ │ │ │ - │ │ │ │ │ - jsCache[property] = null; │ │ │ │ │ - for (; i < l; i++) { │ │ │ │ │ - prefix = VENDOR_PREFIXES[i]; │ │ │ │ │ - if (prefix) { │ │ │ │ │ - if (!isStyleObj) { │ │ │ │ │ - // js prefix should be lower-case, while style │ │ │ │ │ - // properties have upper case on first character │ │ │ │ │ - prefix = prefix.toLowerCase(); │ │ │ │ │ - } │ │ │ │ │ - tmpProp = prefix + property.charAt(0).toUpperCase() + property.slice(1); │ │ │ │ │ - } else { │ │ │ │ │ - tmpProp = property; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (obj[tmpProp] !== undefined) { │ │ │ │ │ - jsCache[property] = tmpProp; │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ + addClass: function(element, name) { │ │ │ │ │ + if (!OpenLayers.Element.hasClass(element, name)) { │ │ │ │ │ + element.className += (element.className ? " " : "") + name; │ │ │ │ │ } │ │ │ │ │ - return jsCache[property]; │ │ │ │ │ - } │ │ │ │ │ + return element; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: style │ │ │ │ │ - * Detect which property is used for a DOM style property │ │ │ │ │ + * Function: removeClass │ │ │ │ │ + * Remove a CSS class name from an element. Safe where element does not │ │ │ │ │ + * have the class name. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * property - {String} The standard (unprefixed) style property name │ │ │ │ │ + * element - {DOMElement} A DOM element node. │ │ │ │ │ + * name - {String} The CSS class name to remove. │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {String} The standard style property, prefixed property or null if not │ │ │ │ │ - * supported │ │ │ │ │ - */ │ │ │ │ │ - function style(property) { │ │ │ │ │ - return js(divStyle, property); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - return { │ │ │ │ │ - css: css, │ │ │ │ │ - js: js, │ │ │ │ │ - style: style, │ │ │ │ │ - │ │ │ │ │ - // used for testing │ │ │ │ │ - cssCache: cssCache, │ │ │ │ │ - jsCache: jsCache │ │ │ │ │ - }; │ │ │ │ │ -}()); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Animation.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/SingleFile.js │ │ │ │ │ - * @requires OpenLayers/Util/vendorPrefix.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Namespace: OpenLayers.Animation │ │ │ │ │ - * A collection of utility functions for executing methods that repaint a │ │ │ │ │ - * portion of the browser window. These methods take advantage of the │ │ │ │ │ - * browser's scheduled repaints where requestAnimationFrame is available. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Animation = (function(window) { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: isNative │ │ │ │ │ - * {Boolean} true if a native requestAnimationFrame function is available │ │ │ │ │ + * {DOMElement} The element. │ │ │ │ │ */ │ │ │ │ │ - var requestAnimationFrame = OpenLayers.Util.vendorPrefix.js(window, "requestAnimationFrame"); │ │ │ │ │ - var isNative = !!(requestAnimationFrame); │ │ │ │ │ + removeClass: function(element, name) { │ │ │ │ │ + var names = element.className; │ │ │ │ │ + if (names) { │ │ │ │ │ + element.className = OpenLayers.String.trim( │ │ │ │ │ + names.replace( │ │ │ │ │ + new RegExp("(^|\\s+)" + name + "(\\s+|$)"), " " │ │ │ │ │ + ) │ │ │ │ │ + ); │ │ │ │ │ + } │ │ │ │ │ + return element; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Function: requestFrame │ │ │ │ │ - * Schedule a function to be called at the next available animation frame. │ │ │ │ │ - * Uses the native method where available. Where requestAnimationFrame is │ │ │ │ │ - * not available, setTimeout will be called with a 16ms delay. │ │ │ │ │ + * Function: toggleClass │ │ │ │ │ + * Remove a CSS class name from an element if it exists. Add the class name │ │ │ │ │ + * if it doesn't exist. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * callback - {Function} The function to be called at the next animation frame. │ │ │ │ │ - * element - {DOMElement} Optional element that visually bounds the animation. │ │ │ │ │ + * element - {DOMElement} A DOM element node. │ │ │ │ │ + * name - {String} The CSS class name to toggle. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {DOMElement} The element. │ │ │ │ │ */ │ │ │ │ │ - var requestFrame = (function() { │ │ │ │ │ - var request = window[requestAnimationFrame] || │ │ │ │ │ - function(callback, element) { │ │ │ │ │ - window.setTimeout(callback, 16); │ │ │ │ │ - }; │ │ │ │ │ - // bind to window to avoid illegal invocation of native function │ │ │ │ │ - return function(callback, element) { │ │ │ │ │ - request.apply(window, [callback, element]); │ │ │ │ │ - }; │ │ │ │ │ - })(); │ │ │ │ │ - │ │ │ │ │ - // private variables for animation loops │ │ │ │ │ - var counter = 0; │ │ │ │ │ - var loops = {}; │ │ │ │ │ + toggleClass: function(element, name) { │ │ │ │ │ + if (OpenLayers.Element.hasClass(element, name)) { │ │ │ │ │ + OpenLayers.Element.removeClass(element, name); │ │ │ │ │ + } else { │ │ │ │ │ + OpenLayers.Element.addClass(element, name); │ │ │ │ │ + } │ │ │ │ │ + return element; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Function: start │ │ │ │ │ - * Executes a method with in series for some │ │ │ │ │ - * duration. │ │ │ │ │ - * │ │ │ │ │ + * APIFunction: getStyle │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * callback - {Function} The function to be called at the next animation frame. │ │ │ │ │ - * duration - {Number} Optional duration for the loop. If not provided, the │ │ │ │ │ - * animation loop will execute indefinitely. │ │ │ │ │ - * element - {DOMElement} Optional element that visually bounds the animation. │ │ │ │ │ - * │ │ │ │ │ + * element - {DOMElement} │ │ │ │ │ + * style - {?} │ │ │ │ │ + * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Number} Identifier for the animation loop. Used to stop animations with │ │ │ │ │ - * . │ │ │ │ │ + * {?} │ │ │ │ │ */ │ │ │ │ │ - function start(callback, duration, element) { │ │ │ │ │ - duration = duration > 0 ? duration : Number.POSITIVE_INFINITY; │ │ │ │ │ - var id = ++counter; │ │ │ │ │ - var start = +new Date; │ │ │ │ │ - loops[id] = function() { │ │ │ │ │ - if (loops[id] && +new Date - start <= duration) { │ │ │ │ │ - callback(); │ │ │ │ │ - if (loops[id]) { │ │ │ │ │ - requestFrame(loops[id], element); │ │ │ │ │ + getStyle: function(element, style) { │ │ │ │ │ + element = OpenLayers.Util.getElement(element); │ │ │ │ │ + │ │ │ │ │ + var value = null; │ │ │ │ │ + if (element && element.style) { │ │ │ │ │ + value = element.style[OpenLayers.String.camelize(style)]; │ │ │ │ │ + if (!value) { │ │ │ │ │ + if (document.defaultView && │ │ │ │ │ + document.defaultView.getComputedStyle) { │ │ │ │ │ + │ │ │ │ │ + var css = document.defaultView.getComputedStyle(element, null); │ │ │ │ │ + value = css ? css.getPropertyValue(style) : null; │ │ │ │ │ + } else if (element.currentStyle) { │ │ │ │ │ + value = element.currentStyle[OpenLayers.String.camelize(style)]; │ │ │ │ │ } │ │ │ │ │ - } else { │ │ │ │ │ - delete loops[id]; │ │ │ │ │ } │ │ │ │ │ - }; │ │ │ │ │ - requestFrame(loops[id], element); │ │ │ │ │ - return id; │ │ │ │ │ - } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Function: stop │ │ │ │ │ - * Terminates an animation loop started with . │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * id - {Number} Identifier returned from . │ │ │ │ │ - */ │ │ │ │ │ - function stop(id) { │ │ │ │ │ - delete loops[id]; │ │ │ │ │ - } │ │ │ │ │ + var positions = ['left', 'top', 'right', 'bottom']; │ │ │ │ │ + if (window.opera && │ │ │ │ │ + (OpenLayers.Util.indexOf(positions, style) != -1) && │ │ │ │ │ + (OpenLayers.Element.getStyle(element, 'position') == 'static')) { │ │ │ │ │ + value = 'auto'; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - return { │ │ │ │ │ - isNative: isNative, │ │ │ │ │ - requestFrame: requestFrame, │ │ │ │ │ - start: start, │ │ │ │ │ - stop: stop │ │ │ │ │ - }; │ │ │ │ │ + return value == 'auto' ? null : value; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ -})(window); │ │ │ │ │ +}; │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Kinetic.js │ │ │ │ │ + Rico/Color.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ +/** │ │ │ │ │ + * @requires Rico/license.js │ │ │ │ │ + * @requires OpenLayers/Console.js │ │ │ │ │ * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Animation.js │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Element.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ -OpenLayers.Kinetic = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: threshold │ │ │ │ │ - * In most cases changing the threshold isn't needed. │ │ │ │ │ - * In px/ms, default to 0. │ │ │ │ │ - */ │ │ │ │ │ - threshold: 0, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: deceleration │ │ │ │ │ - * {Float} the deseleration in px/ms², default to 0.0035. │ │ │ │ │ - */ │ │ │ │ │ - deceleration: 0.0035, │ │ │ │ │ +/* │ │ │ │ │ + * This file has been edited substantially from the Rico-released version by │ │ │ │ │ + * the OpenLayers development team. │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: nbPoints │ │ │ │ │ - * {Integer} the number of points we use to calculate the kinetic │ │ │ │ │ - * initial values. │ │ │ │ │ - */ │ │ │ │ │ - nbPoints: 100, │ │ │ │ │ +OpenLayers.Console.warn("OpenLayers.Rico is deprecated"); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: delay │ │ │ │ │ - * {Float} time to consider to calculate the kinetic initial values. │ │ │ │ │ - * In ms, default to 200. │ │ │ │ │ - */ │ │ │ │ │ - delay: 200, │ │ │ │ │ +OpenLayers.Rico = OpenLayers.Rico || {}; │ │ │ │ │ +OpenLayers.Rico.Color = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: points │ │ │ │ │ - * List of points use to calculate the kinetic initial values. │ │ │ │ │ - */ │ │ │ │ │ - points: undefined, │ │ │ │ │ + initialize: function(red, green, blue) { │ │ │ │ │ + this.rgb = { │ │ │ │ │ + r: red, │ │ │ │ │ + g: green, │ │ │ │ │ + b: blue │ │ │ │ │ + }; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: timerId │ │ │ │ │ - * ID of the timer. │ │ │ │ │ - */ │ │ │ │ │ - timerId: undefined, │ │ │ │ │ + setRed: function(r) { │ │ │ │ │ + this.rgb.r = r; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Kinetic │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(options) { │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ + setGreen: function(g) { │ │ │ │ │ + this.rgb.g = g; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: begin │ │ │ │ │ - * Begins the dragging. │ │ │ │ │ - */ │ │ │ │ │ - begin: function() { │ │ │ │ │ - OpenLayers.Animation.stop(this.timerId); │ │ │ │ │ - this.timerId = undefined; │ │ │ │ │ - this.points = []; │ │ │ │ │ + setBlue: function(b) { │ │ │ │ │ + this.rgb.b = b; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: update │ │ │ │ │ - * Updates during the dragging. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * xy - {} The new position. │ │ │ │ │ - */ │ │ │ │ │ - update: function(xy) { │ │ │ │ │ - this.points.unshift({ │ │ │ │ │ - xy: xy, │ │ │ │ │ - tick: new Date().getTime() │ │ │ │ │ - }); │ │ │ │ │ - if (this.points.length > this.nbPoints) { │ │ │ │ │ - this.points.pop(); │ │ │ │ │ - } │ │ │ │ │ + setHue: function(h) { │ │ │ │ │ + │ │ │ │ │ + // get an HSB model, and set the new hue... │ │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ │ + hsb.h = h; │ │ │ │ │ + │ │ │ │ │ + // convert back to RGB... │ │ │ │ │ + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: end │ │ │ │ │ - * Ends the dragging, start the kinetic. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * xy - {} The last position. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} An object with two properties: "speed", and "theta". The │ │ │ │ │ - * "speed" and "theta" values are to be passed to the move │ │ │ │ │ - * function when starting the animation. │ │ │ │ │ - */ │ │ │ │ │ - end: function(xy) { │ │ │ │ │ - var last, now = new Date().getTime(); │ │ │ │ │ - for (var i = 0, l = this.points.length, point; i < l; i++) { │ │ │ │ │ - point = this.points[i]; │ │ │ │ │ - if (now - point.tick > this.delay) { │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - last = point; │ │ │ │ │ - } │ │ │ │ │ - if (!last) { │ │ │ │ │ - return; │ │ │ │ │ - } │ │ │ │ │ - var time = new Date().getTime() - last.tick; │ │ │ │ │ - var dist = Math.sqrt(Math.pow(xy.x - last.xy.x, 2) + │ │ │ │ │ - Math.pow(xy.y - last.xy.y, 2)); │ │ │ │ │ - var speed = dist / time; │ │ │ │ │ - if (speed == 0 || speed < this.threshold) { │ │ │ │ │ - return; │ │ │ │ │ - } │ │ │ │ │ - var theta = Math.asin((xy.y - last.xy.y) / dist); │ │ │ │ │ - if (last.xy.x <= xy.x) { │ │ │ │ │ - theta = Math.PI - theta; │ │ │ │ │ - } │ │ │ │ │ - return { │ │ │ │ │ - speed: speed, │ │ │ │ │ - theta: theta │ │ │ │ │ - }; │ │ │ │ │ + setSaturation: function(s) { │ │ │ │ │ + // get an HSB model, and set the new hue... │ │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ │ + hsb.s = s; │ │ │ │ │ + │ │ │ │ │ + // convert back to RGB and set values... │ │ │ │ │ + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: move │ │ │ │ │ - * Launch the kinetic move pan. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * info - {Object} An object with two properties, "speed", and "theta". │ │ │ │ │ - * These values are those returned from the "end" call. │ │ │ │ │ - * callback - {Function} Function called on every step of the animation, │ │ │ │ │ - * receives x, y (values to pan), end (is the last point). │ │ │ │ │ - */ │ │ │ │ │ - move: function(info, callback) { │ │ │ │ │ - var v0 = info.speed; │ │ │ │ │ - var fx = Math.cos(info.theta); │ │ │ │ │ - var fy = -Math.sin(info.theta); │ │ │ │ │ + setBrightness: function(b) { │ │ │ │ │ + // get an HSB model, and set the new hue... │ │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ │ + hsb.b = b; │ │ │ │ │ │ │ │ │ │ - var initialTime = new Date().getTime(); │ │ │ │ │ + // convert back to RGB and set values... │ │ │ │ │ + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var lastX = 0; │ │ │ │ │ - var lastY = 0; │ │ │ │ │ + darken: function(percent) { │ │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ │ + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent, 0)); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var timerCallback = function() { │ │ │ │ │ - if (this.timerId == null) { │ │ │ │ │ - return; │ │ │ │ │ - } │ │ │ │ │ + brighten: function(percent) { │ │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ │ + this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent, 1)); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var t = new Date().getTime() - initialTime; │ │ │ │ │ + blend: function(other) { │ │ │ │ │ + this.rgb.r = Math.floor((this.rgb.r + other.rgb.r) / 2); │ │ │ │ │ + this.rgb.g = Math.floor((this.rgb.g + other.rgb.g) / 2); │ │ │ │ │ + this.rgb.b = Math.floor((this.rgb.b + other.rgb.b) / 2); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var p = (-this.deceleration * Math.pow(t, 2)) / 2.0 + v0 * t; │ │ │ │ │ - var x = p * fx; │ │ │ │ │ - var y = p * fy; │ │ │ │ │ + isBright: function() { │ │ │ │ │ + var hsb = this.asHSB(); │ │ │ │ │ + return this.asHSB().b > 0.5; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var args = {}; │ │ │ │ │ - args.end = false; │ │ │ │ │ - var v = -this.deceleration * t + v0; │ │ │ │ │ + isDark: function() { │ │ │ │ │ + return !this.isBright(); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (v <= 0) { │ │ │ │ │ - OpenLayers.Animation.stop(this.timerId); │ │ │ │ │ - this.timerId = null; │ │ │ │ │ - args.end = true; │ │ │ │ │ - } │ │ │ │ │ + asRGB: function() { │ │ │ │ │ + return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")"; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - args.x = x - lastX; │ │ │ │ │ - args.y = y - lastY; │ │ │ │ │ - lastX = x; │ │ │ │ │ - lastY = y; │ │ │ │ │ - callback(args.x, args.y, args.end); │ │ │ │ │ - }; │ │ │ │ │ + asHex: function() { │ │ │ │ │ + return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart(); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - this.timerId = OpenLayers.Animation.start( │ │ │ │ │ - OpenLayers.Function.bind(timerCallback, this) │ │ │ │ │ - ); │ │ │ │ │ + asHSB: function() { │ │ │ │ │ + return OpenLayers.Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Kinetic" │ │ │ │ │ + toString: function() { │ │ │ │ │ + return this.asHex(); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ }); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Tween.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ +OpenLayers.Rico.Color.createFromHex = function(hexCode) { │ │ │ │ │ + if (hexCode.length == 4) { │ │ │ │ │ + var shortHexCode = hexCode; │ │ │ │ │ + var hexCode = '#'; │ │ │ │ │ + for (var i = 1; i < 4; i++) { │ │ │ │ │ + hexCode += (shortHexCode.charAt(i) + │ │ │ │ │ + shortHexCode.charAt(i)); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + if (hexCode.indexOf('#') == 0) { │ │ │ │ │ + hexCode = hexCode.substring(1); │ │ │ │ │ + } │ │ │ │ │ + var red = hexCode.substring(0, 2); │ │ │ │ │ + var green = hexCode.substring(2, 4); │ │ │ │ │ + var blue = hexCode.substring(4, 6); │ │ │ │ │ + return new OpenLayers.Rico.Color(parseInt(red, 16), parseInt(green, 16), parseInt(blue, 16)); │ │ │ │ │ +}; │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Animation.js │ │ │ │ │ + * Factory method for creating a color from the background of │ │ │ │ │ + * an HTML element. │ │ │ │ │ */ │ │ │ │ │ +OpenLayers.Rico.Color.createColorFromBackground = function(elem) { │ │ │ │ │ + │ │ │ │ │ + var actualColor = │ │ │ │ │ + OpenLayers.Element.getStyle(OpenLayers.Util.getElement(elem), │ │ │ │ │ + "backgroundColor"); │ │ │ │ │ + │ │ │ │ │ + if (actualColor == "transparent" && elem.parentNode) { │ │ │ │ │ + return OpenLayers.Rico.Color.createColorFromBackground(elem.parentNode); │ │ │ │ │ + } │ │ │ │ │ + if (actualColor == null) { │ │ │ │ │ + return new OpenLayers.Rico.Color(255, 255, 255); │ │ │ │ │ + } │ │ │ │ │ + if (actualColor.indexOf("rgb(") == 0) { │ │ │ │ │ + var colors = actualColor.substring(4, actualColor.length - 1); │ │ │ │ │ + var colorArray = colors.split(","); │ │ │ │ │ + return new OpenLayers.Rico.Color(parseInt(colorArray[0]), │ │ │ │ │ + parseInt(colorArray[1]), │ │ │ │ │ + parseInt(colorArray[2])); │ │ │ │ │ + │ │ │ │ │ + } else if (actualColor.indexOf("#") == 0) { │ │ │ │ │ + return OpenLayers.Rico.Color.createFromHex(actualColor); │ │ │ │ │ + } else { │ │ │ │ │ + return new OpenLayers.Rico.Color(255, 255, 255); │ │ │ │ │ + } │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +OpenLayers.Rico.Color.HSBtoRGB = function(hue, saturation, brightness) { │ │ │ │ │ + │ │ │ │ │ + var red = 0; │ │ │ │ │ + var green = 0; │ │ │ │ │ + var blue = 0; │ │ │ │ │ + │ │ │ │ │ + if (saturation == 0) { │ │ │ │ │ + red = parseInt(brightness * 255.0 + 0.5); │ │ │ │ │ + green = red; │ │ │ │ │ + blue = red; │ │ │ │ │ + } else { │ │ │ │ │ + var h = (hue - Math.floor(hue)) * 6.0; │ │ │ │ │ + var f = h - Math.floor(h); │ │ │ │ │ + var p = brightness * (1.0 - saturation); │ │ │ │ │ + var q = brightness * (1.0 - saturation * f); │ │ │ │ │ + var t = brightness * (1.0 - (saturation * (1.0 - f))); │ │ │ │ │ + │ │ │ │ │ + switch (parseInt(h)) { │ │ │ │ │ + case 0: │ │ │ │ │ + red = (brightness * 255.0 + 0.5); │ │ │ │ │ + green = (t * 255.0 + 0.5); │ │ │ │ │ + blue = (p * 255.0 + 0.5); │ │ │ │ │ + break; │ │ │ │ │ + case 1: │ │ │ │ │ + red = (q * 255.0 + 0.5); │ │ │ │ │ + green = (brightness * 255.0 + 0.5); │ │ │ │ │ + blue = (p * 255.0 + 0.5); │ │ │ │ │ + break; │ │ │ │ │ + case 2: │ │ │ │ │ + red = (p * 255.0 + 0.5); │ │ │ │ │ + green = (brightness * 255.0 + 0.5); │ │ │ │ │ + blue = (t * 255.0 + 0.5); │ │ │ │ │ + break; │ │ │ │ │ + case 3: │ │ │ │ │ + red = (p * 255.0 + 0.5); │ │ │ │ │ + green = (q * 255.0 + 0.5); │ │ │ │ │ + blue = (brightness * 255.0 + 0.5); │ │ │ │ │ + break; │ │ │ │ │ + case 4: │ │ │ │ │ + red = (t * 255.0 + 0.5); │ │ │ │ │ + green = (p * 255.0 + 0.5); │ │ │ │ │ + blue = (brightness * 255.0 + 0.5); │ │ │ │ │ + break; │ │ │ │ │ + case 5: │ │ │ │ │ + red = (brightness * 255.0 + 0.5); │ │ │ │ │ + green = (p * 255.0 + 0.5); │ │ │ │ │ + blue = (q * 255.0 + 0.5); │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + return { │ │ │ │ │ + r: parseInt(red), │ │ │ │ │ + g: parseInt(green), │ │ │ │ │ + b: parseInt(blue) │ │ │ │ │ + }; │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +OpenLayers.Rico.Color.RGBtoHSB = function(r, g, b) { │ │ │ │ │ + │ │ │ │ │ + var hue; │ │ │ │ │ + var saturation; │ │ │ │ │ + var brightness; │ │ │ │ │ + │ │ │ │ │ + var cmax = (r > g) ? r : g; │ │ │ │ │ + if (b > cmax) { │ │ │ │ │ + cmax = b; │ │ │ │ │ + } │ │ │ │ │ + var cmin = (r < g) ? r : g; │ │ │ │ │ + if (b < cmin) { │ │ │ │ │ + cmin = b; │ │ │ │ │ + } │ │ │ │ │ + brightness = cmax / 255.0; │ │ │ │ │ + if (cmax != 0) { │ │ │ │ │ + saturation = (cmax - cmin) / cmax; │ │ │ │ │ + } else { │ │ │ │ │ + saturation = 0; │ │ │ │ │ + } │ │ │ │ │ + if (saturation == 0) { │ │ │ │ │ + hue = 0; │ │ │ │ │ + } else { │ │ │ │ │ + var redc = (cmax - r) / (cmax - cmin); │ │ │ │ │ + var greenc = (cmax - g) / (cmax - cmin); │ │ │ │ │ + var bluec = (cmax - b) / (cmax - cmin); │ │ │ │ │ + │ │ │ │ │ + if (r == cmax) { │ │ │ │ │ + hue = bluec - greenc; │ │ │ │ │ + } else if (g == cmax) { │ │ │ │ │ + hue = 2.0 + redc - bluec; │ │ │ │ │ + } else { │ │ │ │ │ + hue = 4.0 + greenc - redc; │ │ │ │ │ + } │ │ │ │ │ + hue = hue / 6.0; │ │ │ │ │ + if (hue < 0) { │ │ │ │ │ + hue = hue + 1.0; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + return { │ │ │ │ │ + h: hue, │ │ │ │ │ + s: saturation, │ │ │ │ │ + b: brightness │ │ │ │ │ + }; │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + Rico/Corner.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Namespace: OpenLayers.Tween │ │ │ │ │ + * @requires OpenLayers/Console.js │ │ │ │ │ + * @requires Rico/Color.js │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Tween = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: easing │ │ │ │ │ - * {(Function)} Easing equation used for the animation │ │ │ │ │ - * Defaultly set to OpenLayers.Easing.Expo.easeOut │ │ │ │ │ - */ │ │ │ │ │ - easing: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: begin │ │ │ │ │ - * {Object} Values to start the animation with │ │ │ │ │ - */ │ │ │ │ │ - begin: null, │ │ │ │ │ +/* │ │ │ │ │ + * This file has been edited substantially from the Rico-released │ │ │ │ │ + * version by the OpenLayers development team. │ │ │ │ │ + * │ │ │ │ │ + * Copyright 2005 Sabre Airline Solutions │ │ │ │ │ + * │ │ │ │ │ + * Licensed under the Apache License, Version 2.0 (the "License"); │ │ │ │ │ + * you may not use this file except in compliance with the │ │ │ │ │ + * License. You may obtain a copy of the License at │ │ │ │ │ + * │ │ │ │ │ + * http://www.apache.org/licenses/LICENSE-2.0 │ │ │ │ │ + * │ │ │ │ │ + * Unless required by applicable law or agreed to in writing, software │ │ │ │ │ + * distributed under the * License is distributed on an "AS IS" BASIS, │ │ │ │ │ + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or │ │ │ │ │ + * implied. See the License for the specific language governing │ │ │ │ │ + * permissions * and limitations under the License. │ │ │ │ │ + * │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: finish │ │ │ │ │ - * {Object} Values to finish the animation with │ │ │ │ │ - */ │ │ │ │ │ - finish: null, │ │ │ │ │ +OpenLayers.Console.warn("OpenLayers.Rico is deprecated"); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: duration │ │ │ │ │ - * {int} duration of the tween (number of steps) │ │ │ │ │ - */ │ │ │ │ │ - duration: null, │ │ │ │ │ +OpenLayers.Rico = OpenLayers.Rico || {}; │ │ │ │ │ +OpenLayers.Rico.Corner = { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: callbacks │ │ │ │ │ - * {Object} An object with start, eachStep and done properties whose values │ │ │ │ │ - * are functions to be call during the animation. They are passed the │ │ │ │ │ - * current computed value as argument. │ │ │ │ │ - */ │ │ │ │ │ - callbacks: null, │ │ │ │ │ + round: function(e, options) { │ │ │ │ │ + e = OpenLayers.Util.getElement(e); │ │ │ │ │ + this._setOptions(options); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: time │ │ │ │ │ - * {int} Step counter │ │ │ │ │ - */ │ │ │ │ │ - time: null, │ │ │ │ │ + var color = this.options.color; │ │ │ │ │ + if (this.options.color == "fromElement") { │ │ │ │ │ + color = this._background(e); │ │ │ │ │ + } │ │ │ │ │ + var bgColor = this.options.bgColor; │ │ │ │ │ + if (this.options.bgColor == "fromParent") { │ │ │ │ │ + bgColor = this._background(e.offsetParent); │ │ │ │ │ + } │ │ │ │ │ + this._roundCornersImpl(e, color, bgColor); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: minFrameRate │ │ │ │ │ - * {Number} The minimum framerate for animations in frames per second. After │ │ │ │ │ - * each step, the time spent in the animation is compared to the calculated │ │ │ │ │ - * time at this frame rate. If the animation runs longer than the calculated │ │ │ │ │ - * time, the next step is skipped. Default is 30. │ │ │ │ │ + /** This is a helper function to change the background │ │ │ │ │ + * color of
that has had Rico rounded corners added. │ │ │ │ │ + * │ │ │ │ │ + * It seems we cannot just set the background color for the │ │ │ │ │ + * outer
so each element used to create the │ │ │ │ │ + * corners must have its background color set individually. │ │ │ │ │ + * │ │ │ │ │ + * @param {DOM} theDiv - A child of the outer
that was │ │ │ │ │ + * supplied to the `round` method. │ │ │ │ │ + * │ │ │ │ │ + * @param {String} newColor - The new background color to use. │ │ │ │ │ */ │ │ │ │ │ - minFrameRate: null, │ │ │ │ │ + changeColor: function(theDiv, newColor) { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: startTime │ │ │ │ │ - * {Number} The timestamp of the first execution step. Used for skipping │ │ │ │ │ - * frames │ │ │ │ │ - */ │ │ │ │ │ - startTime: null, │ │ │ │ │ + theDiv.style.backgroundColor = newColor; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: animationId │ │ │ │ │ - * {int} Loop id returned by OpenLayers.Animation.start │ │ │ │ │ - */ │ │ │ │ │ - animationId: null, │ │ │ │ │ + var spanElements = theDiv.parentNode.getElementsByTagName("span"); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: playing │ │ │ │ │ - * {Boolean} Tells if the easing is currently playing │ │ │ │ │ - */ │ │ │ │ │ - playing: false, │ │ │ │ │ + for (var currIdx = 0; currIdx < spanElements.length; currIdx++) { │ │ │ │ │ + spanElements[currIdx].style.backgroundColor = newColor; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Tween │ │ │ │ │ - * Creates a Tween. │ │ │ │ │ + │ │ │ │ │ + /** This is a helper function to change the background │ │ │ │ │ + * opacity of
that has had Rico rounded corners added. │ │ │ │ │ * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * easing - {(Function)} easing function method to use │ │ │ │ │ + * See changeColor (above) for algorithm explanation │ │ │ │ │ + * │ │ │ │ │ + * @param {DOM} theDiv A child of the outer
that was │ │ │ │ │ + * supplied to the `round` method. │ │ │ │ │ + * │ │ │ │ │ + * @param {int} newOpacity The new opacity to use (0-1). │ │ │ │ │ */ │ │ │ │ │ - initialize: function(easing) { │ │ │ │ │ - this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut; │ │ │ │ │ - }, │ │ │ │ │ + changeOpacity: function(theDiv, newOpacity) { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: start │ │ │ │ │ - * Plays the Tween, and calls the callback method on each step │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * begin - {Object} values to start the animation with │ │ │ │ │ - * finish - {Object} values to finish the animation with │ │ │ │ │ - * duration - {int} duration of the tween (number of steps) │ │ │ │ │ - * options - {Object} hash of options (callbacks (start, eachStep, done), │ │ │ │ │ - * minFrameRate) │ │ │ │ │ - */ │ │ │ │ │ - start: function(begin, finish, duration, options) { │ │ │ │ │ - this.playing = true; │ │ │ │ │ - this.begin = begin; │ │ │ │ │ - this.finish = finish; │ │ │ │ │ - this.duration = duration; │ │ │ │ │ - this.callbacks = options.callbacks; │ │ │ │ │ - this.minFrameRate = options.minFrameRate || 30; │ │ │ │ │ - this.time = 0; │ │ │ │ │ - this.startTime = new Date().getTime(); │ │ │ │ │ - OpenLayers.Animation.stop(this.animationId); │ │ │ │ │ - this.animationId = null; │ │ │ │ │ - if (this.callbacks && this.callbacks.start) { │ │ │ │ │ - this.callbacks.start.call(this, this.begin); │ │ │ │ │ + var mozillaOpacity = newOpacity; │ │ │ │ │ + var ieOpacity = 'alpha(opacity=' + newOpacity * 100 + ')'; │ │ │ │ │ + │ │ │ │ │ + theDiv.style.opacity = mozillaOpacity; │ │ │ │ │ + theDiv.style.filter = ieOpacity; │ │ │ │ │ + │ │ │ │ │ + var spanElements = theDiv.parentNode.getElementsByTagName("span"); │ │ │ │ │ + │ │ │ │ │ + for (var currIdx = 0; currIdx < spanElements.length; currIdx++) { │ │ │ │ │ + spanElements[currIdx].style.opacity = mozillaOpacity; │ │ │ │ │ + spanElements[currIdx].style.filter = ieOpacity; │ │ │ │ │ } │ │ │ │ │ - this.animationId = OpenLayers.Animation.start( │ │ │ │ │ - OpenLayers.Function.bind(this.play, this) │ │ │ │ │ - ); │ │ │ │ │ + │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: stop │ │ │ │ │ - * Stops the Tween, and calls the done callback │ │ │ │ │ - * Doesn't do anything if animation is already finished │ │ │ │ │ + /** this function takes care of redoing the rico cornering │ │ │ │ │ + * │ │ │ │ │ + * you can't just call updateRicoCorners() again and pass it a │ │ │ │ │ + * new options string. you have to first remove the divs that │ │ │ │ │ + * rico puts on top and below the content div. │ │ │ │ │ + * │ │ │ │ │ + * @param {DOM} theDiv - A child of the outer
that was │ │ │ │ │ + * supplied to the `round` method. │ │ │ │ │ + * │ │ │ │ │ + * @param {Object} options - list of options │ │ │ │ │ */ │ │ │ │ │ - stop: function() { │ │ │ │ │ - if (!this.playing) { │ │ │ │ │ - return; │ │ │ │ │ - } │ │ │ │ │ + reRound: function(theDiv, options) { │ │ │ │ │ │ │ │ │ │ - if (this.callbacks && this.callbacks.done) { │ │ │ │ │ - this.callbacks.done.call(this, this.finish); │ │ │ │ │ + var topRico = theDiv.parentNode.childNodes[0]; │ │ │ │ │ + //theDiv would be theDiv.parentNode.childNodes[1] │ │ │ │ │ + var bottomRico = theDiv.parentNode.childNodes[2]; │ │ │ │ │ + │ │ │ │ │ + theDiv.parentNode.removeChild(topRico); │ │ │ │ │ + theDiv.parentNode.removeChild(bottomRico); │ │ │ │ │ + │ │ │ │ │ + this.round(theDiv.parentNode, options); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + _roundCornersImpl: function(e, color, bgColor) { │ │ │ │ │ + if (this.options.border) { │ │ │ │ │ + this._renderBorder(e, bgColor); │ │ │ │ │ + } │ │ │ │ │ + if (this._isTopRounded()) { │ │ │ │ │ + this._roundTopCorners(e, color, bgColor); │ │ │ │ │ + } │ │ │ │ │ + if (this._isBottomRounded()) { │ │ │ │ │ + this._roundBottomCorners(e, color, bgColor); │ │ │ │ │ } │ │ │ │ │ - OpenLayers.Animation.stop(this.animationId); │ │ │ │ │ - this.animationId = null; │ │ │ │ │ - this.playing = false; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: play │ │ │ │ │ - * Calls the appropriate easing method │ │ │ │ │ - */ │ │ │ │ │ - play: function() { │ │ │ │ │ - var value = {}; │ │ │ │ │ - for (var i in this.begin) { │ │ │ │ │ - var b = this.begin[i]; │ │ │ │ │ - var f = this.finish[i]; │ │ │ │ │ - if (b == null || f == null || isNaN(b) || isNaN(f)) { │ │ │ │ │ - throw new TypeError('invalid value for Tween'); │ │ │ │ │ - } │ │ │ │ │ + _renderBorder: function(el, bgColor) { │ │ │ │ │ + var borderValue = "1px solid " + this._borderColor(bgColor); │ │ │ │ │ + var borderL = "border-left: " + borderValue; │ │ │ │ │ + var borderR = "border-right: " + borderValue; │ │ │ │ │ + var style = "style='" + borderL + ";" + borderR + "'"; │ │ │ │ │ + el.innerHTML = "
" + el.innerHTML + "
"; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var c = f - b; │ │ │ │ │ - value[i] = this.easing.apply(this, [this.time, b, c, this.duration]); │ │ │ │ │ + _roundTopCorners: function(el, color, bgColor) { │ │ │ │ │ + var corner = this._createCorner(bgColor); │ │ │ │ │ + for (var i = 0; i < this.options.numSlices; i++) { │ │ │ │ │ + corner.appendChild(this._createCornerSlice(color, bgColor, i, "top")); │ │ │ │ │ } │ │ │ │ │ - this.time++; │ │ │ │ │ + el.style.paddingTop = 0; │ │ │ │ │ + el.insertBefore(corner, el.firstChild); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (this.callbacks && this.callbacks.eachStep) { │ │ │ │ │ - // skip frames if frame rate drops below threshold │ │ │ │ │ - if ((new Date().getTime() - this.startTime) / this.time <= 1000 / this.minFrameRate) { │ │ │ │ │ - this.callbacks.eachStep.call(this, value); │ │ │ │ │ - } │ │ │ │ │ + _roundBottomCorners: function(el, color, bgColor) { │ │ │ │ │ + var corner = this._createCorner(bgColor); │ │ │ │ │ + for (var i = (this.options.numSlices - 1); i >= 0; i--) { │ │ │ │ │ + corner.appendChild(this._createCornerSlice(color, bgColor, i, "bottom")); │ │ │ │ │ } │ │ │ │ │ + el.style.paddingBottom = 0; │ │ │ │ │ + el.appendChild(corner); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (this.time > this.duration) { │ │ │ │ │ - this.stop(); │ │ │ │ │ - } │ │ │ │ │ + _createCorner: function(bgColor) { │ │ │ │ │ + var corner = document.createElement("div"); │ │ │ │ │ + corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor); │ │ │ │ │ + return corner; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Create empty functions for all easing methods. │ │ │ │ │ - */ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Tween" │ │ │ │ │ -}); │ │ │ │ │ + _createCornerSlice: function(color, bgColor, n, position) { │ │ │ │ │ + var slice = document.createElement("span"); │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Namespace: OpenLayers.Easing │ │ │ │ │ - * │ │ │ │ │ - * Credits: │ │ │ │ │ - * Easing Equations by Robert Penner, │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Easing = { │ │ │ │ │ - /** │ │ │ │ │ - * Create empty functions for all easing methods. │ │ │ │ │ - */ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Easing" │ │ │ │ │ -}; │ │ │ │ │ + var inStyle = slice.style; │ │ │ │ │ + inStyle.backgroundColor = color; │ │ │ │ │ + inStyle.display = "block"; │ │ │ │ │ + inStyle.height = "1px"; │ │ │ │ │ + inStyle.overflow = "hidden"; │ │ │ │ │ + inStyle.fontSize = "1px"; │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Namespace: OpenLayers.Easing.Linear │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Easing.Linear = { │ │ │ │ │ + var borderColor = this._borderColor(color, bgColor); │ │ │ │ │ + if (this.options.border && n == 0) { │ │ │ │ │ + inStyle.borderTopStyle = "solid"; │ │ │ │ │ + inStyle.borderTopWidth = "1px"; │ │ │ │ │ + inStyle.borderLeftWidth = "0px"; │ │ │ │ │ + inStyle.borderRightWidth = "0px"; │ │ │ │ │ + inStyle.borderBottomWidth = "0px"; │ │ │ │ │ + inStyle.height = "0px"; // assumes css compliant box model │ │ │ │ │ + inStyle.borderColor = borderColor; │ │ │ │ │ + } else if (borderColor) { │ │ │ │ │ + inStyle.borderColor = borderColor; │ │ │ │ │ + inStyle.borderStyle = "solid"; │ │ │ │ │ + inStyle.borderWidth = "0px 1px"; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Function: easeIn │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * t - {Float} time │ │ │ │ │ - * b - {Float} beginning position │ │ │ │ │ - * c - {Float} total change │ │ │ │ │ - * d - {Float} duration of the transition │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Float} │ │ │ │ │ - */ │ │ │ │ │ - easeIn: function(t, b, c, d) { │ │ │ │ │ - return c * t / d + b; │ │ │ │ │ + if (!this.options.compact && (n == (this.options.numSlices - 1))) { │ │ │ │ │ + inStyle.height = "2px"; │ │ │ │ │ + } │ │ │ │ │ + this._setMargin(slice, n, position); │ │ │ │ │ + this._setBorder(slice, n, position); │ │ │ │ │ + return slice; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Function: easeOut │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * t - {Float} time │ │ │ │ │ - * b - {Float} beginning position │ │ │ │ │ - * c - {Float} total change │ │ │ │ │ - * d - {Float} duration of the transition │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Float} │ │ │ │ │ - */ │ │ │ │ │ - easeOut: function(t, b, c, d) { │ │ │ │ │ - return c * t / d + b; │ │ │ │ │ - }, │ │ │ │ │ + _setOptions: function(options) { │ │ │ │ │ + this.options = { │ │ │ │ │ + corners: "all", │ │ │ │ │ + color: "fromElement", │ │ │ │ │ + bgColor: "fromParent", │ │ │ │ │ + blend: true, │ │ │ │ │ + border: false, │ │ │ │ │ + compact: false │ │ │ │ │ + }; │ │ │ │ │ + OpenLayers.Util.extend(this.options, options || {}); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Function: easeInOut │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * t - {Float} time │ │ │ │ │ - * b - {Float} beginning position │ │ │ │ │ - * c - {Float} total change │ │ │ │ │ - * d - {Float} duration of the transition │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Float} │ │ │ │ │ - */ │ │ │ │ │ - easeInOut: function(t, b, c, d) { │ │ │ │ │ - return c * t / d + b; │ │ │ │ │ + this.options.numSlices = this.options.compact ? 2 : 4; │ │ │ │ │ + if (this._isTransparent()) { │ │ │ │ │ + this.options.blend = false; │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Easing.Linear" │ │ │ │ │ -}; │ │ │ │ │ + _whichSideTop: function() { │ │ │ │ │ + if (this._hasString(this.options.corners, "all", "top")) { │ │ │ │ │ + return ""; │ │ │ │ │ + } │ │ │ │ │ + if (this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0) { │ │ │ │ │ + return ""; │ │ │ │ │ + } │ │ │ │ │ + if (this.options.corners.indexOf("tl") >= 0) { │ │ │ │ │ + return "left"; │ │ │ │ │ + } else if (this.options.corners.indexOf("tr") >= 0) { │ │ │ │ │ + return "right"; │ │ │ │ │ + } │ │ │ │ │ + return ""; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Namespace: OpenLayers.Easing.Expo │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Easing.Expo = { │ │ │ │ │ + _whichSideBottom: function() { │ │ │ │ │ + if (this._hasString(this.options.corners, "all", "bottom")) { │ │ │ │ │ + return ""; │ │ │ │ │ + } │ │ │ │ │ + if (this.options.corners.indexOf("bl") >= 0 && this.options.corners.indexOf("br") >= 0) { │ │ │ │ │ + return ""; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Function: easeIn │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * t - {Float} time │ │ │ │ │ - * b - {Float} beginning position │ │ │ │ │ - * c - {Float} total change │ │ │ │ │ - * d - {Float} duration of the transition │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Float} │ │ │ │ │ - */ │ │ │ │ │ - easeIn: function(t, b, c, d) { │ │ │ │ │ - return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b; │ │ │ │ │ + if (this.options.corners.indexOf("bl") >= 0) { │ │ │ │ │ + return "left"; │ │ │ │ │ + } else if (this.options.corners.indexOf("br") >= 0) { │ │ │ │ │ + return "right"; │ │ │ │ │ + } │ │ │ │ │ + return ""; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Function: easeOut │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * t - {Float} time │ │ │ │ │ - * b - {Float} beginning position │ │ │ │ │ - * c - {Float} total change │ │ │ │ │ - * d - {Float} duration of the transition │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Float} │ │ │ │ │ - */ │ │ │ │ │ - easeOut: function(t, b, c, d) { │ │ │ │ │ - return (t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b; │ │ │ │ │ + _borderColor: function(color, bgColor) { │ │ │ │ │ + if (color == "transparent") { │ │ │ │ │ + return bgColor; │ │ │ │ │ + } else if (this.options.border) { │ │ │ │ │ + return this.options.border; │ │ │ │ │ + } else if (this.options.blend) { │ │ │ │ │ + return this._blend(bgColor, color); │ │ │ │ │ + } else { │ │ │ │ │ + return ""; │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Function: easeInOut │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * t - {Float} time │ │ │ │ │ - * b - {Float} beginning position │ │ │ │ │ - * c - {Float} total change │ │ │ │ │ - * d - {Float} duration of the transition │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Float} │ │ │ │ │ - */ │ │ │ │ │ - easeInOut: function(t, b, c, d) { │ │ │ │ │ - if (t == 0) return b; │ │ │ │ │ - if (t == d) return b + c; │ │ │ │ │ - if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b; │ │ │ │ │ - return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b; │ │ │ │ │ - }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Easing.Expo" │ │ │ │ │ -}; │ │ │ │ │ + _setMargin: function(el, n, corners) { │ │ │ │ │ + var marginSize = this._marginSize(n); │ │ │ │ │ + var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom(); │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Namespace: OpenLayers.Easing.Quad │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Easing.Quad = { │ │ │ │ │ + if (whichSide == "left") { │ │ │ │ │ + el.style.marginLeft = marginSize + "px"; │ │ │ │ │ + el.style.marginRight = "0px"; │ │ │ │ │ + } else if (whichSide == "right") { │ │ │ │ │ + el.style.marginRight = marginSize + "px"; │ │ │ │ │ + el.style.marginLeft = "0px"; │ │ │ │ │ + } else { │ │ │ │ │ + el.style.marginLeft = marginSize + "px"; │ │ │ │ │ + el.style.marginRight = marginSize + "px"; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Function: easeIn │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * t - {Float} time │ │ │ │ │ - * b - {Float} beginning position │ │ │ │ │ - * c - {Float} total change │ │ │ │ │ - * d - {Float} duration of the transition │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Float} │ │ │ │ │ - */ │ │ │ │ │ - easeIn: function(t, b, c, d) { │ │ │ │ │ - return c * (t /= d) * t + b; │ │ │ │ │ + _setBorder: function(el, n, corners) { │ │ │ │ │ + var borderSize = this._borderSize(n); │ │ │ │ │ + var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom(); │ │ │ │ │ + if (whichSide == "left") { │ │ │ │ │ + el.style.borderLeftWidth = borderSize + "px"; │ │ │ │ │ + el.style.borderRightWidth = "0px"; │ │ │ │ │ + } else if (whichSide == "right") { │ │ │ │ │ + el.style.borderRightWidth = borderSize + "px"; │ │ │ │ │ + el.style.borderLeftWidth = "0px"; │ │ │ │ │ + } else { │ │ │ │ │ + el.style.borderLeftWidth = borderSize + "px"; │ │ │ │ │ + el.style.borderRightWidth = borderSize + "px"; │ │ │ │ │ + } │ │ │ │ │ + if (this.options.border != false) { │ │ │ │ │ + el.style.borderLeftWidth = borderSize + "px"; │ │ │ │ │ + el.style.borderRightWidth = borderSize + "px"; │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Function: easeOut │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * t - {Float} time │ │ │ │ │ - * b - {Float} beginning position │ │ │ │ │ - * c - {Float} total change │ │ │ │ │ - * d - {Float} duration of the transition │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Float} │ │ │ │ │ - */ │ │ │ │ │ - easeOut: function(t, b, c, d) { │ │ │ │ │ - return -c * (t /= d) * (t - 2) + b; │ │ │ │ │ + _marginSize: function(n) { │ │ │ │ │ + if (this._isTransparent()) { │ │ │ │ │ + return 0; │ │ │ │ │ + } │ │ │ │ │ + var marginSizes = [5, 3, 2, 1]; │ │ │ │ │ + var blendedMarginSizes = [3, 2, 1, 0]; │ │ │ │ │ + var compactMarginSizes = [2, 1]; │ │ │ │ │ + var smBlendedMarginSizes = [1, 0]; │ │ │ │ │ + │ │ │ │ │ + if (this.options.compact && this.options.blend) { │ │ │ │ │ + return smBlendedMarginSizes[n]; │ │ │ │ │ + } else if (this.options.compact) { │ │ │ │ │ + return compactMarginSizes[n]; │ │ │ │ │ + } else if (this.options.blend) { │ │ │ │ │ + return blendedMarginSizes[n]; │ │ │ │ │ + } else { │ │ │ │ │ + return marginSizes[n]; │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Function: easeInOut │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * t - {Float} time │ │ │ │ │ - * b - {Float} beginning position │ │ │ │ │ - * c - {Float} total change │ │ │ │ │ - * d - {Float} duration of the transition │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Float} │ │ │ │ │ - */ │ │ │ │ │ - easeInOut: function(t, b, c, d) { │ │ │ │ │ - if ((t /= d / 2) < 1) return c / 2 * t * t + b; │ │ │ │ │ - return -c / 2 * ((--t) * (t - 2) - 1) + b; │ │ │ │ │ + _borderSize: function(n) { │ │ │ │ │ + var transparentBorderSizes = [5, 3, 2, 1]; │ │ │ │ │ + var blendedBorderSizes = [2, 1, 1, 1]; │ │ │ │ │ + var compactBorderSizes = [1, 0]; │ │ │ │ │ + var actualBorderSizes = [0, 2, 0, 0]; │ │ │ │ │ + │ │ │ │ │ + if (this.options.compact && (this.options.blend || this._isTransparent())) { │ │ │ │ │ + return 1; │ │ │ │ │ + } else if (this.options.compact) { │ │ │ │ │ + return compactBorderSizes[n]; │ │ │ │ │ + } else if (this.options.blend) { │ │ │ │ │ + return blendedBorderSizes[n]; │ │ │ │ │ + } else if (this.options.border) { │ │ │ │ │ + return actualBorderSizes[n]; │ │ │ │ │ + } else if (this._isTransparent()) { │ │ │ │ │ + return transparentBorderSizes[n]; │ │ │ │ │ + } │ │ │ │ │ + return 0; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Easing.Quad" │ │ │ │ │ + _hasString: function(str) { │ │ │ │ │ + for (var i = 1; i < arguments.length; i++) │ │ │ │ │ + if (str.indexOf(arguments[i]) >= 0) { │ │ │ │ │ + return true; │ │ │ │ │ + } return false; │ │ │ │ │ + }, │ │ │ │ │ + _blend: function(c1, c2) { │ │ │ │ │ + var cc1 = OpenLayers.Rico.Color.createFromHex(c1); │ │ │ │ │ + cc1.blend(OpenLayers.Rico.Color.createFromHex(c2)); │ │ │ │ │ + return cc1; │ │ │ │ │ + }, │ │ │ │ │ + _background: function(el) { │ │ │ │ │ + try { │ │ │ │ │ + return OpenLayers.Rico.Color.createColorFromBackground(el).asHex(); │ │ │ │ │ + } catch (err) { │ │ │ │ │ + return "#ffffff"; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + _isTransparent: function() { │ │ │ │ │ + return this.options.color == "transparent"; │ │ │ │ │ + }, │ │ │ │ │ + _isTopRounded: function() { │ │ │ │ │ + return this._hasString(this.options.corners, "all", "top", "tl", "tr"); │ │ │ │ │ + }, │ │ │ │ │ + _isBottomRounded: function() { │ │ │ │ │ + return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); │ │ │ │ │ + }, │ │ │ │ │ + _hasSingleTextChild: function(el) { │ │ │ │ │ + return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; │ │ │ │ │ + } │ │ │ │ │ }; │ │ │ │ │ /* ====================================================================== │ │ │ │ │ OpenLayers/Events.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ @@ -6402,876 +6259,4976 @@ │ │ │ │ │ │ │ │ │ │ OpenLayers.Event.observe(element, 'MSPointerUp', cb); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Events" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Projection.js │ │ │ │ │ + OpenLayers/Request/XMLHttpRequest.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ +// XMLHttpRequest.js Copyright (C) 2010 Sergey Ilinsky (http://www.ilinsky.com) │ │ │ │ │ +// │ │ │ │ │ +// Licensed under the Apache License, Version 2.0 (the "License"); │ │ │ │ │ +// you may not use this file except in compliance with the License. │ │ │ │ │ +// You may obtain a copy of the License at │ │ │ │ │ +// │ │ │ │ │ +// http://www.apache.org/licenses/LICENSE-2.0 │ │ │ │ │ +// │ │ │ │ │ +// Unless required by applicable law or agreed to in writing, software │ │ │ │ │ +// distributed under the License is distributed on an "AS IS" BASIS, │ │ │ │ │ +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ │ │ │ │ +// See the License for the specific language governing permissions and │ │ │ │ │ +// limitations under the License. │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ │ + * @requires OpenLayers/Request.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Namespace: OpenLayers.Projection │ │ │ │ │ - * Methods for coordinate transforms between coordinate systems. By default, │ │ │ │ │ - * OpenLayers ships with the ability to transform coordinates between │ │ │ │ │ - * geographic (EPSG:4326) and web or spherical mercator (EPSG:900913 et al.) │ │ │ │ │ - * coordinate reference systems. See the method for details │ │ │ │ │ - * on usage. │ │ │ │ │ - * │ │ │ │ │ - * Additional transforms may be added by using the │ │ │ │ │ - * library. If the proj4js library is included, the method │ │ │ │ │ - * will work between any two coordinate reference systems with proj4js │ │ │ │ │ - * definitions. │ │ │ │ │ - * │ │ │ │ │ - * If the proj4js library is not included, or if you wish to allow transforms │ │ │ │ │ - * between arbitrary coordinate reference systems, use the │ │ │ │ │ - * method to register a custom transform method. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Projection = OpenLayers.Class({ │ │ │ │ │ +(function() { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: proj │ │ │ │ │ - * {Object} Proj4js.Proj instance. │ │ │ │ │ - */ │ │ │ │ │ - proj: null, │ │ │ │ │ + // Save reference to earlier defined object implementation (if any) │ │ │ │ │ + var oXMLHttpRequest = window.XMLHttpRequest; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: projCode │ │ │ │ │ - * {String} │ │ │ │ │ - */ │ │ │ │ │ - projCode: null, │ │ │ │ │ + // Define on browser type │ │ │ │ │ + var bGecko = !!window.controllers, │ │ │ │ │ + bIE = window.document.all && !window.opera, │ │ │ │ │ + bIE7 = bIE && window.navigator.userAgent.match(/MSIE 7.0/); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: titleRegEx │ │ │ │ │ - * {RegExp} regular expression to strip the title from a proj4js definition │ │ │ │ │ - */ │ │ │ │ │ - titleRegEx: /\+title=[^\+]*/, │ │ │ │ │ + // Enables "XMLHttpRequest()" call next to "new XMLHttpReques()" │ │ │ │ │ + function fXMLHttpRequest() { │ │ │ │ │ + this._object = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP"); │ │ │ │ │ + this._listeners = []; │ │ │ │ │ + }; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Projection │ │ │ │ │ - * This class offers several methods for interacting with a wrapped │ │ │ │ │ - * pro4js projection object. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * projCode - {String} A string identifying the Well Known Identifier for │ │ │ │ │ - * the projection. │ │ │ │ │ - * options - {Object} An optional object to set additional properties │ │ │ │ │ - * on the projection. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} A projection object. │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(projCode, options) { │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ - this.projCode = projCode; │ │ │ │ │ - if (typeof Proj4js == "object") { │ │ │ │ │ - this.proj = new Proj4js.Proj(projCode); │ │ │ │ │ + // Constructor │ │ │ │ │ + function cXMLHttpRequest() { │ │ │ │ │ + return new fXMLHttpRequest; │ │ │ │ │ + }; │ │ │ │ │ + cXMLHttpRequest.prototype = fXMLHttpRequest.prototype; │ │ │ │ │ + │ │ │ │ │ + // BUGFIX: Firefox with Firebug installed would break pages if not executed │ │ │ │ │ + if (bGecko && oXMLHttpRequest.wrapped) │ │ │ │ │ + cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped; │ │ │ │ │ + │ │ │ │ │ + // Constants │ │ │ │ │ + cXMLHttpRequest.UNSENT = 0; │ │ │ │ │ + cXMLHttpRequest.OPENED = 1; │ │ │ │ │ + cXMLHttpRequest.HEADERS_RECEIVED = 2; │ │ │ │ │ + cXMLHttpRequest.LOADING = 3; │ │ │ │ │ + cXMLHttpRequest.DONE = 4; │ │ │ │ │ + │ │ │ │ │ + // Public Properties │ │ │ │ │ + cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ │ + cXMLHttpRequest.prototype.responseText = ''; │ │ │ │ │ + cXMLHttpRequest.prototype.responseXML = null; │ │ │ │ │ + cXMLHttpRequest.prototype.status = 0; │ │ │ │ │ + cXMLHttpRequest.prototype.statusText = ''; │ │ │ │ │ + │ │ │ │ │ + // Priority proposal │ │ │ │ │ + cXMLHttpRequest.prototype.priority = "NORMAL"; │ │ │ │ │ + │ │ │ │ │ + // Instance-level Events Handlers │ │ │ │ │ + cXMLHttpRequest.prototype.onreadystatechange = null; │ │ │ │ │ + │ │ │ │ │ + // Class-level Events Handlers │ │ │ │ │ + cXMLHttpRequest.onreadystatechange = null; │ │ │ │ │ + cXMLHttpRequest.onopen = null; │ │ │ │ │ + cXMLHttpRequest.onsend = null; │ │ │ │ │ + cXMLHttpRequest.onabort = null; │ │ │ │ │ + │ │ │ │ │ + // Public Methods │ │ │ │ │ + cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) { │ │ │ │ │ + // Delete headers, required when object is reused │ │ │ │ │ + delete this._headers; │ │ │ │ │ + │ │ │ │ │ + // When bAsync parameter value is omitted, use true as default │ │ │ │ │ + if (arguments.length < 3) │ │ │ │ │ + bAsync = true; │ │ │ │ │ + │ │ │ │ │ + // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests │ │ │ │ │ + this._async = bAsync; │ │ │ │ │ + │ │ │ │ │ + // Set the onreadystatechange handler │ │ │ │ │ + var oRequest = this, │ │ │ │ │ + nState = this.readyState, │ │ │ │ │ + fOnUnload; │ │ │ │ │ + │ │ │ │ │ + // BUGFIX: IE - memory leak on page unload (inter-page leak) │ │ │ │ │ + if (bIE && bAsync) { │ │ │ │ │ + fOnUnload = function() { │ │ │ │ │ + if (nState != cXMLHttpRequest.DONE) { │ │ │ │ │ + fCleanTransport(oRequest); │ │ │ │ │ + // Safe to abort here since onreadystatechange handler removed │ │ │ │ │ + oRequest.abort(); │ │ │ │ │ + } │ │ │ │ │ + }; │ │ │ │ │ + window.attachEvent("onunload", fOnUnload); │ │ │ │ │ } │ │ │ │ │ - }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getCode │ │ │ │ │ - * Get the string SRS code. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} The SRS code. │ │ │ │ │ - */ │ │ │ │ │ - getCode: function() { │ │ │ │ │ - return this.proj ? this.proj.srsCode : this.projCode; │ │ │ │ │ - }, │ │ │ │ │ + // Add method sniffer │ │ │ │ │ + if (cXMLHttpRequest.onopen) │ │ │ │ │ + cXMLHttpRequest.onopen.apply(this, arguments); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getUnits │ │ │ │ │ - * Get the units string for the projection -- returns null if │ │ │ │ │ - * proj4js is not available. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} The units abbreviation. │ │ │ │ │ - */ │ │ │ │ │ - getUnits: function() { │ │ │ │ │ - return this.proj ? this.proj.units : null; │ │ │ │ │ - }, │ │ │ │ │ + if (arguments.length > 4) │ │ │ │ │ + this._object.open(sMethod, sUrl, bAsync, sUser, sPassword); │ │ │ │ │ + else │ │ │ │ │ + if (arguments.length > 3) │ │ │ │ │ + this._object.open(sMethod, sUrl, bAsync, sUser); │ │ │ │ │ + else │ │ │ │ │ + this._object.open(sMethod, sUrl, bAsync); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: toString │ │ │ │ │ - * Convert projection to string (getCode wrapper). │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} The projection code. │ │ │ │ │ - */ │ │ │ │ │ - toString: function() { │ │ │ │ │ - return this.getCode(); │ │ │ │ │ - }, │ │ │ │ │ + this.readyState = cXMLHttpRequest.OPENED; │ │ │ │ │ + fReadyStateChange(this); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: equals │ │ │ │ │ - * Test equality of two projection instances. Determines equality based │ │ │ │ │ - * soley on the projection code. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The two projections are equivalent. │ │ │ │ │ - */ │ │ │ │ │ - equals: function(projection) { │ │ │ │ │ - var p = projection, │ │ │ │ │ - equals = false; │ │ │ │ │ - if (p) { │ │ │ │ │ - if (!(p instanceof OpenLayers.Projection)) { │ │ │ │ │ - p = new OpenLayers.Projection(p); │ │ │ │ │ - } │ │ │ │ │ - if ((typeof Proj4js == "object") && this.proj.defData && p.proj.defData) { │ │ │ │ │ - equals = this.proj.defData.replace(this.titleRegEx, "") == │ │ │ │ │ - p.proj.defData.replace(this.titleRegEx, ""); │ │ │ │ │ - } else if (p.getCode) { │ │ │ │ │ - var source = this.getCode(), │ │ │ │ │ - target = p.getCode(); │ │ │ │ │ - equals = source == target || │ │ │ │ │ - !!OpenLayers.Projection.transforms[source] && │ │ │ │ │ - OpenLayers.Projection.transforms[source][target] === │ │ │ │ │ - OpenLayers.Projection.nullTransform; │ │ │ │ │ + this._object.onreadystatechange = function() { │ │ │ │ │ + if (bGecko && !bAsync) │ │ │ │ │ + return; │ │ │ │ │ + │ │ │ │ │ + // Synchronize state │ │ │ │ │ + oRequest.readyState = oRequest._object.readyState; │ │ │ │ │ + │ │ │ │ │ + // │ │ │ │ │ + fSynchronizeValues(oRequest); │ │ │ │ │ + │ │ │ │ │ + // BUGFIX: Firefox fires unnecessary DONE when aborting │ │ │ │ │ + if (oRequest._aborted) { │ │ │ │ │ + // Reset readyState to UNSENT │ │ │ │ │ + oRequest.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ │ + │ │ │ │ │ + // Return now │ │ │ │ │ + return; │ │ │ │ │ } │ │ │ │ │ - } │ │ │ │ │ - return equals; │ │ │ │ │ - }, │ │ │ │ │ │ │ │ │ │ - /* Method: destroy │ │ │ │ │ - * Destroy projection object. │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - delete this.proj; │ │ │ │ │ - delete this.projCode; │ │ │ │ │ - }, │ │ │ │ │ + if (oRequest.readyState == cXMLHttpRequest.DONE) { │ │ │ │ │ + // Free up queue │ │ │ │ │ + delete oRequest._data; │ │ │ │ │ + /* if (bAsync) │ │ │ │ │ + fQueue_remove(oRequest);*/ │ │ │ │ │ + // │ │ │ │ │ + fCleanTransport(oRequest); │ │ │ │ │ + // Uncomment this block if you need a fix for IE cache │ │ │ │ │ + /* │ │ │ │ │ + // BUGFIX: IE - cache issue │ │ │ │ │ + if (!oRequest._object.getResponseHeader("Date")) { │ │ │ │ │ + // Save object to cache │ │ │ │ │ + oRequest._cached = oRequest._object; │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Projection" │ │ │ │ │ -}); │ │ │ │ │ + // Instantiate a new transport object │ │ │ │ │ + cXMLHttpRequest.call(oRequest); │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Property: transforms │ │ │ │ │ - * {Object} Transforms is an object, with from properties, each of which may │ │ │ │ │ - * have a to property. This allows you to define projections without │ │ │ │ │ - * requiring support for proj4js to be included. │ │ │ │ │ - * │ │ │ │ │ - * This object has keys which correspond to a 'source' projection object. The │ │ │ │ │ - * keys should be strings, corresponding to the projection.getCode() value. │ │ │ │ │ - * Each source projection object should have a set of destination projection │ │ │ │ │ - * keys included in the object. │ │ │ │ │ - * │ │ │ │ │ - * Each value in the destination object should be a transformation function, │ │ │ │ │ - * where the function is expected to be passed an object with a .x and a .y │ │ │ │ │ - * property. The function should return the object, with the .x and .y │ │ │ │ │ - * transformed according to the transformation function. │ │ │ │ │ - * │ │ │ │ │ - * Note - Properties on this object should not be set directly. To add a │ │ │ │ │ - * transform method to this object, use the method. For an │ │ │ │ │ - * example of usage, see the OpenLayers.Layer.SphericalMercator file. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Projection.transforms = {}; │ │ │ │ │ + // Re-send request │ │ │ │ │ + if (sUser) { │ │ │ │ │ + if (sPassword) │ │ │ │ │ + oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword); │ │ │ │ │ + else │ │ │ │ │ + oRequest._object.open(sMethod, sUrl, bAsync, sUser); │ │ │ │ │ + } │ │ │ │ │ + else │ │ │ │ │ + oRequest._object.open(sMethod, sUrl, bAsync); │ │ │ │ │ + oRequest._object.setRequestHeader("If-Modified-Since", oRequest._cached.getResponseHeader("Last-Modified") || new window.Date(0)); │ │ │ │ │ + // Copy headers set │ │ │ │ │ + if (oRequest._headers) │ │ │ │ │ + for (var sHeader in oRequest._headers) │ │ │ │ │ + if (typeof oRequest._headers[sHeader] == "string") // Some frameworks prototype objects with functions │ │ │ │ │ + oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]); │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * APIProperty: defaults │ │ │ │ │ - * {Object} Defaults for the SRS codes known to OpenLayers (currently │ │ │ │ │ - * EPSG:4326, CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, EPSG:900913, EPSG:3857, │ │ │ │ │ - * EPSG:102113 and EPSG:102100). Keys are the SRS code, values are units, │ │ │ │ │ - * maxExtent (the validity extent for the SRS) and yx (true if this SRS is │ │ │ │ │ - * known to have a reverse axis order). │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Projection.defaults = { │ │ │ │ │ - "EPSG:4326": { │ │ │ │ │ - units: "degrees", │ │ │ │ │ - maxExtent: [-180, -90, 180, 90], │ │ │ │ │ - yx: true │ │ │ │ │ - }, │ │ │ │ │ - "CRS:84": { │ │ │ │ │ - units: "degrees", │ │ │ │ │ - maxExtent: [-180, -90, 180, 90] │ │ │ │ │ - }, │ │ │ │ │ - "EPSG:900913": { │ │ │ │ │ - units: "m", │ │ │ │ │ - maxExtent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34] │ │ │ │ │ - } │ │ │ │ │ -}; │ │ │ │ │ + oRequest._object.onreadystatechange = function() { │ │ │ │ │ + // Synchronize state │ │ │ │ │ + oRequest.readyState = oRequest._object.readyState; │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * APIMethod: addTransform │ │ │ │ │ - * Set a custom transform method between two projections. Use this method in │ │ │ │ │ - * cases where the proj4js lib is not available or where custom projections │ │ │ │ │ - * need to be handled. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * from - {String} The code for the source projection │ │ │ │ │ - * to - {String} the code for the destination projection │ │ │ │ │ - * method - {Function} A function that takes a point as an argument and │ │ │ │ │ - * transforms that point from the source to the destination projection │ │ │ │ │ - * in place. The original point should be modified. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Projection.addTransform = function(from, to, method) { │ │ │ │ │ - if (method === OpenLayers.Projection.nullTransform) { │ │ │ │ │ - var defaults = OpenLayers.Projection.defaults[from]; │ │ │ │ │ - if (defaults && !OpenLayers.Projection.defaults[to]) { │ │ │ │ │ - OpenLayers.Projection.defaults[to] = defaults; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - if (!OpenLayers.Projection.transforms[from]) { │ │ │ │ │ - OpenLayers.Projection.transforms[from] = {}; │ │ │ │ │ - } │ │ │ │ │ - OpenLayers.Projection.transforms[from][to] = method; │ │ │ │ │ -}; │ │ │ │ │ + if (oRequest._aborted) { │ │ │ │ │ + // │ │ │ │ │ + oRequest.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * APIMethod: transform │ │ │ │ │ - * Transform a point coordinate from one projection to another. Note that │ │ │ │ │ - * the input point is transformed in place. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * point - { | Object} An object with x and y │ │ │ │ │ - * properties representing coordinates in those dimensions. │ │ │ │ │ - * source - {OpenLayers.Projection} Source map coordinate system │ │ │ │ │ - * dest - {OpenLayers.Projection} Destination map coordinate system │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * point - {object} A transformed coordinate. The original point is modified. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Projection.transform = function(point, source, dest) { │ │ │ │ │ - if (source && dest) { │ │ │ │ │ - if (!(source instanceof OpenLayers.Projection)) { │ │ │ │ │ - source = new OpenLayers.Projection(source); │ │ │ │ │ - } │ │ │ │ │ - if (!(dest instanceof OpenLayers.Projection)) { │ │ │ │ │ - dest = new OpenLayers.Projection(dest); │ │ │ │ │ + // Return │ │ │ │ │ + return; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (oRequest.readyState == cXMLHttpRequest.DONE) { │ │ │ │ │ + // Clean Object │ │ │ │ │ + fCleanTransport(oRequest); │ │ │ │ │ + │ │ │ │ │ + // get cached request │ │ │ │ │ + if (oRequest.status == 304) │ │ │ │ │ + oRequest._object = oRequest._cached; │ │ │ │ │ + │ │ │ │ │ + // │ │ │ │ │ + delete oRequest._cached; │ │ │ │ │ + │ │ │ │ │ + // │ │ │ │ │ + fSynchronizeValues(oRequest); │ │ │ │ │ + │ │ │ │ │ + // │ │ │ │ │ + fReadyStateChange(oRequest); │ │ │ │ │ + │ │ │ │ │ + // BUGFIX: IE - memory leak in interrupted │ │ │ │ │ + if (bIE && bAsync) │ │ │ │ │ + window.detachEvent("onunload", fOnUnload); │ │ │ │ │ + } │ │ │ │ │ + }; │ │ │ │ │ + oRequest._object.send(null); │ │ │ │ │ + │ │ │ │ │ + // Return now - wait until re-sent request is finished │ │ │ │ │ + return; │ │ │ │ │ + }; │ │ │ │ │ + */ │ │ │ │ │ + // BUGFIX: IE - memory leak in interrupted │ │ │ │ │ + if (bIE && bAsync) │ │ │ │ │ + window.detachEvent("onunload", fOnUnload); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice │ │ │ │ │ + if (nState != oRequest.readyState) │ │ │ │ │ + fReadyStateChange(oRequest); │ │ │ │ │ + │ │ │ │ │ + nState = oRequest.readyState; │ │ │ │ │ } │ │ │ │ │ - if (source.proj && dest.proj) { │ │ │ │ │ - point = Proj4js.transform(source.proj, dest.proj, point); │ │ │ │ │ - } else { │ │ │ │ │ - var sourceCode = source.getCode(); │ │ │ │ │ - var destCode = dest.getCode(); │ │ │ │ │ - var transforms = OpenLayers.Projection.transforms; │ │ │ │ │ - if (transforms[sourceCode] && transforms[sourceCode][destCode]) { │ │ │ │ │ - transforms[sourceCode][destCode](point); │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ + function fXMLHttpRequest_send(oRequest) { │ │ │ │ │ + oRequest._object.send(oRequest._data); │ │ │ │ │ + │ │ │ │ │ + // BUGFIX: Gecko - missing readystatechange calls in synchronous requests │ │ │ │ │ + if (bGecko && !oRequest._async) { │ │ │ │ │ + oRequest.readyState = cXMLHttpRequest.OPENED; │ │ │ │ │ + │ │ │ │ │ + // Synchronize state │ │ │ │ │ + fSynchronizeValues(oRequest); │ │ │ │ │ + │ │ │ │ │ + // Simulate missing states │ │ │ │ │ + while (oRequest.readyState < cXMLHttpRequest.DONE) { │ │ │ │ │ + oRequest.readyState++; │ │ │ │ │ + fReadyStateChange(oRequest); │ │ │ │ │ + // Check if we are aborted │ │ │ │ │ + if (oRequest._aborted) │ │ │ │ │ + return; │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ - } │ │ │ │ │ - return point; │ │ │ │ │ -}; │ │ │ │ │ + }; │ │ │ │ │ + cXMLHttpRequest.prototype.send = function(vData) { │ │ │ │ │ + // Add method sniffer │ │ │ │ │ + if (cXMLHttpRequest.onsend) │ │ │ │ │ + cXMLHttpRequest.onsend.apply(this, arguments); │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * APIFunction: nullTransform │ │ │ │ │ - * A null transformation - useful for defining projection aliases when │ │ │ │ │ - * proj4js is not available: │ │ │ │ │ - * │ │ │ │ │ - * (code) │ │ │ │ │ - * OpenLayers.Projection.addTransform("EPSG:3857", "EPSG:900913", │ │ │ │ │ - * OpenLayers.Projection.nullTransform); │ │ │ │ │ - * OpenLayers.Projection.addTransform("EPSG:900913", "EPSG:3857", │ │ │ │ │ - * OpenLayers.Projection.nullTransform); │ │ │ │ │ - * (end) │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Projection.nullTransform = function(point) { │ │ │ │ │ - return point; │ │ │ │ │ -}; │ │ │ │ │ + if (!arguments.length) │ │ │ │ │ + vData = null; │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Note: Transforms for web mercator <-> geographic │ │ │ │ │ - * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113 and EPSG:102100. │ │ │ │ │ - * OpenLayers originally started referring to EPSG:900913 as web mercator. │ │ │ │ │ - * The EPSG has declared EPSG:3857 to be web mercator. │ │ │ │ │ - * ArcGIS 10 recognizes the EPSG:3857, EPSG:102113, and EPSG:102100 as │ │ │ │ │ - * equivalent. See http://blogs.esri.com/Dev/blogs/arcgisserver/archive/2009/11/20/ArcGIS-Online-moving-to-Google-_2F00_-Bing-tiling-scheme_3A00_-What-does-this-mean-for-you_3F00_.aspx#12084. │ │ │ │ │ - * For geographic, OpenLayers recognizes EPSG:4326, CRS:84 and │ │ │ │ │ - * urn:ogc:def:crs:EPSG:6.6:4326. OpenLayers also knows about the reverse axis │ │ │ │ │ - * order for EPSG:4326. │ │ │ │ │ - */ │ │ │ │ │ -(function() { │ │ │ │ │ + // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required │ │ │ │ │ + // BUGFIX: IE - rewrites any custom mime-type to "text/xml" in case an XMLNode is sent │ │ │ │ │ + // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard) │ │ │ │ │ + if (vData && vData.nodeType) { │ │ │ │ │ + vData = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml; │ │ │ │ │ + if (!this._headers["Content-Type"]) │ │ │ │ │ + this._object.setRequestHeader("Content-Type", "application/xml"); │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - var pole = 20037508.34; │ │ │ │ │ + this._data = vData; │ │ │ │ │ + /* │ │ │ │ │ + // Add to queue │ │ │ │ │ + if (this._async) │ │ │ │ │ + fQueue_add(this); │ │ │ │ │ + else*/ │ │ │ │ │ + fXMLHttpRequest_send(this); │ │ │ │ │ + }; │ │ │ │ │ + cXMLHttpRequest.prototype.abort = function() { │ │ │ │ │ + // Add method sniffer │ │ │ │ │ + if (cXMLHttpRequest.onabort) │ │ │ │ │ + cXMLHttpRequest.onabort.apply(this, arguments); │ │ │ │ │ │ │ │ │ │ - function inverseMercator(xy) { │ │ │ │ │ - xy.x = 180 * xy.x / pole; │ │ │ │ │ - xy.y = 180 / Math.PI * (2 * Math.atan(Math.exp((xy.y / pole) * Math.PI)) - Math.PI / 2); │ │ │ │ │ - return xy; │ │ │ │ │ - } │ │ │ │ │ + // BUGFIX: Gecko - unnecessary DONE when aborting │ │ │ │ │ + if (this.readyState > cXMLHttpRequest.UNSENT) │ │ │ │ │ + this._aborted = true; │ │ │ │ │ │ │ │ │ │ - function forwardMercator(xy) { │ │ │ │ │ - xy.x = xy.x * pole / 180; │ │ │ │ │ - var y = Math.log(Math.tan((90 + xy.y) * Math.PI / 360)) / Math.PI * pole; │ │ │ │ │ - xy.y = Math.max(-20037508.34, Math.min(y, 20037508.34)); │ │ │ │ │ - return xy; │ │ │ │ │ - } │ │ │ │ │ + this._object.abort(); │ │ │ │ │ │ │ │ │ │ - function map(base, codes) { │ │ │ │ │ - var add = OpenLayers.Projection.addTransform; │ │ │ │ │ - var same = OpenLayers.Projection.nullTransform; │ │ │ │ │ - var i, len, code, other, j; │ │ │ │ │ - for (i = 0, len = codes.length; i < len; ++i) { │ │ │ │ │ - code = codes[i]; │ │ │ │ │ - add(base, code, forwardMercator); │ │ │ │ │ - add(code, base, inverseMercator); │ │ │ │ │ - for (j = i + 1; j < len; ++j) { │ │ │ │ │ - other = codes[j]; │ │ │ │ │ - add(code, other, same); │ │ │ │ │ - add(other, code, same); │ │ │ │ │ - } │ │ │ │ │ + // BUGFIX: IE - memory leak │ │ │ │ │ + fCleanTransport(this); │ │ │ │ │ + │ │ │ │ │ + this.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ │ + │ │ │ │ │ + delete this._data; │ │ │ │ │ + /* if (this._async) │ │ │ │ │ + fQueue_remove(this);*/ │ │ │ │ │ + }; │ │ │ │ │ + cXMLHttpRequest.prototype.getAllResponseHeaders = function() { │ │ │ │ │ + return this._object.getAllResponseHeaders(); │ │ │ │ │ + }; │ │ │ │ │ + cXMLHttpRequest.prototype.getResponseHeader = function(sName) { │ │ │ │ │ + return this._object.getResponseHeader(sName); │ │ │ │ │ + }; │ │ │ │ │ + cXMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) { │ │ │ │ │ + // BUGFIX: IE - cache issue │ │ │ │ │ + if (!this._headers) │ │ │ │ │ + this._headers = {}; │ │ │ │ │ + this._headers[sName] = sValue; │ │ │ │ │ + │ │ │ │ │ + return this._object.setRequestHeader(sName, sValue); │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ + // EventTarget interface implementation │ │ │ │ │ + cXMLHttpRequest.prototype.addEventListener = function(sName, fHandler, bUseCapture) { │ │ │ │ │ + for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) │ │ │ │ │ + if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture) │ │ │ │ │ + return; │ │ │ │ │ + // Add listener │ │ │ │ │ + this._listeners.push([sName, fHandler, bUseCapture]); │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ + cXMLHttpRequest.prototype.removeEventListener = function(sName, fHandler, bUseCapture) { │ │ │ │ │ + for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) │ │ │ │ │ + if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture) │ │ │ │ │ + break; │ │ │ │ │ + // Remove listener │ │ │ │ │ + if (oListener) │ │ │ │ │ + this._listeners.splice(nIndex, 1); │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ + cXMLHttpRequest.prototype.dispatchEvent = function(oEvent) { │ │ │ │ │ + var oEventPseudo = { │ │ │ │ │ + 'type': oEvent.type, │ │ │ │ │ + 'target': this, │ │ │ │ │ + 'currentTarget': this, │ │ │ │ │ + 'eventPhase': 2, │ │ │ │ │ + 'bubbles': oEvent.bubbles, │ │ │ │ │ + 'cancelable': oEvent.cancelable, │ │ │ │ │ + 'timeStamp': oEvent.timeStamp, │ │ │ │ │ + 'stopPropagation': function() {}, // There is no flow │ │ │ │ │ + 'preventDefault': function() {}, // There is no default action │ │ │ │ │ + 'initEvent': function() {} // Original event object should be initialized │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ + // Execute onreadystatechange │ │ │ │ │ + if (oEventPseudo.type == "readystatechange" && this.onreadystatechange) │ │ │ │ │ + (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]); │ │ │ │ │ + │ │ │ │ │ + // Execute listeners │ │ │ │ │ + for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) │ │ │ │ │ + if (oListener[0] == oEventPseudo.type && !oListener[2]) │ │ │ │ │ + (oListener[1].handleEvent || oListener[1]).apply(this, [oEventPseudo]); │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ + // │ │ │ │ │ + cXMLHttpRequest.prototype.toString = function() { │ │ │ │ │ + return '[' + "object" + ' ' + "XMLHttpRequest" + ']'; │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ + cXMLHttpRequest.toString = function() { │ │ │ │ │ + return '[' + "XMLHttpRequest" + ']'; │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ + // Helper function │ │ │ │ │ + function fReadyStateChange(oRequest) { │ │ │ │ │ + // Sniffing code │ │ │ │ │ + if (cXMLHttpRequest.onreadystatechange) │ │ │ │ │ + cXMLHttpRequest.onreadystatechange.apply(oRequest); │ │ │ │ │ + │ │ │ │ │ + // Fake event │ │ │ │ │ + oRequest.dispatchEvent({ │ │ │ │ │ + 'type': "readystatechange", │ │ │ │ │ + 'bubbles': false, │ │ │ │ │ + 'cancelable': false, │ │ │ │ │ + 'timeStamp': new Date + 0 │ │ │ │ │ + }); │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ + function fGetDocument(oRequest) { │ │ │ │ │ + var oDocument = oRequest.responseXML, │ │ │ │ │ + sResponse = oRequest.responseText; │ │ │ │ │ + // Try parsing responseText │ │ │ │ │ + if (bIE && sResponse && oDocument && !oDocument.documentElement && oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)) { │ │ │ │ │ + oDocument = new window.ActiveXObject("Microsoft.XMLDOM"); │ │ │ │ │ + oDocument.async = false; │ │ │ │ │ + oDocument.validateOnParse = false; │ │ │ │ │ + oDocument.loadXML(sResponse); │ │ │ │ │ } │ │ │ │ │ - } │ │ │ │ │ + // Check if there is no error in document │ │ │ │ │ + if (oDocument) │ │ │ │ │ + if ((bIE && oDocument.parseError != 0) || !oDocument.documentElement || (oDocument.documentElement && oDocument.documentElement.tagName == "parsererror")) │ │ │ │ │ + return null; │ │ │ │ │ + return oDocument; │ │ │ │ │ + }; │ │ │ │ │ │ │ │ │ │ - // list of equivalent codes for web mercator │ │ │ │ │ - var mercator = ["EPSG:900913", "EPSG:3857", "EPSG:102113", "EPSG:102100"], │ │ │ │ │ - geographic = ["CRS:84", "urn:ogc:def:crs:EPSG:6.6:4326", "EPSG:4326"], │ │ │ │ │ - i; │ │ │ │ │ - for (i = mercator.length - 1; i >= 0; --i) { │ │ │ │ │ - map(mercator[i], geographic); │ │ │ │ │ - } │ │ │ │ │ - for (i = geographic.length - 1; i >= 0; --i) { │ │ │ │ │ - map(geographic[i], mercator); │ │ │ │ │ - } │ │ │ │ │ + function fSynchronizeValues(oRequest) { │ │ │ │ │ + try { │ │ │ │ │ + oRequest.responseText = oRequest._object.responseText; │ │ │ │ │ + } catch (e) {} │ │ │ │ │ + try { │ │ │ │ │ + oRequest.responseXML = fGetDocument(oRequest._object); │ │ │ │ │ + } catch (e) {} │ │ │ │ │ + try { │ │ │ │ │ + oRequest.status = oRequest._object.status; │ │ │ │ │ + } catch (e) {} │ │ │ │ │ + try { │ │ │ │ │ + oRequest.statusText = oRequest._object.statusText; │ │ │ │ │ + } catch (e) {} │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ + function fCleanTransport(oRequest) { │ │ │ │ │ + // BUGFIX: IE - memory leak (on-page leak) │ │ │ │ │ + oRequest._object.onreadystatechange = new window.Function; │ │ │ │ │ + }; │ │ │ │ │ + /* │ │ │ │ │ + // Queue manager │ │ │ │ │ + var oQueuePending = {"CRITICAL":[],"HIGH":[],"NORMAL":[],"LOW":[],"LOWEST":[]}, │ │ │ │ │ + aQueueRunning = []; │ │ │ │ │ + function fQueue_add(oRequest) { │ │ │ │ │ + oQueuePending[oRequest.priority in oQueuePending ? oRequest.priority : "NORMAL"].push(oRequest); │ │ │ │ │ + // │ │ │ │ │ + setTimeout(fQueue_process); │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ + function fQueue_remove(oRequest) { │ │ │ │ │ + for (var nIndex = 0, bFound = false; nIndex < aQueueRunning.length; nIndex++) │ │ │ │ │ + if (bFound) │ │ │ │ │ + aQueueRunning[nIndex - 1] = aQueueRunning[nIndex]; │ │ │ │ │ + else │ │ │ │ │ + if (aQueueRunning[nIndex] == oRequest) │ │ │ │ │ + bFound = true; │ │ │ │ │ + if (bFound) │ │ │ │ │ + aQueueRunning.length--; │ │ │ │ │ + // │ │ │ │ │ + setTimeout(fQueue_process); │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ + function fQueue_process() { │ │ │ │ │ + if (aQueueRunning.length < 6) { │ │ │ │ │ + for (var sPriority in oQueuePending) { │ │ │ │ │ + if (oQueuePending[sPriority].length) { │ │ │ │ │ + var oRequest = oQueuePending[sPriority][0]; │ │ │ │ │ + oQueuePending[sPriority] = oQueuePending[sPriority].slice(1); │ │ │ │ │ + // │ │ │ │ │ + aQueueRunning.push(oRequest); │ │ │ │ │ + // Send request │ │ │ │ │ + fXMLHttpRequest_send(oRequest); │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + }; │ │ │ │ │ + */ │ │ │ │ │ + // Internet Explorer 5.0 (missing apply) │ │ │ │ │ + if (!window.Function.prototype.apply) { │ │ │ │ │ + window.Function.prototype.apply = function(oRequest, oArguments) { │ │ │ │ │ + if (!oArguments) │ │ │ │ │ + oArguments = []; │ │ │ │ │ + oRequest.__func = this; │ │ │ │ │ + oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]); │ │ │ │ │ + delete oRequest.__func; │ │ │ │ │ + }; │ │ │ │ │ + }; │ │ │ │ │ │ │ │ │ │ + // Register new object with window │ │ │ │ │ + /** │ │ │ │ │ + * Class: OpenLayers.Request.XMLHttpRequest │ │ │ │ │ + * Standard-compliant (W3C) cross-browser implementation of the │ │ │ │ │ + * XMLHttpRequest object. From │ │ │ │ │ + * http://code.google.com/p/xmlhttprequest/. │ │ │ │ │ + */ │ │ │ │ │ + if (!OpenLayers.Request) { │ │ │ │ │ + /** │ │ │ │ │ + * This allows for OpenLayers/Request.js to be included │ │ │ │ │ + * before or after this script. │ │ │ │ │ + */ │ │ │ │ │ + OpenLayers.Request = {}; │ │ │ │ │ + } │ │ │ │ │ + OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest; │ │ │ │ │ })(); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Map.js │ │ │ │ │ + OpenLayers/Request.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ │ - * @requires OpenLayers/Util/vendorPrefix.js │ │ │ │ │ * @requires OpenLayers/Events.js │ │ │ │ │ - * @requires OpenLayers/Tween.js │ │ │ │ │ - * @requires OpenLayers/Projection.js │ │ │ │ │ + * @requires OpenLayers/Request/XMLHttpRequest.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Map │ │ │ │ │ - * Instances of OpenLayers.Map are interactive maps embedded in a web page. │ │ │ │ │ - * Create a new map with the constructor. │ │ │ │ │ - * │ │ │ │ │ - * On their own maps do not provide much functionality. To extend a map │ │ │ │ │ - * it's necessary to add controls () and │ │ │ │ │ - * layers () to the map. │ │ │ │ │ + * TODO: deprecate me │ │ │ │ │ + * Use OpenLayers.Request.proxy instead. │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Map = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constant: Z_INDEX_BASE │ │ │ │ │ - * {Object} Base z-indexes for different classes of thing │ │ │ │ │ - */ │ │ │ │ │ - Z_INDEX_BASE: { │ │ │ │ │ - BaseLayer: 100, │ │ │ │ │ - Overlay: 325, │ │ │ │ │ - Feature: 725, │ │ │ │ │ - Popup: 750, │ │ │ │ │ - Control: 1000 │ │ │ │ │ - }, │ │ │ │ │ +OpenLayers.ProxyHost = ""; │ │ │ │ │ │ │ │ │ │ +/** │ │ │ │ │ + * Namespace: OpenLayers.Request │ │ │ │ │ + * The OpenLayers.Request namespace contains convenience methods for working │ │ │ │ │ + * with XMLHttpRequests. These methods work with a cross-browser │ │ │ │ │ + * W3C compliant class. │ │ │ │ │ + */ │ │ │ │ │ +if (!OpenLayers.Request) { │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: events │ │ │ │ │ - * {} │ │ │ │ │ - * │ │ │ │ │ - * Register a listener for a particular event with the following syntax: │ │ │ │ │ - * (code) │ │ │ │ │ - * map.events.register(type, obj, listener); │ │ │ │ │ - * (end) │ │ │ │ │ - * │ │ │ │ │ - * Listeners will be called with a reference to an event object. The │ │ │ │ │ - * properties of this event depends on exactly what happened. │ │ │ │ │ - * │ │ │ │ │ - * All event objects have at least the following properties: │ │ │ │ │ - * object - {Object} A reference to map.events.object. │ │ │ │ │ - * element - {DOMElement} A reference to map.events.element. │ │ │ │ │ - * │ │ │ │ │ - * Browser events have the following additional properties: │ │ │ │ │ - * xy - {} The pixel location of the event (relative │ │ │ │ │ - * to the the map viewport). │ │ │ │ │ - * │ │ │ │ │ - * Supported map event types: │ │ │ │ │ - * preaddlayer - triggered before a layer has been added. The event │ │ │ │ │ - * object will include a *layer* property that references the layer │ │ │ │ │ - * to be added. When a listener returns "false" the adding will be │ │ │ │ │ - * aborted. │ │ │ │ │ - * addlayer - triggered after a layer has been added. The event object │ │ │ │ │ - * will include a *layer* property that references the added layer. │ │ │ │ │ - * preremovelayer - triggered before a layer has been removed. The event │ │ │ │ │ - * object will include a *layer* property that references the layer │ │ │ │ │ - * to be removed. When a listener returns "false" the removal will be │ │ │ │ │ - * aborted. │ │ │ │ │ - * removelayer - triggered after a layer has been removed. The event │ │ │ │ │ - * object will include a *layer* property that references the removed │ │ │ │ │ - * layer. │ │ │ │ │ - * changelayer - triggered after a layer name change, order change, │ │ │ │ │ - * opacity change, params change, visibility change (actual visibility, │ │ │ │ │ - * not the layer's visibility property) or attribution change (due to │ │ │ │ │ - * extent change). Listeners will receive an event object with *layer* │ │ │ │ │ - * and *property* properties. The *layer* property will be a reference │ │ │ │ │ - * to the changed layer. The *property* property will be a key to the │ │ │ │ │ - * changed property (name, order, opacity, params, visibility or │ │ │ │ │ - * attribution). │ │ │ │ │ - * movestart - triggered after the start of a drag, pan, or zoom. The event │ │ │ │ │ - * object may include a *zoomChanged* property that tells whether the │ │ │ │ │ - * zoom has changed. │ │ │ │ │ - * move - triggered after each drag, pan, or zoom │ │ │ │ │ - * moveend - triggered after a drag, pan, or zoom completes │ │ │ │ │ - * zoomend - triggered after a zoom completes │ │ │ │ │ - * mouseover - triggered after mouseover the map │ │ │ │ │ - * mouseout - triggered after mouseout the map │ │ │ │ │ - * mousemove - triggered after mousemove the map │ │ │ │ │ - * changebaselayer - triggered after the base layer changes │ │ │ │ │ - * updatesize - triggered after the method was executed │ │ │ │ │ + * This allows for OpenLayers/Request/XMLHttpRequest.js to be included │ │ │ │ │ + * before or after this script. │ │ │ │ │ */ │ │ │ │ │ + OpenLayers.Request = {}; │ │ │ │ │ +} │ │ │ │ │ +OpenLayers.Util.extend(OpenLayers.Request, { │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: id │ │ │ │ │ - * {String} Unique identifier for the map │ │ │ │ │ + * Constant: DEFAULT_CONFIG │ │ │ │ │ + * {Object} Default configuration for all requests. │ │ │ │ │ */ │ │ │ │ │ - id: null, │ │ │ │ │ + DEFAULT_CONFIG: { │ │ │ │ │ + method: "GET", │ │ │ │ │ + url: window.location.href, │ │ │ │ │ + async: true, │ │ │ │ │ + user: undefined, │ │ │ │ │ + password: undefined, │ │ │ │ │ + params: null, │ │ │ │ │ + proxy: OpenLayers.ProxyHost, │ │ │ │ │ + headers: {}, │ │ │ │ │ + data: null, │ │ │ │ │ + callback: function() {}, │ │ │ │ │ + success: null, │ │ │ │ │ + failure: null, │ │ │ │ │ + scope: null │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: fractionalZoom │ │ │ │ │ - * {Boolean} For a base layer that supports it, allow the map resolution │ │ │ │ │ - * to be set to a value between one of the values in the resolutions │ │ │ │ │ - * array. Default is false. │ │ │ │ │ - * │ │ │ │ │ - * When fractionalZoom is set to true, it is possible to zoom to │ │ │ │ │ - * an arbitrary extent. This requires a base layer from a source │ │ │ │ │ - * that supports requests for arbitrary extents (i.e. not cached │ │ │ │ │ - * tiles on a regular lattice). This means that fractionalZoom │ │ │ │ │ - * will not work with commercial layers (Google, Yahoo, VE), layers │ │ │ │ │ - * using TileCache, or any other pre-cached data sources. │ │ │ │ │ - * │ │ │ │ │ - * If you are using fractionalZoom, then you should also use │ │ │ │ │ - * instead of layer.resolutions[zoom] as the │ │ │ │ │ - * former works for non-integer zoom levels. │ │ │ │ │ + * Constant: URL_SPLIT_REGEX │ │ │ │ │ */ │ │ │ │ │ - fractionalZoom: false, │ │ │ │ │ + URL_SPLIT_REGEX: /([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ * APIProperty: events │ │ │ │ │ * {} An events object that handles all │ │ │ │ │ - * events on the map │ │ │ │ │ + * events on the {} object. │ │ │ │ │ + * │ │ │ │ │ + * All event listeners will receive an event object with three properties: │ │ │ │ │ + * request - {} The request object. │ │ │ │ │ + * config - {Object} The config object sent to the specific request method. │ │ │ │ │ + * requestUrl - {String} The request url. │ │ │ │ │ + * │ │ │ │ │ + * Supported event types: │ │ │ │ │ + * complete - Triggered when we have a response from the request, if a │ │ │ │ │ + * listener returns false, no further response processing will take │ │ │ │ │ + * place. │ │ │ │ │ + * success - Triggered when the HTTP response has a success code (200-299). │ │ │ │ │ + * failure - Triggered when the HTTP response does not have a success code. │ │ │ │ │ */ │ │ │ │ │ - events: null, │ │ │ │ │ + events: new OpenLayers.Events(this), │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: allOverlays │ │ │ │ │ - * {Boolean} Allow the map to function with "overlays" only. Defaults to │ │ │ │ │ - * false. If true, the lowest layer in the draw order will act as │ │ │ │ │ - * the base layer. In addition, if set to true, all layers will │ │ │ │ │ - * have isBaseLayer set to false when they are added to the map. │ │ │ │ │ + * Method: makeSameOrigin │ │ │ │ │ + * Using the specified proxy, returns a same origin url of the provided url. │ │ │ │ │ * │ │ │ │ │ - * Note: │ │ │ │ │ - * If you set map.allOverlays to true, then you *cannot* use │ │ │ │ │ - * map.setBaseLayer or layer.setIsBaseLayer. With allOverlays true, │ │ │ │ │ - * the lowest layer in the draw layer is the base layer. So, to change │ │ │ │ │ - * the base layer, use or to set the layer │ │ │ │ │ - * index to 0. │ │ │ │ │ + * Parameters: │ │ │ │ │ + * url - {String} An arbitrary url │ │ │ │ │ + * proxy {String|Function} The proxy to use to make the provided url a │ │ │ │ │ + * same origin url. │ │ │ │ │ + * │ │ │ │ │ + * Returns │ │ │ │ │ + * {String} the same origin url. If no proxy is provided, the returned url │ │ │ │ │ + * will be the same as the provided url. │ │ │ │ │ */ │ │ │ │ │ - allOverlays: false, │ │ │ │ │ + makeSameOrigin: function(url, proxy) { │ │ │ │ │ + var sameOrigin = url.indexOf("http") !== 0; │ │ │ │ │ + var urlParts = !sameOrigin && url.match(this.URL_SPLIT_REGEX); │ │ │ │ │ + if (urlParts) { │ │ │ │ │ + var location = window.location; │ │ │ │ │ + sameOrigin = │ │ │ │ │ + urlParts[1] == location.protocol && │ │ │ │ │ + urlParts[3] == location.hostname; │ │ │ │ │ + var uPort = urlParts[4], │ │ │ │ │ + lPort = location.port; │ │ │ │ │ + if (uPort != 80 && uPort != "" || lPort != "80" && lPort != "") { │ │ │ │ │ + sameOrigin = sameOrigin && uPort == lPort; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + if (!sameOrigin) { │ │ │ │ │ + if (proxy) { │ │ │ │ │ + if (typeof proxy == "function") { │ │ │ │ │ + url = proxy(url); │ │ │ │ │ + } else { │ │ │ │ │ + url = proxy + encodeURIComponent(url); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return url; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: div │ │ │ │ │ - * {DOMElement|String} The element that contains the map (or an id for │ │ │ │ │ - * that element). If the constructor is called │ │ │ │ │ - * with two arguments, this should be provided as the first argument. │ │ │ │ │ - * Alternatively, the map constructor can be called with the options │ │ │ │ │ - * object as the only argument. In this case (one argument), a │ │ │ │ │ - * div property may or may not be provided. If the div property │ │ │ │ │ - * is not provided, the map can be rendered to a container later │ │ │ │ │ - * using the method. │ │ │ │ │ - * │ │ │ │ │ - * Note: │ │ │ │ │ - * If you are calling after map construction, do not use │ │ │ │ │ - * auto. Instead, divide your by your │ │ │ │ │ - * maximum expected dimension. │ │ │ │ │ + * APIMethod: issue │ │ │ │ │ + * Create a new XMLHttpRequest object, open it, set any headers, bind │ │ │ │ │ + * a callback to done state, and send any data. It is recommended that │ │ │ │ │ + * you use one , , , , , or . │ │ │ │ │ + * This method is only documented to provide detail on the configuration │ │ │ │ │ + * options available to all request methods. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} Object containing properties for configuring the │ │ │ │ │ + * request. Allowed configuration properties are described below. │ │ │ │ │ + * This object is modified and should not be reused. │ │ │ │ │ + * │ │ │ │ │ + * Allowed config properties: │ │ │ │ │ + * method - {String} One of GET, POST, PUT, DELETE, HEAD, or │ │ │ │ │ + * OPTIONS. Default is GET. │ │ │ │ │ + * url - {String} URL for the request. │ │ │ │ │ + * async - {Boolean} Open an asynchronous request. Default is true. │ │ │ │ │ + * user - {String} User for relevant authentication scheme. Set │ │ │ │ │ + * to null to clear current user. │ │ │ │ │ + * password - {String} Password for relevant authentication scheme. │ │ │ │ │ + * Set to null to clear current password. │ │ │ │ │ + * proxy - {String} Optional proxy. Defaults to │ │ │ │ │ + * . │ │ │ │ │ + * params - {Object} Any key:value pairs to be appended to the │ │ │ │ │ + * url as a query string. Assumes url doesn't already include a query │ │ │ │ │ + * string or hash. Typically, this is only appropriate for │ │ │ │ │ + * requests where the query string will be appended to the url. │ │ │ │ │ + * Parameter values that are arrays will be │ │ │ │ │ + * concatenated with a comma (note that this goes against form-encoding) │ │ │ │ │ + * as is done with . │ │ │ │ │ + * headers - {Object} Object with header:value pairs to be set on │ │ │ │ │ + * the request. │ │ │ │ │ + * data - {String | Document} Optional data to send with the request. │ │ │ │ │ + * Typically, this is only used with and requests. │ │ │ │ │ + * Make sure to provide the appropriate "Content-Type" header for your │ │ │ │ │ + * data. For and requests, the content type defaults to │ │ │ │ │ + * "application-xml". If your data is a different content type, or │ │ │ │ │ + * if you are using a different HTTP method, set the "Content-Type" │ │ │ │ │ + * header to match your data type. │ │ │ │ │ + * callback - {Function} Function to call when request is done. │ │ │ │ │ + * To determine if the request failed, check request.status (200 │ │ │ │ │ + * indicates success). │ │ │ │ │ + * success - {Function} Optional function to call if request status is in │ │ │ │ │ + * the 200s. This will be called in addition to callback above and │ │ │ │ │ + * would typically only be used as an alternative. │ │ │ │ │ + * failure - {Function} Optional function to call if request status is not │ │ │ │ │ + * in the 200s. This will be called in addition to callback above and │ │ │ │ │ + * would typically only be used as an alternative. │ │ │ │ │ + * scope - {Object} If callback is a public method on some object, │ │ │ │ │ + * set the scope to that object. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {XMLHttpRequest} Request object. To abort the request before a response │ │ │ │ │ + * is received, call abort() on the request object. │ │ │ │ │ */ │ │ │ │ │ - div: null, │ │ │ │ │ + issue: function(config) { │ │ │ │ │ + // apply default config - proxy host may have changed │ │ │ │ │ + var defaultConfig = OpenLayers.Util.extend( │ │ │ │ │ + this.DEFAULT_CONFIG, { │ │ │ │ │ + proxy: OpenLayers.ProxyHost │ │ │ │ │ + } │ │ │ │ │ + ); │ │ │ │ │ + config = config || {}; │ │ │ │ │ + config.headers = config.headers || {}; │ │ │ │ │ + config = OpenLayers.Util.applyDefaults(config, defaultConfig); │ │ │ │ │ + config.headers = OpenLayers.Util.applyDefaults(config.headers, defaultConfig.headers); │ │ │ │ │ + // Always set the "X-Requested-With" header to signal that this request │ │ │ │ │ + // was issued through the XHR-object. Since header keys are case │ │ │ │ │ + // insensitive and we want to allow overriding of the "X-Requested-With" │ │ │ │ │ + // header through the user we cannot use applyDefaults, but have to │ │ │ │ │ + // check manually whether we were called with a "X-Requested-With" │ │ │ │ │ + // header. │ │ │ │ │ + var customRequestedWithHeader = false, │ │ │ │ │ + headerKey; │ │ │ │ │ + for (headerKey in config.headers) { │ │ │ │ │ + if (config.headers.hasOwnProperty(headerKey)) { │ │ │ │ │ + if (headerKey.toLowerCase() === 'x-requested-with') { │ │ │ │ │ + customRequestedWithHeader = true; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + if (customRequestedWithHeader === false) { │ │ │ │ │ + // we did not have a custom "X-Requested-With" header │ │ │ │ │ + config.headers['X-Requested-With'] = 'XMLHttpRequest'; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: dragging │ │ │ │ │ - * {Boolean} The map is currently being dragged. │ │ │ │ │ - */ │ │ │ │ │ - dragging: false, │ │ │ │ │ + // create request, open, and set headers │ │ │ │ │ + var request = new OpenLayers.Request.XMLHttpRequest(); │ │ │ │ │ + var url = OpenLayers.Util.urlAppend(config.url, │ │ │ │ │ + OpenLayers.Util.getParameterString(config.params || {})); │ │ │ │ │ + url = OpenLayers.Request.makeSameOrigin(url, config.proxy); │ │ │ │ │ + request.open( │ │ │ │ │ + config.method, url, config.async, config.user, config.password │ │ │ │ │ + ); │ │ │ │ │ + for (var header in config.headers) { │ │ │ │ │ + request.setRequestHeader(header, config.headers[header]); │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: size │ │ │ │ │ - * {} Size of the main div (this.div) │ │ │ │ │ - */ │ │ │ │ │ - size: null, │ │ │ │ │ + var events = this.events; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: viewPortDiv │ │ │ │ │ - * {HTMLDivElement} The element that represents the map viewport │ │ │ │ │ - */ │ │ │ │ │ - viewPortDiv: null, │ │ │ │ │ + // we want to execute runCallbacks with "this" as the │ │ │ │ │ + // execution scope │ │ │ │ │ + var self = this; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: layerContainerOrigin │ │ │ │ │ - * {} The lonlat at which the later container was │ │ │ │ │ - * re-initialized (on-zoom) │ │ │ │ │ - */ │ │ │ │ │ - layerContainerOrigin: null, │ │ │ │ │ + request.onreadystatechange = function() { │ │ │ │ │ + if (request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) { │ │ │ │ │ + var proceed = events.triggerEvent( │ │ │ │ │ + "complete", { │ │ │ │ │ + request: request, │ │ │ │ │ + config: config, │ │ │ │ │ + requestUrl: url │ │ │ │ │ + } │ │ │ │ │ + ); │ │ │ │ │ + if (proceed !== false) { │ │ │ │ │ + self.runCallbacks({ │ │ │ │ │ + request: request, │ │ │ │ │ + config: config, │ │ │ │ │ + requestUrl: url │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + }; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: layerContainerDiv │ │ │ │ │ - * {HTMLDivElement} The element that contains the layers. │ │ │ │ │ - */ │ │ │ │ │ - layerContainerDiv: null, │ │ │ │ │ + // send request (optionally with data) and return │ │ │ │ │ + // call in a timeout for asynchronous requests so the return is │ │ │ │ │ + // available before readyState == 4 for cached docs │ │ │ │ │ + if (config.async === false) { │ │ │ │ │ + request.send(config.data); │ │ │ │ │ + } else { │ │ │ │ │ + window.setTimeout(function() { │ │ │ │ │ + if (request.readyState !== 0) { // W3C: 0-UNSENT │ │ │ │ │ + request.send(config.data); │ │ │ │ │ + } │ │ │ │ │ + }, 0); │ │ │ │ │ + } │ │ │ │ │ + return request; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: layers │ │ │ │ │ - * {Array()} Ordered list of layers in the map │ │ │ │ │ + * Method: runCallbacks │ │ │ │ │ + * Calls the complete, success and failure callbacks. Application │ │ │ │ │ + * can listen to the "complete" event, have the listener │ │ │ │ │ + * display a confirm window and always return false, and │ │ │ │ │ + * execute OpenLayers.Request.runCallbacks if the user │ │ │ │ │ + * hits "yes" in the confirm window. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} Hash containing request, config and requestUrl keys │ │ │ │ │ */ │ │ │ │ │ - layers: null, │ │ │ │ │ + runCallbacks: function(options) { │ │ │ │ │ + var request = options.request; │ │ │ │ │ + var config = options.config; │ │ │ │ │ + │ │ │ │ │ + // bind callbacks to readyState 4 (done) │ │ │ │ │ + var complete = (config.scope) ? │ │ │ │ │ + OpenLayers.Function.bind(config.callback, config.scope) : │ │ │ │ │ + config.callback; │ │ │ │ │ + │ │ │ │ │ + // optional success callback │ │ │ │ │ + var success; │ │ │ │ │ + if (config.success) { │ │ │ │ │ + success = (config.scope) ? │ │ │ │ │ + OpenLayers.Function.bind(config.success, config.scope) : │ │ │ │ │ + config.success; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // optional failure callback │ │ │ │ │ + var failure; │ │ │ │ │ + if (config.failure) { │ │ │ │ │ + failure = (config.scope) ? │ │ │ │ │ + OpenLayers.Function.bind(config.failure, config.scope) : │ │ │ │ │ + config.failure; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (OpenLayers.Util.createUrlObject(config.url).protocol == "file:" && │ │ │ │ │ + request.responseText) { │ │ │ │ │ + request.status = 200; │ │ │ │ │ + } │ │ │ │ │ + complete(request); │ │ │ │ │ + │ │ │ │ │ + if (!request.status || (request.status >= 200 && request.status < 300)) { │ │ │ │ │ + this.events.triggerEvent("success", options); │ │ │ │ │ + if (success) { │ │ │ │ │ + success(request); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + if (request.status && (request.status < 200 || request.status >= 300)) { │ │ │ │ │ + this.events.triggerEvent("failure", options); │ │ │ │ │ + if (failure) { │ │ │ │ │ + failure(request); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: controls │ │ │ │ │ - * {Array()} List of controls associated with the map. │ │ │ │ │ + * APIMethod: GET │ │ │ │ │ + * Send an HTTP GET request. Additional configuration properties are │ │ │ │ │ + * documented in the method, with the method property set │ │ │ │ │ + * to GET. │ │ │ │ │ * │ │ │ │ │ - * If not provided in the map options at construction, the map will │ │ │ │ │ - * by default be given the following controls if present in the build: │ │ │ │ │ - * - or │ │ │ │ │ - * - or │ │ │ │ │ - * - │ │ │ │ │ - * - │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} Object with properties for configuring the request. │ │ │ │ │ + * See the method for documentation of allowed properties. │ │ │ │ │ + * This object is modified and should not be reused. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {XMLHttpRequest} Request object. │ │ │ │ │ */ │ │ │ │ │ - controls: null, │ │ │ │ │ + GET: function(config) { │ │ │ │ │ + config = OpenLayers.Util.extend(config, { │ │ │ │ │ + method: "GET" │ │ │ │ │ + }); │ │ │ │ │ + return OpenLayers.Request.issue(config); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: popups │ │ │ │ │ - * {Array()} List of popups associated with the map │ │ │ │ │ + * APIMethod: POST │ │ │ │ │ + * Send a POST request. Additional configuration properties are │ │ │ │ │ + * documented in the method, with the method property set │ │ │ │ │ + * to POST and "Content-Type" header set to "application/xml". │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} Object with properties for configuring the request. │ │ │ │ │ + * See the method for documentation of allowed properties. The │ │ │ │ │ + * default "Content-Type" header will be set to "application-xml" if │ │ │ │ │ + * none is provided. This object is modified and should not be reused. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {XMLHttpRequest} Request object. │ │ │ │ │ */ │ │ │ │ │ - popups: null, │ │ │ │ │ + POST: function(config) { │ │ │ │ │ + config = OpenLayers.Util.extend(config, { │ │ │ │ │ + method: "POST" │ │ │ │ │ + }); │ │ │ │ │ + // set content type to application/xml if it isn't already set │ │ │ │ │ + config.headers = config.headers ? config.headers : {}; │ │ │ │ │ + if (!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) { │ │ │ │ │ + config.headers["Content-Type"] = "application/xml"; │ │ │ │ │ + } │ │ │ │ │ + return OpenLayers.Request.issue(config); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: baseLayer │ │ │ │ │ - * {} The currently selected base layer. This determines │ │ │ │ │ - * min/max zoom level, projection, etc. │ │ │ │ │ + * APIMethod: PUT │ │ │ │ │ + * Send an HTTP PUT request. Additional configuration properties are │ │ │ │ │ + * documented in the method, with the method property set │ │ │ │ │ + * to PUT and "Content-Type" header set to "application/xml". │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} Object with properties for configuring the request. │ │ │ │ │ + * See the method for documentation of allowed properties. The │ │ │ │ │ + * default "Content-Type" header will be set to "application-xml" if │ │ │ │ │ + * none is provided. This object is modified and should not be reused. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {XMLHttpRequest} Request object. │ │ │ │ │ */ │ │ │ │ │ - baseLayer: null, │ │ │ │ │ + PUT: function(config) { │ │ │ │ │ + config = OpenLayers.Util.extend(config, { │ │ │ │ │ + method: "PUT" │ │ │ │ │ + }); │ │ │ │ │ + // set content type to application/xml if it isn't already set │ │ │ │ │ + config.headers = config.headers ? config.headers : {}; │ │ │ │ │ + if (!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) { │ │ │ │ │ + config.headers["Content-Type"] = "application/xml"; │ │ │ │ │ + } │ │ │ │ │ + return OpenLayers.Request.issue(config); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: center │ │ │ │ │ - * {} The current center of the map │ │ │ │ │ + * APIMethod: DELETE │ │ │ │ │ + * Send an HTTP DELETE request. Additional configuration properties are │ │ │ │ │ + * documented in the method, with the method property set │ │ │ │ │ + * to DELETE. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} Object with properties for configuring the request. │ │ │ │ │ + * See the method for documentation of allowed properties. │ │ │ │ │ + * This object is modified and should not be reused. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {XMLHttpRequest} Request object. │ │ │ │ │ */ │ │ │ │ │ - center: null, │ │ │ │ │ + DELETE: function(config) { │ │ │ │ │ + config = OpenLayers.Util.extend(config, { │ │ │ │ │ + method: "DELETE" │ │ │ │ │ + }); │ │ │ │ │ + return OpenLayers.Request.issue(config); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: resolution │ │ │ │ │ - * {Float} The resolution of the map. │ │ │ │ │ + * APIMethod: HEAD │ │ │ │ │ + * Send an HTTP HEAD request. Additional configuration properties are │ │ │ │ │ + * documented in the method, with the method property set │ │ │ │ │ + * to HEAD. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} Object with properties for configuring the request. │ │ │ │ │ + * See the method for documentation of allowed properties. │ │ │ │ │ + * This object is modified and should not be reused. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {XMLHttpRequest} Request object. │ │ │ │ │ */ │ │ │ │ │ - resolution: null, │ │ │ │ │ + HEAD: function(config) { │ │ │ │ │ + config = OpenLayers.Util.extend(config, { │ │ │ │ │ + method: "HEAD" │ │ │ │ │ + }); │ │ │ │ │ + return OpenLayers.Request.issue(config); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: zoom │ │ │ │ │ - * {Integer} The current zoom level of the map │ │ │ │ │ + * APIMethod: OPTIONS │ │ │ │ │ + * Send an HTTP OPTIONS request. Additional configuration properties are │ │ │ │ │ + * documented in the method, with the method property set │ │ │ │ │ + * to OPTIONS. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} Object with properties for configuring the request. │ │ │ │ │ + * See the method for documentation of allowed properties. │ │ │ │ │ + * This object is modified and should not be reused. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {XMLHttpRequest} Request object. │ │ │ │ │ */ │ │ │ │ │ - zoom: 0, │ │ │ │ │ + OPTIONS: function(config) { │ │ │ │ │ + config = OpenLayers.Util.extend(config, { │ │ │ │ │ + method: "OPTIONS" │ │ │ │ │ + }); │ │ │ │ │ + return OpenLayers.Request.issue(config); │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: panRatio │ │ │ │ │ - * {Float} The ratio of the current extent within │ │ │ │ │ - * which panning will tween. │ │ │ │ │ - */ │ │ │ │ │ - panRatio: 1.5, │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Feature.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: options │ │ │ │ │ - * {Object} The options object passed to the class constructor. Read-only. │ │ │ │ │ - */ │ │ │ │ │ - options: null, │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - // Options │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: tileSize │ │ │ │ │ - * {} Set in the map options to override the default tile │ │ │ │ │ - * size for this map. │ │ │ │ │ - */ │ │ │ │ │ - tileSize: null, │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: projection │ │ │ │ │ - * {String} Set in the map options to specify the default projection │ │ │ │ │ - * for layers added to this map. When using a projection other than EPSG:4326 │ │ │ │ │ - * (CRS:84, Geographic) or EPSG:3857 (EPSG:900913, Web Mercator), │ │ │ │ │ - * also set maxExtent, maxResolution or resolutions. Default is "EPSG:4326". │ │ │ │ │ - * Note that the projection of the map is usually determined │ │ │ │ │ - * by that of the current baseLayer (see and ). │ │ │ │ │ - */ │ │ │ │ │ - projection: "EPSG:4326", │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Feature │ │ │ │ │ + * Features are combinations of geography and attributes. The OpenLayers.Feature │ │ │ │ │ + * class specifically combines a marker and a lonlat. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Feature = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: units │ │ │ │ │ - * {String} The map units. Possible values are 'degrees' (or 'dd'), 'm', │ │ │ │ │ - * 'ft', 'km', 'mi', 'inches'. Normally taken from the projection. │ │ │ │ │ - * Only required if both map and layers do not define a projection, │ │ │ │ │ - * or if they define a projection which does not define units │ │ │ │ │ + /** │ │ │ │ │ + * Property: layer │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - units: null, │ │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: resolutions │ │ │ │ │ - * {Array(Float)} A list of map resolutions (map units per pixel) in │ │ │ │ │ - * descending order. If this is not set in the layer constructor, it │ │ │ │ │ - * will be set based on other resolution related properties │ │ │ │ │ - * (maxExtent, maxResolution, maxScale, etc.). │ │ │ │ │ + /** │ │ │ │ │ + * Property: id │ │ │ │ │ + * {String} │ │ │ │ │ */ │ │ │ │ │ - resolutions: null, │ │ │ │ │ + id: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: maxResolution │ │ │ │ │ - * {Float} Required if you are not displaying the whole world on a tile │ │ │ │ │ - * with the size specified in . │ │ │ │ │ + /** │ │ │ │ │ + * Property: lonlat │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - maxResolution: null, │ │ │ │ │ + lonlat: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: minResolution │ │ │ │ │ - * {Float} │ │ │ │ │ + /** │ │ │ │ │ + * Property: data │ │ │ │ │ + * {Object} │ │ │ │ │ */ │ │ │ │ │ - minResolution: null, │ │ │ │ │ + data: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: maxScale │ │ │ │ │ - * {Float} │ │ │ │ │ + /** │ │ │ │ │ + * Property: marker │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - maxScale: null, │ │ │ │ │ + marker: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: minScale │ │ │ │ │ - * {Float} │ │ │ │ │ + * APIProperty: popupClass │ │ │ │ │ + * {} The class which will be used to instantiate │ │ │ │ │ + * a new Popup. Default is . │ │ │ │ │ */ │ │ │ │ │ - minScale: null, │ │ │ │ │ + popupClass: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: maxExtent │ │ │ │ │ - * {|Array} If provided as an array, the array │ │ │ │ │ - * should consist of four values (left, bottom, right, top). │ │ │ │ │ - * The maximum extent for the map. │ │ │ │ │ - * Default depends on projection; if this is one of those defined in OpenLayers.Projection.defaults │ │ │ │ │ - * (EPSG:4326 or web mercator), maxExtent will be set to the value defined there; │ │ │ │ │ - * else, defaults to null. │ │ │ │ │ - * To restrict user panning and zooming of the map, use instead. │ │ │ │ │ - * The value for will change calculations for tile URLs. │ │ │ │ │ + /** │ │ │ │ │ + * Property: popup │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - maxExtent: null, │ │ │ │ │ + popup: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: minExtent │ │ │ │ │ - * {|Array} If provided as an array, the array │ │ │ │ │ - * should consist of four values (left, bottom, right, top). │ │ │ │ │ - * The minimum extent for the map. Defaults to null. │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Feature │ │ │ │ │ + * Constructor for features. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * layer - {} │ │ │ │ │ + * lonlat - {} │ │ │ │ │ + * data - {Object} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - minExtent: null, │ │ │ │ │ + initialize: function(layer, lonlat, data) { │ │ │ │ │ + this.layer = layer; │ │ │ │ │ + this.lonlat = lonlat; │ │ │ │ │ + this.data = (data != null) ? data : {}; │ │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: restrictedExtent │ │ │ │ │ - * {|Array} If provided as an array, the array │ │ │ │ │ - * should consist of four values (left, bottom, right, top). │ │ │ │ │ - * Limit map navigation to this extent where possible. │ │ │ │ │ - * If a non-null restrictedExtent is set, panning will be restricted │ │ │ │ │ - * to the given bounds. In addition, zooming to a resolution that │ │ │ │ │ - * displays more than the restricted extent will center the map │ │ │ │ │ - * on the restricted extent. If you wish to limit the zoom level │ │ │ │ │ - * or resolution, use maxResolution. │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroy │ │ │ │ │ + * nullify references to prevent circular references and memory leaks │ │ │ │ │ */ │ │ │ │ │ - restrictedExtent: null, │ │ │ │ │ + destroy: function() { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: numZoomLevels │ │ │ │ │ - * {Integer} Number of zoom levels for the map. Defaults to 16. Set a │ │ │ │ │ - * different value in the map options if needed. │ │ │ │ │ - */ │ │ │ │ │ - numZoomLevels: 16, │ │ │ │ │ + //remove the popup from the map │ │ │ │ │ + if ((this.layer != null) && (this.layer.map != null)) { │ │ │ │ │ + if (this.popup != null) { │ │ │ │ │ + this.layer.map.removePopup(this.popup); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + // remove the marker from the layer │ │ │ │ │ + if (this.layer != null && this.marker != null) { │ │ │ │ │ + this.layer.removeMarker(this.marker); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.layer = null; │ │ │ │ │ + this.id = null; │ │ │ │ │ + this.lonlat = null; │ │ │ │ │ + this.data = null; │ │ │ │ │ + if (this.marker != null) { │ │ │ │ │ + this.destroyMarker(this.marker); │ │ │ │ │ + this.marker = null; │ │ │ │ │ + } │ │ │ │ │ + if (this.popup != null) { │ │ │ │ │ + this.destroyPopup(this.popup); │ │ │ │ │ + this.popup = null; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: theme │ │ │ │ │ - * {String} Relative path to a CSS file from which to load theme styles. │ │ │ │ │ - * Specify null in the map options (e.g. {theme: null}) if you │ │ │ │ │ - * want to get cascading style declarations - by putting links to │ │ │ │ │ - * stylesheets or style declarations directly in your page. │ │ │ │ │ + * Method: onScreen │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Whether or not the feature is currently visible on screen │ │ │ │ │ + * (based on its 'lonlat' property) │ │ │ │ │ */ │ │ │ │ │ - theme: null, │ │ │ │ │ + onScreen: function() { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: displayProjection │ │ │ │ │ - * {} Requires proj4js support for projections other │ │ │ │ │ - * than EPSG:4326 or EPSG:900913/EPSG:3857. Projection used by │ │ │ │ │ - * several controls to display data to user. If this property is set, │ │ │ │ │ - * it will be set on any control which has a null displayProjection │ │ │ │ │ - * property at the time the control is added to the map. │ │ │ │ │ - */ │ │ │ │ │ - displayProjection: null, │ │ │ │ │ + var onScreen = false; │ │ │ │ │ + if ((this.layer != null) && (this.layer.map != null)) { │ │ │ │ │ + var screenBounds = this.layer.map.getExtent(); │ │ │ │ │ + onScreen = screenBounds.containsLonLat(this.lonlat); │ │ │ │ │ + } │ │ │ │ │ + return onScreen; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: tileManager │ │ │ │ │ - * {|Object} By default, and if the build contains │ │ │ │ │ - * TileManager.js, the map will use the TileManager to queue image requests │ │ │ │ │ - * and to cache tile image elements. To create a map without a TileManager │ │ │ │ │ - * configure the map with tileManager: null. To create a TileManager with │ │ │ │ │ - * non-default options, supply the options instead or alternatively supply │ │ │ │ │ - * an instance of {}. │ │ │ │ │ - */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: fallThrough │ │ │ │ │ - * {Boolean} Should OpenLayers allow events on the map to fall through to │ │ │ │ │ - * other elements on the page, or should it swallow them? (#457) │ │ │ │ │ - * Default is to swallow. │ │ │ │ │ + * Method: createMarker │ │ │ │ │ + * Based on the data associated with the Feature, create and return a marker object. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} A Marker Object created from the 'lonlat' and 'icon' properties │ │ │ │ │ + * set in this.data. If no 'lonlat' is set, returns null. If no │ │ │ │ │ + * 'icon' is set, OpenLayers.Marker() will load the default image. │ │ │ │ │ + * │ │ │ │ │ + * Note - this.marker is set to return value │ │ │ │ │ + * │ │ │ │ │ */ │ │ │ │ │ - fallThrough: false, │ │ │ │ │ + createMarker: function() { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: autoUpdateSize │ │ │ │ │ - * {Boolean} Should OpenLayers automatically update the size of the map │ │ │ │ │ - * when the resize event is fired. Default is true. │ │ │ │ │ - */ │ │ │ │ │ - autoUpdateSize: true, │ │ │ │ │ + if (this.lonlat != null) { │ │ │ │ │ + this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon); │ │ │ │ │ + } │ │ │ │ │ + return this.marker; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: eventListeners │ │ │ │ │ - * {Object} If set as an option at construction, the eventListeners │ │ │ │ │ - * object will be registered with . Object │ │ │ │ │ - * structure must be a listeners object as shown in the example for │ │ │ │ │ - * the events.on method. │ │ │ │ │ + * Method: destroyMarker │ │ │ │ │ + * Destroys marker. │ │ │ │ │ + * If user overrides the createMarker() function, s/he should be able │ │ │ │ │ + * to also specify an alternative function for destroying it │ │ │ │ │ */ │ │ │ │ │ - eventListeners: null, │ │ │ │ │ + destroyMarker: function() { │ │ │ │ │ + this.marker.destroy(); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: panTween │ │ │ │ │ - * {} Animated panning tween object, see panTo() │ │ │ │ │ + * Method: createPopup │ │ │ │ │ + * Creates a popup object created from the 'lonlat', 'popupSize', │ │ │ │ │ + * and 'popupContentHTML' properties set in this.data. It uses │ │ │ │ │ + * this.marker.icon as default anchor. │ │ │ │ │ + * │ │ │ │ │ + * If no 'lonlat' is set, returns null. │ │ │ │ │ + * If no this.marker has been created, no anchor is sent. │ │ │ │ │ + * │ │ │ │ │ + * Note - the returned popup object is 'owned' by the feature, so you │ │ │ │ │ + * cannot use the popup's destroy method to discard the popup. │ │ │ │ │ + * Instead, you must use the feature's destroyPopup │ │ │ │ │ + * │ │ │ │ │ + * Note - this.popup is set to return value │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * closeBox - {Boolean} create popup with closebox or not │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} Returns the created popup, which is also set │ │ │ │ │ + * as 'popup' property of this feature. Will be of whatever type │ │ │ │ │ + * specified by this feature's 'popupClass' property, but must be │ │ │ │ │ + * of type . │ │ │ │ │ + * │ │ │ │ │ */ │ │ │ │ │ - panTween: null, │ │ │ │ │ + createPopup: function(closeBox) { │ │ │ │ │ + │ │ │ │ │ + if (this.lonlat != null) { │ │ │ │ │ + if (!this.popup) { │ │ │ │ │ + var anchor = (this.marker) ? this.marker.icon : null; │ │ │ │ │ + var popupClass = this.popupClass ? │ │ │ │ │ + this.popupClass : OpenLayers.Popup.Anchored; │ │ │ │ │ + this.popup = new popupClass(this.id + "_popup", │ │ │ │ │ + this.lonlat, │ │ │ │ │ + this.data.popupSize, │ │ │ │ │ + this.data.popupContentHTML, │ │ │ │ │ + anchor, │ │ │ │ │ + closeBox); │ │ │ │ │ + } │ │ │ │ │ + if (this.data.overflow != null) { │ │ │ │ │ + this.popup.contentDiv.style.overflow = this.data.overflow; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.popup.feature = this; │ │ │ │ │ + } │ │ │ │ │ + return this.popup; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: panMethod │ │ │ │ │ - * {Function} The Easing function to be used for tweening. Default is │ │ │ │ │ - * OpenLayers.Easing.Expo.easeOut. Setting this to 'null' turns off │ │ │ │ │ - * animated panning. │ │ │ │ │ + * Method: destroyPopup │ │ │ │ │ + * Destroys the popup created via createPopup. │ │ │ │ │ + * │ │ │ │ │ + * As with the marker, if user overrides the createPopup() function, s/he │ │ │ │ │ + * should also be able to override the destruction │ │ │ │ │ */ │ │ │ │ │ - panMethod: OpenLayers.Easing.Expo.easeOut, │ │ │ │ │ + destroyPopup: function() { │ │ │ │ │ + if (this.popup) { │ │ │ │ │ + this.popup.feature = null; │ │ │ │ │ + this.popup.destroy(); │ │ │ │ │ + this.popup = null; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: panDuration │ │ │ │ │ - * {Integer} The number of steps to be passed to the │ │ │ │ │ - * OpenLayers.Tween.start() method when the map is │ │ │ │ │ - * panned. │ │ │ │ │ - * Default is 50. │ │ │ │ │ + CLASS_NAME: "OpenLayers.Feature" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Feature/Vector.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +// TRASH THIS │ │ │ │ │ +OpenLayers.State = { │ │ │ │ │ + /** states */ │ │ │ │ │ + UNKNOWN: 'Unknown', │ │ │ │ │ + INSERT: 'Insert', │ │ │ │ │ + UPDATE: 'Update', │ │ │ │ │ + DELETE: 'Delete' │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Feature.js │ │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Feature.Vector │ │ │ │ │ + * Vector features use the OpenLayers.Geometry classes as geometry description. │ │ │ │ │ + * They have an 'attributes' property, which is the data object, and a 'style' │ │ │ │ │ + * property, the default values of which are defined in the │ │ │ │ │ + * objects. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: fid │ │ │ │ │ + * {String} │ │ │ │ │ */ │ │ │ │ │ - panDuration: 50, │ │ │ │ │ + fid: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: zoomTween │ │ │ │ │ - * {} Animated zooming tween object, see zoomTo() │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: geometry │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - zoomTween: null, │ │ │ │ │ + geometry: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: zoomMethod │ │ │ │ │ - * {Function} The Easing function to be used for tweening. Default is │ │ │ │ │ - * OpenLayers.Easing.Quad.easeOut. Setting this to 'null' turns off │ │ │ │ │ - * animated zooming. │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: attributes │ │ │ │ │ + * {Object} This object holds arbitrary, serializable properties that │ │ │ │ │ + * describe the feature. │ │ │ │ │ */ │ │ │ │ │ - zoomMethod: OpenLayers.Easing.Quad.easeOut, │ │ │ │ │ + attributes: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: zoomDuration │ │ │ │ │ - * {Integer} The number of steps to be passed to the │ │ │ │ │ - * OpenLayers.Tween.start() method when the map is zoomed. │ │ │ │ │ - * Default is 20. │ │ │ │ │ + * Property: bounds │ │ │ │ │ + * {} The box bounding that feature's geometry, that │ │ │ │ │ + * property can be set by an object when │ │ │ │ │ + * deserializing the feature, so in most cases it represents an │ │ │ │ │ + * information set by the server. │ │ │ │ │ */ │ │ │ │ │ - zoomDuration: 20, │ │ │ │ │ + bounds: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: paddingForPopups │ │ │ │ │ - * {} Outside margin of the popup. Used to prevent │ │ │ │ │ - * the popup from getting too close to the map border. │ │ │ │ │ + /** │ │ │ │ │ + * Property: state │ │ │ │ │ + * {String} │ │ │ │ │ */ │ │ │ │ │ - paddingForPopups: null, │ │ │ │ │ + state: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: layerContainerOriginPx │ │ │ │ │ - * {Object} Cached object representing the layer container origin (in pixels). │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: style │ │ │ │ │ + * {Object} │ │ │ │ │ */ │ │ │ │ │ - layerContainerOriginPx: null, │ │ │ │ │ + style: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: minPx │ │ │ │ │ - * {Object} An object with a 'x' and 'y' values that is the lower │ │ │ │ │ - * left of maxExtent in viewport pixel space. │ │ │ │ │ - * Used to verify in moveByPx that the new location we're moving to │ │ │ │ │ - * is valid. It is also used in the getLonLatFromViewPortPx function │ │ │ │ │ - * of Layer. │ │ │ │ │ + * APIProperty: url │ │ │ │ │ + * {String} If this property is set it will be taken into account by │ │ │ │ │ + * {} when upadting or deleting the feature. │ │ │ │ │ */ │ │ │ │ │ - minPx: null, │ │ │ │ │ + url: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: maxPx │ │ │ │ │ - * {Object} An object with a 'x' and 'y' values that is the top │ │ │ │ │ - * right of maxExtent in viewport pixel space. │ │ │ │ │ - * Used to verify in moveByPx that the new location we're moving to │ │ │ │ │ - * is valid. │ │ │ │ │ + * Property: renderIntent │ │ │ │ │ + * {String} rendering intent currently being used │ │ │ │ │ */ │ │ │ │ │ - maxPx: null, │ │ │ │ │ + renderIntent: "default", │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Map │ │ │ │ │ - * Constructor for a new OpenLayers.Map instance. There are two possible │ │ │ │ │ - * ways to call the map constructor. See the examples below. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * div - {DOMElement|String} The element or id of an element in your page │ │ │ │ │ - * that will contain the map. May be omitted if the
option is │ │ │ │ │ - * provided or if you intend to call the method later. │ │ │ │ │ - * options - {Object} Optional object with properties to tag onto the map. │ │ │ │ │ + * APIProperty: modified │ │ │ │ │ + * {Object} An object with the originals of the geometry and attributes of │ │ │ │ │ + * the feature, if they were changed. Currently this property is only read │ │ │ │ │ + * by , and written by │ │ │ │ │ + * , which sets the geometry property. │ │ │ │ │ + * Applications can set the originals of modified attributes in the │ │ │ │ │ + * attributes property. Note that applications have to check if this │ │ │ │ │ + * object and the attributes property is already created before using it. │ │ │ │ │ + * After a change made with ModifyFeature, this object could look like │ │ │ │ │ * │ │ │ │ │ - * Valid options (in addition to the listed API properties): │ │ │ │ │ - * center - {|Array} The default initial center of the map. │ │ │ │ │ - * If provided as array, the first value is the x coordinate, │ │ │ │ │ - * and the 2nd value is the y coordinate. │ │ │ │ │ - * Only specify if is provided. │ │ │ │ │ - * Note that if an ArgParser/Permalink control is present, │ │ │ │ │ - * and the querystring contains coordinates, center will be set │ │ │ │ │ - * by that, and this option will be ignored. │ │ │ │ │ - * zoom - {Number} The initial zoom level for the map. Only specify if │ │ │ │ │ - * is provided. │ │ │ │ │ - * Note that if an ArgParser/Permalink control is present, │ │ │ │ │ - * and the querystring contains a zoom level, zoom will be set │ │ │ │ │ - * by that, and this option will be ignored. │ │ │ │ │ - * extent - {|Array} The initial extent of the map. │ │ │ │ │ - * If provided as an array, the array should consist of │ │ │ │ │ - * four values (left, bottom, right, top). │ │ │ │ │ - * Only specify if
and are not provided. │ │ │ │ │ - * │ │ │ │ │ - * Examples: │ │ │ │ │ * (code) │ │ │ │ │ - * // create a map with default options in an element with the id "map1" │ │ │ │ │ - * var map = new OpenLayers.Map("map1"); │ │ │ │ │ + * { │ │ │ │ │ + * geometry: >Object │ │ │ │ │ + * } │ │ │ │ │ + * (end) │ │ │ │ │ * │ │ │ │ │ - * // create a map with non-default options in an element with id "map2" │ │ │ │ │ - * var options = { │ │ │ │ │ - * projection: "EPSG:3857", │ │ │ │ │ - * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000), │ │ │ │ │ - * center: new OpenLayers.LonLat(-12356463.476333, 5621521.4854095) │ │ │ │ │ - * }; │ │ │ │ │ - * var map = new OpenLayers.Map("map2", options); │ │ │ │ │ + * When an application has made changes to feature attributes, it could │ │ │ │ │ + * have set the attributes to something like this: │ │ │ │ │ * │ │ │ │ │ - * // map with non-default options - same as above but with a single argument, │ │ │ │ │ - * // a restricted extent, and using arrays for bounds and center │ │ │ │ │ - * var map = new OpenLayers.Map({ │ │ │ │ │ + * (code) │ │ │ │ │ + * { │ │ │ │ │ + * attributes: { │ │ │ │ │ + * myAttribute: "original" │ │ │ │ │ + * } │ │ │ │ │ + * } │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Note that only checks for truthy values in │ │ │ │ │ + * *modified.geometry* and the attribute names in *modified.attributes*, │ │ │ │ │ + * but it is recommended to set the original values (and not just true) as │ │ │ │ │ + * attribute value, so applications could use this information to undo │ │ │ │ │ + * changes. │ │ │ │ │ + */ │ │ │ │ │ + modified: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Feature.Vector │ │ │ │ │ + * Create a vector feature. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * geometry - {} The geometry that this feature │ │ │ │ │ + * represents. │ │ │ │ │ + * attributes - {Object} An optional object that will be mapped to the │ │ │ │ │ + * property. │ │ │ │ │ + * style - {Object} An optional style object. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(geometry, attributes, style) { │ │ │ │ │ + OpenLayers.Feature.prototype.initialize.apply(this, │ │ │ │ │ + [null, null, attributes]); │ │ │ │ │ + this.lonlat = null; │ │ │ │ │ + this.geometry = geometry ? geometry : null; │ │ │ │ │ + this.state = null; │ │ │ │ │ + this.attributes = {}; │ │ │ │ │ + if (attributes) { │ │ │ │ │ + this.attributes = OpenLayers.Util.extend(this.attributes, │ │ │ │ │ + attributes); │ │ │ │ │ + } │ │ │ │ │ + this.style = style ? style : null; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroy │ │ │ │ │ + * nullify references to prevent circular references and memory leaks │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + if (this.layer) { │ │ │ │ │ + this.layer.removeFeatures(this); │ │ │ │ │ + this.layer = null; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.geometry = null; │ │ │ │ │ + this.modified = null; │ │ │ │ │ + OpenLayers.Feature.prototype.destroy.apply(this, arguments); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: clone │ │ │ │ │ + * Create a clone of this vector feature. Does not set any non-standard │ │ │ │ │ + * properties. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} An exact clone of this vector feature. │ │ │ │ │ + */ │ │ │ │ │ + clone: function() { │ │ │ │ │ + return new OpenLayers.Feature.Vector( │ │ │ │ │ + this.geometry ? this.geometry.clone() : null, │ │ │ │ │ + this.attributes, │ │ │ │ │ + this.style); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: onScreen │ │ │ │ │ + * Determine whether the feature is within the map viewport. This method │ │ │ │ │ + * tests for an intersection between the geometry and the viewport │ │ │ │ │ + * bounds. If a more effecient but less precise geometry bounds │ │ │ │ │ + * intersection is desired, call the method with the boundsOnly │ │ │ │ │ + * parameter true. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * boundsOnly - {Boolean} Only test whether a feature's bounds intersects │ │ │ │ │ + * the viewport bounds. Default is false. If false, the feature's │ │ │ │ │ + * geometry must intersect the viewport for onScreen to return true. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The feature is currently visible on screen (optionally │ │ │ │ │ + * based on its bounds if boundsOnly is true). │ │ │ │ │ + */ │ │ │ │ │ + onScreen: function(boundsOnly) { │ │ │ │ │ + var onScreen = false; │ │ │ │ │ + if (this.layer && this.layer.map) { │ │ │ │ │ + var screenBounds = this.layer.map.getExtent(); │ │ │ │ │ + if (boundsOnly) { │ │ │ │ │ + var featureBounds = this.geometry.getBounds(); │ │ │ │ │ + onScreen = screenBounds.intersectsBounds(featureBounds); │ │ │ │ │ + } else { │ │ │ │ │ + var screenPoly = screenBounds.toGeometry(); │ │ │ │ │ + onScreen = screenPoly.intersects(this.geometry); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return onScreen; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: getVisibility │ │ │ │ │ + * Determine whether the feature is displayed or not. It may not displayed │ │ │ │ │ + * because: │ │ │ │ │ + * - its style display property is set to 'none', │ │ │ │ │ + * - it doesn't belong to any layer, │ │ │ │ │ + * - the styleMap creates a symbolizer with display property set to 'none' │ │ │ │ │ + * for it, │ │ │ │ │ + * - the layer which it belongs to is not visible. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The feature is currently displayed. │ │ │ │ │ + */ │ │ │ │ │ + getVisibility: function() { │ │ │ │ │ + return !(this.style && this.style.display == 'none' || │ │ │ │ │ + !this.layer || │ │ │ │ │ + this.layer && this.layer.styleMap && │ │ │ │ │ + this.layer.styleMap.createSymbolizer(this, this.renderIntent).display == 'none' || │ │ │ │ │ + this.layer && !this.layer.getVisibility()); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: createMarker │ │ │ │ │ + * HACK - we need to decide if all vector features should be able to │ │ │ │ │ + * create markers │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} For now just returns null │ │ │ │ │ + */ │ │ │ │ │ + createMarker: function() { │ │ │ │ │ + return null; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroyMarker │ │ │ │ │ + * HACK - we need to decide if all vector features should be able to │ │ │ │ │ + * delete markers │ │ │ │ │ + * │ │ │ │ │ + * If user overrides the createMarker() function, s/he should be able │ │ │ │ │ + * to also specify an alternative function for destroying it │ │ │ │ │ + */ │ │ │ │ │ + destroyMarker: function() { │ │ │ │ │ + // pass │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: createPopup │ │ │ │ │ + * HACK - we need to decide if all vector features should be able to │ │ │ │ │ + * create popups │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} For now just returns null │ │ │ │ │ + */ │ │ │ │ │ + createPopup: function() { │ │ │ │ │ + return null; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: atPoint │ │ │ │ │ + * Determins whether the feature intersects with the specified location. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * lonlat - {|Object} OpenLayers.LonLat or an │ │ │ │ │ + * object with a 'lon' and 'lat' properties. │ │ │ │ │ + * toleranceLon - {float} Optional tolerance in Geometric Coords │ │ │ │ │ + * toleranceLat - {float} Optional tolerance in Geographic Coords │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Whether or not the feature is at the specified location │ │ │ │ │ + */ │ │ │ │ │ + atPoint: function(lonlat, toleranceLon, toleranceLat) { │ │ │ │ │ + var atPoint = false; │ │ │ │ │ + if (this.geometry) { │ │ │ │ │ + atPoint = this.geometry.atPoint(lonlat, toleranceLon, │ │ │ │ │ + toleranceLat); │ │ │ │ │ + } │ │ │ │ │ + return atPoint; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroyPopup │ │ │ │ │ + * HACK - we need to decide if all vector features should be able to │ │ │ │ │ + * delete popups │ │ │ │ │ + */ │ │ │ │ │ + destroyPopup: function() { │ │ │ │ │ + // pass │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: move │ │ │ │ │ + * Moves the feature and redraws it at its new location │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * location - { or } the │ │ │ │ │ + * location to which to move the feature. │ │ │ │ │ + */ │ │ │ │ │ + move: function(location) { │ │ │ │ │ + │ │ │ │ │ + if (!this.layer || !this.geometry.move) { │ │ │ │ │ + //do nothing if no layer or immoveable geometry │ │ │ │ │ + return undefined; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + var pixel; │ │ │ │ │ + if (location.CLASS_NAME == "OpenLayers.LonLat") { │ │ │ │ │ + pixel = this.layer.getViewPortPxFromLonLat(location); │ │ │ │ │ + } else { │ │ │ │ │ + pixel = location; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + var lastPixel = this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat()); │ │ │ │ │ + var res = this.layer.map.getResolution(); │ │ │ │ │ + this.geometry.move(res * (pixel.x - lastPixel.x), │ │ │ │ │ + res * (lastPixel.y - pixel.y)); │ │ │ │ │ + this.layer.drawFeature(this); │ │ │ │ │ + return lastPixel; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: toState │ │ │ │ │ + * Sets the new state │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * state - {String} │ │ │ │ │ + */ │ │ │ │ │ + toState: function(state) { │ │ │ │ │ + if (state == OpenLayers.State.UPDATE) { │ │ │ │ │ + switch (this.state) { │ │ │ │ │ + case OpenLayers.State.UNKNOWN: │ │ │ │ │ + case OpenLayers.State.DELETE: │ │ │ │ │ + this.state = state; │ │ │ │ │ + break; │ │ │ │ │ + case OpenLayers.State.UPDATE: │ │ │ │ │ + case OpenLayers.State.INSERT: │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } else if (state == OpenLayers.State.INSERT) { │ │ │ │ │ + switch (this.state) { │ │ │ │ │ + case OpenLayers.State.UNKNOWN: │ │ │ │ │ + break; │ │ │ │ │ + default: │ │ │ │ │ + this.state = state; │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } else if (state == OpenLayers.State.DELETE) { │ │ │ │ │ + switch (this.state) { │ │ │ │ │ + case OpenLayers.State.INSERT: │ │ │ │ │ + // the feature should be destroyed │ │ │ │ │ + break; │ │ │ │ │ + case OpenLayers.State.DELETE: │ │ │ │ │ + break; │ │ │ │ │ + case OpenLayers.State.UNKNOWN: │ │ │ │ │ + case OpenLayers.State.UPDATE: │ │ │ │ │ + this.state = state; │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } else if (state == OpenLayers.State.UNKNOWN) { │ │ │ │ │ + this.state = state; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Feature.Vector" │ │ │ │ │ +}); │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Constant: OpenLayers.Feature.Vector.style │ │ │ │ │ + * OpenLayers features can have a number of style attributes. The 'default' │ │ │ │ │ + * style will typically be used if no other style is specified. These │ │ │ │ │ + * styles correspond for the most part, to the styling properties defined │ │ │ │ │ + * by the SVG standard. │ │ │ │ │ + * Information on fill properties: http://www.w3.org/TR/SVG/painting.html#FillProperties │ │ │ │ │ + * Information on stroke properties: http://www.w3.org/TR/SVG/painting.html#StrokeProperties │ │ │ │ │ + * │ │ │ │ │ + * Symbolizer properties: │ │ │ │ │ + * fill - {Boolean} Set to false if no fill is desired. │ │ │ │ │ + * fillColor - {String} Hex fill color. Default is "#ee9900". │ │ │ │ │ + * fillOpacity - {Number} Fill opacity (0-1). Default is 0.4 │ │ │ │ │ + * stroke - {Boolean} Set to false if no stroke is desired. │ │ │ │ │ + * strokeColor - {String} Hex stroke color. Default is "#ee9900". │ │ │ │ │ + * strokeOpacity - {Number} Stroke opacity (0-1). Default is 1. │ │ │ │ │ + * strokeWidth - {Number} Pixel stroke width. Default is 1. │ │ │ │ │ + * strokeLinecap - {String} Stroke cap type. Default is "round". [butt | round | square] │ │ │ │ │ + * strokeDashstyle - {String} Stroke dash style. Default is "solid". [dot | dash | dashdot | longdash | longdashdot | solid] │ │ │ │ │ + * graphic - {Boolean} Set to false if no graphic is desired. │ │ │ │ │ + * pointRadius - {Number} Pixel point radius. Default is 6. │ │ │ │ │ + * pointerEvents - {String} Default is "visiblePainted". │ │ │ │ │ + * cursor - {String} Default is "". │ │ │ │ │ + * externalGraphic - {String} Url to an external graphic that will be used for rendering points. │ │ │ │ │ + * graphicWidth - {Number} Pixel width for sizing an external graphic. │ │ │ │ │ + * graphicHeight - {Number} Pixel height for sizing an external graphic. │ │ │ │ │ + * graphicOpacity - {Number} Opacity (0-1) for an external graphic. │ │ │ │ │ + * graphicXOffset - {Number} Pixel offset along the positive x axis for displacing an external graphic. │ │ │ │ │ + * graphicYOffset - {Number} Pixel offset along the positive y axis for displacing an external graphic. │ │ │ │ │ + * rotation - {Number} For point symbolizers, this is the rotation of a graphic in the clockwise direction about its center point (or any point off center as specified by graphicXOffset and graphicYOffset). │ │ │ │ │ + * graphicZIndex - {Number} The integer z-index value to use in rendering. │ │ │ │ │ + * graphicName - {String} Named graphic to use when rendering points. Supported values include "circle" (default), │ │ │ │ │ + * "square", "star", "x", "cross", "triangle". │ │ │ │ │ + * graphicTitle - {String} Tooltip when hovering over a feature. *deprecated*, use title instead │ │ │ │ │ + * title - {String} Tooltip when hovering over a feature. Not supported by the canvas renderer. │ │ │ │ │ + * backgroundGraphic - {String} Url to a graphic to be used as the background under an externalGraphic. │ │ │ │ │ + * backgroundGraphicZIndex - {Number} The integer z-index value to use in rendering the background graphic. │ │ │ │ │ + * backgroundXOffset - {Number} The x offset (in pixels) for the background graphic. │ │ │ │ │ + * backgroundYOffset - {Number} The y offset (in pixels) for the background graphic. │ │ │ │ │ + * backgroundHeight - {Number} The height of the background graphic. If not provided, the graphicHeight will be used. │ │ │ │ │ + * backgroundWidth - {Number} The width of the background width. If not provided, the graphicWidth will be used. │ │ │ │ │ + * label - {String} The text for an optional label. For browsers that use the canvas renderer, this requires either │ │ │ │ │ + * fillText or mozDrawText to be available. │ │ │ │ │ + * labelAlign - {String} Label alignment. This specifies the insertion point relative to the text. It is a string │ │ │ │ │ + * composed of two characters. The first character is for the horizontal alignment, the second for the vertical │ │ │ │ │ + * alignment. Valid values for horizontal alignment: "l"=left, "c"=center, "r"=right. Valid values for vertical │ │ │ │ │ + * alignment: "t"=top, "m"=middle, "b"=bottom. Example values: "lt", "cm", "rb". Default is "cm". │ │ │ │ │ + * labelXOffset - {Number} Pixel offset along the positive x axis for displacing the label. Not supported by the canvas renderer. │ │ │ │ │ + * labelYOffset - {Number} Pixel offset along the positive y axis for displacing the label. Not supported by the canvas renderer. │ │ │ │ │ + * labelSelect - {Boolean} If set to true, labels will be selectable using SelectFeature or similar controls. │ │ │ │ │ + * Default is false. │ │ │ │ │ + * labelOutlineColor - {String} The color of the label outline. Default is 'white'. Only supported by the canvas & SVG renderers. │ │ │ │ │ + * labelOutlineWidth - {Number} The width of the label outline. Default is 3, set to 0 or null to disable. Only supported by the SVG renderers. │ │ │ │ │ + * labelOutlineOpacity - {Number} The opacity (0-1) of the label outline. Default is fontOpacity. Only supported by the canvas & SVG renderers. │ │ │ │ │ + * fontColor - {String} The font color for the label, to be provided like CSS. │ │ │ │ │ + * fontOpacity - {Number} Opacity (0-1) for the label │ │ │ │ │ + * fontFamily - {String} The font family for the label, to be provided like in CSS. │ │ │ │ │ + * fontSize - {String} The font size for the label, to be provided like in CSS. │ │ │ │ │ + * fontStyle - {String} The font style for the label, to be provided like in CSS. │ │ │ │ │ + * fontWeight - {String} The font weight for the label, to be provided like in CSS. │ │ │ │ │ + * display - {String} Symbolizers will have no effect if display is set to "none". All other values have no effect. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Feature.Vector.style = { │ │ │ │ │ + 'default': { │ │ │ │ │ + fillColor: "#ee9900", │ │ │ │ │ + fillOpacity: 0.4, │ │ │ │ │ + hoverFillColor: "white", │ │ │ │ │ + hoverFillOpacity: 0.8, │ │ │ │ │ + strokeColor: "#ee9900", │ │ │ │ │ + strokeOpacity: 1, │ │ │ │ │ + strokeWidth: 1, │ │ │ │ │ + strokeLinecap: "round", │ │ │ │ │ + strokeDashstyle: "solid", │ │ │ │ │ + hoverStrokeColor: "red", │ │ │ │ │ + hoverStrokeOpacity: 1, │ │ │ │ │ + hoverStrokeWidth: 0.2, │ │ │ │ │ + pointRadius: 6, │ │ │ │ │ + hoverPointRadius: 1, │ │ │ │ │ + hoverPointUnit: "%", │ │ │ │ │ + pointerEvents: "visiblePainted", │ │ │ │ │ + cursor: "inherit", │ │ │ │ │ + fontColor: "#000000", │ │ │ │ │ + labelAlign: "cm", │ │ │ │ │ + labelOutlineColor: "white", │ │ │ │ │ + labelOutlineWidth: 3 │ │ │ │ │ + }, │ │ │ │ │ + 'select': { │ │ │ │ │ + fillColor: "blue", │ │ │ │ │ + fillOpacity: 0.4, │ │ │ │ │ + hoverFillColor: "white", │ │ │ │ │ + hoverFillOpacity: 0.8, │ │ │ │ │ + strokeColor: "blue", │ │ │ │ │ + strokeOpacity: 1, │ │ │ │ │ + strokeWidth: 2, │ │ │ │ │ + strokeLinecap: "round", │ │ │ │ │ + strokeDashstyle: "solid", │ │ │ │ │ + hoverStrokeColor: "red", │ │ │ │ │ + hoverStrokeOpacity: 1, │ │ │ │ │ + hoverStrokeWidth: 0.2, │ │ │ │ │ + pointRadius: 6, │ │ │ │ │ + hoverPointRadius: 1, │ │ │ │ │ + hoverPointUnit: "%", │ │ │ │ │ + pointerEvents: "visiblePainted", │ │ │ │ │ + cursor: "pointer", │ │ │ │ │ + fontColor: "#000000", │ │ │ │ │ + labelAlign: "cm", │ │ │ │ │ + labelOutlineColor: "white", │ │ │ │ │ + labelOutlineWidth: 3 │ │ │ │ │ + │ │ │ │ │ + }, │ │ │ │ │ + 'temporary': { │ │ │ │ │ + fillColor: "#66cccc", │ │ │ │ │ + fillOpacity: 0.2, │ │ │ │ │ + hoverFillColor: "white", │ │ │ │ │ + hoverFillOpacity: 0.8, │ │ │ │ │ + strokeColor: "#66cccc", │ │ │ │ │ + strokeOpacity: 1, │ │ │ │ │ + strokeLinecap: "round", │ │ │ │ │ + strokeWidth: 2, │ │ │ │ │ + strokeDashstyle: "solid", │ │ │ │ │ + hoverStrokeColor: "red", │ │ │ │ │ + hoverStrokeOpacity: 1, │ │ │ │ │ + hoverStrokeWidth: 0.2, │ │ │ │ │ + pointRadius: 6, │ │ │ │ │ + hoverPointRadius: 1, │ │ │ │ │ + hoverPointUnit: "%", │ │ │ │ │ + pointerEvents: "visiblePainted", │ │ │ │ │ + cursor: "inherit", │ │ │ │ │ + fontColor: "#000000", │ │ │ │ │ + labelAlign: "cm", │ │ │ │ │ + labelOutlineColor: "white", │ │ │ │ │ + labelOutlineWidth: 3 │ │ │ │ │ + │ │ │ │ │ + }, │ │ │ │ │ + 'delete': { │ │ │ │ │ + display: "none" │ │ │ │ │ + } │ │ │ │ │ +}; │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Style.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ │ + * @requires OpenLayers/Feature/Vector.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Style │ │ │ │ │ + * This class represents a UserStyle obtained │ │ │ │ │ + * from a SLD, containing styling rules. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Style = OpenLayers.Class({ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: id │ │ │ │ │ + * {String} A unique id for this session. │ │ │ │ │ + */ │ │ │ │ │ + id: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: name │ │ │ │ │ + * {String} │ │ │ │ │ + */ │ │ │ │ │ + name: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: title │ │ │ │ │ + * {String} Title of this style (set if included in SLD) │ │ │ │ │ + */ │ │ │ │ │ + title: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: description │ │ │ │ │ + * {String} Description of this style (set if abstract is included in SLD) │ │ │ │ │ + */ │ │ │ │ │ + description: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: layerName │ │ │ │ │ + * {} name of the layer that this style belongs to, usually │ │ │ │ │ + * according to the NamedLayer attribute of an SLD document. │ │ │ │ │ + */ │ │ │ │ │ + layerName: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: isDefault │ │ │ │ │ + * {Boolean} │ │ │ │ │ + */ │ │ │ │ │ + isDefault: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: rules │ │ │ │ │ + * {Array()} │ │ │ │ │ + */ │ │ │ │ │ + rules: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: context │ │ │ │ │ + * {Object} An optional object with properties that symbolizers' property │ │ │ │ │ + * values should be evaluated against. If no context is specified, │ │ │ │ │ + * feature.attributes will be used │ │ │ │ │ + */ │ │ │ │ │ + context: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: defaultStyle │ │ │ │ │ + * {Object} hash of style properties to use as default for merging │ │ │ │ │ + * rule-based style symbolizers onto. If no rules are defined, │ │ │ │ │ + * createSymbolizer will return this style. If is set to │ │ │ │ │ + * true, the defaultStyle will only be taken into account if there are │ │ │ │ │ + * rules defined. │ │ │ │ │ + */ │ │ │ │ │ + defaultStyle: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: defaultsPerSymbolizer │ │ │ │ │ + * {Boolean} If set to true, the will extend the symbolizer │ │ │ │ │ + * of every rule. Properties of the will also be used to set │ │ │ │ │ + * missing symbolizer properties if the symbolizer has stroke, fill or │ │ │ │ │ + * graphic set to true. Default is false. │ │ │ │ │ + */ │ │ │ │ │ + defaultsPerSymbolizer: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: propertyStyles │ │ │ │ │ + * {Hash of Boolean} cache of style properties that need to be parsed for │ │ │ │ │ + * propertyNames. Property names are keys, values won't be used. │ │ │ │ │ + */ │ │ │ │ │ + propertyStyles: null, │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Style │ │ │ │ │ + * Creates a UserStyle. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * style - {Object} Optional hash of style properties that will be │ │ │ │ │ + * used as default style for this style object. This style │ │ │ │ │ + * applies if no rules are specified. Symbolizers defined in │ │ │ │ │ + * rules will extend this default style. │ │ │ │ │ + * options - {Object} An optional object with properties to set on the │ │ │ │ │ + * style. │ │ │ │ │ + * │ │ │ │ │ + * Valid options: │ │ │ │ │ + * rules - {Array()} List of rules to be added to the │ │ │ │ │ + * style. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(style, options) { │ │ │ │ │ + │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + this.rules = []; │ │ │ │ │ + if (options && options.rules) { │ │ │ │ │ + this.addRules(options.rules); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // use the default style from OpenLayers.Feature.Vector if no style │ │ │ │ │ + // was given in the constructor │ │ │ │ │ + this.setDefaultStyle(style || │ │ │ │ │ + OpenLayers.Feature.Vector.style["default"]); │ │ │ │ │ + │ │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ + * nullify references to prevent circular references and memory leaks │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + for (var i = 0, len = this.rules.length; i < len; i++) { │ │ │ │ │ + this.rules[i].destroy(); │ │ │ │ │ + this.rules[i] = null; │ │ │ │ │ + } │ │ │ │ │ + this.rules = null; │ │ │ │ │ + this.defaultStyle = null; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: createSymbolizer │ │ │ │ │ + * creates a style by applying all feature-dependent rules to the base │ │ │ │ │ + * style. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * feature - {} feature to evaluate rules for │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Object} symbolizer hash │ │ │ │ │ + */ │ │ │ │ │ + createSymbolizer: function(feature) { │ │ │ │ │ + var style = this.defaultsPerSymbolizer ? {} : this.createLiterals( │ │ │ │ │ + OpenLayers.Util.extend({}, this.defaultStyle), feature); │ │ │ │ │ + │ │ │ │ │ + var rules = this.rules; │ │ │ │ │ + │ │ │ │ │ + var rule, context; │ │ │ │ │ + var elseRules = []; │ │ │ │ │ + var appliedRules = false; │ │ │ │ │ + for (var i = 0, len = rules.length; i < len; i++) { │ │ │ │ │ + rule = rules[i]; │ │ │ │ │ + // does the rule apply? │ │ │ │ │ + var applies = rule.evaluate(feature); │ │ │ │ │ + │ │ │ │ │ + if (applies) { │ │ │ │ │ + if (rule instanceof OpenLayers.Rule && rule.elseFilter) { │ │ │ │ │ + elseRules.push(rule); │ │ │ │ │ + } else { │ │ │ │ │ + appliedRules = true; │ │ │ │ │ + this.applySymbolizer(rule, style, feature); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // if no other rules apply, apply the rules with else filters │ │ │ │ │ + if (appliedRules == false && elseRules.length > 0) { │ │ │ │ │ + appliedRules = true; │ │ │ │ │ + for (var i = 0, len = elseRules.length; i < len; i++) { │ │ │ │ │ + this.applySymbolizer(elseRules[i], style, feature); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // don't display if there were rules but none applied │ │ │ │ │ + if (rules.length > 0 && appliedRules == false) { │ │ │ │ │ + style.display = "none"; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (style.label != null && typeof style.label !== "string") { │ │ │ │ │ + style.label = String(style.label); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + return style; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: applySymbolizer │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * rule - {} │ │ │ │ │ + * style - {Object} │ │ │ │ │ + * feature - {} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Object} A style with new symbolizer applied. │ │ │ │ │ + */ │ │ │ │ │ + applySymbolizer: function(rule, style, feature) { │ │ │ │ │ + var symbolizerPrefix = feature.geometry ? │ │ │ │ │ + this.getSymbolizerPrefix(feature.geometry) : │ │ │ │ │ + OpenLayers.Style.SYMBOLIZER_PREFIXES[0]; │ │ │ │ │ + │ │ │ │ │ + var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer; │ │ │ │ │ + │ │ │ │ │ + if (this.defaultsPerSymbolizer === true) { │ │ │ │ │ + var defaults = this.defaultStyle; │ │ │ │ │ + OpenLayers.Util.applyDefaults(symbolizer, { │ │ │ │ │ + pointRadius: defaults.pointRadius │ │ │ │ │ + }); │ │ │ │ │ + if (symbolizer.stroke === true || symbolizer.graphic === true) { │ │ │ │ │ + OpenLayers.Util.applyDefaults(symbolizer, { │ │ │ │ │ + strokeWidth: defaults.strokeWidth, │ │ │ │ │ + strokeColor: defaults.strokeColor, │ │ │ │ │ + strokeOpacity: defaults.strokeOpacity, │ │ │ │ │ + strokeDashstyle: defaults.strokeDashstyle, │ │ │ │ │ + strokeLinecap: defaults.strokeLinecap │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + if (symbolizer.fill === true || symbolizer.graphic === true) { │ │ │ │ │ + OpenLayers.Util.applyDefaults(symbolizer, { │ │ │ │ │ + fillColor: defaults.fillColor, │ │ │ │ │ + fillOpacity: defaults.fillOpacity │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + if (symbolizer.graphic === true) { │ │ │ │ │ + OpenLayers.Util.applyDefaults(symbolizer, { │ │ │ │ │ + pointRadius: this.defaultStyle.pointRadius, │ │ │ │ │ + externalGraphic: this.defaultStyle.externalGraphic, │ │ │ │ │ + graphicName: this.defaultStyle.graphicName, │ │ │ │ │ + graphicOpacity: this.defaultStyle.graphicOpacity, │ │ │ │ │ + graphicWidth: this.defaultStyle.graphicWidth, │ │ │ │ │ + graphicHeight: this.defaultStyle.graphicHeight, │ │ │ │ │ + graphicXOffset: this.defaultStyle.graphicXOffset, │ │ │ │ │ + graphicYOffset: this.defaultStyle.graphicYOffset │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // merge the style with the current style │ │ │ │ │ + return this.createLiterals( │ │ │ │ │ + OpenLayers.Util.extend(style, symbolizer), feature); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: createLiterals │ │ │ │ │ + * creates literals for all style properties that have an entry in │ │ │ │ │ + * . │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * style - {Object} style to create literals for. Will be modified │ │ │ │ │ + * inline. │ │ │ │ │ + * feature - {Object} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Object} the modified style │ │ │ │ │ + */ │ │ │ │ │ + createLiterals: function(style, feature) { │ │ │ │ │ + var context = OpenLayers.Util.extend({}, feature.attributes || feature.data); │ │ │ │ │ + OpenLayers.Util.extend(context, this.context); │ │ │ │ │ + │ │ │ │ │ + for (var i in this.propertyStyles) { │ │ │ │ │ + style[i] = OpenLayers.Style.createLiteral(style[i], context, feature, i); │ │ │ │ │ + } │ │ │ │ │ + return style; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: findPropertyStyles │ │ │ │ │ + * Looks into all rules for this style and the defaultStyle to collect │ │ │ │ │ + * all the style hash property names containing ${...} strings that have │ │ │ │ │ + * to be replaced using the createLiteral method before returning them. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Object} hash of property names that need createLiteral parsing. The │ │ │ │ │ + * name of the property is the key, and the value is true; │ │ │ │ │ + */ │ │ │ │ │ + findPropertyStyles: function() { │ │ │ │ │ + var propertyStyles = {}; │ │ │ │ │ + │ │ │ │ │ + // check the default style │ │ │ │ │ + var style = this.defaultStyle; │ │ │ │ │ + this.addPropertyStyles(propertyStyles, style); │ │ │ │ │ + │ │ │ │ │ + // walk through all rules to check for properties in their symbolizer │ │ │ │ │ + var rules = this.rules; │ │ │ │ │ + var symbolizer, value; │ │ │ │ │ + for (var i = 0, len = rules.length; i < len; i++) { │ │ │ │ │ + symbolizer = rules[i].symbolizer; │ │ │ │ │ + for (var key in symbolizer) { │ │ │ │ │ + value = symbolizer[key]; │ │ │ │ │ + if (typeof value == "object") { │ │ │ │ │ + // symbolizer key is "Point", "Line" or "Polygon" │ │ │ │ │ + this.addPropertyStyles(propertyStyles, value); │ │ │ │ │ + } else { │ │ │ │ │ + // symbolizer is a hash of style properties │ │ │ │ │ + this.addPropertyStyles(propertyStyles, symbolizer); │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return propertyStyles; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: addPropertyStyles │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * propertyStyles - {Object} hash to add new property styles to. Will be │ │ │ │ │ + * modified inline │ │ │ │ │ + * symbolizer - {Object} search this symbolizer for property styles │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Object} propertyStyles hash │ │ │ │ │ + */ │ │ │ │ │ + addPropertyStyles: function(propertyStyles, symbolizer) { │ │ │ │ │ + var property; │ │ │ │ │ + for (var key in symbolizer) { │ │ │ │ │ + property = symbolizer[key]; │ │ │ │ │ + if (typeof property == "string" && │ │ │ │ │ + property.match(/\$\{\w+\}/)) { │ │ │ │ │ + propertyStyles[key] = true; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return propertyStyles; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: addRules │ │ │ │ │ + * Adds rules to this style. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * rules - {Array()} │ │ │ │ │ + */ │ │ │ │ │ + addRules: function(rules) { │ │ │ │ │ + Array.prototype.push.apply(this.rules, rules); │ │ │ │ │ + this.propertyStyles = this.findPropertyStyles(); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: setDefaultStyle │ │ │ │ │ + * Sets the default style for this style object. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * style - {Object} Hash of style properties │ │ │ │ │ + */ │ │ │ │ │ + setDefaultStyle: function(style) { │ │ │ │ │ + this.defaultStyle = style; │ │ │ │ │ + this.propertyStyles = this.findPropertyStyles(); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: getSymbolizerPrefix │ │ │ │ │ + * Returns the correct symbolizer prefix according to the │ │ │ │ │ + * geometry type of the passed geometry │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * geometry - {} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {String} key of the according symbolizer │ │ │ │ │ + */ │ │ │ │ │ + getSymbolizerPrefix: function(geometry) { │ │ │ │ │ + var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES; │ │ │ │ │ + for (var i = 0, len = prefixes.length; i < len; i++) { │ │ │ │ │ + if (geometry.CLASS_NAME.indexOf(prefixes[i]) != -1) { │ │ │ │ │ + return prefixes[i]; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: clone │ │ │ │ │ + * Clones this style. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} Clone of this style. │ │ │ │ │ + */ │ │ │ │ │ + clone: function() { │ │ │ │ │ + var options = OpenLayers.Util.extend({}, this); │ │ │ │ │ + // clone rules │ │ │ │ │ + if (this.rules) { │ │ │ │ │ + options.rules = []; │ │ │ │ │ + for (var i = 0, len = this.rules.length; i < len; ++i) { │ │ │ │ │ + options.rules.push(this.rules[i].clone()); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + // clone context │ │ │ │ │ + options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ │ + //clone default style │ │ │ │ │ + var defaultStyle = OpenLayers.Util.extend({}, this.defaultStyle); │ │ │ │ │ + return new OpenLayers.Style(defaultStyle, options); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Style" │ │ │ │ │ +}); │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Function: createLiteral │ │ │ │ │ + * converts a style value holding a combination of PropertyName and Literal │ │ │ │ │ + * into a Literal, taking the property values from the passed features. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * value - {String} value to parse. If this string contains a construct like │ │ │ │ │ + * "foo ${bar}", then "foo " will be taken as literal, and "${bar}" │ │ │ │ │ + * will be replaced by the value of the "bar" attribute of the passed │ │ │ │ │ + * feature. │ │ │ │ │ + * context - {Object} context to take attribute values from │ │ │ │ │ + * feature - {} optional feature to pass to │ │ │ │ │ + * for evaluating functions in the │ │ │ │ │ + * context. │ │ │ │ │ + * property - {String} optional, name of the property for which the literal is │ │ │ │ │ + * being created for evaluating functions in the context. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {String} the parsed value. In the example of the value parameter above, the │ │ │ │ │ + * result would be "foo valueOfBar", assuming that the passed feature has an │ │ │ │ │ + * attribute named "bar" with the value "valueOfBar". │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Style.createLiteral = function(value, context, feature, property) { │ │ │ │ │ + if (typeof value == "string" && value.indexOf("${") != -1) { │ │ │ │ │ + value = OpenLayers.String.format(value, context, [feature, property]); │ │ │ │ │ + value = (isNaN(value) || !value) ? value : parseFloat(value); │ │ │ │ │ + } │ │ │ │ │ + return value; │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Constant: OpenLayers.Style.SYMBOLIZER_PREFIXES │ │ │ │ │ + * {Array} prefixes of the sld symbolizers. These are the │ │ │ │ │ + * same as the main geometry types │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Style.SYMBOLIZER_PREFIXES = ['Point', 'Line', 'Polygon', 'Text', │ │ │ │ │ + 'Raster' │ │ │ │ │ +]; │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Tile.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Tile │ │ │ │ │ + * This is a class designed to designate a single tile, however │ │ │ │ │ + * it is explicitly designed to do relatively little. Tiles store │ │ │ │ │ + * information about themselves -- such as the URL that they are related │ │ │ │ │ + * to, and their size - but do not add themselves to the layer div │ │ │ │ │ + * automatically, for example. Create a new tile with the │ │ │ │ │ + * constructor, or a subclass. │ │ │ │ │ + * │ │ │ │ │ + * TBD 3.0 - remove reference to url in above paragraph │ │ │ │ │ + * │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Tile = OpenLayers.Class({ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: events │ │ │ │ │ + * {} An events object that handles all │ │ │ │ │ + * events on the tile. │ │ │ │ │ + * │ │ │ │ │ + * Register a listener for a particular event with the following syntax: │ │ │ │ │ + * (code) │ │ │ │ │ + * tile.events.register(type, obj, listener); │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Supported event types: │ │ │ │ │ + * beforedraw - Triggered before the tile is drawn. Used to defer │ │ │ │ │ + * drawing to an animation queue. To defer drawing, listeners need │ │ │ │ │ + * to return false, which will abort drawing. The queue handler needs │ │ │ │ │ + * to call (true) to actually draw the tile. │ │ │ │ │ + * loadstart - Triggered when tile loading starts. │ │ │ │ │ + * loadend - Triggered when tile loading ends. │ │ │ │ │ + * loaderror - Triggered before the loadend event (i.e. when the tile is │ │ │ │ │ + * still hidden) if the tile could not be loaded. │ │ │ │ │ + * reload - Triggered when an already loading tile is reloaded. │ │ │ │ │ + * unload - Triggered before a tile is unloaded. │ │ │ │ │ + */ │ │ │ │ │ + events: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: eventListeners │ │ │ │ │ + * {Object} If set as an option at construction, the eventListeners │ │ │ │ │ + * object will be registered with . Object │ │ │ │ │ + * structure must be a listeners object as shown in the example for │ │ │ │ │ + * the events.on method. │ │ │ │ │ + * │ │ │ │ │ + * This options can be set in the ``tileOptions`` option from │ │ │ │ │ + * . For example, to be notified of the │ │ │ │ │ + * ``loadend`` event of each tiles: │ │ │ │ │ + * (code) │ │ │ │ │ + * new OpenLayers.Layer.OSM('osm', 'http://tile.openstreetmap.org/${z}/${x}/${y}.png', { │ │ │ │ │ + * tileOptions: { │ │ │ │ │ + * eventListeners: { │ │ │ │ │ + * 'loadend': function(evt) { │ │ │ │ │ + * // do something on loadend │ │ │ │ │ + * } │ │ │ │ │ + * } │ │ │ │ │ + * } │ │ │ │ │ + * }); │ │ │ │ │ + * (end) │ │ │ │ │ + */ │ │ │ │ │ + eventListeners: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: id │ │ │ │ │ + * {String} null │ │ │ │ │ + */ │ │ │ │ │ + id: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: layer │ │ │ │ │ + * {} layer the tile is attached to │ │ │ │ │ + */ │ │ │ │ │ + layer: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: url │ │ │ │ │ + * {String} url of the request. │ │ │ │ │ + * │ │ │ │ │ + * TBD 3.0 │ │ │ │ │ + * Deprecated. The base tile class does not need an url. This should be │ │ │ │ │ + * handled in subclasses. Does not belong here. │ │ │ │ │ + */ │ │ │ │ │ + url: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: bounds │ │ │ │ │ + * {} null │ │ │ │ │ + */ │ │ │ │ │ + bounds: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: size │ │ │ │ │ + * {} null │ │ │ │ │ + */ │ │ │ │ │ + size: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: position │ │ │ │ │ + * {} Top Left pixel of the tile │ │ │ │ │ + */ │ │ │ │ │ + position: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: isLoading │ │ │ │ │ + * {Boolean} Is the tile loading? │ │ │ │ │ + */ │ │ │ │ │ + isLoading: false, │ │ │ │ │ + │ │ │ │ │ + /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor. │ │ │ │ │ + * there is no need for the base tile class to have a url. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Tile │ │ │ │ │ + * Constructor for a new instance. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * layer - {} layer that the tile will go in. │ │ │ │ │ + * position - {} │ │ │ │ │ + * bounds - {} │ │ │ │ │ + * url - {} │ │ │ │ │ + * size - {} │ │ │ │ │ + * options - {Object} │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(layer, position, bounds, url, size, options) { │ │ │ │ │ + this.layer = layer; │ │ │ │ │ + this.position = position.clone(); │ │ │ │ │ + this.setBounds(bounds); │ │ │ │ │ + this.url = url; │ │ │ │ │ + if (size) { │ │ │ │ │ + this.size = size.clone(); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + //give the tile a unique id based on its BBOX. │ │ │ │ │ + this.id = OpenLayers.Util.createUniqueID("Tile_"); │ │ │ │ │ + │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + │ │ │ │ │ + this.events = new OpenLayers.Events(this); │ │ │ │ │ + if (this.eventListeners instanceof Object) { │ │ │ │ │ + this.events.on(this.eventListeners); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: unload │ │ │ │ │ + * Call immediately before destroying if you are listening to tile │ │ │ │ │ + * events, so that counters are properly handled if tile is still │ │ │ │ │ + * loading at destroy-time. Will only fire an event if the tile is │ │ │ │ │ + * still loading. │ │ │ │ │ + */ │ │ │ │ │ + unload: function() { │ │ │ │ │ + if (this.isLoading) { │ │ │ │ │ + this.isLoading = false; │ │ │ │ │ + this.events.triggerEvent("unload"); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ + * Nullify references to prevent circular references and memory leaks. │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + this.layer = null; │ │ │ │ │ + this.bounds = null; │ │ │ │ │ + this.size = null; │ │ │ │ │ + this.position = null; │ │ │ │ │ + │ │ │ │ │ + if (this.eventListeners) { │ │ │ │ │ + this.events.un(this.eventListeners); │ │ │ │ │ + } │ │ │ │ │ + this.events.destroy(); │ │ │ │ │ + this.eventListeners = null; │ │ │ │ │ + this.events = null; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: draw │ │ │ │ │ + * Clear whatever is currently in the tile, then return whether or not │ │ │ │ │ + * it should actually be re-drawn. This is an example implementation │ │ │ │ │ + * that can be overridden by subclasses. The minimum thing to do here │ │ │ │ │ + * is to call and return the result from . │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * force - {Boolean} If true, the tile will not be cleared and no beforedraw │ │ │ │ │ + * event will be fired. This is used for drawing tiles asynchronously │ │ │ │ │ + * after drawing has been cancelled by returning false from a beforedraw │ │ │ │ │ + * listener. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Whether or not the tile should actually be drawn. Returns null │ │ │ │ │ + * if a beforedraw listener returned false. │ │ │ │ │ + */ │ │ │ │ │ + draw: function(force) { │ │ │ │ │ + if (!force) { │ │ │ │ │ + //clear tile's contents and mark as not drawn │ │ │ │ │ + this.clear(); │ │ │ │ │ + } │ │ │ │ │ + var draw = this.shouldDraw(); │ │ │ │ │ + if (draw && !force && this.events.triggerEvent("beforedraw") === false) { │ │ │ │ │ + draw = null; │ │ │ │ │ + } │ │ │ │ │ + return draw; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: shouldDraw │ │ │ │ │ + * Return whether or not the tile should actually be (re-)drawn. The only │ │ │ │ │ + * case where we *wouldn't* want to draw the tile is if the tile is outside │ │ │ │ │ + * its layer's maxExtent │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Whether or not the tile should actually be drawn. │ │ │ │ │ + */ │ │ │ │ │ + shouldDraw: function() { │ │ │ │ │ + var withinMaxExtent = false, │ │ │ │ │ + maxExtent = this.layer.maxExtent; │ │ │ │ │ + if (maxExtent) { │ │ │ │ │ + var map = this.layer.map; │ │ │ │ │ + var worldBounds = map.baseLayer.wrapDateLine && map.getMaxExtent(); │ │ │ │ │ + if (this.bounds.intersectsBounds(maxExtent, { │ │ │ │ │ + inclusive: false, │ │ │ │ │ + worldBounds: worldBounds │ │ │ │ │ + })) { │ │ │ │ │ + withinMaxExtent = true; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + return withinMaxExtent || this.layer.displayOutsideMaxExtent; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: setBounds │ │ │ │ │ + * Sets the bounds on this instance │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * bounds {} │ │ │ │ │ + */ │ │ │ │ │ + setBounds: function(bounds) { │ │ │ │ │ + bounds = bounds.clone(); │ │ │ │ │ + if (this.layer.map.baseLayer.wrapDateLine) { │ │ │ │ │ + var worldExtent = this.layer.map.getMaxExtent(), │ │ │ │ │ + tolerance = this.layer.map.getResolution(); │ │ │ │ │ + bounds = bounds.wrapDateLine(worldExtent, { │ │ │ │ │ + leftTolerance: tolerance, │ │ │ │ │ + rightTolerance: tolerance │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + this.bounds = bounds; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: moveTo │ │ │ │ │ + * Reposition the tile. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * bounds - {} │ │ │ │ │ + * position - {} │ │ │ │ │ + * redraw - {Boolean} Call draw method on tile after moving. │ │ │ │ │ + * Default is true │ │ │ │ │ + */ │ │ │ │ │ + moveTo: function(bounds, position, redraw) { │ │ │ │ │ + if (redraw == null) { │ │ │ │ │ + redraw = true; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.setBounds(bounds); │ │ │ │ │ + this.position = position.clone(); │ │ │ │ │ + if (redraw) { │ │ │ │ │ + this.draw(); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: clear │ │ │ │ │ + * Clear the tile of any bounds/position-related data so that it can │ │ │ │ │ + * be reused in a new location. │ │ │ │ │ + */ │ │ │ │ │ + clear: function(draw) { │ │ │ │ │ + // to be extended by subclasses │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Tile" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Strategy.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Strategy │ │ │ │ │ + * Abstract vector layer strategy class. Not to be instantiated directly. Use │ │ │ │ │ + * one of the strategy subclasses instead. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Strategy = OpenLayers.Class({ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: layer │ │ │ │ │ + * {} The layer this strategy belongs to. │ │ │ │ │ + */ │ │ │ │ │ + layer: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: options │ │ │ │ │ + * {Object} Any options sent to the constructor. │ │ │ │ │ + */ │ │ │ │ │ + options: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: active │ │ │ │ │ + * {Boolean} The control is active. │ │ │ │ │ + */ │ │ │ │ │ + active: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: autoActivate │ │ │ │ │ + * {Boolean} The creator of the strategy can set autoActivate to false │ │ │ │ │ + * to fully control when the protocol is activated and deactivated. │ │ │ │ │ + * Defaults to true. │ │ │ │ │ + */ │ │ │ │ │ + autoActivate: true, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: autoDestroy │ │ │ │ │ + * {Boolean} The creator of the strategy can set autoDestroy to false │ │ │ │ │ + * to fully control when the strategy is destroyed. Defaults to │ │ │ │ │ + * true. │ │ │ │ │ + */ │ │ │ │ │ + autoDestroy: true, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Strategy │ │ │ │ │ + * Abstract class for vector strategies. Create instances of a subclass. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ + * instance. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + this.options = options; │ │ │ │ │ + // set the active property here, so that user cannot override it │ │ │ │ │ + this.active = false; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ + * Clean up the strategy. │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + this.deactivate(); │ │ │ │ │ + this.layer = null; │ │ │ │ │ + this.options = null; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: setLayer │ │ │ │ │ + * Called to set the property. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * layer - {} │ │ │ │ │ + */ │ │ │ │ │ + setLayer: function(layer) { │ │ │ │ │ + this.layer = layer; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: activate │ │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} True if the strategy was successfully activated or false if │ │ │ │ │ + * the strategy was already active. │ │ │ │ │ + */ │ │ │ │ │ + activate: function() { │ │ │ │ │ + if (!this.active) { │ │ │ │ │ + this.active = true; │ │ │ │ │ + return true; │ │ │ │ │ + } │ │ │ │ │ + return false; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: deactivate │ │ │ │ │ + * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ │ + * tear-down. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} True if the strategy was successfully deactivated or false if │ │ │ │ │ + * the strategy was already inactive. │ │ │ │ │ + */ │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + if (this.active) { │ │ │ │ │ + this.active = false; │ │ │ │ │ + return true; │ │ │ │ │ + } │ │ │ │ │ + return false; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Handler.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Events.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Handler │ │ │ │ │ + * Base class to construct a higher-level handler for event sequences. All │ │ │ │ │ + * handlers have activate and deactivate methods. In addition, they have │ │ │ │ │ + * methods named like browser events. When a handler is activated, any │ │ │ │ │ + * additional methods named like a browser event is registered as a │ │ │ │ │ + * listener for the corresponding event. When a handler is deactivated, │ │ │ │ │ + * those same methods are unregistered as event listeners. │ │ │ │ │ + * │ │ │ │ │ + * Handlers also typically have a callbacks object with keys named like │ │ │ │ │ + * the abstracted events or event sequences that they are in charge of │ │ │ │ │ + * handling. The controls that wrap handlers define the methods that │ │ │ │ │ + * correspond to these abstract events - so instead of listening for │ │ │ │ │ + * individual browser events, they only listen for the abstract events │ │ │ │ │ + * defined by the handler. │ │ │ │ │ + * │ │ │ │ │ + * Handlers are created by controls, which ultimately have the responsibility │ │ │ │ │ + * of making changes to the the state of the application. Handlers │ │ │ │ │ + * themselves may make temporary changes, but in general are expected to │ │ │ │ │ + * return the application in the same state that they found it. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Handler = OpenLayers.Class({ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: id │ │ │ │ │ + * {String} │ │ │ │ │ + */ │ │ │ │ │ + id: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: control │ │ │ │ │ + * {}. The control that initialized this handler. The │ │ │ │ │ + * control is assumed to have a valid map property - that map is used │ │ │ │ │ + * in the handler's own setMap method. │ │ │ │ │ + */ │ │ │ │ │ + control: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: map │ │ │ │ │ + * {} │ │ │ │ │ + */ │ │ │ │ │ + map: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: keyMask │ │ │ │ │ + * {Integer} Use bitwise operators and one or more of the OpenLayers.Handler │ │ │ │ │ + * constants to construct a keyMask. The keyMask is used by │ │ │ │ │ + * . If the keyMask matches the combination of keys │ │ │ │ │ + * down on an event, checkModifiers returns true. │ │ │ │ │ + * │ │ │ │ │ + * Example: │ │ │ │ │ + * (code) │ │ │ │ │ + * // handler only responds if the Shift key is down │ │ │ │ │ + * handler.keyMask = OpenLayers.Handler.MOD_SHIFT; │ │ │ │ │ + * │ │ │ │ │ + * // handler only responds if Ctrl-Shift is down │ │ │ │ │ + * handler.keyMask = OpenLayers.Handler.MOD_SHIFT | │ │ │ │ │ + * OpenLayers.Handler.MOD_CTRL; │ │ │ │ │ + * (end) │ │ │ │ │ + */ │ │ │ │ │ + keyMask: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: active │ │ │ │ │ + * {Boolean} │ │ │ │ │ + */ │ │ │ │ │ + active: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: evt │ │ │ │ │ + * {Event} This property references the last event handled by the handler. │ │ │ │ │ + * Note that this property is not part of the stable API. Use of the │ │ │ │ │ + * evt property should be restricted to controls in the library │ │ │ │ │ + * or other applications that are willing to update with changes to │ │ │ │ │ + * the OpenLayers code. │ │ │ │ │ + */ │ │ │ │ │ + evt: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: touch │ │ │ │ │ + * {Boolean} Indicates the support of touch events. When touch events are │ │ │ │ │ + * started touch will be true and all mouse related listeners will do │ │ │ │ │ + * nothing. │ │ │ │ │ + */ │ │ │ │ │ + touch: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Handler │ │ │ │ │ + * Construct a handler. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * control - {} The control that initialized this │ │ │ │ │ + * handler. The control is assumed to have a valid map property; that │ │ │ │ │ + * map is used in the handler's own setMap method. If a map property │ │ │ │ │ + * is present in the options argument it will be used instead. │ │ │ │ │ + * callbacks - {Object} An object whose properties correspond to abstracted │ │ │ │ │ + * events or sequences of browser events. The values for these │ │ │ │ │ + * properties are functions defined by the control that get called by │ │ │ │ │ + * the handler. │ │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ │ + * the handler. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + this.control = control; │ │ │ │ │ + this.callbacks = callbacks; │ │ │ │ │ + │ │ │ │ │ + var map = this.map || control.map; │ │ │ │ │ + if (map) { │ │ │ │ │ + this.setMap(map); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: setMap │ │ │ │ │ + */ │ │ │ │ │ + setMap: function(map) { │ │ │ │ │ + this.map = map; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: checkModifiers │ │ │ │ │ + * Check the keyMask on the handler. If no is set, this always │ │ │ │ │ + * returns true. If a is set and it matches the combination │ │ │ │ │ + * of keys down on an event, this returns true. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The keyMask matches the keys down on an event. │ │ │ │ │ + */ │ │ │ │ │ + checkModifiers: function(evt) { │ │ │ │ │ + if (this.keyMask == null) { │ │ │ │ │ + return true; │ │ │ │ │ + } │ │ │ │ │ + /* calculate the keyboard modifier mask for this event */ │ │ │ │ │ + var keyModifiers = │ │ │ │ │ + (evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) | │ │ │ │ │ + (evt.ctrlKey ? OpenLayers.Handler.MOD_CTRL : 0) | │ │ │ │ │ + (evt.altKey ? OpenLayers.Handler.MOD_ALT : 0) | │ │ │ │ │ + (evt.metaKey ? OpenLayers.Handler.MOD_META : 0); │ │ │ │ │ + │ │ │ │ │ + /* if it differs from the handler object's key mask, │ │ │ │ │ + bail out of the event handler */ │ │ │ │ │ + return (keyModifiers == this.keyMask); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: activate │ │ │ │ │ + * Turn on the handler. Returns false if the handler was already active. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The handler was activated. │ │ │ │ │ + */ │ │ │ │ │ + activate: function() { │ │ │ │ │ + if (this.active) { │ │ │ │ │ + return false; │ │ │ │ │ + } │ │ │ │ │ + // register for event handlers defined on this class. │ │ │ │ │ + var events = OpenLayers.Events.prototype.BROWSER_EVENTS; │ │ │ │ │ + for (var i = 0, len = events.length; i < len; i++) { │ │ │ │ │ + if (this[events[i]]) { │ │ │ │ │ + this.register(events[i], this[events[i]]); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + this.active = true; │ │ │ │ │ + return true; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: deactivate │ │ │ │ │ + * Turn off the handler. Returns false if the handler was already inactive. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The handler was deactivated. │ │ │ │ │ + */ │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + if (!this.active) { │ │ │ │ │ + return false; │ │ │ │ │ + } │ │ │ │ │ + // unregister event handlers defined on this class. │ │ │ │ │ + var events = OpenLayers.Events.prototype.BROWSER_EVENTS; │ │ │ │ │ + for (var i = 0, len = events.length; i < len; i++) { │ │ │ │ │ + if (this[events[i]]) { │ │ │ │ │ + this.unregister(events[i], this[events[i]]); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + this.touch = false; │ │ │ │ │ + this.active = false; │ │ │ │ │ + return true; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: startTouch │ │ │ │ │ + * Start touch events, this method must be called by subclasses in │ │ │ │ │ + * "touchstart" method. When touch events are started will be │ │ │ │ │ + * true and all mouse related listeners will do nothing. │ │ │ │ │ + */ │ │ │ │ │ + startTouch: function() { │ │ │ │ │ + if (!this.touch) { │ │ │ │ │ + this.touch = true; │ │ │ │ │ + var events = [ │ │ │ │ │ + "mousedown", "mouseup", "mousemove", "click", "dblclick", │ │ │ │ │ + "mouseout" │ │ │ │ │ + ]; │ │ │ │ │ + for (var i = 0, len = events.length; i < len; i++) { │ │ │ │ │ + if (this[events[i]]) { │ │ │ │ │ + this.unregister(events[i], this[events[i]]); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: callback │ │ │ │ │ + * Trigger the control's named callback with the given arguments │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * name - {String} The key for the callback that is one of the properties │ │ │ │ │ + * of the handler's callbacks object. │ │ │ │ │ + * args - {Array(*)} An array of arguments (any type) with which to call │ │ │ │ │ + * the callback (defined by the control). │ │ │ │ │ + */ │ │ │ │ │ + callback: function(name, args) { │ │ │ │ │ + if (name && this.callbacks[name]) { │ │ │ │ │ + this.callbacks[name].apply(this.control, args); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: register │ │ │ │ │ + * register an event on the map │ │ │ │ │ + */ │ │ │ │ │ + register: function(name, method) { │ │ │ │ │ + // TODO: deal with registerPriority in 3.0 │ │ │ │ │ + this.map.events.registerPriority(name, this, method); │ │ │ │ │ + this.map.events.registerPriority(name, this, this.setEvent); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: unregister │ │ │ │ │ + * unregister an event from the map │ │ │ │ │ + */ │ │ │ │ │ + unregister: function(name, method) { │ │ │ │ │ + this.map.events.unregister(name, this, method); │ │ │ │ │ + this.map.events.unregister(name, this, this.setEvent); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: setEvent │ │ │ │ │ + * With each registered browser event, the handler sets its own evt │ │ │ │ │ + * property. This property can be accessed by controls if needed │ │ │ │ │ + * to get more information about the event that the handler is │ │ │ │ │ + * processing. │ │ │ │ │ + * │ │ │ │ │ + * This allows modifier keys on the event to be checked (alt, shift, ctrl, │ │ │ │ │ + * and meta cannot be checked with the keyboard handler). For a │ │ │ │ │ + * control to determine which modifier keys are associated with the │ │ │ │ │ + * event that a handler is currently processing, it should access │ │ │ │ │ + * (code)handler.evt.altKey || handler.evt.shiftKey || │ │ │ │ │ + * handler.evt.ctrlKey || handler.evt.metaKey(end). │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {Event} The browser event. │ │ │ │ │ + */ │ │ │ │ │ + setEvent: function(evt) { │ │ │ │ │ + this.evt = evt; │ │ │ │ │ + return true; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroy │ │ │ │ │ + * Deconstruct the handler. │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + // unregister event listeners │ │ │ │ │ + this.deactivate(); │ │ │ │ │ + // eliminate circular references │ │ │ │ │ + this.control = this.map = null; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Handler" │ │ │ │ │ +}); │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Constant: OpenLayers.Handler.MOD_NONE │ │ │ │ │ + * If set as the , returns false if any key is down. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Handler.MOD_NONE = 0; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Constant: OpenLayers.Handler.MOD_SHIFT │ │ │ │ │ + * If set as the , returns false if Shift is down. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Handler.MOD_SHIFT = 1; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Constant: OpenLayers.Handler.MOD_CTRL │ │ │ │ │ + * If set as the , returns false if Ctrl is down. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Handler.MOD_CTRL = 2; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Constant: OpenLayers.Handler.MOD_ALT │ │ │ │ │ + * If set as the , returns false if Alt is down. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Handler.MOD_ALT = 4; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Constant: OpenLayers.Handler.MOD_META │ │ │ │ │ + * If set as the , returns false if Cmd is down. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Handler.MOD_META = 8; │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Protocol.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Protocol │ │ │ │ │ + * Abstract vector layer protocol class. Not to be instantiated directly. Use │ │ │ │ │ + * one of the protocol subclasses instead. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Protocol = OpenLayers.Class({ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: format │ │ │ │ │ + * {} The format used by this protocol. │ │ │ │ │ + */ │ │ │ │ │ + format: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: options │ │ │ │ │ + * {Object} Any options sent to the constructor. │ │ │ │ │ + */ │ │ │ │ │ + options: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: autoDestroy │ │ │ │ │ + * {Boolean} The creator of the protocol can set autoDestroy to false │ │ │ │ │ + * to fully control when the protocol is destroyed. Defaults to │ │ │ │ │ + * true. │ │ │ │ │ + */ │ │ │ │ │ + autoDestroy: true, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: defaultFilter │ │ │ │ │ + * {} Optional default filter to read requests │ │ │ │ │ + */ │ │ │ │ │ + defaultFilter: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Protocol │ │ │ │ │ + * Abstract class for vector protocols. Create instances of a subclass. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ + * instance. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + options = options || {}; │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + this.options = options; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: mergeWithDefaultFilter │ │ │ │ │ + * Merge filter passed to the read method with the default one │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * filter - {} │ │ │ │ │ + */ │ │ │ │ │ + mergeWithDefaultFilter: function(filter) { │ │ │ │ │ + var merged; │ │ │ │ │ + if (filter && this.defaultFilter) { │ │ │ │ │ + merged = new OpenLayers.Filter.Logical({ │ │ │ │ │ + type: OpenLayers.Filter.Logical.AND, │ │ │ │ │ + filters: [this.defaultFilter, filter] │ │ │ │ │ + }); │ │ │ │ │ + } else { │ │ │ │ │ + merged = filter || this.defaultFilter || undefined; │ │ │ │ │ + } │ │ │ │ │ + return merged; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ + * Clean up the protocol. │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + this.options = null; │ │ │ │ │ + this.format = null; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: read │ │ │ │ │ + * Construct a request for reading new features. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} Optional object for configuring the request. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} An │ │ │ │ │ + * object, the same object will be passed to the callback function passed │ │ │ │ │ + * if one exists in the options object. │ │ │ │ │ + */ │ │ │ │ │ + read: function(options) { │ │ │ │ │ + options = options || {}; │ │ │ │ │ + options.filter = this.mergeWithDefaultFilter(options.filter); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: create │ │ │ │ │ + * Construct a request for writing newly created features. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * features - {Array({})} or │ │ │ │ │ + * {} │ │ │ │ │ + * options - {Object} Optional object for configuring the request. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} An │ │ │ │ │ + * object, the same object will be passed to the callback function passed │ │ │ │ │ + * if one exists in the options object. │ │ │ │ │ + */ │ │ │ │ │ + create: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: update │ │ │ │ │ + * Construct a request updating modified features. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * features - {Array({})} or │ │ │ │ │ + * {} │ │ │ │ │ + * options - {Object} Optional object for configuring the request. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} An │ │ │ │ │ + * object, the same object will be passed to the callback function passed │ │ │ │ │ + * if one exists in the options object. │ │ │ │ │ + */ │ │ │ │ │ + update: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: delete │ │ │ │ │ + * Construct a request deleting a removed feature. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * feature - {} │ │ │ │ │ + * options - {Object} Optional object for configuring the request. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} An │ │ │ │ │ + * object, the same object will be passed to the callback function passed │ │ │ │ │ + * if one exists in the options object. │ │ │ │ │ + */ │ │ │ │ │ + "delete": function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: commit │ │ │ │ │ + * Go over the features and for each take action │ │ │ │ │ + * based on the feature state. Possible actions are create, │ │ │ │ │ + * update and delete. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * features - {Array({})} │ │ │ │ │ + * options - {Object} Object whose possible keys are "create", "update", │ │ │ │ │ + * "delete", "callback" and "scope", the values referenced by the │ │ │ │ │ + * first three are objects as passed to the "create", "update", and │ │ │ │ │ + * "delete" methods, the value referenced by the "callback" key is │ │ │ │ │ + * a function which is called when the commit operation is complete │ │ │ │ │ + * using the scope referenced by the "scope" key. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Array({})} An array of │ │ │ │ │ + * objects. │ │ │ │ │ + */ │ │ │ │ │ + commit: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: abort │ │ │ │ │ + * Abort an ongoing request. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * response - {} │ │ │ │ │ + */ │ │ │ │ │ + abort: function(response) {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: createCallback │ │ │ │ │ + * Returns a function that applies the given public method with resp and │ │ │ │ │ + * options arguments. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * method - {Function} The method to be applied by the callback. │ │ │ │ │ + * response - {} The protocol response object. │ │ │ │ │ + * options - {Object} Options sent to the protocol method │ │ │ │ │ + */ │ │ │ │ │ + createCallback: function(method, response, options) { │ │ │ │ │ + return OpenLayers.Function.bind(function() { │ │ │ │ │ + method.apply(this, [response, options]); │ │ │ │ │ + }, this); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol" │ │ │ │ │ +}); │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Protocol.Response │ │ │ │ │ + * Protocols return Response objects to their users. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Protocol.Response = OpenLayers.Class({ │ │ │ │ │ + /** │ │ │ │ │ + * Property: code │ │ │ │ │ + * {Number} - OpenLayers.Protocol.Response.SUCCESS or │ │ │ │ │ + * OpenLayers.Protocol.Response.FAILURE │ │ │ │ │ + */ │ │ │ │ │ + code: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: requestType │ │ │ │ │ + * {String} The type of request this response corresponds to. Either │ │ │ │ │ + * "create", "read", "update" or "delete". │ │ │ │ │ + */ │ │ │ │ │ + requestType: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: last │ │ │ │ │ + * {Boolean} - true if this is the last response expected in a commit, │ │ │ │ │ + * false otherwise, defaults to true. │ │ │ │ │ + */ │ │ │ │ │ + last: true, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: features │ │ │ │ │ + * {Array({})} or {} │ │ │ │ │ + * The features returned in the response by the server. Depending on the │ │ │ │ │ + * protocol's read payload, either features or data will be populated. │ │ │ │ │ + */ │ │ │ │ │ + features: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: data │ │ │ │ │ + * {Object} │ │ │ │ │ + * The data returned in the response by the server. Depending on the │ │ │ │ │ + * protocol's read payload, either features or data will be populated. │ │ │ │ │ + */ │ │ │ │ │ + data: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: reqFeatures │ │ │ │ │ + * {Array({})} or {} │ │ │ │ │ + * The features provided by the user and placed in the request by the │ │ │ │ │ + * protocol. │ │ │ │ │ + */ │ │ │ │ │ + reqFeatures: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: priv │ │ │ │ │ + */ │ │ │ │ │ + priv: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: error │ │ │ │ │ + * {Object} The error object in case a service exception was encountered. │ │ │ │ │ + */ │ │ │ │ │ + error: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Protocol.Response │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ + * instance. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: success │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} - true on success, false otherwise │ │ │ │ │ + */ │ │ │ │ │ + success: function() { │ │ │ │ │ + return this.code > 0; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Protocol.Response" │ │ │ │ │ +}); │ │ │ │ │ + │ │ │ │ │ +OpenLayers.Protocol.Response.SUCCESS = 1; │ │ │ │ │ +OpenLayers.Protocol.Response.FAILURE = 0; │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/StyleMap.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Style.js │ │ │ │ │ + * @requires OpenLayers/Feature/Vector.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.StyleMap │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.StyleMap = OpenLayers.Class({ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: styles │ │ │ │ │ + * {Object} Hash of {}, keyed by names of well known │ │ │ │ │ + * rendering intents (e.g. "default", "temporary", "select", "delete"). │ │ │ │ │ + */ │ │ │ │ │ + styles: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: extendDefault │ │ │ │ │ + * {Boolean} if true, every render intent will extend the symbolizers │ │ │ │ │ + * specified for the "default" intent at rendering time. Otherwise, every │ │ │ │ │ + * rendering intent will be treated as a completely independent style. │ │ │ │ │ + */ │ │ │ │ │ + extendDefault: true, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.StyleMap │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * style - {Object} Optional. Either a style hash, or a style object, or │ │ │ │ │ + * a hash of style objects (style hashes) keyed by rendering │ │ │ │ │ + * intent. If just one style hash or style object is passed, │ │ │ │ │ + * this will be used for all known render intents (default, │ │ │ │ │ + * select, temporary) │ │ │ │ │ + * options - {Object} optional hash of additional options for this │ │ │ │ │ + * instance │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(style, options) { │ │ │ │ │ + this.styles = { │ │ │ │ │ + "default": new OpenLayers.Style( │ │ │ │ │ + OpenLayers.Feature.Vector.style["default"]), │ │ │ │ │ + "select": new OpenLayers.Style( │ │ │ │ │ + OpenLayers.Feature.Vector.style["select"]), │ │ │ │ │ + "temporary": new OpenLayers.Style( │ │ │ │ │ + OpenLayers.Feature.Vector.style["temporary"]), │ │ │ │ │ + "delete": new OpenLayers.Style( │ │ │ │ │ + OpenLayers.Feature.Vector.style["delete"]) │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ + // take whatever the user passed as style parameter and convert it │ │ │ │ │ + // into parts of stylemap. │ │ │ │ │ + if (style instanceof OpenLayers.Style) { │ │ │ │ │ + // user passed a style object │ │ │ │ │ + this.styles["default"] = style; │ │ │ │ │ + this.styles["select"] = style; │ │ │ │ │ + this.styles["temporary"] = style; │ │ │ │ │ + this.styles["delete"] = style; │ │ │ │ │ + } else if (typeof style == "object") { │ │ │ │ │ + for (var key in style) { │ │ │ │ │ + if (style[key] instanceof OpenLayers.Style) { │ │ │ │ │ + // user passed a hash of style objects │ │ │ │ │ + this.styles[key] = style[key]; │ │ │ │ │ + } else if (typeof style[key] == "object") { │ │ │ │ │ + // user passsed a hash of style hashes │ │ │ │ │ + this.styles[key] = new OpenLayers.Style(style[key]); │ │ │ │ │ + } else { │ │ │ │ │ + // user passed a style hash (i.e. symbolizer) │ │ │ │ │ + this.styles["default"] = new OpenLayers.Style(style); │ │ │ │ │ + this.styles["select"] = new OpenLayers.Style(style); │ │ │ │ │ + this.styles["temporary"] = new OpenLayers.Style(style); │ │ │ │ │ + this.styles["delete"] = new OpenLayers.Style(style); │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroy │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + for (var key in this.styles) { │ │ │ │ │ + this.styles[key].destroy(); │ │ │ │ │ + } │ │ │ │ │ + this.styles = null; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: createSymbolizer │ │ │ │ │ + * Creates the symbolizer for a feature for a render intent. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * feature - {} The feature to evaluate the rules │ │ │ │ │ + * of the intended style against. │ │ │ │ │ + * intent - {String} The intent determines the symbolizer that will be │ │ │ │ │ + * used to draw the feature. Well known intents are "default" │ │ │ │ │ + * (for just drawing the features), "select" (for selected │ │ │ │ │ + * features) and "temporary" (for drawing features). │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Object} symbolizer hash │ │ │ │ │ + */ │ │ │ │ │ + createSymbolizer: function(feature, intent) { │ │ │ │ │ + if (!feature) { │ │ │ │ │ + feature = new OpenLayers.Feature.Vector(); │ │ │ │ │ + } │ │ │ │ │ + if (!this.styles[intent]) { │ │ │ │ │ + intent = "default"; │ │ │ │ │ + } │ │ │ │ │ + feature.renderIntent = intent; │ │ │ │ │ + var defaultSymbolizer = {}; │ │ │ │ │ + if (this.extendDefault && intent != "default") { │ │ │ │ │ + defaultSymbolizer = this.styles["default"].createSymbolizer(feature); │ │ │ │ │ + } │ │ │ │ │ + return OpenLayers.Util.extend(defaultSymbolizer, │ │ │ │ │ + this.styles[intent].createSymbolizer(feature)); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: addUniqueValueRules │ │ │ │ │ + * Convenience method to create comparison rules for unique values of a │ │ │ │ │ + * property. The rules will be added to the style object for a specified │ │ │ │ │ + * rendering intent. This method is a shortcut for creating something like │ │ │ │ │ + * the "unique value legends" familiar from well known desktop GIS systems │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * renderIntent - {String} rendering intent to add the rules to │ │ │ │ │ + * property - {String} values of feature attributes to create the │ │ │ │ │ + * rules for │ │ │ │ │ + * symbolizers - {Object} Hash of symbolizers, keyed by the desired │ │ │ │ │ + * property values │ │ │ │ │ + * context - {Object} An optional object with properties that │ │ │ │ │ + * symbolizers' property values should be evaluated │ │ │ │ │ + * against. If no context is specified, feature.attributes │ │ │ │ │ + * will be used │ │ │ │ │ + */ │ │ │ │ │ + addUniqueValueRules: function(renderIntent, property, symbolizers, context) { │ │ │ │ │ + var rules = []; │ │ │ │ │ + for (var value in symbolizers) { │ │ │ │ │ + rules.push(new OpenLayers.Rule({ │ │ │ │ │ + symbolizer: symbolizers[value], │ │ │ │ │ + context: context, │ │ │ │ │ + filter: new OpenLayers.Filter.Comparison({ │ │ │ │ │ + type: OpenLayers.Filter.Comparison.EQUAL_TO, │ │ │ │ │ + property: property, │ │ │ │ │ + value: value │ │ │ │ │ + }) │ │ │ │ │ + })); │ │ │ │ │ + } │ │ │ │ │ + this.styles[renderIntent].addRules(rules); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.StyleMap" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Spherical.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/SingleFile.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Namespace: Spherical │ │ │ │ │ + * The OpenLayers.Spherical namespace includes utility functions for │ │ │ │ │ + * calculations on the basis of a spherical earth (ignoring ellipsoidal │ │ │ │ │ + * effects), which is accurate enough for most purposes. │ │ │ │ │ + * │ │ │ │ │ + * Relevant links: │ │ │ │ │ + * * http://www.movable-type.co.uk/scripts/latlong.html │ │ │ │ │ + * * http://code.google.com/apis/maps/documentation/javascript/reference.html#spherical │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +OpenLayers.Spherical = OpenLayers.Spherical || {}; │ │ │ │ │ + │ │ │ │ │ +OpenLayers.Spherical.DEFAULT_RADIUS = 6378137; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * APIFunction: computeDistanceBetween │ │ │ │ │ + * Computes the distance between two LonLats. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * from - {} or {Object} Starting point. A LonLat or │ │ │ │ │ + * a JavaScript literal with lon lat properties. │ │ │ │ │ + * to - {} or {Object} Ending point. A LonLat or a │ │ │ │ │ + * JavaScript literal with lon lat properties. │ │ │ │ │ + * radius - {Float} The radius. Optional. Defaults to 6378137 meters. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} The distance in meters. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Spherical.computeDistanceBetween = function(from, to, radius) { │ │ │ │ │ + var R = radius || OpenLayers.Spherical.DEFAULT_RADIUS; │ │ │ │ │ + var sinHalfDeltaLon = Math.sin(Math.PI * (to.lon - from.lon) / 360); │ │ │ │ │ + var sinHalfDeltaLat = Math.sin(Math.PI * (to.lat - from.lat) / 360); │ │ │ │ │ + var a = sinHalfDeltaLat * sinHalfDeltaLat + │ │ │ │ │ + sinHalfDeltaLon * sinHalfDeltaLon * Math.cos(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ │ + return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * APIFunction: computeHeading │ │ │ │ │ + * Computes the heading from one LonLat to another LonLat. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * from - {} or {Object} Starting point. A LonLat or │ │ │ │ │ + * a JavaScript literal with lon lat properties. │ │ │ │ │ + * to - {} or {Object} Ending point. A LonLat or a │ │ │ │ │ + * JavaScript literal with lon lat properties. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} The heading in degrees. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Spherical.computeHeading = function(from, to) { │ │ │ │ │ + var y = Math.sin(Math.PI * (from.lon - to.lon) / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ │ + var x = Math.cos(Math.PI * from.lat / 180) * Math.sin(Math.PI * to.lat / 180) - │ │ │ │ │ + Math.sin(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180) * Math.cos(Math.PI * (from.lon - to.lon) / 180); │ │ │ │ │ + return 180 * Math.atan2(y, x) / Math.PI; │ │ │ │ │ +}; │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Filter.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ │ + * @requires OpenLayers/Style.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Filter │ │ │ │ │ + * This class represents an OGC Filter. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Filter = OpenLayers.Class({ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Filter │ │ │ │ │ + * This class represents a generic filter. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ + * instance. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ + * Remove reference to anything added. │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: evaluate │ │ │ │ │ + * Evaluates this filter in a specific context. Instances or subclasses │ │ │ │ │ + * are supposed to override this method. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * context - {Object} Context to use in evaluating the filter. If a vector │ │ │ │ │ + * feature is provided, the feature.attributes will be used as context. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The filter applies. │ │ │ │ │ + */ │ │ │ │ │ + evaluate: function(context) { │ │ │ │ │ + return true; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: clone │ │ │ │ │ + * Clones this filter. Should be implemented by subclasses. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} Clone of this filter. │ │ │ │ │ + */ │ │ │ │ │ + clone: function() { │ │ │ │ │ + return null; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: toString │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {String} Include in your build to get a CQL │ │ │ │ │ + * representation of the filter returned. Otherwise "[Object object]" │ │ │ │ │ + * will be returned. │ │ │ │ │ + */ │ │ │ │ │ + toString: function() { │ │ │ │ │ + var string; │ │ │ │ │ + if (OpenLayers.Format && OpenLayers.Format.CQL) { │ │ │ │ │ + string = OpenLayers.Format.CQL.prototype.write(this); │ │ │ │ │ + } else { │ │ │ │ │ + string = Object.prototype.toString.call(this); │ │ │ │ │ + } │ │ │ │ │ + return string; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Filter" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Util/vendorPrefix.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/SingleFile.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +OpenLayers.Util = OpenLayers.Util || {}; │ │ │ │ │ +/** │ │ │ │ │ + * Namespace: OpenLayers.Util.vendorPrefix │ │ │ │ │ + * A collection of utility functions to detect vendor prefixed features │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Util.vendorPrefix = (function() { │ │ │ │ │ + "use strict"; │ │ │ │ │ + │ │ │ │ │ + var VENDOR_PREFIXES = ["", "O", "ms", "Moz", "Webkit"], │ │ │ │ │ + divStyle = document.createElement("div").style, │ │ │ │ │ + cssCache = {}, │ │ │ │ │ + jsCache = {}; │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Function: domToCss │ │ │ │ │ + * Converts a upper camel case DOM style property name to a CSS property │ │ │ │ │ + * i.e. transformOrigin -> transform-origin │ │ │ │ │ + * or WebkitTransformOrigin -> -webkit-transform-origin │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * prefixedDom - {String} The property to convert │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {String} The CSS property │ │ │ │ │ + */ │ │ │ │ │ + function domToCss(prefixedDom) { │ │ │ │ │ + if (!prefixedDom) { │ │ │ │ │ + return null; │ │ │ │ │ + } │ │ │ │ │ + return prefixedDom. │ │ │ │ │ + replace(/([A-Z])/g, function(c) { │ │ │ │ │ + return "-" + c.toLowerCase(); │ │ │ │ │ + }). │ │ │ │ │ + replace(/^ms-/, "-ms-"); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: css │ │ │ │ │ + * Detect which property is used for a CSS property │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * property - {String} The standard (unprefixed) CSS property name │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {String} The standard CSS property, prefixed property or null if not │ │ │ │ │ + * supported │ │ │ │ │ + */ │ │ │ │ │ + function css(property) { │ │ │ │ │ + if (cssCache[property] === undefined) { │ │ │ │ │ + var domProperty = property. │ │ │ │ │ + replace(/(-[\s\S])/g, function(c) { │ │ │ │ │ + return c.charAt(1).toUpperCase(); │ │ │ │ │ + }); │ │ │ │ │ + var prefixedDom = style(domProperty); │ │ │ │ │ + cssCache[property] = domToCss(prefixedDom); │ │ │ │ │ + } │ │ │ │ │ + return cssCache[property]; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: js │ │ │ │ │ + * Detect which property is used for a JS property/method │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * obj - {Object} The object to test on │ │ │ │ │ + * property - {String} The standard (unprefixed) JS property name │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {String} The standard JS property, prefixed property or null if not │ │ │ │ │ + * supported │ │ │ │ │ + */ │ │ │ │ │ + function js(obj, property) { │ │ │ │ │ + if (jsCache[property] === undefined) { │ │ │ │ │ + var tmpProp, │ │ │ │ │ + i = 0, │ │ │ │ │ + l = VENDOR_PREFIXES.length, │ │ │ │ │ + prefix, │ │ │ │ │ + isStyleObj = (typeof obj.cssText !== "undefined"); │ │ │ │ │ + │ │ │ │ │ + jsCache[property] = null; │ │ │ │ │ + for (; i < l; i++) { │ │ │ │ │ + prefix = VENDOR_PREFIXES[i]; │ │ │ │ │ + if (prefix) { │ │ │ │ │ + if (!isStyleObj) { │ │ │ │ │ + // js prefix should be lower-case, while style │ │ │ │ │ + // properties have upper case on first character │ │ │ │ │ + prefix = prefix.toLowerCase(); │ │ │ │ │ + } │ │ │ │ │ + tmpProp = prefix + property.charAt(0).toUpperCase() + property.slice(1); │ │ │ │ │ + } else { │ │ │ │ │ + tmpProp = property; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (obj[tmpProp] !== undefined) { │ │ │ │ │ + jsCache[property] = tmpProp; │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return jsCache[property]; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: style │ │ │ │ │ + * Detect which property is used for a DOM style property │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * property - {String} The standard (unprefixed) style property name │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {String} The standard style property, prefixed property or null if not │ │ │ │ │ + * supported │ │ │ │ │ + */ │ │ │ │ │ + function style(property) { │ │ │ │ │ + return js(divStyle, property); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + return { │ │ │ │ │ + css: css, │ │ │ │ │ + js: js, │ │ │ │ │ + style: style, │ │ │ │ │ + │ │ │ │ │ + // used for testing │ │ │ │ │ + cssCache: cssCache, │ │ │ │ │ + jsCache: jsCache │ │ │ │ │ + }; │ │ │ │ │ +}()); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Animation.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/SingleFile.js │ │ │ │ │ + * @requires OpenLayers/Util/vendorPrefix.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Namespace: OpenLayers.Animation │ │ │ │ │ + * A collection of utility functions for executing methods that repaint a │ │ │ │ │ + * portion of the browser window. These methods take advantage of the │ │ │ │ │ + * browser's scheduled repaints where requestAnimationFrame is available. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Animation = (function(window) { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: isNative │ │ │ │ │ + * {Boolean} true if a native requestAnimationFrame function is available │ │ │ │ │ + */ │ │ │ │ │ + var requestAnimationFrame = OpenLayers.Util.vendorPrefix.js(window, "requestAnimationFrame"); │ │ │ │ │ + var isNative = !!(requestAnimationFrame); │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Function: requestFrame │ │ │ │ │ + * Schedule a function to be called at the next available animation frame. │ │ │ │ │ + * Uses the native method where available. Where requestAnimationFrame is │ │ │ │ │ + * not available, setTimeout will be called with a 16ms delay. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * callback - {Function} The function to be called at the next animation frame. │ │ │ │ │ + * element - {DOMElement} Optional element that visually bounds the animation. │ │ │ │ │ + */ │ │ │ │ │ + var requestFrame = (function() { │ │ │ │ │ + var request = window[requestAnimationFrame] || │ │ │ │ │ + function(callback, element) { │ │ │ │ │ + window.setTimeout(callback, 16); │ │ │ │ │ + }; │ │ │ │ │ + // bind to window to avoid illegal invocation of native function │ │ │ │ │ + return function(callback, element) { │ │ │ │ │ + request.apply(window, [callback, element]); │ │ │ │ │ + }; │ │ │ │ │ + })(); │ │ │ │ │ + │ │ │ │ │ + // private variables for animation loops │ │ │ │ │ + var counter = 0; │ │ │ │ │ + var loops = {}; │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Function: start │ │ │ │ │ + * Executes a method with in series for some │ │ │ │ │ + * duration. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * callback - {Function} The function to be called at the next animation frame. │ │ │ │ │ + * duration - {Number} Optional duration for the loop. If not provided, the │ │ │ │ │ + * animation loop will execute indefinitely. │ │ │ │ │ + * element - {DOMElement} Optional element that visually bounds the animation. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Number} Identifier for the animation loop. Used to stop animations with │ │ │ │ │ + * . │ │ │ │ │ + */ │ │ │ │ │ + function start(callback, duration, element) { │ │ │ │ │ + duration = duration > 0 ? duration : Number.POSITIVE_INFINITY; │ │ │ │ │ + var id = ++counter; │ │ │ │ │ + var start = +new Date; │ │ │ │ │ + loops[id] = function() { │ │ │ │ │ + if (loops[id] && +new Date - start <= duration) { │ │ │ │ │ + callback(); │ │ │ │ │ + if (loops[id]) { │ │ │ │ │ + requestFrame(loops[id], element); │ │ │ │ │ + } │ │ │ │ │ + } else { │ │ │ │ │ + delete loops[id]; │ │ │ │ │ + } │ │ │ │ │ + }; │ │ │ │ │ + requestFrame(loops[id], element); │ │ │ │ │ + return id; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Function: stop │ │ │ │ │ + * Terminates an animation loop started with . │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * id - {Number} Identifier returned from . │ │ │ │ │ + */ │ │ │ │ │ + function stop(id) { │ │ │ │ │ + delete loops[id]; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + return { │ │ │ │ │ + isNative: isNative, │ │ │ │ │ + requestFrame: requestFrame, │ │ │ │ │ + start: start, │ │ │ │ │ + stop: stop │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ +})(window); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Tween.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Animation.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Namespace: OpenLayers.Tween │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Tween = OpenLayers.Class({ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: easing │ │ │ │ │ + * {(Function)} Easing equation used for the animation │ │ │ │ │ + * Defaultly set to OpenLayers.Easing.Expo.easeOut │ │ │ │ │ + */ │ │ │ │ │ + easing: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: begin │ │ │ │ │ + * {Object} Values to start the animation with │ │ │ │ │ + */ │ │ │ │ │ + begin: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: finish │ │ │ │ │ + * {Object} Values to finish the animation with │ │ │ │ │ + */ │ │ │ │ │ + finish: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: duration │ │ │ │ │ + * {int} duration of the tween (number of steps) │ │ │ │ │ + */ │ │ │ │ │ + duration: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: callbacks │ │ │ │ │ + * {Object} An object with start, eachStep and done properties whose values │ │ │ │ │ + * are functions to be call during the animation. They are passed the │ │ │ │ │ + * current computed value as argument. │ │ │ │ │ + */ │ │ │ │ │ + callbacks: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: time │ │ │ │ │ + * {int} Step counter │ │ │ │ │ + */ │ │ │ │ │ + time: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: minFrameRate │ │ │ │ │ + * {Number} The minimum framerate for animations in frames per second. After │ │ │ │ │ + * each step, the time spent in the animation is compared to the calculated │ │ │ │ │ + * time at this frame rate. If the animation runs longer than the calculated │ │ │ │ │ + * time, the next step is skipped. Default is 30. │ │ │ │ │ + */ │ │ │ │ │ + minFrameRate: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: startTime │ │ │ │ │ + * {Number} The timestamp of the first execution step. Used for skipping │ │ │ │ │ + * frames │ │ │ │ │ + */ │ │ │ │ │ + startTime: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: animationId │ │ │ │ │ + * {int} Loop id returned by OpenLayers.Animation.start │ │ │ │ │ + */ │ │ │ │ │ + animationId: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: playing │ │ │ │ │ + * {Boolean} Tells if the easing is currently playing │ │ │ │ │ + */ │ │ │ │ │ + playing: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Tween │ │ │ │ │ + * Creates a Tween. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * easing - {(Function)} easing function method to use │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(easing) { │ │ │ │ │ + this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: start │ │ │ │ │ + * Plays the Tween, and calls the callback method on each step │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * begin - {Object} values to start the animation with │ │ │ │ │ + * finish - {Object} values to finish the animation with │ │ │ │ │ + * duration - {int} duration of the tween (number of steps) │ │ │ │ │ + * options - {Object} hash of options (callbacks (start, eachStep, done), │ │ │ │ │ + * minFrameRate) │ │ │ │ │ + */ │ │ │ │ │ + start: function(begin, finish, duration, options) { │ │ │ │ │ + this.playing = true; │ │ │ │ │ + this.begin = begin; │ │ │ │ │ + this.finish = finish; │ │ │ │ │ + this.duration = duration; │ │ │ │ │ + this.callbacks = options.callbacks; │ │ │ │ │ + this.minFrameRate = options.minFrameRate || 30; │ │ │ │ │ + this.time = 0; │ │ │ │ │ + this.startTime = new Date().getTime(); │ │ │ │ │ + OpenLayers.Animation.stop(this.animationId); │ │ │ │ │ + this.animationId = null; │ │ │ │ │ + if (this.callbacks && this.callbacks.start) { │ │ │ │ │ + this.callbacks.start.call(this, this.begin); │ │ │ │ │ + } │ │ │ │ │ + this.animationId = OpenLayers.Animation.start( │ │ │ │ │ + OpenLayers.Function.bind(this.play, this) │ │ │ │ │ + ); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: stop │ │ │ │ │ + * Stops the Tween, and calls the done callback │ │ │ │ │ + * Doesn't do anything if animation is already finished │ │ │ │ │ + */ │ │ │ │ │ + stop: function() { │ │ │ │ │ + if (!this.playing) { │ │ │ │ │ + return; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (this.callbacks && this.callbacks.done) { │ │ │ │ │ + this.callbacks.done.call(this, this.finish); │ │ │ │ │ + } │ │ │ │ │ + OpenLayers.Animation.stop(this.animationId); │ │ │ │ │ + this.animationId = null; │ │ │ │ │ + this.playing = false; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: play │ │ │ │ │ + * Calls the appropriate easing method │ │ │ │ │ + */ │ │ │ │ │ + play: function() { │ │ │ │ │ + var value = {}; │ │ │ │ │ + for (var i in this.begin) { │ │ │ │ │ + var b = this.begin[i]; │ │ │ │ │ + var f = this.finish[i]; │ │ │ │ │ + if (b == null || f == null || isNaN(b) || isNaN(f)) { │ │ │ │ │ + throw new TypeError('invalid value for Tween'); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + var c = f - b; │ │ │ │ │ + value[i] = this.easing.apply(this, [this.time, b, c, this.duration]); │ │ │ │ │ + } │ │ │ │ │ + this.time++; │ │ │ │ │ + │ │ │ │ │ + if (this.callbacks && this.callbacks.eachStep) { │ │ │ │ │ + // skip frames if frame rate drops below threshold │ │ │ │ │ + if ((new Date().getTime() - this.startTime) / this.time <= 1000 / this.minFrameRate) { │ │ │ │ │ + this.callbacks.eachStep.call(this, value); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (this.time > this.duration) { │ │ │ │ │ + this.stop(); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Create empty functions for all easing methods. │ │ │ │ │ + */ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Tween" │ │ │ │ │ +}); │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Namespace: OpenLayers.Easing │ │ │ │ │ + * │ │ │ │ │ + * Credits: │ │ │ │ │ + * Easing Equations by Robert Penner, │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Easing = { │ │ │ │ │ + /** │ │ │ │ │ + * Create empty functions for all easing methods. │ │ │ │ │ + */ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Easing" │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Namespace: OpenLayers.Easing.Linear │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Easing.Linear = { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Function: easeIn │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + easeIn: function(t, b, c, d) { │ │ │ │ │ + return c * t / d + b; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Function: easeOut │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + easeOut: function(t, b, c, d) { │ │ │ │ │ + return c * t / d + b; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Function: easeInOut │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + easeInOut: function(t, b, c, d) { │ │ │ │ │ + return c * t / d + b; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Easing.Linear" │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Namespace: OpenLayers.Easing.Expo │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Easing.Expo = { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Function: easeIn │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + easeIn: function(t, b, c, d) { │ │ │ │ │ + return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Function: easeOut │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + easeOut: function(t, b, c, d) { │ │ │ │ │ + return (t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Function: easeInOut │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + easeInOut: function(t, b, c, d) { │ │ │ │ │ + if (t == 0) return b; │ │ │ │ │ + if (t == d) return b + c; │ │ │ │ │ + if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b; │ │ │ │ │ + return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Easing.Expo" │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Namespace: OpenLayers.Easing.Quad │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Easing.Quad = { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Function: easeIn │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + easeIn: function(t, b, c, d) { │ │ │ │ │ + return c * (t /= d) * t + b; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Function: easeOut │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + easeOut: function(t, b, c, d) { │ │ │ │ │ + return -c * (t /= d) * (t - 2) + b; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Function: easeInOut │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * t - {Float} time │ │ │ │ │ + * b - {Float} beginning position │ │ │ │ │ + * c - {Float} total change │ │ │ │ │ + * d - {Float} duration of the transition │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + easeInOut: function(t, b, c, d) { │ │ │ │ │ + if ((t /= d / 2) < 1) return c / 2 * t * t + b; │ │ │ │ │ + return -c / 2 * ((--t) * (t - 2) - 1) + b; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Easing.Quad" │ │ │ │ │ +}; │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Projection.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Namespace: OpenLayers.Projection │ │ │ │ │ + * Methods for coordinate transforms between coordinate systems. By default, │ │ │ │ │ + * OpenLayers ships with the ability to transform coordinates between │ │ │ │ │ + * geographic (EPSG:4326) and web or spherical mercator (EPSG:900913 et al.) │ │ │ │ │ + * coordinate reference systems. See the method for details │ │ │ │ │ + * on usage. │ │ │ │ │ + * │ │ │ │ │ + * Additional transforms may be added by using the │ │ │ │ │ + * library. If the proj4js library is included, the method │ │ │ │ │ + * will work between any two coordinate reference systems with proj4js │ │ │ │ │ + * definitions. │ │ │ │ │ + * │ │ │ │ │ + * If the proj4js library is not included, or if you wish to allow transforms │ │ │ │ │ + * between arbitrary coordinate reference systems, use the │ │ │ │ │ + * method to register a custom transform method. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Projection = OpenLayers.Class({ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: proj │ │ │ │ │ + * {Object} Proj4js.Proj instance. │ │ │ │ │ + */ │ │ │ │ │ + proj: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: projCode │ │ │ │ │ + * {String} │ │ │ │ │ + */ │ │ │ │ │ + projCode: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: titleRegEx │ │ │ │ │ + * {RegExp} regular expression to strip the title from a proj4js definition │ │ │ │ │ + */ │ │ │ │ │ + titleRegEx: /\+title=[^\+]*/, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Projection │ │ │ │ │ + * This class offers several methods for interacting with a wrapped │ │ │ │ │ + * pro4js projection object. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * projCode - {String} A string identifying the Well Known Identifier for │ │ │ │ │ + * the projection. │ │ │ │ │ + * options - {Object} An optional object to set additional properties │ │ │ │ │ + * on the projection. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} A projection object. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(projCode, options) { │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + this.projCode = projCode; │ │ │ │ │ + if (typeof Proj4js == "object") { │ │ │ │ │ + this.proj = new Proj4js.Proj(projCode); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: getCode │ │ │ │ │ + * Get the string SRS code. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {String} The SRS code. │ │ │ │ │ + */ │ │ │ │ │ + getCode: function() { │ │ │ │ │ + return this.proj ? this.proj.srsCode : this.projCode; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: getUnits │ │ │ │ │ + * Get the units string for the projection -- returns null if │ │ │ │ │ + * proj4js is not available. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {String} The units abbreviation. │ │ │ │ │ + */ │ │ │ │ │ + getUnits: function() { │ │ │ │ │ + return this.proj ? this.proj.units : null; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: toString │ │ │ │ │ + * Convert projection to string (getCode wrapper). │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {String} The projection code. │ │ │ │ │ + */ │ │ │ │ │ + toString: function() { │ │ │ │ │ + return this.getCode(); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: equals │ │ │ │ │ + * Test equality of two projection instances. Determines equality based │ │ │ │ │ + * soley on the projection code. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The two projections are equivalent. │ │ │ │ │ + */ │ │ │ │ │ + equals: function(projection) { │ │ │ │ │ + var p = projection, │ │ │ │ │ + equals = false; │ │ │ │ │ + if (p) { │ │ │ │ │ + if (!(p instanceof OpenLayers.Projection)) { │ │ │ │ │ + p = new OpenLayers.Projection(p); │ │ │ │ │ + } │ │ │ │ │ + if ((typeof Proj4js == "object") && this.proj.defData && p.proj.defData) { │ │ │ │ │ + equals = this.proj.defData.replace(this.titleRegEx, "") == │ │ │ │ │ + p.proj.defData.replace(this.titleRegEx, ""); │ │ │ │ │ + } else if (p.getCode) { │ │ │ │ │ + var source = this.getCode(), │ │ │ │ │ + target = p.getCode(); │ │ │ │ │ + equals = source == target || │ │ │ │ │ + !!OpenLayers.Projection.transforms[source] && │ │ │ │ │ + OpenLayers.Projection.transforms[source][target] === │ │ │ │ │ + OpenLayers.Projection.nullTransform; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return equals; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /* Method: destroy │ │ │ │ │ + * Destroy projection object. │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + delete this.proj; │ │ │ │ │ + delete this.projCode; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Projection" │ │ │ │ │ +}); │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Property: transforms │ │ │ │ │ + * {Object} Transforms is an object, with from properties, each of which may │ │ │ │ │ + * have a to property. This allows you to define projections without │ │ │ │ │ + * requiring support for proj4js to be included. │ │ │ │ │ + * │ │ │ │ │ + * This object has keys which correspond to a 'source' projection object. The │ │ │ │ │ + * keys should be strings, corresponding to the projection.getCode() value. │ │ │ │ │ + * Each source projection object should have a set of destination projection │ │ │ │ │ + * keys included in the object. │ │ │ │ │ + * │ │ │ │ │ + * Each value in the destination object should be a transformation function, │ │ │ │ │ + * where the function is expected to be passed an object with a .x and a .y │ │ │ │ │ + * property. The function should return the object, with the .x and .y │ │ │ │ │ + * transformed according to the transformation function. │ │ │ │ │ + * │ │ │ │ │ + * Note - Properties on this object should not be set directly. To add a │ │ │ │ │ + * transform method to this object, use the method. For an │ │ │ │ │ + * example of usage, see the OpenLayers.Layer.SphericalMercator file. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Projection.transforms = {}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * APIProperty: defaults │ │ │ │ │ + * {Object} Defaults for the SRS codes known to OpenLayers (currently │ │ │ │ │ + * EPSG:4326, CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, EPSG:900913, EPSG:3857, │ │ │ │ │ + * EPSG:102113 and EPSG:102100). Keys are the SRS code, values are units, │ │ │ │ │ + * maxExtent (the validity extent for the SRS) and yx (true if this SRS is │ │ │ │ │ + * known to have a reverse axis order). │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Projection.defaults = { │ │ │ │ │ + "EPSG:4326": { │ │ │ │ │ + units: "degrees", │ │ │ │ │ + maxExtent: [-180, -90, 180, 90], │ │ │ │ │ + yx: true │ │ │ │ │ + }, │ │ │ │ │ + "CRS:84": { │ │ │ │ │ + units: "degrees", │ │ │ │ │ + maxExtent: [-180, -90, 180, 90] │ │ │ │ │ + }, │ │ │ │ │ + "EPSG:900913": { │ │ │ │ │ + units: "m", │ │ │ │ │ + maxExtent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34] │ │ │ │ │ + } │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * APIMethod: addTransform │ │ │ │ │ + * Set a custom transform method between two projections. Use this method in │ │ │ │ │ + * cases where the proj4js lib is not available or where custom projections │ │ │ │ │ + * need to be handled. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * from - {String} The code for the source projection │ │ │ │ │ + * to - {String} the code for the destination projection │ │ │ │ │ + * method - {Function} A function that takes a point as an argument and │ │ │ │ │ + * transforms that point from the source to the destination projection │ │ │ │ │ + * in place. The original point should be modified. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Projection.addTransform = function(from, to, method) { │ │ │ │ │ + if (method === OpenLayers.Projection.nullTransform) { │ │ │ │ │ + var defaults = OpenLayers.Projection.defaults[from]; │ │ │ │ │ + if (defaults && !OpenLayers.Projection.defaults[to]) { │ │ │ │ │ + OpenLayers.Projection.defaults[to] = defaults; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + if (!OpenLayers.Projection.transforms[from]) { │ │ │ │ │ + OpenLayers.Projection.transforms[from] = {}; │ │ │ │ │ + } │ │ │ │ │ + OpenLayers.Projection.transforms[from][to] = method; │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * APIMethod: transform │ │ │ │ │ + * Transform a point coordinate from one projection to another. Note that │ │ │ │ │ + * the input point is transformed in place. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * point - { | Object} An object with x and y │ │ │ │ │ + * properties representing coordinates in those dimensions. │ │ │ │ │ + * source - {OpenLayers.Projection} Source map coordinate system │ │ │ │ │ + * dest - {OpenLayers.Projection} Destination map coordinate system │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * point - {object} A transformed coordinate. The original point is modified. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Projection.transform = function(point, source, dest) { │ │ │ │ │ + if (source && dest) { │ │ │ │ │ + if (!(source instanceof OpenLayers.Projection)) { │ │ │ │ │ + source = new OpenLayers.Projection(source); │ │ │ │ │ + } │ │ │ │ │ + if (!(dest instanceof OpenLayers.Projection)) { │ │ │ │ │ + dest = new OpenLayers.Projection(dest); │ │ │ │ │ + } │ │ │ │ │ + if (source.proj && dest.proj) { │ │ │ │ │ + point = Proj4js.transform(source.proj, dest.proj, point); │ │ │ │ │ + } else { │ │ │ │ │ + var sourceCode = source.getCode(); │ │ │ │ │ + var destCode = dest.getCode(); │ │ │ │ │ + var transforms = OpenLayers.Projection.transforms; │ │ │ │ │ + if (transforms[sourceCode] && transforms[sourceCode][destCode]) { │ │ │ │ │ + transforms[sourceCode][destCode](point); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return point; │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * APIFunction: nullTransform │ │ │ │ │ + * A null transformation - useful for defining projection aliases when │ │ │ │ │ + * proj4js is not available: │ │ │ │ │ + * │ │ │ │ │ + * (code) │ │ │ │ │ + * OpenLayers.Projection.addTransform("EPSG:3857", "EPSG:900913", │ │ │ │ │ + * OpenLayers.Projection.nullTransform); │ │ │ │ │ + * OpenLayers.Projection.addTransform("EPSG:900913", "EPSG:3857", │ │ │ │ │ + * OpenLayers.Projection.nullTransform); │ │ │ │ │ + * (end) │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Projection.nullTransform = function(point) { │ │ │ │ │ + return point; │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Note: Transforms for web mercator <-> geographic │ │ │ │ │ + * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113 and EPSG:102100. │ │ │ │ │ + * OpenLayers originally started referring to EPSG:900913 as web mercator. │ │ │ │ │ + * The EPSG has declared EPSG:3857 to be web mercator. │ │ │ │ │ + * ArcGIS 10 recognizes the EPSG:3857, EPSG:102113, and EPSG:102100 as │ │ │ │ │ + * equivalent. See http://blogs.esri.com/Dev/blogs/arcgisserver/archive/2009/11/20/ArcGIS-Online-moving-to-Google-_2F00_-Bing-tiling-scheme_3A00_-What-does-this-mean-for-you_3F00_.aspx#12084. │ │ │ │ │ + * For geographic, OpenLayers recognizes EPSG:4326, CRS:84 and │ │ │ │ │ + * urn:ogc:def:crs:EPSG:6.6:4326. OpenLayers also knows about the reverse axis │ │ │ │ │ + * order for EPSG:4326. │ │ │ │ │ + */ │ │ │ │ │ +(function() { │ │ │ │ │ + │ │ │ │ │ + var pole = 20037508.34; │ │ │ │ │ + │ │ │ │ │ + function inverseMercator(xy) { │ │ │ │ │ + xy.x = 180 * xy.x / pole; │ │ │ │ │ + xy.y = 180 / Math.PI * (2 * Math.atan(Math.exp((xy.y / pole) * Math.PI)) - Math.PI / 2); │ │ │ │ │ + return xy; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + function forwardMercator(xy) { │ │ │ │ │ + xy.x = xy.x * pole / 180; │ │ │ │ │ + var y = Math.log(Math.tan((90 + xy.y) * Math.PI / 360)) / Math.PI * pole; │ │ │ │ │ + xy.y = Math.max(-20037508.34, Math.min(y, 20037508.34)); │ │ │ │ │ + return xy; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + function map(base, codes) { │ │ │ │ │ + var add = OpenLayers.Projection.addTransform; │ │ │ │ │ + var same = OpenLayers.Projection.nullTransform; │ │ │ │ │ + var i, len, code, other, j; │ │ │ │ │ + for (i = 0, len = codes.length; i < len; ++i) { │ │ │ │ │ + code = codes[i]; │ │ │ │ │ + add(base, code, forwardMercator); │ │ │ │ │ + add(code, base, inverseMercator); │ │ │ │ │ + for (j = i + 1; j < len; ++j) { │ │ │ │ │ + other = codes[j]; │ │ │ │ │ + add(code, other, same); │ │ │ │ │ + add(other, code, same); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // list of equivalent codes for web mercator │ │ │ │ │ + var mercator = ["EPSG:900913", "EPSG:3857", "EPSG:102113", "EPSG:102100"], │ │ │ │ │ + geographic = ["CRS:84", "urn:ogc:def:crs:EPSG:6.6:4326", "EPSG:4326"], │ │ │ │ │ + i; │ │ │ │ │ + for (i = mercator.length - 1; i >= 0; --i) { │ │ │ │ │ + map(mercator[i], geographic); │ │ │ │ │ + } │ │ │ │ │ + for (i = geographic.length - 1; i >= 0; --i) { │ │ │ │ │ + map(geographic[i], mercator); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ +})(); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Map.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ │ + * @requires OpenLayers/Util/vendorPrefix.js │ │ │ │ │ + * @requires OpenLayers/Events.js │ │ │ │ │ + * @requires OpenLayers/Tween.js │ │ │ │ │ + * @requires OpenLayers/Projection.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Map │ │ │ │ │ + * Instances of OpenLayers.Map are interactive maps embedded in a web page. │ │ │ │ │ + * Create a new map with the constructor. │ │ │ │ │ + * │ │ │ │ │ + * On their own maps do not provide much functionality. To extend a map │ │ │ │ │ + * it's necessary to add controls () and │ │ │ │ │ + * layers () to the map. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Map = OpenLayers.Class({ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constant: Z_INDEX_BASE │ │ │ │ │ + * {Object} Base z-indexes for different classes of thing │ │ │ │ │ + */ │ │ │ │ │ + Z_INDEX_BASE: { │ │ │ │ │ + BaseLayer: 100, │ │ │ │ │ + Overlay: 325, │ │ │ │ │ + Feature: 725, │ │ │ │ │ + Popup: 750, │ │ │ │ │ + Control: 1000 │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: events │ │ │ │ │ + * {} │ │ │ │ │ + * │ │ │ │ │ + * Register a listener for a particular event with the following syntax: │ │ │ │ │ + * (code) │ │ │ │ │ + * map.events.register(type, obj, listener); │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Listeners will be called with a reference to an event object. The │ │ │ │ │ + * properties of this event depends on exactly what happened. │ │ │ │ │ + * │ │ │ │ │ + * All event objects have at least the following properties: │ │ │ │ │ + * object - {Object} A reference to map.events.object. │ │ │ │ │ + * element - {DOMElement} A reference to map.events.element. │ │ │ │ │ + * │ │ │ │ │ + * Browser events have the following additional properties: │ │ │ │ │ + * xy - {} The pixel location of the event (relative │ │ │ │ │ + * to the the map viewport). │ │ │ │ │ + * │ │ │ │ │ + * Supported map event types: │ │ │ │ │ + * preaddlayer - triggered before a layer has been added. The event │ │ │ │ │ + * object will include a *layer* property that references the layer │ │ │ │ │ + * to be added. When a listener returns "false" the adding will be │ │ │ │ │ + * aborted. │ │ │ │ │ + * addlayer - triggered after a layer has been added. The event object │ │ │ │ │ + * will include a *layer* property that references the added layer. │ │ │ │ │ + * preremovelayer - triggered before a layer has been removed. The event │ │ │ │ │ + * object will include a *layer* property that references the layer │ │ │ │ │ + * to be removed. When a listener returns "false" the removal will be │ │ │ │ │ + * aborted. │ │ │ │ │ + * removelayer - triggered after a layer has been removed. The event │ │ │ │ │ + * object will include a *layer* property that references the removed │ │ │ │ │ + * layer. │ │ │ │ │ + * changelayer - triggered after a layer name change, order change, │ │ │ │ │ + * opacity change, params change, visibility change (actual visibility, │ │ │ │ │ + * not the layer's visibility property) or attribution change (due to │ │ │ │ │ + * extent change). Listeners will receive an event object with *layer* │ │ │ │ │ + * and *property* properties. The *layer* property will be a reference │ │ │ │ │ + * to the changed layer. The *property* property will be a key to the │ │ │ │ │ + * changed property (name, order, opacity, params, visibility or │ │ │ │ │ + * attribution). │ │ │ │ │ + * movestart - triggered after the start of a drag, pan, or zoom. The event │ │ │ │ │ + * object may include a *zoomChanged* property that tells whether the │ │ │ │ │ + * zoom has changed. │ │ │ │ │ + * move - triggered after each drag, pan, or zoom │ │ │ │ │ + * moveend - triggered after a drag, pan, or zoom completes │ │ │ │ │ + * zoomend - triggered after a zoom completes │ │ │ │ │ + * mouseover - triggered after mouseover the map │ │ │ │ │ + * mouseout - triggered after mouseout the map │ │ │ │ │ + * mousemove - triggered after mousemove the map │ │ │ │ │ + * changebaselayer - triggered after the base layer changes │ │ │ │ │ + * updatesize - triggered after the method was executed │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: id │ │ │ │ │ + * {String} Unique identifier for the map │ │ │ │ │ + */ │ │ │ │ │ + id: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: fractionalZoom │ │ │ │ │ + * {Boolean} For a base layer that supports it, allow the map resolution │ │ │ │ │ + * to be set to a value between one of the values in the resolutions │ │ │ │ │ + * array. Default is false. │ │ │ │ │ + * │ │ │ │ │ + * When fractionalZoom is set to true, it is possible to zoom to │ │ │ │ │ + * an arbitrary extent. This requires a base layer from a source │ │ │ │ │ + * that supports requests for arbitrary extents (i.e. not cached │ │ │ │ │ + * tiles on a regular lattice). This means that fractionalZoom │ │ │ │ │ + * will not work with commercial layers (Google, Yahoo, VE), layers │ │ │ │ │ + * using TileCache, or any other pre-cached data sources. │ │ │ │ │ + * │ │ │ │ │ + * If you are using fractionalZoom, then you should also use │ │ │ │ │ + * instead of layer.resolutions[zoom] as the │ │ │ │ │ + * former works for non-integer zoom levels. │ │ │ │ │ + */ │ │ │ │ │ + fractionalZoom: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: events │ │ │ │ │ + * {} An events object that handles all │ │ │ │ │ + * events on the map │ │ │ │ │ + */ │ │ │ │ │ + events: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: allOverlays │ │ │ │ │ + * {Boolean} Allow the map to function with "overlays" only. Defaults to │ │ │ │ │ + * false. If true, the lowest layer in the draw order will act as │ │ │ │ │ + * the base layer. In addition, if set to true, all layers will │ │ │ │ │ + * have isBaseLayer set to false when they are added to the map. │ │ │ │ │ + * │ │ │ │ │ + * Note: │ │ │ │ │ + * If you set map.allOverlays to true, then you *cannot* use │ │ │ │ │ + * map.setBaseLayer or layer.setIsBaseLayer. With allOverlays true, │ │ │ │ │ + * the lowest layer in the draw layer is the base layer. So, to change │ │ │ │ │ + * the base layer, use or to set the layer │ │ │ │ │ + * index to 0. │ │ │ │ │ + */ │ │ │ │ │ + allOverlays: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: div │ │ │ │ │ + * {DOMElement|String} The element that contains the map (or an id for │ │ │ │ │ + * that element). If the constructor is called │ │ │ │ │ + * with two arguments, this should be provided as the first argument. │ │ │ │ │ + * Alternatively, the map constructor can be called with the options │ │ │ │ │ + * object as the only argument. In this case (one argument), a │ │ │ │ │ + * div property may or may not be provided. If the div property │ │ │ │ │ + * is not provided, the map can be rendered to a container later │ │ │ │ │ + * using the method. │ │ │ │ │ + * │ │ │ │ │ + * Note: │ │ │ │ │ + * If you are calling after map construction, do not use │ │ │ │ │ + * auto. Instead, divide your by your │ │ │ │ │ + * maximum expected dimension. │ │ │ │ │ + */ │ │ │ │ │ + div: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: dragging │ │ │ │ │ + * {Boolean} The map is currently being dragged. │ │ │ │ │ + */ │ │ │ │ │ + dragging: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: size │ │ │ │ │ + * {} Size of the main div (this.div) │ │ │ │ │ + */ │ │ │ │ │ + size: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: viewPortDiv │ │ │ │ │ + * {HTMLDivElement} The element that represents the map viewport │ │ │ │ │ + */ │ │ │ │ │ + viewPortDiv: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: layerContainerOrigin │ │ │ │ │ + * {} The lonlat at which the later container was │ │ │ │ │ + * re-initialized (on-zoom) │ │ │ │ │ + */ │ │ │ │ │ + layerContainerOrigin: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: layerContainerDiv │ │ │ │ │ + * {HTMLDivElement} The element that contains the layers. │ │ │ │ │ + */ │ │ │ │ │ + layerContainerDiv: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: layers │ │ │ │ │ + * {Array()} Ordered list of layers in the map │ │ │ │ │ + */ │ │ │ │ │ + layers: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: controls │ │ │ │ │ + * {Array()} List of controls associated with the map. │ │ │ │ │ + * │ │ │ │ │ + * If not provided in the map options at construction, the map will │ │ │ │ │ + * by default be given the following controls if present in the build: │ │ │ │ │ + * - or │ │ │ │ │ + * - or │ │ │ │ │ + * - │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ + controls: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: popups │ │ │ │ │ + * {Array()} List of popups associated with the map │ │ │ │ │ + */ │ │ │ │ │ + popups: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: baseLayer │ │ │ │ │ + * {} The currently selected base layer. This determines │ │ │ │ │ + * min/max zoom level, projection, etc. │ │ │ │ │ + */ │ │ │ │ │ + baseLayer: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: center │ │ │ │ │ + * {} The current center of the map │ │ │ │ │ + */ │ │ │ │ │ + center: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: resolution │ │ │ │ │ + * {Float} The resolution of the map. │ │ │ │ │ + */ │ │ │ │ │ + resolution: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: zoom │ │ │ │ │ + * {Integer} The current zoom level of the map │ │ │ │ │ + */ │ │ │ │ │ + zoom: 0, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: panRatio │ │ │ │ │ + * {Float} The ratio of the current extent within │ │ │ │ │ + * which panning will tween. │ │ │ │ │ + */ │ │ │ │ │ + panRatio: 1.5, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: options │ │ │ │ │ + * {Object} The options object passed to the class constructor. Read-only. │ │ │ │ │ + */ │ │ │ │ │ + options: null, │ │ │ │ │ + │ │ │ │ │ + // Options │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: tileSize │ │ │ │ │ + * {} Set in the map options to override the default tile │ │ │ │ │ + * size for this map. │ │ │ │ │ + */ │ │ │ │ │ + tileSize: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: projection │ │ │ │ │ + * {String} Set in the map options to specify the default projection │ │ │ │ │ + * for layers added to this map. When using a projection other than EPSG:4326 │ │ │ │ │ + * (CRS:84, Geographic) or EPSG:3857 (EPSG:900913, Web Mercator), │ │ │ │ │ + * also set maxExtent, maxResolution or resolutions. Default is "EPSG:4326". │ │ │ │ │ + * Note that the projection of the map is usually determined │ │ │ │ │ + * by that of the current baseLayer (see and ). │ │ │ │ │ + */ │ │ │ │ │ + projection: "EPSG:4326", │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: units │ │ │ │ │ + * {String} The map units. Possible values are 'degrees' (or 'dd'), 'm', │ │ │ │ │ + * 'ft', 'km', 'mi', 'inches'. Normally taken from the projection. │ │ │ │ │ + * Only required if both map and layers do not define a projection, │ │ │ │ │ + * or if they define a projection which does not define units │ │ │ │ │ + */ │ │ │ │ │ + units: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: resolutions │ │ │ │ │ + * {Array(Float)} A list of map resolutions (map units per pixel) in │ │ │ │ │ + * descending order. If this is not set in the layer constructor, it │ │ │ │ │ + * will be set based on other resolution related properties │ │ │ │ │ + * (maxExtent, maxResolution, maxScale, etc.). │ │ │ │ │ + */ │ │ │ │ │ + resolutions: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: maxResolution │ │ │ │ │ + * {Float} Required if you are not displaying the whole world on a tile │ │ │ │ │ + * with the size specified in . │ │ │ │ │ + */ │ │ │ │ │ + maxResolution: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: minResolution │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + minResolution: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: maxScale │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + maxScale: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: minScale │ │ │ │ │ + * {Float} │ │ │ │ │ + */ │ │ │ │ │ + minScale: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: maxExtent │ │ │ │ │ + * {|Array} If provided as an array, the array │ │ │ │ │ + * should consist of four values (left, bottom, right, top). │ │ │ │ │ + * The maximum extent for the map. │ │ │ │ │ + * Default depends on projection; if this is one of those defined in OpenLayers.Projection.defaults │ │ │ │ │ + * (EPSG:4326 or web mercator), maxExtent will be set to the value defined there; │ │ │ │ │ + * else, defaults to null. │ │ │ │ │ + * To restrict user panning and zooming of the map, use instead. │ │ │ │ │ + * The value for will change calculations for tile URLs. │ │ │ │ │ + */ │ │ │ │ │ + maxExtent: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: minExtent │ │ │ │ │ + * {|Array} If provided as an array, the array │ │ │ │ │ + * should consist of four values (left, bottom, right, top). │ │ │ │ │ + * The minimum extent for the map. Defaults to null. │ │ │ │ │ + */ │ │ │ │ │ + minExtent: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: restrictedExtent │ │ │ │ │ + * {|Array} If provided as an array, the array │ │ │ │ │ + * should consist of four values (left, bottom, right, top). │ │ │ │ │ + * Limit map navigation to this extent where possible. │ │ │ │ │ + * If a non-null restrictedExtent is set, panning will be restricted │ │ │ │ │ + * to the given bounds. In addition, zooming to a resolution that │ │ │ │ │ + * displays more than the restricted extent will center the map │ │ │ │ │ + * on the restricted extent. If you wish to limit the zoom level │ │ │ │ │ + * or resolution, use maxResolution. │ │ │ │ │ + */ │ │ │ │ │ + restrictedExtent: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: numZoomLevels │ │ │ │ │ + * {Integer} Number of zoom levels for the map. Defaults to 16. Set a │ │ │ │ │ + * different value in the map options if needed. │ │ │ │ │ + */ │ │ │ │ │ + numZoomLevels: 16, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: theme │ │ │ │ │ + * {String} Relative path to a CSS file from which to load theme styles. │ │ │ │ │ + * Specify null in the map options (e.g. {theme: null}) if you │ │ │ │ │ + * want to get cascading style declarations - by putting links to │ │ │ │ │ + * stylesheets or style declarations directly in your page. │ │ │ │ │ + */ │ │ │ │ │ + theme: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: displayProjection │ │ │ │ │ + * {} Requires proj4js support for projections other │ │ │ │ │ + * than EPSG:4326 or EPSG:900913/EPSG:3857. Projection used by │ │ │ │ │ + * several controls to display data to user. If this property is set, │ │ │ │ │ + * it will be set on any control which has a null displayProjection │ │ │ │ │ + * property at the time the control is added to the map. │ │ │ │ │ + */ │ │ │ │ │ + displayProjection: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: tileManager │ │ │ │ │ + * {|Object} By default, and if the build contains │ │ │ │ │ + * TileManager.js, the map will use the TileManager to queue image requests │ │ │ │ │ + * and to cache tile image elements. To create a map without a TileManager │ │ │ │ │ + * configure the map with tileManager: null. To create a TileManager with │ │ │ │ │ + * non-default options, supply the options instead or alternatively supply │ │ │ │ │ + * an instance of {}. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: fallThrough │ │ │ │ │ + * {Boolean} Should OpenLayers allow events on the map to fall through to │ │ │ │ │ + * other elements on the page, or should it swallow them? (#457) │ │ │ │ │ + * Default is to swallow. │ │ │ │ │ + */ │ │ │ │ │ + fallThrough: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: autoUpdateSize │ │ │ │ │ + * {Boolean} Should OpenLayers automatically update the size of the map │ │ │ │ │ + * when the resize event is fired. Default is true. │ │ │ │ │ + */ │ │ │ │ │ + autoUpdateSize: true, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: eventListeners │ │ │ │ │ + * {Object} If set as an option at construction, the eventListeners │ │ │ │ │ + * object will be registered with . Object │ │ │ │ │ + * structure must be a listeners object as shown in the example for │ │ │ │ │ + * the events.on method. │ │ │ │ │ + */ │ │ │ │ │ + eventListeners: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: panTween │ │ │ │ │ + * {} Animated panning tween object, see panTo() │ │ │ │ │ + */ │ │ │ │ │ + panTween: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: panMethod │ │ │ │ │ + * {Function} The Easing function to be used for tweening. Default is │ │ │ │ │ + * OpenLayers.Easing.Expo.easeOut. Setting this to 'null' turns off │ │ │ │ │ + * animated panning. │ │ │ │ │ + */ │ │ │ │ │ + panMethod: OpenLayers.Easing.Expo.easeOut, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: panDuration │ │ │ │ │ + * {Integer} The number of steps to be passed to the │ │ │ │ │ + * OpenLayers.Tween.start() method when the map is │ │ │ │ │ + * panned. │ │ │ │ │ + * Default is 50. │ │ │ │ │ + */ │ │ │ │ │ + panDuration: 50, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: zoomTween │ │ │ │ │ + * {} Animated zooming tween object, see zoomTo() │ │ │ │ │ + */ │ │ │ │ │ + zoomTween: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: zoomMethod │ │ │ │ │ + * {Function} The Easing function to be used for tweening. Default is │ │ │ │ │ + * OpenLayers.Easing.Quad.easeOut. Setting this to 'null' turns off │ │ │ │ │ + * animated zooming. │ │ │ │ │ + */ │ │ │ │ │ + zoomMethod: OpenLayers.Easing.Quad.easeOut, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: zoomDuration │ │ │ │ │ + * {Integer} The number of steps to be passed to the │ │ │ │ │ + * OpenLayers.Tween.start() method when the map is zoomed. │ │ │ │ │ + * Default is 20. │ │ │ │ │ + */ │ │ │ │ │ + zoomDuration: 20, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: paddingForPopups │ │ │ │ │ + * {} Outside margin of the popup. Used to prevent │ │ │ │ │ + * the popup from getting too close to the map border. │ │ │ │ │ + */ │ │ │ │ │ + paddingForPopups: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: layerContainerOriginPx │ │ │ │ │ + * {Object} Cached object representing the layer container origin (in pixels). │ │ │ │ │ + */ │ │ │ │ │ + layerContainerOriginPx: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: minPx │ │ │ │ │ + * {Object} An object with a 'x' and 'y' values that is the lower │ │ │ │ │ + * left of maxExtent in viewport pixel space. │ │ │ │ │ + * Used to verify in moveByPx that the new location we're moving to │ │ │ │ │ + * is valid. It is also used in the getLonLatFromViewPortPx function │ │ │ │ │ + * of Layer. │ │ │ │ │ + */ │ │ │ │ │ + minPx: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: maxPx │ │ │ │ │ + * {Object} An object with a 'x' and 'y' values that is the top │ │ │ │ │ + * right of maxExtent in viewport pixel space. │ │ │ │ │ + * Used to verify in moveByPx that the new location we're moving to │ │ │ │ │ + * is valid. │ │ │ │ │ + */ │ │ │ │ │ + maxPx: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Map │ │ │ │ │ + * Constructor for a new OpenLayers.Map instance. There are two possible │ │ │ │ │ + * ways to call the map constructor. See the examples below. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * div - {DOMElement|String} The element or id of an element in your page │ │ │ │ │ + * that will contain the map. May be omitted if the
option is │ │ │ │ │ + * provided or if you intend to call the method later. │ │ │ │ │ + * options - {Object} Optional object with properties to tag onto the map. │ │ │ │ │ + * │ │ │ │ │ + * Valid options (in addition to the listed API properties): │ │ │ │ │ + * center - {|Array} The default initial center of the map. │ │ │ │ │ + * If provided as array, the first value is the x coordinate, │ │ │ │ │ + * and the 2nd value is the y coordinate. │ │ │ │ │ + * Only specify if is provided. │ │ │ │ │ + * Note that if an ArgParser/Permalink control is present, │ │ │ │ │ + * and the querystring contains coordinates, center will be set │ │ │ │ │ + * by that, and this option will be ignored. │ │ │ │ │ + * zoom - {Number} The initial zoom level for the map. Only specify if │ │ │ │ │ + * is provided. │ │ │ │ │ + * Note that if an ArgParser/Permalink control is present, │ │ │ │ │ + * and the querystring contains a zoom level, zoom will be set │ │ │ │ │ + * by that, and this option will be ignored. │ │ │ │ │ + * extent - {|Array} The initial extent of the map. │ │ │ │ │ + * If provided as an array, the array should consist of │ │ │ │ │ + * four values (left, bottom, right, top). │ │ │ │ │ + * Only specify if
and are not provided. │ │ │ │ │ + * │ │ │ │ │ + * Examples: │ │ │ │ │ + * (code) │ │ │ │ │ + * // create a map with default options in an element with the id "map1" │ │ │ │ │ + * var map = new OpenLayers.Map("map1"); │ │ │ │ │ + * │ │ │ │ │ + * // create a map with non-default options in an element with id "map2" │ │ │ │ │ + * var options = { │ │ │ │ │ + * projection: "EPSG:3857", │ │ │ │ │ + * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000), │ │ │ │ │ + * center: new OpenLayers.LonLat(-12356463.476333, 5621521.4854095) │ │ │ │ │ + * }; │ │ │ │ │ + * var map = new OpenLayers.Map("map2", options); │ │ │ │ │ + * │ │ │ │ │ + * // map with non-default options - same as above but with a single argument, │ │ │ │ │ + * // a restricted extent, and using arrays for bounds and center │ │ │ │ │ + * var map = new OpenLayers.Map({ │ │ │ │ │ * div: "map_id", │ │ │ │ │ * projection: "EPSG:3857", │ │ │ │ │ * maxExtent: [-18924313.432222, -15538711.094146, 18924313.432222, 15538711.094146], │ │ │ │ │ * restrictedExtent: [-13358338.893333, -9608371.5085962, 13358338.893333, 9608371.5085962], │ │ │ │ │ * center: [-12356463.476333, 5621521.4854095] │ │ │ │ │ * }); │ │ │ │ │ * │ │ │ │ │ @@ -9645,1311 +13602,516 @@ │ │ │ │ │ OpenLayers.Map.TILE_WIDTH = 256; │ │ │ │ │ /** │ │ │ │ │ * Constant: TILE_HEIGHT │ │ │ │ │ * {Integer} 256 Default tile height (unless otherwise specified) │ │ │ │ │ */ │ │ │ │ │ OpenLayers.Map.TILE_HEIGHT = 256; │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Request/XMLHttpRequest.js │ │ │ │ │ + OpenLayers/Icon.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ -// XMLHttpRequest.js Copyright (C) 2010 Sergey Ilinsky (http://www.ilinsky.com) │ │ │ │ │ -// │ │ │ │ │ -// Licensed under the Apache License, Version 2.0 (the "License"); │ │ │ │ │ -// you may not use this file except in compliance with the License. │ │ │ │ │ -// You may obtain a copy of the License at │ │ │ │ │ -// │ │ │ │ │ -// http://www.apache.org/licenses/LICENSE-2.0 │ │ │ │ │ -// │ │ │ │ │ -// Unless required by applicable law or agreed to in writing, software │ │ │ │ │ -// distributed under the License is distributed on an "AS IS" BASIS, │ │ │ │ │ -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ │ │ │ │ -// See the License for the specific language governing permissions and │ │ │ │ │ -// limitations under the License. │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Request.js │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ -(function() { │ │ │ │ │ - │ │ │ │ │ - // Save reference to earlier defined object implementation (if any) │ │ │ │ │ - var oXMLHttpRequest = window.XMLHttpRequest; │ │ │ │ │ - │ │ │ │ │ - // Define on browser type │ │ │ │ │ - var bGecko = !!window.controllers, │ │ │ │ │ - bIE = window.document.all && !window.opera, │ │ │ │ │ - bIE7 = bIE && window.navigator.userAgent.match(/MSIE 7.0/); │ │ │ │ │ - │ │ │ │ │ - // Enables "XMLHttpRequest()" call next to "new XMLHttpReques()" │ │ │ │ │ - function fXMLHttpRequest() { │ │ │ │ │ - this._object = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP"); │ │ │ │ │ - this._listeners = []; │ │ │ │ │ - }; │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Icon │ │ │ │ │ + * │ │ │ │ │ + * The icon represents a graphical icon on the screen. Typically used in │ │ │ │ │ + * conjunction with a to represent markers on a screen. │ │ │ │ │ + * │ │ │ │ │ + * An icon has a url, size and position. It also contains an offset which │ │ │ │ │ + * allows the center point to be represented correctly. This can be │ │ │ │ │ + * provided either as a fixed offset or a function provided to calculate │ │ │ │ │ + * the desired offset. │ │ │ │ │ + * │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Icon = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ - // Constructor │ │ │ │ │ - function cXMLHttpRequest() { │ │ │ │ │ - return new fXMLHttpRequest; │ │ │ │ │ - }; │ │ │ │ │ - cXMLHttpRequest.prototype = fXMLHttpRequest.prototype; │ │ │ │ │ + /** │ │ │ │ │ + * Property: url │ │ │ │ │ + * {String} image url │ │ │ │ │ + */ │ │ │ │ │ + url: null, │ │ │ │ │ │ │ │ │ │ - // BUGFIX: Firefox with Firebug installed would break pages if not executed │ │ │ │ │ - if (bGecko && oXMLHttpRequest.wrapped) │ │ │ │ │ - cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped; │ │ │ │ │ + /** │ │ │ │ │ + * Property: size │ │ │ │ │ + * {|Object} An OpenLayers.Size or │ │ │ │ │ + * an object with a 'w' and 'h' properties. │ │ │ │ │ + */ │ │ │ │ │ + size: null, │ │ │ │ │ │ │ │ │ │ - // Constants │ │ │ │ │ - cXMLHttpRequest.UNSENT = 0; │ │ │ │ │ - cXMLHttpRequest.OPENED = 1; │ │ │ │ │ - cXMLHttpRequest.HEADERS_RECEIVED = 2; │ │ │ │ │ - cXMLHttpRequest.LOADING = 3; │ │ │ │ │ - cXMLHttpRequest.DONE = 4; │ │ │ │ │ + /** │ │ │ │ │ + * Property: offset │ │ │ │ │ + * {|Object} distance in pixels to offset the │ │ │ │ │ + * image when being rendered. An OpenLayers.Pixel or an object │ │ │ │ │ + * with a 'x' and 'y' properties. │ │ │ │ │ + */ │ │ │ │ │ + offset: null, │ │ │ │ │ │ │ │ │ │ - // Public Properties │ │ │ │ │ - cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ │ - cXMLHttpRequest.prototype.responseText = ''; │ │ │ │ │ - cXMLHttpRequest.prototype.responseXML = null; │ │ │ │ │ - cXMLHttpRequest.prototype.status = 0; │ │ │ │ │ - cXMLHttpRequest.prototype.statusText = ''; │ │ │ │ │ + /** │ │ │ │ │ + * Property: calculateOffset │ │ │ │ │ + * {Function} Function to calculate the offset (based on the size) │ │ │ │ │ + */ │ │ │ │ │ + calculateOffset: null, │ │ │ │ │ │ │ │ │ │ - // Priority proposal │ │ │ │ │ - cXMLHttpRequest.prototype.priority = "NORMAL"; │ │ │ │ │ + /** │ │ │ │ │ + * Property: imageDiv │ │ │ │ │ + * {DOMElement} │ │ │ │ │ + */ │ │ │ │ │ + imageDiv: null, │ │ │ │ │ │ │ │ │ │ - // Instance-level Events Handlers │ │ │ │ │ - cXMLHttpRequest.prototype.onreadystatechange = null; │ │ │ │ │ + /** │ │ │ │ │ + * Property: px │ │ │ │ │ + * {|Object} An OpenLayers.Pixel or an object │ │ │ │ │ + * with a 'x' and 'y' properties. │ │ │ │ │ + */ │ │ │ │ │ + px: null, │ │ │ │ │ │ │ │ │ │ - // Class-level Events Handlers │ │ │ │ │ - cXMLHttpRequest.onreadystatechange = null; │ │ │ │ │ - cXMLHttpRequest.onopen = null; │ │ │ │ │ - cXMLHttpRequest.onsend = null; │ │ │ │ │ - cXMLHttpRequest.onabort = null; │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Icon │ │ │ │ │ + * Creates an icon, which is an image tag in a div. │ │ │ │ │ + * │ │ │ │ │ + * url - {String} │ │ │ │ │ + * size - {|Object} An OpenLayers.Size or an │ │ │ │ │ + * object with a 'w' and 'h' │ │ │ │ │ + * properties. │ │ │ │ │ + * offset - {|Object} An OpenLayers.Pixel or an │ │ │ │ │ + * object with a 'x' and 'y' │ │ │ │ │ + * properties. │ │ │ │ │ + * calculateOffset - {Function} │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(url, size, offset, calculateOffset) { │ │ │ │ │ + this.url = url; │ │ │ │ │ + this.size = size || { │ │ │ │ │ + w: 20, │ │ │ │ │ + h: 20 │ │ │ │ │ + }; │ │ │ │ │ + this.offset = offset || { │ │ │ │ │ + x: -(this.size.w / 2), │ │ │ │ │ + y: -(this.size.h / 2) │ │ │ │ │ + }; │ │ │ │ │ + this.calculateOffset = calculateOffset; │ │ │ │ │ │ │ │ │ │ - // Public Methods │ │ │ │ │ - cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) { │ │ │ │ │ - // Delete headers, required when object is reused │ │ │ │ │ - delete this._headers; │ │ │ │ │ + var id = OpenLayers.Util.createUniqueID("OL_Icon_"); │ │ │ │ │ + this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // When bAsync parameter value is omitted, use true as default │ │ │ │ │ - if (arguments.length < 3) │ │ │ │ │ - bAsync = true; │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroy │ │ │ │ │ + * Nullify references and remove event listeners to prevent circular │ │ │ │ │ + * references and memory leaks │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + // erase any drawn elements │ │ │ │ │ + this.erase(); │ │ │ │ │ │ │ │ │ │ - // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests │ │ │ │ │ - this._async = bAsync; │ │ │ │ │ + OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild); │ │ │ │ │ + this.imageDiv.innerHTML = ""; │ │ │ │ │ + this.imageDiv = null; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // Set the onreadystatechange handler │ │ │ │ │ - var oRequest = this, │ │ │ │ │ - nState = this.readyState, │ │ │ │ │ - fOnUnload; │ │ │ │ │ + /** │ │ │ │ │ + * Method: clone │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} A fresh copy of the icon. │ │ │ │ │ + */ │ │ │ │ │ + clone: function() { │ │ │ │ │ + return new OpenLayers.Icon(this.url, │ │ │ │ │ + this.size, │ │ │ │ │ + this.offset, │ │ │ │ │ + this.calculateOffset); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // BUGFIX: IE - memory leak on page unload (inter-page leak) │ │ │ │ │ - if (bIE && bAsync) { │ │ │ │ │ - fOnUnload = function() { │ │ │ │ │ - if (nState != cXMLHttpRequest.DONE) { │ │ │ │ │ - fCleanTransport(oRequest); │ │ │ │ │ - // Safe to abort here since onreadystatechange handler removed │ │ │ │ │ - oRequest.abort(); │ │ │ │ │ - } │ │ │ │ │ - }; │ │ │ │ │ - window.attachEvent("onunload", fOnUnload); │ │ │ │ │ + /** │ │ │ │ │ + * Method: setSize │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * size - {|Object} An OpenLayers.Size or │ │ │ │ │ + * an object with a 'w' and 'h' properties. │ │ │ │ │ + */ │ │ │ │ │ + setSize: function(size) { │ │ │ │ │ + if (size != null) { │ │ │ │ │ + this.size = size; │ │ │ │ │ } │ │ │ │ │ + this.draw(); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // Add method sniffer │ │ │ │ │ - if (cXMLHttpRequest.onopen) │ │ │ │ │ - cXMLHttpRequest.onopen.apply(this, arguments); │ │ │ │ │ - │ │ │ │ │ - if (arguments.length > 4) │ │ │ │ │ - this._object.open(sMethod, sUrl, bAsync, sUser, sPassword); │ │ │ │ │ - else │ │ │ │ │ - if (arguments.length > 3) │ │ │ │ │ - this._object.open(sMethod, sUrl, bAsync, sUser); │ │ │ │ │ - else │ │ │ │ │ - this._object.open(sMethod, sUrl, bAsync); │ │ │ │ │ + /** │ │ │ │ │ + * Method: setUrl │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * url - {String} │ │ │ │ │ + */ │ │ │ │ │ + setUrl: function(url) { │ │ │ │ │ + if (url != null) { │ │ │ │ │ + this.url = url; │ │ │ │ │ + } │ │ │ │ │ + this.draw(); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - this.readyState = cXMLHttpRequest.OPENED; │ │ │ │ │ - fReadyStateChange(this); │ │ │ │ │ + /** │ │ │ │ │ + * Method: draw │ │ │ │ │ + * Move the div to the given pixel. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * px - {|Object} An OpenLayers.Pixel or an │ │ │ │ │ + * object with a 'x' and 'y' properties. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {DOMElement} A new DOM Image of this icon set at the location passed-in │ │ │ │ │ + */ │ │ │ │ │ + draw: function(px) { │ │ │ │ │ + OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, │ │ │ │ │ + null, │ │ │ │ │ + null, │ │ │ │ │ + this.size, │ │ │ │ │ + this.url, │ │ │ │ │ + "absolute"); │ │ │ │ │ + this.moveTo(px); │ │ │ │ │ + return this.imageDiv; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - this._object.onreadystatechange = function() { │ │ │ │ │ - if (bGecko && !bAsync) │ │ │ │ │ - return; │ │ │ │ │ + /** │ │ │ │ │ + * Method: erase │ │ │ │ │ + * Erase the underlying image element. │ │ │ │ │ + */ │ │ │ │ │ + erase: function() { │ │ │ │ │ + if (this.imageDiv != null && this.imageDiv.parentNode != null) { │ │ │ │ │ + OpenLayers.Element.remove(this.imageDiv); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // Synchronize state │ │ │ │ │ - oRequest.readyState = oRequest._object.readyState; │ │ │ │ │ + /** │ │ │ │ │ + * Method: setOpacity │ │ │ │ │ + * Change the icon's opacity │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * opacity - {float} │ │ │ │ │ + */ │ │ │ │ │ + setOpacity: function(opacity) { │ │ │ │ │ + OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, │ │ │ │ │ + null, null, null, null, opacity); │ │ │ │ │ │ │ │ │ │ - // │ │ │ │ │ - fSynchronizeValues(oRequest); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // BUGFIX: Firefox fires unnecessary DONE when aborting │ │ │ │ │ - if (oRequest._aborted) { │ │ │ │ │ - // Reset readyState to UNSENT │ │ │ │ │ - oRequest.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ │ + /** │ │ │ │ │ + * Method: moveTo │ │ │ │ │ + * move icon to passed in px. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * px - {|Object} the pixel position to move to. │ │ │ │ │ + * An OpenLayers.Pixel or an object with a 'x' and 'y' properties. │ │ │ │ │ + */ │ │ │ │ │ + moveTo: function(px) { │ │ │ │ │ + //if no px passed in, use stored location │ │ │ │ │ + if (px != null) { │ │ │ │ │ + this.px = px; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - // Return now │ │ │ │ │ - return; │ │ │ │ │ + if (this.imageDiv != null) { │ │ │ │ │ + if (this.px == null) { │ │ │ │ │ + this.display(false); │ │ │ │ │ + } else { │ │ │ │ │ + if (this.calculateOffset) { │ │ │ │ │ + this.offset = this.calculateOffset(this.size); │ │ │ │ │ + } │ │ │ │ │ + OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, { │ │ │ │ │ + x: this.px.x + this.offset.x, │ │ │ │ │ + y: this.px.y + this.offset.y │ │ │ │ │ + }); │ │ │ │ │ } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (oRequest.readyState == cXMLHttpRequest.DONE) { │ │ │ │ │ - // Free up queue │ │ │ │ │ - delete oRequest._data; │ │ │ │ │ - /* if (bAsync) │ │ │ │ │ - fQueue_remove(oRequest);*/ │ │ │ │ │ - // │ │ │ │ │ - fCleanTransport(oRequest); │ │ │ │ │ - // Uncomment this block if you need a fix for IE cache │ │ │ │ │ - /* │ │ │ │ │ - // BUGFIX: IE - cache issue │ │ │ │ │ - if (!oRequest._object.getResponseHeader("Date")) { │ │ │ │ │ - // Save object to cache │ │ │ │ │ - oRequest._cached = oRequest._object; │ │ │ │ │ - │ │ │ │ │ - // Instantiate a new transport object │ │ │ │ │ - cXMLHttpRequest.call(oRequest); │ │ │ │ │ - │ │ │ │ │ - // Re-send request │ │ │ │ │ - if (sUser) { │ │ │ │ │ - if (sPassword) │ │ │ │ │ - oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword); │ │ │ │ │ - else │ │ │ │ │ - oRequest._object.open(sMethod, sUrl, bAsync, sUser); │ │ │ │ │ - } │ │ │ │ │ - else │ │ │ │ │ - oRequest._object.open(sMethod, sUrl, bAsync); │ │ │ │ │ - oRequest._object.setRequestHeader("If-Modified-Since", oRequest._cached.getResponseHeader("Last-Modified") || new window.Date(0)); │ │ │ │ │ - // Copy headers set │ │ │ │ │ - if (oRequest._headers) │ │ │ │ │ - for (var sHeader in oRequest._headers) │ │ │ │ │ - if (typeof oRequest._headers[sHeader] == "string") // Some frameworks prototype objects with functions │ │ │ │ │ - oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]); │ │ │ │ │ + /** │ │ │ │ │ + * Method: display │ │ │ │ │ + * Hide or show the icon │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * display - {Boolean} │ │ │ │ │ + */ │ │ │ │ │ + display: function(display) { │ │ │ │ │ + this.imageDiv.style.display = (display) ? "" : "none"; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - oRequest._object.onreadystatechange = function() { │ │ │ │ │ - // Synchronize state │ │ │ │ │ - oRequest.readyState = oRequest._object.readyState; │ │ │ │ │ │ │ │ │ │ - if (oRequest._aborted) { │ │ │ │ │ - // │ │ │ │ │ - oRequest.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: isDrawn │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Whether or not the icon is drawn. │ │ │ │ │ + */ │ │ │ │ │ + isDrawn: function() { │ │ │ │ │ + // nodeType 11 for ie, whose nodes *always* have a parentNode │ │ │ │ │ + // (of type document fragment) │ │ │ │ │ + var isDrawn = (this.imageDiv && this.imageDiv.parentNode && │ │ │ │ │ + (this.imageDiv.parentNode.nodeType != 11)); │ │ │ │ │ │ │ │ │ │ - // Return │ │ │ │ │ - return; │ │ │ │ │ - } │ │ │ │ │ + return isDrawn; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (oRequest.readyState == cXMLHttpRequest.DONE) { │ │ │ │ │ - // Clean Object │ │ │ │ │ - fCleanTransport(oRequest); │ │ │ │ │ + CLASS_NAME: "OpenLayers.Icon" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Marker.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - // get cached request │ │ │ │ │ - if (oRequest.status == 304) │ │ │ │ │ - oRequest._object = oRequest._cached; │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - // │ │ │ │ │ - delete oRequest._cached; │ │ │ │ │ │ │ │ │ │ - // │ │ │ │ │ - fSynchronizeValues(oRequest); │ │ │ │ │ - │ │ │ │ │ - // │ │ │ │ │ - fReadyStateChange(oRequest); │ │ │ │ │ - │ │ │ │ │ - // BUGFIX: IE - memory leak in interrupted │ │ │ │ │ - if (bIE && bAsync) │ │ │ │ │ - window.detachEvent("onunload", fOnUnload); │ │ │ │ │ - } │ │ │ │ │ - }; │ │ │ │ │ - oRequest._object.send(null); │ │ │ │ │ - │ │ │ │ │ - // Return now - wait until re-sent request is finished │ │ │ │ │ - return; │ │ │ │ │ - }; │ │ │ │ │ - */ │ │ │ │ │ - // BUGFIX: IE - memory leak in interrupted │ │ │ │ │ - if (bIE && bAsync) │ │ │ │ │ - window.detachEvent("onunload", fOnUnload); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice │ │ │ │ │ - if (nState != oRequest.readyState) │ │ │ │ │ - fReadyStateChange(oRequest); │ │ │ │ │ - │ │ │ │ │ - nState = oRequest.readyState; │ │ │ │ │ - } │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - function fXMLHttpRequest_send(oRequest) { │ │ │ │ │ - oRequest._object.send(oRequest._data); │ │ │ │ │ - │ │ │ │ │ - // BUGFIX: Gecko - missing readystatechange calls in synchronous requests │ │ │ │ │ - if (bGecko && !oRequest._async) { │ │ │ │ │ - oRequest.readyState = cXMLHttpRequest.OPENED; │ │ │ │ │ - │ │ │ │ │ - // Synchronize state │ │ │ │ │ - fSynchronizeValues(oRequest); │ │ │ │ │ - │ │ │ │ │ - // Simulate missing states │ │ │ │ │ - while (oRequest.readyState < cXMLHttpRequest.DONE) { │ │ │ │ │ - oRequest.readyState++; │ │ │ │ │ - fReadyStateChange(oRequest); │ │ │ │ │ - // Check if we are aborted │ │ │ │ │ - if (oRequest._aborted) │ │ │ │ │ - return; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }; │ │ │ │ │ - cXMLHttpRequest.prototype.send = function(vData) { │ │ │ │ │ - // Add method sniffer │ │ │ │ │ - if (cXMLHttpRequest.onsend) │ │ │ │ │ - cXMLHttpRequest.onsend.apply(this, arguments); │ │ │ │ │ - │ │ │ │ │ - if (!arguments.length) │ │ │ │ │ - vData = null; │ │ │ │ │ - │ │ │ │ │ - // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required │ │ │ │ │ - // BUGFIX: IE - rewrites any custom mime-type to "text/xml" in case an XMLNode is sent │ │ │ │ │ - // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard) │ │ │ │ │ - if (vData && vData.nodeType) { │ │ │ │ │ - vData = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml; │ │ │ │ │ - if (!this._headers["Content-Type"]) │ │ │ │ │ - this._object.setRequestHeader("Content-Type", "application/xml"); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - this._data = vData; │ │ │ │ │ - /* │ │ │ │ │ - // Add to queue │ │ │ │ │ - if (this._async) │ │ │ │ │ - fQueue_add(this); │ │ │ │ │ - else*/ │ │ │ │ │ - fXMLHttpRequest_send(this); │ │ │ │ │ - }; │ │ │ │ │ - cXMLHttpRequest.prototype.abort = function() { │ │ │ │ │ - // Add method sniffer │ │ │ │ │ - if (cXMLHttpRequest.onabort) │ │ │ │ │ - cXMLHttpRequest.onabort.apply(this, arguments); │ │ │ │ │ - │ │ │ │ │ - // BUGFIX: Gecko - unnecessary DONE when aborting │ │ │ │ │ - if (this.readyState > cXMLHttpRequest.UNSENT) │ │ │ │ │ - this._aborted = true; │ │ │ │ │ - │ │ │ │ │ - this._object.abort(); │ │ │ │ │ - │ │ │ │ │ - // BUGFIX: IE - memory leak │ │ │ │ │ - fCleanTransport(this); │ │ │ │ │ - │ │ │ │ │ - this.readyState = cXMLHttpRequest.UNSENT; │ │ │ │ │ - │ │ │ │ │ - delete this._data; │ │ │ │ │ - /* if (this._async) │ │ │ │ │ - fQueue_remove(this);*/ │ │ │ │ │ - }; │ │ │ │ │ - cXMLHttpRequest.prototype.getAllResponseHeaders = function() { │ │ │ │ │ - return this._object.getAllResponseHeaders(); │ │ │ │ │ - }; │ │ │ │ │ - cXMLHttpRequest.prototype.getResponseHeader = function(sName) { │ │ │ │ │ - return this._object.getResponseHeader(sName); │ │ │ │ │ - }; │ │ │ │ │ - cXMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) { │ │ │ │ │ - // BUGFIX: IE - cache issue │ │ │ │ │ - if (!this._headers) │ │ │ │ │ - this._headers = {}; │ │ │ │ │ - this._headers[sName] = sValue; │ │ │ │ │ - │ │ │ │ │ - return this._object.setRequestHeader(sName, sValue); │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - // EventTarget interface implementation │ │ │ │ │ - cXMLHttpRequest.prototype.addEventListener = function(sName, fHandler, bUseCapture) { │ │ │ │ │ - for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) │ │ │ │ │ - if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture) │ │ │ │ │ - return; │ │ │ │ │ - // Add listener │ │ │ │ │ - this._listeners.push([sName, fHandler, bUseCapture]); │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - cXMLHttpRequest.prototype.removeEventListener = function(sName, fHandler, bUseCapture) { │ │ │ │ │ - for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) │ │ │ │ │ - if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture) │ │ │ │ │ - break; │ │ │ │ │ - // Remove listener │ │ │ │ │ - if (oListener) │ │ │ │ │ - this._listeners.splice(nIndex, 1); │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - cXMLHttpRequest.prototype.dispatchEvent = function(oEvent) { │ │ │ │ │ - var oEventPseudo = { │ │ │ │ │ - 'type': oEvent.type, │ │ │ │ │ - 'target': this, │ │ │ │ │ - 'currentTarget': this, │ │ │ │ │ - 'eventPhase': 2, │ │ │ │ │ - 'bubbles': oEvent.bubbles, │ │ │ │ │ - 'cancelable': oEvent.cancelable, │ │ │ │ │ - 'timeStamp': oEvent.timeStamp, │ │ │ │ │ - 'stopPropagation': function() {}, // There is no flow │ │ │ │ │ - 'preventDefault': function() {}, // There is no default action │ │ │ │ │ - 'initEvent': function() {} // Original event object should be initialized │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - // Execute onreadystatechange │ │ │ │ │ - if (oEventPseudo.type == "readystatechange" && this.onreadystatechange) │ │ │ │ │ - (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]); │ │ │ │ │ - │ │ │ │ │ - // Execute listeners │ │ │ │ │ - for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) │ │ │ │ │ - if (oListener[0] == oEventPseudo.type && !oListener[2]) │ │ │ │ │ - (oListener[1].handleEvent || oListener[1]).apply(this, [oEventPseudo]); │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - // │ │ │ │ │ - cXMLHttpRequest.prototype.toString = function() { │ │ │ │ │ - return '[' + "object" + ' ' + "XMLHttpRequest" + ']'; │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - cXMLHttpRequest.toString = function() { │ │ │ │ │ - return '[' + "XMLHttpRequest" + ']'; │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - // Helper function │ │ │ │ │ - function fReadyStateChange(oRequest) { │ │ │ │ │ - // Sniffing code │ │ │ │ │ - if (cXMLHttpRequest.onreadystatechange) │ │ │ │ │ - cXMLHttpRequest.onreadystatechange.apply(oRequest); │ │ │ │ │ - │ │ │ │ │ - // Fake event │ │ │ │ │ - oRequest.dispatchEvent({ │ │ │ │ │ - 'type': "readystatechange", │ │ │ │ │ - 'bubbles': false, │ │ │ │ │ - 'cancelable': false, │ │ │ │ │ - 'timeStamp': new Date + 0 │ │ │ │ │ - }); │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - function fGetDocument(oRequest) { │ │ │ │ │ - var oDocument = oRequest.responseXML, │ │ │ │ │ - sResponse = oRequest.responseText; │ │ │ │ │ - // Try parsing responseText │ │ │ │ │ - if (bIE && sResponse && oDocument && !oDocument.documentElement && oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)) { │ │ │ │ │ - oDocument = new window.ActiveXObject("Microsoft.XMLDOM"); │ │ │ │ │ - oDocument.async = false; │ │ │ │ │ - oDocument.validateOnParse = false; │ │ │ │ │ - oDocument.loadXML(sResponse); │ │ │ │ │ - } │ │ │ │ │ - // Check if there is no error in document │ │ │ │ │ - if (oDocument) │ │ │ │ │ - if ((bIE && oDocument.parseError != 0) || !oDocument.documentElement || (oDocument.documentElement && oDocument.documentElement.tagName == "parsererror")) │ │ │ │ │ - return null; │ │ │ │ │ - return oDocument; │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - function fSynchronizeValues(oRequest) { │ │ │ │ │ - try { │ │ │ │ │ - oRequest.responseText = oRequest._object.responseText; │ │ │ │ │ - } catch (e) {} │ │ │ │ │ - try { │ │ │ │ │ - oRequest.responseXML = fGetDocument(oRequest._object); │ │ │ │ │ - } catch (e) {} │ │ │ │ │ - try { │ │ │ │ │ - oRequest.status = oRequest._object.status; │ │ │ │ │ - } catch (e) {} │ │ │ │ │ - try { │ │ │ │ │ - oRequest.statusText = oRequest._object.statusText; │ │ │ │ │ - } catch (e) {} │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - function fCleanTransport(oRequest) { │ │ │ │ │ - // BUGFIX: IE - memory leak (on-page leak) │ │ │ │ │ - oRequest._object.onreadystatechange = new window.Function; │ │ │ │ │ - }; │ │ │ │ │ - /* │ │ │ │ │ - // Queue manager │ │ │ │ │ - var oQueuePending = {"CRITICAL":[],"HIGH":[],"NORMAL":[],"LOW":[],"LOWEST":[]}, │ │ │ │ │ - aQueueRunning = []; │ │ │ │ │ - function fQueue_add(oRequest) { │ │ │ │ │ - oQueuePending[oRequest.priority in oQueuePending ? oRequest.priority : "NORMAL"].push(oRequest); │ │ │ │ │ - // │ │ │ │ │ - setTimeout(fQueue_process); │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - function fQueue_remove(oRequest) { │ │ │ │ │ - for (var nIndex = 0, bFound = false; nIndex < aQueueRunning.length; nIndex++) │ │ │ │ │ - if (bFound) │ │ │ │ │ - aQueueRunning[nIndex - 1] = aQueueRunning[nIndex]; │ │ │ │ │ - else │ │ │ │ │ - if (aQueueRunning[nIndex] == oRequest) │ │ │ │ │ - bFound = true; │ │ │ │ │ - if (bFound) │ │ │ │ │ - aQueueRunning.length--; │ │ │ │ │ - // │ │ │ │ │ - setTimeout(fQueue_process); │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - function fQueue_process() { │ │ │ │ │ - if (aQueueRunning.length < 6) { │ │ │ │ │ - for (var sPriority in oQueuePending) { │ │ │ │ │ - if (oQueuePending[sPriority].length) { │ │ │ │ │ - var oRequest = oQueuePending[sPriority][0]; │ │ │ │ │ - oQueuePending[sPriority] = oQueuePending[sPriority].slice(1); │ │ │ │ │ - // │ │ │ │ │ - aQueueRunning.push(oRequest); │ │ │ │ │ - // Send request │ │ │ │ │ - fXMLHttpRequest_send(oRequest); │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }; │ │ │ │ │ - */ │ │ │ │ │ - // Internet Explorer 5.0 (missing apply) │ │ │ │ │ - if (!window.Function.prototype.apply) { │ │ │ │ │ - window.Function.prototype.apply = function(oRequest, oArguments) { │ │ │ │ │ - if (!oArguments) │ │ │ │ │ - oArguments = []; │ │ │ │ │ - oRequest.__func = this; │ │ │ │ │ - oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]); │ │ │ │ │ - delete oRequest.__func; │ │ │ │ │ - }; │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - // Register new object with window │ │ │ │ │ - /** │ │ │ │ │ - * Class: OpenLayers.Request.XMLHttpRequest │ │ │ │ │ - * Standard-compliant (W3C) cross-browser implementation of the │ │ │ │ │ - * XMLHttpRequest object. From │ │ │ │ │ - * http://code.google.com/p/xmlhttprequest/. │ │ │ │ │ - */ │ │ │ │ │ - if (!OpenLayers.Request) { │ │ │ │ │ - /** │ │ │ │ │ - * This allows for OpenLayers/Request.js to be included │ │ │ │ │ - * before or after this script. │ │ │ │ │ - */ │ │ │ │ │ - OpenLayers.Request = {}; │ │ │ │ │ - } │ │ │ │ │ - OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest; │ │ │ │ │ -})(); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Request.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Events.js │ │ │ │ │ - * @requires OpenLayers/Request/XMLHttpRequest.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * TODO: deprecate me │ │ │ │ │ - * Use OpenLayers.Request.proxy instead. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.ProxyHost = ""; │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Events.js │ │ │ │ │ + * @requires OpenLayers/Icon.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Namespace: OpenLayers.Request │ │ │ │ │ - * The OpenLayers.Request namespace contains convenience methods for working │ │ │ │ │ - * with XMLHttpRequests. These methods work with a cross-browser │ │ │ │ │ - * W3C compliant class. │ │ │ │ │ + * Class: OpenLayers.Marker │ │ │ │ │ + * Instances of OpenLayers.Marker are a combination of a │ │ │ │ │ + * and an . │ │ │ │ │ + * │ │ │ │ │ + * Markers are generally added to a special layer called │ │ │ │ │ + * . │ │ │ │ │ + * │ │ │ │ │ + * Example: │ │ │ │ │ + * (code) │ │ │ │ │ + * var markers = new OpenLayers.Layer.Markers( "Markers" ); │ │ │ │ │ + * map.addLayer(markers); │ │ │ │ │ + * │ │ │ │ │ + * var size = new OpenLayers.Size(21,25); │ │ │ │ │ + * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h); │ │ │ │ │ + * var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset); │ │ │ │ │ + * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon)); │ │ │ │ │ + * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone())); │ │ │ │ │ + * │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Note that if you pass an icon into the Marker constructor, it will take │ │ │ │ │ + * that icon and use it. This means that you should not share icons between │ │ │ │ │ + * markers -- you use them once, but you should clone() for any additional │ │ │ │ │ + * markers using that same icon. │ │ │ │ │ */ │ │ │ │ │ -if (!OpenLayers.Request) { │ │ │ │ │ - /** │ │ │ │ │ - * This allows for OpenLayers/Request/XMLHttpRequest.js to be included │ │ │ │ │ - * before or after this script. │ │ │ │ │ - */ │ │ │ │ │ - OpenLayers.Request = {}; │ │ │ │ │ -} │ │ │ │ │ -OpenLayers.Util.extend(OpenLayers.Request, { │ │ │ │ │ +OpenLayers.Marker = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constant: DEFAULT_CONFIG │ │ │ │ │ - * {Object} Default configuration for all requests. │ │ │ │ │ + /** │ │ │ │ │ + * Property: icon │ │ │ │ │ + * {} The icon used by this marker. │ │ │ │ │ */ │ │ │ │ │ - DEFAULT_CONFIG: { │ │ │ │ │ - method: "GET", │ │ │ │ │ - url: window.location.href, │ │ │ │ │ - async: true, │ │ │ │ │ - user: undefined, │ │ │ │ │ - password: undefined, │ │ │ │ │ - params: null, │ │ │ │ │ - proxy: OpenLayers.ProxyHost, │ │ │ │ │ - headers: {}, │ │ │ │ │ - data: null, │ │ │ │ │ - callback: function() {}, │ │ │ │ │ - success: null, │ │ │ │ │ - failure: null, │ │ │ │ │ - scope: null │ │ │ │ │ - }, │ │ │ │ │ + icon: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constant: URL_SPLIT_REGEX │ │ │ │ │ + /** │ │ │ │ │ + * Property: lonlat │ │ │ │ │ + * {} location of object │ │ │ │ │ */ │ │ │ │ │ - URL_SPLIT_REGEX: /([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/, │ │ │ │ │ + lonlat: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: events │ │ │ │ │ - * {} An events object that handles all │ │ │ │ │ - * events on the {} object. │ │ │ │ │ - * │ │ │ │ │ - * All event listeners will receive an event object with three properties: │ │ │ │ │ - * request - {} The request object. │ │ │ │ │ - * config - {Object} The config object sent to the specific request method. │ │ │ │ │ - * requestUrl - {String} The request url. │ │ │ │ │ - * │ │ │ │ │ - * Supported event types: │ │ │ │ │ - * complete - Triggered when we have a response from the request, if a │ │ │ │ │ - * listener returns false, no further response processing will take │ │ │ │ │ - * place. │ │ │ │ │ - * success - Triggered when the HTTP response has a success code (200-299). │ │ │ │ │ - * failure - Triggered when the HTTP response does not have a success code. │ │ │ │ │ + /** │ │ │ │ │ + * Property: events │ │ │ │ │ + * {} the event handler. │ │ │ │ │ */ │ │ │ │ │ - events: new OpenLayers.Events(this), │ │ │ │ │ + events: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: makeSameOrigin │ │ │ │ │ - * Using the specified proxy, returns a same origin url of the provided url. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * url - {String} An arbitrary url │ │ │ │ │ - * proxy {String|Function} The proxy to use to make the provided url a │ │ │ │ │ - * same origin url. │ │ │ │ │ - * │ │ │ │ │ - * Returns │ │ │ │ │ - * {String} the same origin url. If no proxy is provided, the returned url │ │ │ │ │ - * will be the same as the provided url. │ │ │ │ │ + /** │ │ │ │ │ + * Property: map │ │ │ │ │ + * {} the map this marker is attached to │ │ │ │ │ */ │ │ │ │ │ - makeSameOrigin: function(url, proxy) { │ │ │ │ │ - var sameOrigin = url.indexOf("http") !== 0; │ │ │ │ │ - var urlParts = !sameOrigin && url.match(this.URL_SPLIT_REGEX); │ │ │ │ │ - if (urlParts) { │ │ │ │ │ - var location = window.location; │ │ │ │ │ - sameOrigin = │ │ │ │ │ - urlParts[1] == location.protocol && │ │ │ │ │ - urlParts[3] == location.hostname; │ │ │ │ │ - var uPort = urlParts[4], │ │ │ │ │ - lPort = location.port; │ │ │ │ │ - if (uPort != 80 && uPort != "" || lPort != "80" && lPort != "") { │ │ │ │ │ - sameOrigin = sameOrigin && uPort == lPort; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - if (!sameOrigin) { │ │ │ │ │ - if (proxy) { │ │ │ │ │ - if (typeof proxy == "function") { │ │ │ │ │ - url = proxy(url); │ │ │ │ │ - } else { │ │ │ │ │ - url = proxy + encodeURIComponent(url); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - return url; │ │ │ │ │ - }, │ │ │ │ │ + map: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: issue │ │ │ │ │ - * Create a new XMLHttpRequest object, open it, set any headers, bind │ │ │ │ │ - * a callback to done state, and send any data. It is recommended that │ │ │ │ │ - * you use one , , , , , or . │ │ │ │ │ - * This method is only documented to provide detail on the configuration │ │ │ │ │ - * options available to all request methods. │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Marker │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * config - {Object} Object containing properties for configuring the │ │ │ │ │ - * request. Allowed configuration properties are described below. │ │ │ │ │ - * This object is modified and should not be reused. │ │ │ │ │ - * │ │ │ │ │ - * Allowed config properties: │ │ │ │ │ - * method - {String} One of GET, POST, PUT, DELETE, HEAD, or │ │ │ │ │ - * OPTIONS. Default is GET. │ │ │ │ │ - * url - {String} URL for the request. │ │ │ │ │ - * async - {Boolean} Open an asynchronous request. Default is true. │ │ │ │ │ - * user - {String} User for relevant authentication scheme. Set │ │ │ │ │ - * to null to clear current user. │ │ │ │ │ - * password - {String} Password for relevant authentication scheme. │ │ │ │ │ - * Set to null to clear current password. │ │ │ │ │ - * proxy - {String} Optional proxy. Defaults to │ │ │ │ │ - * . │ │ │ │ │ - * params - {Object} Any key:value pairs to be appended to the │ │ │ │ │ - * url as a query string. Assumes url doesn't already include a query │ │ │ │ │ - * string or hash. Typically, this is only appropriate for │ │ │ │ │ - * requests where the query string will be appended to the url. │ │ │ │ │ - * Parameter values that are arrays will be │ │ │ │ │ - * concatenated with a comma (note that this goes against form-encoding) │ │ │ │ │ - * as is done with . │ │ │ │ │ - * headers - {Object} Object with header:value pairs to be set on │ │ │ │ │ - * the request. │ │ │ │ │ - * data - {String | Document} Optional data to send with the request. │ │ │ │ │ - * Typically, this is only used with and requests. │ │ │ │ │ - * Make sure to provide the appropriate "Content-Type" header for your │ │ │ │ │ - * data. For and requests, the content type defaults to │ │ │ │ │ - * "application-xml". If your data is a different content type, or │ │ │ │ │ - * if you are using a different HTTP method, set the "Content-Type" │ │ │ │ │ - * header to match your data type. │ │ │ │ │ - * callback - {Function} Function to call when request is done. │ │ │ │ │ - * To determine if the request failed, check request.status (200 │ │ │ │ │ - * indicates success). │ │ │ │ │ - * success - {Function} Optional function to call if request status is in │ │ │ │ │ - * the 200s. This will be called in addition to callback above and │ │ │ │ │ - * would typically only be used as an alternative. │ │ │ │ │ - * failure - {Function} Optional function to call if request status is not │ │ │ │ │ - * in the 200s. This will be called in addition to callback above and │ │ │ │ │ - * would typically only be used as an alternative. │ │ │ │ │ - * scope - {Object} If callback is a public method on some object, │ │ │ │ │ - * set the scope to that object. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {XMLHttpRequest} Request object. To abort the request before a response │ │ │ │ │ - * is received, call abort() on the request object. │ │ │ │ │ + * lonlat - {} the position of this marker │ │ │ │ │ + * icon - {} the icon for this marker │ │ │ │ │ */ │ │ │ │ │ - issue: function(config) { │ │ │ │ │ - // apply default config - proxy host may have changed │ │ │ │ │ - var defaultConfig = OpenLayers.Util.extend( │ │ │ │ │ - this.DEFAULT_CONFIG, { │ │ │ │ │ - proxy: OpenLayers.ProxyHost │ │ │ │ │ - } │ │ │ │ │ - ); │ │ │ │ │ - config = config || {}; │ │ │ │ │ - config.headers = config.headers || {}; │ │ │ │ │ - config = OpenLayers.Util.applyDefaults(config, defaultConfig); │ │ │ │ │ - config.headers = OpenLayers.Util.applyDefaults(config.headers, defaultConfig.headers); │ │ │ │ │ - // Always set the "X-Requested-With" header to signal that this request │ │ │ │ │ - // was issued through the XHR-object. Since header keys are case │ │ │ │ │ - // insensitive and we want to allow overriding of the "X-Requested-With" │ │ │ │ │ - // header through the user we cannot use applyDefaults, but have to │ │ │ │ │ - // check manually whether we were called with a "X-Requested-With" │ │ │ │ │ - // header. │ │ │ │ │ - var customRequestedWithHeader = false, │ │ │ │ │ - headerKey; │ │ │ │ │ - for (headerKey in config.headers) { │ │ │ │ │ - if (config.headers.hasOwnProperty(headerKey)) { │ │ │ │ │ - if (headerKey.toLowerCase() === 'x-requested-with') { │ │ │ │ │ - customRequestedWithHeader = true; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - if (customRequestedWithHeader === false) { │ │ │ │ │ - // we did not have a custom "X-Requested-With" header │ │ │ │ │ - config.headers['X-Requested-With'] = 'XMLHttpRequest'; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // create request, open, and set headers │ │ │ │ │ - var request = new OpenLayers.Request.XMLHttpRequest(); │ │ │ │ │ - var url = OpenLayers.Util.urlAppend(config.url, │ │ │ │ │ - OpenLayers.Util.getParameterString(config.params || {})); │ │ │ │ │ - url = OpenLayers.Request.makeSameOrigin(url, config.proxy); │ │ │ │ │ - request.open( │ │ │ │ │ - config.method, url, config.async, config.user, config.password │ │ │ │ │ - ); │ │ │ │ │ - for (var header in config.headers) { │ │ │ │ │ - request.setRequestHeader(header, config.headers[header]); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - var events = this.events; │ │ │ │ │ - │ │ │ │ │ - // we want to execute runCallbacks with "this" as the │ │ │ │ │ - // execution scope │ │ │ │ │ - var self = this; │ │ │ │ │ - │ │ │ │ │ - request.onreadystatechange = function() { │ │ │ │ │ - if (request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) { │ │ │ │ │ - var proceed = events.triggerEvent( │ │ │ │ │ - "complete", { │ │ │ │ │ - request: request, │ │ │ │ │ - config: config, │ │ │ │ │ - requestUrl: url │ │ │ │ │ - } │ │ │ │ │ - ); │ │ │ │ │ - if (proceed !== false) { │ │ │ │ │ - self.runCallbacks({ │ │ │ │ │ - request: request, │ │ │ │ │ - config: config, │ │ │ │ │ - requestUrl: url │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }; │ │ │ │ │ + initialize: function(lonlat, icon) { │ │ │ │ │ + this.lonlat = lonlat; │ │ │ │ │ │ │ │ │ │ - // send request (optionally with data) and return │ │ │ │ │ - // call in a timeout for asynchronous requests so the return is │ │ │ │ │ - // available before readyState == 4 for cached docs │ │ │ │ │ - if (config.async === false) { │ │ │ │ │ - request.send(config.data); │ │ │ │ │ + var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon(); │ │ │ │ │ + if (this.icon == null) { │ │ │ │ │ + this.icon = newIcon; │ │ │ │ │ } else { │ │ │ │ │ - window.setTimeout(function() { │ │ │ │ │ - if (request.readyState !== 0) { // W3C: 0-UNSENT │ │ │ │ │ - request.send(config.data); │ │ │ │ │ - } │ │ │ │ │ - }, 0); │ │ │ │ │ + this.icon.url = newIcon.url; │ │ │ │ │ + this.icon.size = newIcon.size; │ │ │ │ │ + this.icon.offset = newIcon.offset; │ │ │ │ │ + this.icon.calculateOffset = newIcon.calculateOffset; │ │ │ │ │ } │ │ │ │ │ - return request; │ │ │ │ │ + this.events = new OpenLayers.Events(this, this.icon.imageDiv); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: runCallbacks │ │ │ │ │ - * Calls the complete, success and failure callbacks. Application │ │ │ │ │ - * can listen to the "complete" event, have the listener │ │ │ │ │ - * display a confirm window and always return false, and │ │ │ │ │ - * execute OpenLayers.Request.runCallbacks if the user │ │ │ │ │ - * hits "yes" in the confirm window. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} Hash containing request, config and requestUrl keys │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ + * Destroy the marker. You must first remove the marker from any │ │ │ │ │ + * layer which it has been added to, or you will get buggy behavior. │ │ │ │ │ + * (This can not be done within the marker since the marker does not │ │ │ │ │ + * know which layer it is attached to.) │ │ │ │ │ */ │ │ │ │ │ - runCallbacks: function(options) { │ │ │ │ │ - var request = options.request; │ │ │ │ │ - var config = options.config; │ │ │ │ │ - │ │ │ │ │ - // bind callbacks to readyState 4 (done) │ │ │ │ │ - var complete = (config.scope) ? │ │ │ │ │ - OpenLayers.Function.bind(config.callback, config.scope) : │ │ │ │ │ - config.callback; │ │ │ │ │ - │ │ │ │ │ - // optional success callback │ │ │ │ │ - var success; │ │ │ │ │ - if (config.success) { │ │ │ │ │ - success = (config.scope) ? │ │ │ │ │ - OpenLayers.Function.bind(config.success, config.scope) : │ │ │ │ │ - config.success; │ │ │ │ │ - } │ │ │ │ │ + destroy: function() { │ │ │ │ │ + // erase any drawn features │ │ │ │ │ + this.erase(); │ │ │ │ │ │ │ │ │ │ - // optional failure callback │ │ │ │ │ - var failure; │ │ │ │ │ - if (config.failure) { │ │ │ │ │ - failure = (config.scope) ? │ │ │ │ │ - OpenLayers.Function.bind(config.failure, config.scope) : │ │ │ │ │ - config.failure; │ │ │ │ │ - } │ │ │ │ │ + this.map = null; │ │ │ │ │ │ │ │ │ │ - if (OpenLayers.Util.createUrlObject(config.url).protocol == "file:" && │ │ │ │ │ - request.responseText) { │ │ │ │ │ - request.status = 200; │ │ │ │ │ - } │ │ │ │ │ - complete(request); │ │ │ │ │ + this.events.destroy(); │ │ │ │ │ + this.events = null; │ │ │ │ │ │ │ │ │ │ - if (!request.status || (request.status >= 200 && request.status < 300)) { │ │ │ │ │ - this.events.triggerEvent("success", options); │ │ │ │ │ - if (success) { │ │ │ │ │ - success(request); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - if (request.status && (request.status < 200 || request.status >= 300)) { │ │ │ │ │ - this.events.triggerEvent("failure", options); │ │ │ │ │ - if (failure) { │ │ │ │ │ - failure(request); │ │ │ │ │ - } │ │ │ │ │ + if (this.icon != null) { │ │ │ │ │ + this.icon.destroy(); │ │ │ │ │ + this.icon = null; │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: GET │ │ │ │ │ - * Send an HTTP GET request. Additional configuration properties are │ │ │ │ │ - * documented in the method, with the method property set │ │ │ │ │ - * to GET. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * config - {Object} Object with properties for configuring the request. │ │ │ │ │ - * See the method for documentation of allowed properties. │ │ │ │ │ - * This object is modified and should not be reused. │ │ │ │ │ + /** │ │ │ │ │ + * Method: draw │ │ │ │ │ + * Calls draw on the icon, and returns that output. │ │ │ │ │ * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {XMLHttpRequest} Request object. │ │ │ │ │ - */ │ │ │ │ │ - GET: function(config) { │ │ │ │ │ - config = OpenLayers.Util.extend(config, { │ │ │ │ │ - method: "GET" │ │ │ │ │ - }); │ │ │ │ │ - return OpenLayers.Request.issue(config); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: POST │ │ │ │ │ - * Send a POST request. Additional configuration properties are │ │ │ │ │ - * documented in the method, with the method property set │ │ │ │ │ - * to POST and "Content-Type" header set to "application/xml". │ │ │ │ │ - * │ │ │ │ │ * Parameters: │ │ │ │ │ - * config - {Object} Object with properties for configuring the request. │ │ │ │ │ - * See the method for documentation of allowed properties. The │ │ │ │ │ - * default "Content-Type" header will be set to "application-xml" if │ │ │ │ │ - * none is provided. This object is modified and should not be reused. │ │ │ │ │ + * px - {} │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {XMLHttpRequest} Request object. │ │ │ │ │ + * {DOMElement} A new DOM Image with this marker's icon set at the │ │ │ │ │ + * location passed-in │ │ │ │ │ */ │ │ │ │ │ - POST: function(config) { │ │ │ │ │ - config = OpenLayers.Util.extend(config, { │ │ │ │ │ - method: "POST" │ │ │ │ │ - }); │ │ │ │ │ - // set content type to application/xml if it isn't already set │ │ │ │ │ - config.headers = config.headers ? config.headers : {}; │ │ │ │ │ - if (!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) { │ │ │ │ │ - config.headers["Content-Type"] = "application/xml"; │ │ │ │ │ - } │ │ │ │ │ - return OpenLayers.Request.issue(config); │ │ │ │ │ + draw: function(px) { │ │ │ │ │ + return this.icon.draw(px); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: PUT │ │ │ │ │ - * Send an HTTP PUT request. Additional configuration properties are │ │ │ │ │ - * documented in the method, with the method property set │ │ │ │ │ - * to PUT and "Content-Type" header set to "application/xml". │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * config - {Object} Object with properties for configuring the request. │ │ │ │ │ - * See the method for documentation of allowed properties. The │ │ │ │ │ - * default "Content-Type" header will be set to "application-xml" if │ │ │ │ │ - * none is provided. This object is modified and should not be reused. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {XMLHttpRequest} Request object. │ │ │ │ │ + /** │ │ │ │ │ + * Method: erase │ │ │ │ │ + * Erases any drawn elements for this marker. │ │ │ │ │ */ │ │ │ │ │ - PUT: function(config) { │ │ │ │ │ - config = OpenLayers.Util.extend(config, { │ │ │ │ │ - method: "PUT" │ │ │ │ │ - }); │ │ │ │ │ - // set content type to application/xml if it isn't already set │ │ │ │ │ - config.headers = config.headers ? config.headers : {}; │ │ │ │ │ - if (!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) { │ │ │ │ │ - config.headers["Content-Type"] = "application/xml"; │ │ │ │ │ + erase: function() { │ │ │ │ │ + if (this.icon != null) { │ │ │ │ │ + this.icon.erase(); │ │ │ │ │ } │ │ │ │ │ - return OpenLayers.Request.issue(config); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: DELETE │ │ │ │ │ - * Send an HTTP DELETE request. Additional configuration properties are │ │ │ │ │ - * documented in the method, with the method property set │ │ │ │ │ - * to DELETE. │ │ │ │ │ + * Method: moveTo │ │ │ │ │ + * Move the marker to the new location. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * config - {Object} Object with properties for configuring the request. │ │ │ │ │ - * See the method for documentation of allowed properties. │ │ │ │ │ - * This object is modified and should not be reused. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {XMLHttpRequest} Request object. │ │ │ │ │ + * px - {|Object} the pixel position to move to. │ │ │ │ │ + * An OpenLayers.Pixel or an object with a 'x' and 'y' properties. │ │ │ │ │ */ │ │ │ │ │ - DELETE: function(config) { │ │ │ │ │ - config = OpenLayers.Util.extend(config, { │ │ │ │ │ - method: "DELETE" │ │ │ │ │ - }); │ │ │ │ │ - return OpenLayers.Request.issue(config); │ │ │ │ │ + moveTo: function(px) { │ │ │ │ │ + if ((px != null) && (this.icon != null)) { │ │ │ │ │ + this.icon.moveTo(px); │ │ │ │ │ + } │ │ │ │ │ + this.lonlat = this.map.getLonLatFromLayerPx(px); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: HEAD │ │ │ │ │ - * Send an HTTP HEAD request. Additional configuration properties are │ │ │ │ │ - * documented in the method, with the method property set │ │ │ │ │ - * to HEAD. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * config - {Object} Object with properties for configuring the request. │ │ │ │ │ - * See the method for documentation of allowed properties. │ │ │ │ │ - * This object is modified and should not be reused. │ │ │ │ │ + * APIMethod: isDrawn │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {XMLHttpRequest} Request object. │ │ │ │ │ + * {Boolean} Whether or not the marker is drawn. │ │ │ │ │ */ │ │ │ │ │ - HEAD: function(config) { │ │ │ │ │ - config = OpenLayers.Util.extend(config, { │ │ │ │ │ - method: "HEAD" │ │ │ │ │ - }); │ │ │ │ │ - return OpenLayers.Request.issue(config); │ │ │ │ │ + isDrawn: function() { │ │ │ │ │ + var isDrawn = (this.icon && this.icon.isDrawn()); │ │ │ │ │ + return isDrawn; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: OPTIONS │ │ │ │ │ - * Send an HTTP OPTIONS request. Additional configuration properties are │ │ │ │ │ - * documented in the method, with the method property set │ │ │ │ │ - * to OPTIONS. │ │ │ │ │ + * Method: onScreen │ │ │ │ │ * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * config - {Object} Object with properties for configuring the request. │ │ │ │ │ - * See the method for documentation of allowed properties. │ │ │ │ │ - * This object is modified and should not be reused. │ │ │ │ │ - * │ │ │ │ │ * Returns: │ │ │ │ │ - * {XMLHttpRequest} Request object. │ │ │ │ │ - */ │ │ │ │ │ - OPTIONS: function(config) { │ │ │ │ │ - config = OpenLayers.Util.extend(config, { │ │ │ │ │ - method: "OPTIONS" │ │ │ │ │ - }); │ │ │ │ │ - return OpenLayers.Request.issue(config); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Control.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Control │ │ │ │ │ - * Controls affect the display or behavior of the map. They allow everything │ │ │ │ │ - * from panning and zooming to displaying a scale indicator. Controls by │ │ │ │ │ - * default are added to the map they are contained within however it is │ │ │ │ │ - * possible to add a control to an external div by passing the div in the │ │ │ │ │ - * options parameter. │ │ │ │ │ - * │ │ │ │ │ - * Example: │ │ │ │ │ - * The following example shows how to add many of the common controls │ │ │ │ │ - * to a map. │ │ │ │ │ - * │ │ │ │ │ - * > var map = new OpenLayers.Map('map', { controls: [] }); │ │ │ │ │ - * > │ │ │ │ │ - * > map.addControl(new OpenLayers.Control.PanZoomBar()); │ │ │ │ │ - * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false})); │ │ │ │ │ - * > map.addControl(new OpenLayers.Control.Permalink()); │ │ │ │ │ - * > map.addControl(new OpenLayers.Control.Permalink('permalink')); │ │ │ │ │ - * > map.addControl(new OpenLayers.Control.MousePosition()); │ │ │ │ │ - * > map.addControl(new OpenLayers.Control.OverviewMap()); │ │ │ │ │ - * > map.addControl(new OpenLayers.Control.KeyboardDefaults()); │ │ │ │ │ - * │ │ │ │ │ - * The next code fragment is a quick example of how to intercept │ │ │ │ │ - * shift-mouse click to display the extent of the bounding box │ │ │ │ │ - * dragged out by the user. Usually controls are not created │ │ │ │ │ - * in exactly this manner. See the source for a more complete │ │ │ │ │ - * example: │ │ │ │ │ - * │ │ │ │ │ - * > var control = new OpenLayers.Control(); │ │ │ │ │ - * > OpenLayers.Util.extend(control, { │ │ │ │ │ - * > draw: function () { │ │ │ │ │ - * > // this Handler.Box will intercept the shift-mousedown │ │ │ │ │ - * > // before Control.MouseDefault gets to see it │ │ │ │ │ - * > this.box = new OpenLayers.Handler.Box( control, │ │ │ │ │ - * > {"done": this.notice}, │ │ │ │ │ - * > {keyMask: OpenLayers.Handler.MOD_SHIFT}); │ │ │ │ │ - * > this.box.activate(); │ │ │ │ │ - * > }, │ │ │ │ │ - * > │ │ │ │ │ - * > notice: function (bounds) { │ │ │ │ │ - * > OpenLayers.Console.userError(bounds); │ │ │ │ │ - * > } │ │ │ │ │ - * > }); │ │ │ │ │ - * > map.addControl(control); │ │ │ │ │ - * │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Control = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: id │ │ │ │ │ - * {String} │ │ │ │ │ - */ │ │ │ │ │ - id: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: map │ │ │ │ │ - * {} this gets set in the addControl() function in │ │ │ │ │ - * OpenLayers.Map │ │ │ │ │ - */ │ │ │ │ │ - map: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: div │ │ │ │ │ - * {DOMElement} The element that contains the control, if not present the │ │ │ │ │ - * control is placed inside the map. │ │ │ │ │ - */ │ │ │ │ │ - div: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: type │ │ │ │ │ - * {Number} Controls can have a 'type'. The type determines the type of │ │ │ │ │ - * interactions which are possible with them when they are placed in an │ │ │ │ │ - * . │ │ │ │ │ - */ │ │ │ │ │ - type: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: allowSelection │ │ │ │ │ - * {Boolean} By default, controls do not allow selection, because │ │ │ │ │ - * it may interfere with map dragging. If this is true, OpenLayers │ │ │ │ │ - * will not prevent selection of the control. │ │ │ │ │ - * Default is false. │ │ │ │ │ - */ │ │ │ │ │ - allowSelection: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: displayClass │ │ │ │ │ - * {string} This property is used for CSS related to the drawing of the │ │ │ │ │ - * Control. │ │ │ │ │ - */ │ │ │ │ │ - displayClass: "", │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: title │ │ │ │ │ - * {string} This property is used for showing a tooltip over the │ │ │ │ │ - * Control. │ │ │ │ │ - */ │ │ │ │ │ - title: "", │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: autoActivate │ │ │ │ │ - * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ │ - * false. │ │ │ │ │ - */ │ │ │ │ │ - autoActivate: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: active │ │ │ │ │ - * {Boolean} The control is active (read-only). Use and │ │ │ │ │ - * to change control state. │ │ │ │ │ - */ │ │ │ │ │ - active: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: handlerOptions │ │ │ │ │ - * {Object} Used to set non-default properties on the control's handler │ │ │ │ │ - */ │ │ │ │ │ - handlerOptions: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: handler │ │ │ │ │ - * {} null │ │ │ │ │ - */ │ │ │ │ │ - handler: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: eventListeners │ │ │ │ │ - * {Object} If set as an option at construction, the eventListeners │ │ │ │ │ - * object will be registered with . Object │ │ │ │ │ - * structure must be a listeners object as shown in the example for │ │ │ │ │ - * the events.on method. │ │ │ │ │ - */ │ │ │ │ │ - eventListeners: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: events │ │ │ │ │ - * {} Events instance for listeners and triggering │ │ │ │ │ - * control specific events. │ │ │ │ │ - * │ │ │ │ │ - * Register a listener for a particular event with the following syntax: │ │ │ │ │ - * (code) │ │ │ │ │ - * control.events.register(type, obj, listener); │ │ │ │ │ - * (end) │ │ │ │ │ - * │ │ │ │ │ - * Listeners will be called with a reference to an event object. The │ │ │ │ │ - * properties of this event depends on exactly what happened. │ │ │ │ │ - * │ │ │ │ │ - * All event objects have at least the following properties: │ │ │ │ │ - * object - {Object} A reference to control.events.object (a reference │ │ │ │ │ - * to the control). │ │ │ │ │ - * element - {DOMElement} A reference to control.events.element (which │ │ │ │ │ - * will be null unless documented otherwise). │ │ │ │ │ - * │ │ │ │ │ - * Supported map event types: │ │ │ │ │ - * activate - Triggered when activated. │ │ │ │ │ - * deactivate - Triggered when deactivated. │ │ │ │ │ - */ │ │ │ │ │ - events: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Control │ │ │ │ │ - * Create an OpenLayers Control. The options passed as a parameter │ │ │ │ │ - * directly extend the control. For example passing the following: │ │ │ │ │ - * │ │ │ │ │ - * > var control = new OpenLayers.Control({div: myDiv}); │ │ │ │ │ - * │ │ │ │ │ - * Overrides the default div attribute value of null. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(options) { │ │ │ │ │ - // We do this before the extend so that instances can override │ │ │ │ │ - // className in options. │ │ │ │ │ - this.displayClass = │ │ │ │ │ - this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, ""); │ │ │ │ │ - │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ - │ │ │ │ │ - this.events = new OpenLayers.Events(this); │ │ │ │ │ - if (this.eventListeners instanceof Object) { │ │ │ │ │ - this.events.on(this.eventListeners); │ │ │ │ │ - } │ │ │ │ │ - if (this.id == null) { │ │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: destroy │ │ │ │ │ - * The destroy method is used to perform any clean up before the control │ │ │ │ │ - * is dereferenced. Typically this is where event listeners are removed │ │ │ │ │ - * to prevent memory leaks. │ │ │ │ │ + * {Boolean} Whether or not the marker is currently visible on screen. │ │ │ │ │ */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - if (this.events) { │ │ │ │ │ - if (this.eventListeners) { │ │ │ │ │ - this.events.un(this.eventListeners); │ │ │ │ │ - } │ │ │ │ │ - this.events.destroy(); │ │ │ │ │ - this.events = null; │ │ │ │ │ - } │ │ │ │ │ - this.eventListeners = null; │ │ │ │ │ + onScreen: function() { │ │ │ │ │ │ │ │ │ │ - // eliminate circular references │ │ │ │ │ - if (this.handler) { │ │ │ │ │ - this.handler.destroy(); │ │ │ │ │ - this.handler = null; │ │ │ │ │ - } │ │ │ │ │ - if (this.handlers) { │ │ │ │ │ - for (var key in this.handlers) { │ │ │ │ │ - if (this.handlers.hasOwnProperty(key) && │ │ │ │ │ - typeof this.handlers[key].destroy == "function") { │ │ │ │ │ - this.handlers[key].destroy(); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - this.handlers = null; │ │ │ │ │ - } │ │ │ │ │ + var onScreen = false; │ │ │ │ │ if (this.map) { │ │ │ │ │ - this.map.removeControl(this); │ │ │ │ │ - this.map = null; │ │ │ │ │ - } │ │ │ │ │ - this.div = null; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: setMap │ │ │ │ │ - * Set the map property for the control. This is done through an accessor │ │ │ │ │ - * so that subclasses can override this and take special action once │ │ │ │ │ - * they have their map variable set. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * map - {} │ │ │ │ │ - */ │ │ │ │ │ - setMap: function(map) { │ │ │ │ │ - this.map = map; │ │ │ │ │ - if (this.handler) { │ │ │ │ │ - this.handler.setMap(map); │ │ │ │ │ + var screenBounds = this.map.getExtent(); │ │ │ │ │ + onScreen = screenBounds.containsLonLat(this.lonlat); │ │ │ │ │ } │ │ │ │ │ + return onScreen; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: draw │ │ │ │ │ - * The draw method is called when the control is ready to be displayed │ │ │ │ │ - * on the page. If a div has not been created one is created. Controls │ │ │ │ │ - * with a visual component will almost always want to override this method │ │ │ │ │ - * to customize the look of control. │ │ │ │ │ + * Method: inflate │ │ │ │ │ + * Englarges the markers icon by the specified ratio. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * px - {} The top-left pixel position of the control │ │ │ │ │ - * or null. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {DOMElement} A reference to the DIV DOMElement containing the control │ │ │ │ │ + * inflate - {float} the ratio to enlarge the marker by (passing 2 │ │ │ │ │ + * will double the size). │ │ │ │ │ */ │ │ │ │ │ - draw: function(px) { │ │ │ │ │ - if (this.div == null) { │ │ │ │ │ - this.div = OpenLayers.Util.createDiv(this.id); │ │ │ │ │ - this.div.className = this.displayClass; │ │ │ │ │ - if (!this.allowSelection) { │ │ │ │ │ - this.div.className += " olControlNoSelect"; │ │ │ │ │ - this.div.setAttribute("unselectable", "on", 0); │ │ │ │ │ - this.div.onselectstart = OpenLayers.Function.False; │ │ │ │ │ - } │ │ │ │ │ - if (this.title != "") { │ │ │ │ │ - this.div.title = this.title; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - if (px != null) { │ │ │ │ │ - this.position = px.clone(); │ │ │ │ │ + inflate: function(inflate) { │ │ │ │ │ + if (this.icon) { │ │ │ │ │ + this.icon.setSize({ │ │ │ │ │ + w: this.icon.size.w * inflate, │ │ │ │ │ + h: this.icon.size.h * inflate │ │ │ │ │ + }); │ │ │ │ │ } │ │ │ │ │ - this.moveTo(this.position); │ │ │ │ │ - return this.div; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: moveTo │ │ │ │ │ - * Sets the left and top style attributes to the passed in pixel │ │ │ │ │ - * coordinates. │ │ │ │ │ - * │ │ │ │ │ + /** │ │ │ │ │ + * Method: setOpacity │ │ │ │ │ + * Change the opacity of the marker by changin the opacity of │ │ │ │ │ + * its icon │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * px - {} │ │ │ │ │ + * opacity - {float} Specified as fraction (0.4, etc) │ │ │ │ │ */ │ │ │ │ │ - moveTo: function(px) { │ │ │ │ │ - if ((px != null) && (this.div != null)) { │ │ │ │ │ - this.div.style.left = px.x + "px"; │ │ │ │ │ - this.div.style.top = px.y + "px"; │ │ │ │ │ - } │ │ │ │ │ + setOpacity: function(opacity) { │ │ │ │ │ + this.icon.setOpacity(opacity); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: activate │ │ │ │ │ - * Explicitly activates a control and it's associated │ │ │ │ │ - * handler if one has been set. Controls can be │ │ │ │ │ - * deactivated by calling the deactivate() method. │ │ │ │ │ + * Method: setUrl │ │ │ │ │ + * Change URL of the Icon Image. │ │ │ │ │ * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} True if the control was successfully activated or │ │ │ │ │ - * false if the control was already active. │ │ │ │ │ + * url - {String} │ │ │ │ │ */ │ │ │ │ │ - activate: function() { │ │ │ │ │ - if (this.active) { │ │ │ │ │ - return false; │ │ │ │ │ - } │ │ │ │ │ - if (this.handler) { │ │ │ │ │ - this.handler.activate(); │ │ │ │ │ - } │ │ │ │ │ - this.active = true; │ │ │ │ │ - if (this.map) { │ │ │ │ │ - OpenLayers.Element.addClass( │ │ │ │ │ - this.map.viewPortDiv, │ │ │ │ │ - this.displayClass.replace(/ /g, "") + "Active" │ │ │ │ │ - ); │ │ │ │ │ - } │ │ │ │ │ - this.events.triggerEvent("activate"); │ │ │ │ │ - return true; │ │ │ │ │ + setUrl: function(url) { │ │ │ │ │ + this.icon.setUrl(url); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: deactivate │ │ │ │ │ - * Deactivates a control and it's associated handler if any. The exact │ │ │ │ │ - * effect of this depends on the control itself. │ │ │ │ │ + /** │ │ │ │ │ + * Method: display │ │ │ │ │ + * Hide or show the icon │ │ │ │ │ * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} True if the control was effectively deactivated or false │ │ │ │ │ - * if the control was already inactive. │ │ │ │ │ + * display - {Boolean} │ │ │ │ │ */ │ │ │ │ │ - deactivate: function() { │ │ │ │ │ - if (this.active) { │ │ │ │ │ - if (this.handler) { │ │ │ │ │ - this.handler.deactivate(); │ │ │ │ │ - } │ │ │ │ │ - this.active = false; │ │ │ │ │ - if (this.map) { │ │ │ │ │ - OpenLayers.Element.removeClass( │ │ │ │ │ - this.map.viewPortDiv, │ │ │ │ │ - this.displayClass.replace(/ /g, "") + "Active" │ │ │ │ │ - ); │ │ │ │ │ - } │ │ │ │ │ - this.events.triggerEvent("deactivate"); │ │ │ │ │ - return true; │ │ │ │ │ - } │ │ │ │ │ - return false; │ │ │ │ │ + display: function(display) { │ │ │ │ │ + this.icon.display(display); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Control" │ │ │ │ │ + CLASS_NAME: "OpenLayers.Marker" │ │ │ │ │ }); │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Control.TYPE_BUTTON │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Control.TYPE_BUTTON = 1; │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constant: OpenLayers.Control.TYPE_TOGGLE │ │ │ │ │ + * Function: defaultIcon │ │ │ │ │ + * Creates a default . │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} A default OpenLayers.Icon to use for a marker │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Control.TYPE_TOGGLE = 2; │ │ │ │ │ +OpenLayers.Marker.defaultIcon = function() { │ │ │ │ │ + return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"), { │ │ │ │ │ + w: 21, │ │ │ │ │ + h: 25 │ │ │ │ │ + }, { │ │ │ │ │ + x: -10.5, │ │ │ │ │ + y: -25 │ │ │ │ │ + }); │ │ │ │ │ +}; │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Control.TYPE_TOOL │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Control.TYPE_TOOL = 3; │ │ │ │ │ /* ====================================================================== │ │ │ │ │ OpenLayers/Geometry.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ @@ -11449,757 +14611,14 @@ │ │ │ │ │ distance: Math.pow(x - x0, 2) + Math.pow(y - y0, 2), │ │ │ │ │ x: x, │ │ │ │ │ y: y, │ │ │ │ │ along: along │ │ │ │ │ }; │ │ │ │ │ }; │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Feature.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Feature │ │ │ │ │ - * Features are combinations of geography and attributes. The OpenLayers.Feature │ │ │ │ │ - * class specifically combines a marker and a lonlat. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Feature = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: layer │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - layer: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: id │ │ │ │ │ - * {String} │ │ │ │ │ - */ │ │ │ │ │ - id: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: lonlat │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - lonlat: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: data │ │ │ │ │ - * {Object} │ │ │ │ │ - */ │ │ │ │ │ - data: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: marker │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - marker: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: popupClass │ │ │ │ │ - * {} The class which will be used to instantiate │ │ │ │ │ - * a new Popup. Default is . │ │ │ │ │ - */ │ │ │ │ │ - popupClass: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: popup │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - popup: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Feature │ │ │ │ │ - * Constructor for features. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * layer - {} │ │ │ │ │ - * lonlat - {} │ │ │ │ │ - * data - {Object} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(layer, lonlat, data) { │ │ │ │ │ - this.layer = layer; │ │ │ │ │ - this.lonlat = lonlat; │ │ │ │ │ - this.data = (data != null) ? data : {}; │ │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: destroy │ │ │ │ │ - * nullify references to prevent circular references and memory leaks │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - │ │ │ │ │ - //remove the popup from the map │ │ │ │ │ - if ((this.layer != null) && (this.layer.map != null)) { │ │ │ │ │ - if (this.popup != null) { │ │ │ │ │ - this.layer.map.removePopup(this.popup); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - // remove the marker from the layer │ │ │ │ │ - if (this.layer != null && this.marker != null) { │ │ │ │ │ - this.layer.removeMarker(this.marker); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - this.layer = null; │ │ │ │ │ - this.id = null; │ │ │ │ │ - this.lonlat = null; │ │ │ │ │ - this.data = null; │ │ │ │ │ - if (this.marker != null) { │ │ │ │ │ - this.destroyMarker(this.marker); │ │ │ │ │ - this.marker = null; │ │ │ │ │ - } │ │ │ │ │ - if (this.popup != null) { │ │ │ │ │ - this.destroyPopup(this.popup); │ │ │ │ │ - this.popup = null; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: onScreen │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} Whether or not the feature is currently visible on screen │ │ │ │ │ - * (based on its 'lonlat' property) │ │ │ │ │ - */ │ │ │ │ │ - onScreen: function() { │ │ │ │ │ - │ │ │ │ │ - var onScreen = false; │ │ │ │ │ - if ((this.layer != null) && (this.layer.map != null)) { │ │ │ │ │ - var screenBounds = this.layer.map.getExtent(); │ │ │ │ │ - onScreen = screenBounds.containsLonLat(this.lonlat); │ │ │ │ │ - } │ │ │ │ │ - return onScreen; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: createMarker │ │ │ │ │ - * Based on the data associated with the Feature, create and return a marker object. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} A Marker Object created from the 'lonlat' and 'icon' properties │ │ │ │ │ - * set in this.data. If no 'lonlat' is set, returns null. If no │ │ │ │ │ - * 'icon' is set, OpenLayers.Marker() will load the default image. │ │ │ │ │ - * │ │ │ │ │ - * Note - this.marker is set to return value │ │ │ │ │ - * │ │ │ │ │ - */ │ │ │ │ │ - createMarker: function() { │ │ │ │ │ - │ │ │ │ │ - if (this.lonlat != null) { │ │ │ │ │ - this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon); │ │ │ │ │ - } │ │ │ │ │ - return this.marker; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: destroyMarker │ │ │ │ │ - * Destroys marker. │ │ │ │ │ - * If user overrides the createMarker() function, s/he should be able │ │ │ │ │ - * to also specify an alternative function for destroying it │ │ │ │ │ - */ │ │ │ │ │ - destroyMarker: function() { │ │ │ │ │ - this.marker.destroy(); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: createPopup │ │ │ │ │ - * Creates a popup object created from the 'lonlat', 'popupSize', │ │ │ │ │ - * and 'popupContentHTML' properties set in this.data. It uses │ │ │ │ │ - * this.marker.icon as default anchor. │ │ │ │ │ - * │ │ │ │ │ - * If no 'lonlat' is set, returns null. │ │ │ │ │ - * If no this.marker has been created, no anchor is sent. │ │ │ │ │ - * │ │ │ │ │ - * Note - the returned popup object is 'owned' by the feature, so you │ │ │ │ │ - * cannot use the popup's destroy method to discard the popup. │ │ │ │ │ - * Instead, you must use the feature's destroyPopup │ │ │ │ │ - * │ │ │ │ │ - * Note - this.popup is set to return value │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * closeBox - {Boolean} create popup with closebox or not │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} Returns the created popup, which is also set │ │ │ │ │ - * as 'popup' property of this feature. Will be of whatever type │ │ │ │ │ - * specified by this feature's 'popupClass' property, but must be │ │ │ │ │ - * of type . │ │ │ │ │ - * │ │ │ │ │ - */ │ │ │ │ │ - createPopup: function(closeBox) { │ │ │ │ │ - │ │ │ │ │ - if (this.lonlat != null) { │ │ │ │ │ - if (!this.popup) { │ │ │ │ │ - var anchor = (this.marker) ? this.marker.icon : null; │ │ │ │ │ - var popupClass = this.popupClass ? │ │ │ │ │ - this.popupClass : OpenLayers.Popup.Anchored; │ │ │ │ │ - this.popup = new popupClass(this.id + "_popup", │ │ │ │ │ - this.lonlat, │ │ │ │ │ - this.data.popupSize, │ │ │ │ │ - this.data.popupContentHTML, │ │ │ │ │ - anchor, │ │ │ │ │ - closeBox); │ │ │ │ │ - } │ │ │ │ │ - if (this.data.overflow != null) { │ │ │ │ │ - this.popup.contentDiv.style.overflow = this.data.overflow; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - this.popup.feature = this; │ │ │ │ │ - } │ │ │ │ │ - return this.popup; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: destroyPopup │ │ │ │ │ - * Destroys the popup created via createPopup. │ │ │ │ │ - * │ │ │ │ │ - * As with the marker, if user overrides the createPopup() function, s/he │ │ │ │ │ - * should also be able to override the destruction │ │ │ │ │ - */ │ │ │ │ │ - destroyPopup: function() { │ │ │ │ │ - if (this.popup) { │ │ │ │ │ - this.popup.feature = null; │ │ │ │ │ - this.popup.destroy(); │ │ │ │ │ - this.popup = null; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Feature" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Feature/Vector.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -// TRASH THIS │ │ │ │ │ -OpenLayers.State = { │ │ │ │ │ - /** states */ │ │ │ │ │ - UNKNOWN: 'Unknown', │ │ │ │ │ - INSERT: 'Insert', │ │ │ │ │ - UPDATE: 'Update', │ │ │ │ │ - DELETE: 'Delete' │ │ │ │ │ -}; │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Feature.js │ │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Feature.Vector │ │ │ │ │ - * Vector features use the OpenLayers.Geometry classes as geometry description. │ │ │ │ │ - * They have an 'attributes' property, which is the data object, and a 'style' │ │ │ │ │ - * property, the default values of which are defined in the │ │ │ │ │ - * objects. │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: fid │ │ │ │ │ - * {String} │ │ │ │ │ - */ │ │ │ │ │ - fid: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: geometry │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - geometry: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: attributes │ │ │ │ │ - * {Object} This object holds arbitrary, serializable properties that │ │ │ │ │ - * describe the feature. │ │ │ │ │ - */ │ │ │ │ │ - attributes: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: bounds │ │ │ │ │ - * {} The box bounding that feature's geometry, that │ │ │ │ │ - * property can be set by an object when │ │ │ │ │ - * deserializing the feature, so in most cases it represents an │ │ │ │ │ - * information set by the server. │ │ │ │ │ - */ │ │ │ │ │ - bounds: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: state │ │ │ │ │ - * {String} │ │ │ │ │ - */ │ │ │ │ │ - state: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: style │ │ │ │ │ - * {Object} │ │ │ │ │ - */ │ │ │ │ │ - style: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: url │ │ │ │ │ - * {String} If this property is set it will be taken into account by │ │ │ │ │ - * {} when upadting or deleting the feature. │ │ │ │ │ - */ │ │ │ │ │ - url: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: renderIntent │ │ │ │ │ - * {String} rendering intent currently being used │ │ │ │ │ - */ │ │ │ │ │ - renderIntent: "default", │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: modified │ │ │ │ │ - * {Object} An object with the originals of the geometry and attributes of │ │ │ │ │ - * the feature, if they were changed. Currently this property is only read │ │ │ │ │ - * by , and written by │ │ │ │ │ - * , which sets the geometry property. │ │ │ │ │ - * Applications can set the originals of modified attributes in the │ │ │ │ │ - * attributes property. Note that applications have to check if this │ │ │ │ │ - * object and the attributes property is already created before using it. │ │ │ │ │ - * After a change made with ModifyFeature, this object could look like │ │ │ │ │ - * │ │ │ │ │ - * (code) │ │ │ │ │ - * { │ │ │ │ │ - * geometry: >Object │ │ │ │ │ - * } │ │ │ │ │ - * (end) │ │ │ │ │ - * │ │ │ │ │ - * When an application has made changes to feature attributes, it could │ │ │ │ │ - * have set the attributes to something like this: │ │ │ │ │ - * │ │ │ │ │ - * (code) │ │ │ │ │ - * { │ │ │ │ │ - * attributes: { │ │ │ │ │ - * myAttribute: "original" │ │ │ │ │ - * } │ │ │ │ │ - * } │ │ │ │ │ - * (end) │ │ │ │ │ - * │ │ │ │ │ - * Note that only checks for truthy values in │ │ │ │ │ - * *modified.geometry* and the attribute names in *modified.attributes*, │ │ │ │ │ - * but it is recommended to set the original values (and not just true) as │ │ │ │ │ - * attribute value, so applications could use this information to undo │ │ │ │ │ - * changes. │ │ │ │ │ - */ │ │ │ │ │ - modified: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Feature.Vector │ │ │ │ │ - * Create a vector feature. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * geometry - {} The geometry that this feature │ │ │ │ │ - * represents. │ │ │ │ │ - * attributes - {Object} An optional object that will be mapped to the │ │ │ │ │ - * property. │ │ │ │ │ - * style - {Object} An optional style object. │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(geometry, attributes, style) { │ │ │ │ │ - OpenLayers.Feature.prototype.initialize.apply(this, │ │ │ │ │ - [null, null, attributes]); │ │ │ │ │ - this.lonlat = null; │ │ │ │ │ - this.geometry = geometry ? geometry : null; │ │ │ │ │ - this.state = null; │ │ │ │ │ - this.attributes = {}; │ │ │ │ │ - if (attributes) { │ │ │ │ │ - this.attributes = OpenLayers.Util.extend(this.attributes, │ │ │ │ │ - attributes); │ │ │ │ │ - } │ │ │ │ │ - this.style = style ? style : null; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: destroy │ │ │ │ │ - * nullify references to prevent circular references and memory leaks │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - if (this.layer) { │ │ │ │ │ - this.layer.removeFeatures(this); │ │ │ │ │ - this.layer = null; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - this.geometry = null; │ │ │ │ │ - this.modified = null; │ │ │ │ │ - OpenLayers.Feature.prototype.destroy.apply(this, arguments); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: clone │ │ │ │ │ - * Create a clone of this vector feature. Does not set any non-standard │ │ │ │ │ - * properties. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} An exact clone of this vector feature. │ │ │ │ │ - */ │ │ │ │ │ - clone: function() { │ │ │ │ │ - return new OpenLayers.Feature.Vector( │ │ │ │ │ - this.geometry ? this.geometry.clone() : null, │ │ │ │ │ - this.attributes, │ │ │ │ │ - this.style); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: onScreen │ │ │ │ │ - * Determine whether the feature is within the map viewport. This method │ │ │ │ │ - * tests for an intersection between the geometry and the viewport │ │ │ │ │ - * bounds. If a more effecient but less precise geometry bounds │ │ │ │ │ - * intersection is desired, call the method with the boundsOnly │ │ │ │ │ - * parameter true. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * boundsOnly - {Boolean} Only test whether a feature's bounds intersects │ │ │ │ │ - * the viewport bounds. Default is false. If false, the feature's │ │ │ │ │ - * geometry must intersect the viewport for onScreen to return true. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The feature is currently visible on screen (optionally │ │ │ │ │ - * based on its bounds if boundsOnly is true). │ │ │ │ │ - */ │ │ │ │ │ - onScreen: function(boundsOnly) { │ │ │ │ │ - var onScreen = false; │ │ │ │ │ - if (this.layer && this.layer.map) { │ │ │ │ │ - var screenBounds = this.layer.map.getExtent(); │ │ │ │ │ - if (boundsOnly) { │ │ │ │ │ - var featureBounds = this.geometry.getBounds(); │ │ │ │ │ - onScreen = screenBounds.intersectsBounds(featureBounds); │ │ │ │ │ - } else { │ │ │ │ │ - var screenPoly = screenBounds.toGeometry(); │ │ │ │ │ - onScreen = screenPoly.intersects(this.geometry); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - return onScreen; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: getVisibility │ │ │ │ │ - * Determine whether the feature is displayed or not. It may not displayed │ │ │ │ │ - * because: │ │ │ │ │ - * - its style display property is set to 'none', │ │ │ │ │ - * - it doesn't belong to any layer, │ │ │ │ │ - * - the styleMap creates a symbolizer with display property set to 'none' │ │ │ │ │ - * for it, │ │ │ │ │ - * - the layer which it belongs to is not visible. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The feature is currently displayed. │ │ │ │ │ - */ │ │ │ │ │ - getVisibility: function() { │ │ │ │ │ - return !(this.style && this.style.display == 'none' || │ │ │ │ │ - !this.layer || │ │ │ │ │ - this.layer && this.layer.styleMap && │ │ │ │ │ - this.layer.styleMap.createSymbolizer(this, this.renderIntent).display == 'none' || │ │ │ │ │ - this.layer && !this.layer.getVisibility()); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: createMarker │ │ │ │ │ - * HACK - we need to decide if all vector features should be able to │ │ │ │ │ - * create markers │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} For now just returns null │ │ │ │ │ - */ │ │ │ │ │ - createMarker: function() { │ │ │ │ │ - return null; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: destroyMarker │ │ │ │ │ - * HACK - we need to decide if all vector features should be able to │ │ │ │ │ - * delete markers │ │ │ │ │ - * │ │ │ │ │ - * If user overrides the createMarker() function, s/he should be able │ │ │ │ │ - * to also specify an alternative function for destroying it │ │ │ │ │ - */ │ │ │ │ │ - destroyMarker: function() { │ │ │ │ │ - // pass │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: createPopup │ │ │ │ │ - * HACK - we need to decide if all vector features should be able to │ │ │ │ │ - * create popups │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} For now just returns null │ │ │ │ │ - */ │ │ │ │ │ - createPopup: function() { │ │ │ │ │ - return null; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: atPoint │ │ │ │ │ - * Determins whether the feature intersects with the specified location. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * lonlat - {|Object} OpenLayers.LonLat or an │ │ │ │ │ - * object with a 'lon' and 'lat' properties. │ │ │ │ │ - * toleranceLon - {float} Optional tolerance in Geometric Coords │ │ │ │ │ - * toleranceLat - {float} Optional tolerance in Geographic Coords │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} Whether or not the feature is at the specified location │ │ │ │ │ - */ │ │ │ │ │ - atPoint: function(lonlat, toleranceLon, toleranceLat) { │ │ │ │ │ - var atPoint = false; │ │ │ │ │ - if (this.geometry) { │ │ │ │ │ - atPoint = this.geometry.atPoint(lonlat, toleranceLon, │ │ │ │ │ - toleranceLat); │ │ │ │ │ - } │ │ │ │ │ - return atPoint; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: destroyPopup │ │ │ │ │ - * HACK - we need to decide if all vector features should be able to │ │ │ │ │ - * delete popups │ │ │ │ │ - */ │ │ │ │ │ - destroyPopup: function() { │ │ │ │ │ - // pass │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: move │ │ │ │ │ - * Moves the feature and redraws it at its new location │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * location - { or } the │ │ │ │ │ - * location to which to move the feature. │ │ │ │ │ - */ │ │ │ │ │ - move: function(location) { │ │ │ │ │ - │ │ │ │ │ - if (!this.layer || !this.geometry.move) { │ │ │ │ │ - //do nothing if no layer or immoveable geometry │ │ │ │ │ - return undefined; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - var pixel; │ │ │ │ │ - if (location.CLASS_NAME == "OpenLayers.LonLat") { │ │ │ │ │ - pixel = this.layer.getViewPortPxFromLonLat(location); │ │ │ │ │ - } else { │ │ │ │ │ - pixel = location; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - var lastPixel = this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat()); │ │ │ │ │ - var res = this.layer.map.getResolution(); │ │ │ │ │ - this.geometry.move(res * (pixel.x - lastPixel.x), │ │ │ │ │ - res * (lastPixel.y - pixel.y)); │ │ │ │ │ - this.layer.drawFeature(this); │ │ │ │ │ - return lastPixel; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: toState │ │ │ │ │ - * Sets the new state │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * state - {String} │ │ │ │ │ - */ │ │ │ │ │ - toState: function(state) { │ │ │ │ │ - if (state == OpenLayers.State.UPDATE) { │ │ │ │ │ - switch (this.state) { │ │ │ │ │ - case OpenLayers.State.UNKNOWN: │ │ │ │ │ - case OpenLayers.State.DELETE: │ │ │ │ │ - this.state = state; │ │ │ │ │ - break; │ │ │ │ │ - case OpenLayers.State.UPDATE: │ │ │ │ │ - case OpenLayers.State.INSERT: │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } else if (state == OpenLayers.State.INSERT) { │ │ │ │ │ - switch (this.state) { │ │ │ │ │ - case OpenLayers.State.UNKNOWN: │ │ │ │ │ - break; │ │ │ │ │ - default: │ │ │ │ │ - this.state = state; │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } else if (state == OpenLayers.State.DELETE) { │ │ │ │ │ - switch (this.state) { │ │ │ │ │ - case OpenLayers.State.INSERT: │ │ │ │ │ - // the feature should be destroyed │ │ │ │ │ - break; │ │ │ │ │ - case OpenLayers.State.DELETE: │ │ │ │ │ - break; │ │ │ │ │ - case OpenLayers.State.UNKNOWN: │ │ │ │ │ - case OpenLayers.State.UPDATE: │ │ │ │ │ - this.state = state; │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } else if (state == OpenLayers.State.UNKNOWN) { │ │ │ │ │ - this.state = state; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Feature.Vector" │ │ │ │ │ -}); │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Feature.Vector.style │ │ │ │ │ - * OpenLayers features can have a number of style attributes. The 'default' │ │ │ │ │ - * style will typically be used if no other style is specified. These │ │ │ │ │ - * styles correspond for the most part, to the styling properties defined │ │ │ │ │ - * by the SVG standard. │ │ │ │ │ - * Information on fill properties: http://www.w3.org/TR/SVG/painting.html#FillProperties │ │ │ │ │ - * Information on stroke properties: http://www.w3.org/TR/SVG/painting.html#StrokeProperties │ │ │ │ │ - * │ │ │ │ │ - * Symbolizer properties: │ │ │ │ │ - * fill - {Boolean} Set to false if no fill is desired. │ │ │ │ │ - * fillColor - {String} Hex fill color. Default is "#ee9900". │ │ │ │ │ - * fillOpacity - {Number} Fill opacity (0-1). Default is 0.4 │ │ │ │ │ - * stroke - {Boolean} Set to false if no stroke is desired. │ │ │ │ │ - * strokeColor - {String} Hex stroke color. Default is "#ee9900". │ │ │ │ │ - * strokeOpacity - {Number} Stroke opacity (0-1). Default is 1. │ │ │ │ │ - * strokeWidth - {Number} Pixel stroke width. Default is 1. │ │ │ │ │ - * strokeLinecap - {String} Stroke cap type. Default is "round". [butt | round | square] │ │ │ │ │ - * strokeDashstyle - {String} Stroke dash style. Default is "solid". [dot | dash | dashdot | longdash | longdashdot | solid] │ │ │ │ │ - * graphic - {Boolean} Set to false if no graphic is desired. │ │ │ │ │ - * pointRadius - {Number} Pixel point radius. Default is 6. │ │ │ │ │ - * pointerEvents - {String} Default is "visiblePainted". │ │ │ │ │ - * cursor - {String} Default is "". │ │ │ │ │ - * externalGraphic - {String} Url to an external graphic that will be used for rendering points. │ │ │ │ │ - * graphicWidth - {Number} Pixel width for sizing an external graphic. │ │ │ │ │ - * graphicHeight - {Number} Pixel height for sizing an external graphic. │ │ │ │ │ - * graphicOpacity - {Number} Opacity (0-1) for an external graphic. │ │ │ │ │ - * graphicXOffset - {Number} Pixel offset along the positive x axis for displacing an external graphic. │ │ │ │ │ - * graphicYOffset - {Number} Pixel offset along the positive y axis for displacing an external graphic. │ │ │ │ │ - * rotation - {Number} For point symbolizers, this is the rotation of a graphic in the clockwise direction about its center point (or any point off center as specified by graphicXOffset and graphicYOffset). │ │ │ │ │ - * graphicZIndex - {Number} The integer z-index value to use in rendering. │ │ │ │ │ - * graphicName - {String} Named graphic to use when rendering points. Supported values include "circle" (default), │ │ │ │ │ - * "square", "star", "x", "cross", "triangle". │ │ │ │ │ - * graphicTitle - {String} Tooltip when hovering over a feature. *deprecated*, use title instead │ │ │ │ │ - * title - {String} Tooltip when hovering over a feature. Not supported by the canvas renderer. │ │ │ │ │ - * backgroundGraphic - {String} Url to a graphic to be used as the background under an externalGraphic. │ │ │ │ │ - * backgroundGraphicZIndex - {Number} The integer z-index value to use in rendering the background graphic. │ │ │ │ │ - * backgroundXOffset - {Number} The x offset (in pixels) for the background graphic. │ │ │ │ │ - * backgroundYOffset - {Number} The y offset (in pixels) for the background graphic. │ │ │ │ │ - * backgroundHeight - {Number} The height of the background graphic. If not provided, the graphicHeight will be used. │ │ │ │ │ - * backgroundWidth - {Number} The width of the background width. If not provided, the graphicWidth will be used. │ │ │ │ │ - * label - {String} The text for an optional label. For browsers that use the canvas renderer, this requires either │ │ │ │ │ - * fillText or mozDrawText to be available. │ │ │ │ │ - * labelAlign - {String} Label alignment. This specifies the insertion point relative to the text. It is a string │ │ │ │ │ - * composed of two characters. The first character is for the horizontal alignment, the second for the vertical │ │ │ │ │ - * alignment. Valid values for horizontal alignment: "l"=left, "c"=center, "r"=right. Valid values for vertical │ │ │ │ │ - * alignment: "t"=top, "m"=middle, "b"=bottom. Example values: "lt", "cm", "rb". Default is "cm". │ │ │ │ │ - * labelXOffset - {Number} Pixel offset along the positive x axis for displacing the label. Not supported by the canvas renderer. │ │ │ │ │ - * labelYOffset - {Number} Pixel offset along the positive y axis for displacing the label. Not supported by the canvas renderer. │ │ │ │ │ - * labelSelect - {Boolean} If set to true, labels will be selectable using SelectFeature or similar controls. │ │ │ │ │ - * Default is false. │ │ │ │ │ - * labelOutlineColor - {String} The color of the label outline. Default is 'white'. Only supported by the canvas & SVG renderers. │ │ │ │ │ - * labelOutlineWidth - {Number} The width of the label outline. Default is 3, set to 0 or null to disable. Only supported by the SVG renderers. │ │ │ │ │ - * labelOutlineOpacity - {Number} The opacity (0-1) of the label outline. Default is fontOpacity. Only supported by the canvas & SVG renderers. │ │ │ │ │ - * fontColor - {String} The font color for the label, to be provided like CSS. │ │ │ │ │ - * fontOpacity - {Number} Opacity (0-1) for the label │ │ │ │ │ - * fontFamily - {String} The font family for the label, to be provided like in CSS. │ │ │ │ │ - * fontSize - {String} The font size for the label, to be provided like in CSS. │ │ │ │ │ - * fontStyle - {String} The font style for the label, to be provided like in CSS. │ │ │ │ │ - * fontWeight - {String} The font weight for the label, to be provided like in CSS. │ │ │ │ │ - * display - {String} Symbolizers will have no effect if display is set to "none". All other values have no effect. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Feature.Vector.style = { │ │ │ │ │ - 'default': { │ │ │ │ │ - fillColor: "#ee9900", │ │ │ │ │ - fillOpacity: 0.4, │ │ │ │ │ - hoverFillColor: "white", │ │ │ │ │ - hoverFillOpacity: 0.8, │ │ │ │ │ - strokeColor: "#ee9900", │ │ │ │ │ - strokeOpacity: 1, │ │ │ │ │ - strokeWidth: 1, │ │ │ │ │ - strokeLinecap: "round", │ │ │ │ │ - strokeDashstyle: "solid", │ │ │ │ │ - hoverStrokeColor: "red", │ │ │ │ │ - hoverStrokeOpacity: 1, │ │ │ │ │ - hoverStrokeWidth: 0.2, │ │ │ │ │ - pointRadius: 6, │ │ │ │ │ - hoverPointRadius: 1, │ │ │ │ │ - hoverPointUnit: "%", │ │ │ │ │ - pointerEvents: "visiblePainted", │ │ │ │ │ - cursor: "inherit", │ │ │ │ │ - fontColor: "#000000", │ │ │ │ │ - labelAlign: "cm", │ │ │ │ │ - labelOutlineColor: "white", │ │ │ │ │ - labelOutlineWidth: 3 │ │ │ │ │ - }, │ │ │ │ │ - 'select': { │ │ │ │ │ - fillColor: "blue", │ │ │ │ │ - fillOpacity: 0.4, │ │ │ │ │ - hoverFillColor: "white", │ │ │ │ │ - hoverFillOpacity: 0.8, │ │ │ │ │ - strokeColor: "blue", │ │ │ │ │ - strokeOpacity: 1, │ │ │ │ │ - strokeWidth: 2, │ │ │ │ │ - strokeLinecap: "round", │ │ │ │ │ - strokeDashstyle: "solid", │ │ │ │ │ - hoverStrokeColor: "red", │ │ │ │ │ - hoverStrokeOpacity: 1, │ │ │ │ │ - hoverStrokeWidth: 0.2, │ │ │ │ │ - pointRadius: 6, │ │ │ │ │ - hoverPointRadius: 1, │ │ │ │ │ - hoverPointUnit: "%", │ │ │ │ │ - pointerEvents: "visiblePainted", │ │ │ │ │ - cursor: "pointer", │ │ │ │ │ - fontColor: "#000000", │ │ │ │ │ - labelAlign: "cm", │ │ │ │ │ - labelOutlineColor: "white", │ │ │ │ │ - labelOutlineWidth: 3 │ │ │ │ │ - │ │ │ │ │ - }, │ │ │ │ │ - 'temporary': { │ │ │ │ │ - fillColor: "#66cccc", │ │ │ │ │ - fillOpacity: 0.2, │ │ │ │ │ - hoverFillColor: "white", │ │ │ │ │ - hoverFillOpacity: 0.8, │ │ │ │ │ - strokeColor: "#66cccc", │ │ │ │ │ - strokeOpacity: 1, │ │ │ │ │ - strokeLinecap: "round", │ │ │ │ │ - strokeWidth: 2, │ │ │ │ │ - strokeDashstyle: "solid", │ │ │ │ │ - hoverStrokeColor: "red", │ │ │ │ │ - hoverStrokeOpacity: 1, │ │ │ │ │ - hoverStrokeWidth: 0.2, │ │ │ │ │ - pointRadius: 6, │ │ │ │ │ - hoverPointRadius: 1, │ │ │ │ │ - hoverPointUnit: "%", │ │ │ │ │ - pointerEvents: "visiblePainted", │ │ │ │ │ - cursor: "inherit", │ │ │ │ │ - fontColor: "#000000", │ │ │ │ │ - labelAlign: "cm", │ │ │ │ │ - labelOutlineColor: "white", │ │ │ │ │ - labelOutlineWidth: 3 │ │ │ │ │ - │ │ │ │ │ - }, │ │ │ │ │ - 'delete': { │ │ │ │ │ - display: "none" │ │ │ │ │ - } │ │ │ │ │ -}; │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ OpenLayers/Format.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ @@ -18560,557 +20979,14 @@ │ │ │ │ │ * Constant: OpenLayers.Format.WFST.DEFAULTS │ │ │ │ │ * {Object} Default properties for the WFST format. │ │ │ │ │ */ │ │ │ │ │ OpenLayers.Format.WFST.DEFAULTS = { │ │ │ │ │ "version": "1.0.0" │ │ │ │ │ }; │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Style.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ │ - * @requires OpenLayers/Feature/Vector.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Style │ │ │ │ │ - * This class represents a UserStyle obtained │ │ │ │ │ - * from a SLD, containing styling rules. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Style = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: id │ │ │ │ │ - * {String} A unique id for this session. │ │ │ │ │ - */ │ │ │ │ │ - id: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: name │ │ │ │ │ - * {String} │ │ │ │ │ - */ │ │ │ │ │ - name: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: title │ │ │ │ │ - * {String} Title of this style (set if included in SLD) │ │ │ │ │ - */ │ │ │ │ │ - title: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: description │ │ │ │ │ - * {String} Description of this style (set if abstract is included in SLD) │ │ │ │ │ - */ │ │ │ │ │ - description: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: layerName │ │ │ │ │ - * {} name of the layer that this style belongs to, usually │ │ │ │ │ - * according to the NamedLayer attribute of an SLD document. │ │ │ │ │ - */ │ │ │ │ │ - layerName: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: isDefault │ │ │ │ │ - * {Boolean} │ │ │ │ │ - */ │ │ │ │ │ - isDefault: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: rules │ │ │ │ │ - * {Array()} │ │ │ │ │ - */ │ │ │ │ │ - rules: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: context │ │ │ │ │ - * {Object} An optional object with properties that symbolizers' property │ │ │ │ │ - * values should be evaluated against. If no context is specified, │ │ │ │ │ - * feature.attributes will be used │ │ │ │ │ - */ │ │ │ │ │ - context: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: defaultStyle │ │ │ │ │ - * {Object} hash of style properties to use as default for merging │ │ │ │ │ - * rule-based style symbolizers onto. If no rules are defined, │ │ │ │ │ - * createSymbolizer will return this style. If is set to │ │ │ │ │ - * true, the defaultStyle will only be taken into account if there are │ │ │ │ │ - * rules defined. │ │ │ │ │ - */ │ │ │ │ │ - defaultStyle: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: defaultsPerSymbolizer │ │ │ │ │ - * {Boolean} If set to true, the will extend the symbolizer │ │ │ │ │ - * of every rule. Properties of the will also be used to set │ │ │ │ │ - * missing symbolizer properties if the symbolizer has stroke, fill or │ │ │ │ │ - * graphic set to true. Default is false. │ │ │ │ │ - */ │ │ │ │ │ - defaultsPerSymbolizer: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: propertyStyles │ │ │ │ │ - * {Hash of Boolean} cache of style properties that need to be parsed for │ │ │ │ │ - * propertyNames. Property names are keys, values won't be used. │ │ │ │ │ - */ │ │ │ │ │ - propertyStyles: null, │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Style │ │ │ │ │ - * Creates a UserStyle. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * style - {Object} Optional hash of style properties that will be │ │ │ │ │ - * used as default style for this style object. This style │ │ │ │ │ - * applies if no rules are specified. Symbolizers defined in │ │ │ │ │ - * rules will extend this default style. │ │ │ │ │ - * options - {Object} An optional object with properties to set on the │ │ │ │ │ - * style. │ │ │ │ │ - * │ │ │ │ │ - * Valid options: │ │ │ │ │ - * rules - {Array()} List of rules to be added to the │ │ │ │ │ - * style. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(style, options) { │ │ │ │ │ - │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ - this.rules = []; │ │ │ │ │ - if (options && options.rules) { │ │ │ │ │ - this.addRules(options.rules); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // use the default style from OpenLayers.Feature.Vector if no style │ │ │ │ │ - // was given in the constructor │ │ │ │ │ - this.setDefaultStyle(style || │ │ │ │ │ - OpenLayers.Feature.Vector.style["default"]); │ │ │ │ │ - │ │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ - * nullify references to prevent circular references and memory leaks │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - for (var i = 0, len = this.rules.length; i < len; i++) { │ │ │ │ │ - this.rules[i].destroy(); │ │ │ │ │ - this.rules[i] = null; │ │ │ │ │ - } │ │ │ │ │ - this.rules = null; │ │ │ │ │ - this.defaultStyle = null; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: createSymbolizer │ │ │ │ │ - * creates a style by applying all feature-dependent rules to the base │ │ │ │ │ - * style. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * feature - {} feature to evaluate rules for │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} symbolizer hash │ │ │ │ │ - */ │ │ │ │ │ - createSymbolizer: function(feature) { │ │ │ │ │ - var style = this.defaultsPerSymbolizer ? {} : this.createLiterals( │ │ │ │ │ - OpenLayers.Util.extend({}, this.defaultStyle), feature); │ │ │ │ │ - │ │ │ │ │ - var rules = this.rules; │ │ │ │ │ - │ │ │ │ │ - var rule, context; │ │ │ │ │ - var elseRules = []; │ │ │ │ │ - var appliedRules = false; │ │ │ │ │ - for (var i = 0, len = rules.length; i < len; i++) { │ │ │ │ │ - rule = rules[i]; │ │ │ │ │ - // does the rule apply? │ │ │ │ │ - var applies = rule.evaluate(feature); │ │ │ │ │ - │ │ │ │ │ - if (applies) { │ │ │ │ │ - if (rule instanceof OpenLayers.Rule && rule.elseFilter) { │ │ │ │ │ - elseRules.push(rule); │ │ │ │ │ - } else { │ │ │ │ │ - appliedRules = true; │ │ │ │ │ - this.applySymbolizer(rule, style, feature); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // if no other rules apply, apply the rules with else filters │ │ │ │ │ - if (appliedRules == false && elseRules.length > 0) { │ │ │ │ │ - appliedRules = true; │ │ │ │ │ - for (var i = 0, len = elseRules.length; i < len; i++) { │ │ │ │ │ - this.applySymbolizer(elseRules[i], style, feature); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // don't display if there were rules but none applied │ │ │ │ │ - if (rules.length > 0 && appliedRules == false) { │ │ │ │ │ - style.display = "none"; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (style.label != null && typeof style.label !== "string") { │ │ │ │ │ - style.label = String(style.label); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - return style; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: applySymbolizer │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * rule - {} │ │ │ │ │ - * style - {Object} │ │ │ │ │ - * feature - {} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} A style with new symbolizer applied. │ │ │ │ │ - */ │ │ │ │ │ - applySymbolizer: function(rule, style, feature) { │ │ │ │ │ - var symbolizerPrefix = feature.geometry ? │ │ │ │ │ - this.getSymbolizerPrefix(feature.geometry) : │ │ │ │ │ - OpenLayers.Style.SYMBOLIZER_PREFIXES[0]; │ │ │ │ │ - │ │ │ │ │ - var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer; │ │ │ │ │ - │ │ │ │ │ - if (this.defaultsPerSymbolizer === true) { │ │ │ │ │ - var defaults = this.defaultStyle; │ │ │ │ │ - OpenLayers.Util.applyDefaults(symbolizer, { │ │ │ │ │ - pointRadius: defaults.pointRadius │ │ │ │ │ - }); │ │ │ │ │ - if (symbolizer.stroke === true || symbolizer.graphic === true) { │ │ │ │ │ - OpenLayers.Util.applyDefaults(symbolizer, { │ │ │ │ │ - strokeWidth: defaults.strokeWidth, │ │ │ │ │ - strokeColor: defaults.strokeColor, │ │ │ │ │ - strokeOpacity: defaults.strokeOpacity, │ │ │ │ │ - strokeDashstyle: defaults.strokeDashstyle, │ │ │ │ │ - strokeLinecap: defaults.strokeLinecap │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ - if (symbolizer.fill === true || symbolizer.graphic === true) { │ │ │ │ │ - OpenLayers.Util.applyDefaults(symbolizer, { │ │ │ │ │ - fillColor: defaults.fillColor, │ │ │ │ │ - fillOpacity: defaults.fillOpacity │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ - if (symbolizer.graphic === true) { │ │ │ │ │ - OpenLayers.Util.applyDefaults(symbolizer, { │ │ │ │ │ - pointRadius: this.defaultStyle.pointRadius, │ │ │ │ │ - externalGraphic: this.defaultStyle.externalGraphic, │ │ │ │ │ - graphicName: this.defaultStyle.graphicName, │ │ │ │ │ - graphicOpacity: this.defaultStyle.graphicOpacity, │ │ │ │ │ - graphicWidth: this.defaultStyle.graphicWidth, │ │ │ │ │ - graphicHeight: this.defaultStyle.graphicHeight, │ │ │ │ │ - graphicXOffset: this.defaultStyle.graphicXOffset, │ │ │ │ │ - graphicYOffset: this.defaultStyle.graphicYOffset │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // merge the style with the current style │ │ │ │ │ - return this.createLiterals( │ │ │ │ │ - OpenLayers.Util.extend(style, symbolizer), feature); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: createLiterals │ │ │ │ │ - * creates literals for all style properties that have an entry in │ │ │ │ │ - * . │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * style - {Object} style to create literals for. Will be modified │ │ │ │ │ - * inline. │ │ │ │ │ - * feature - {Object} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} the modified style │ │ │ │ │ - */ │ │ │ │ │ - createLiterals: function(style, feature) { │ │ │ │ │ - var context = OpenLayers.Util.extend({}, feature.attributes || feature.data); │ │ │ │ │ - OpenLayers.Util.extend(context, this.context); │ │ │ │ │ - │ │ │ │ │ - for (var i in this.propertyStyles) { │ │ │ │ │ - style[i] = OpenLayers.Style.createLiteral(style[i], context, feature, i); │ │ │ │ │ - } │ │ │ │ │ - return style; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: findPropertyStyles │ │ │ │ │ - * Looks into all rules for this style and the defaultStyle to collect │ │ │ │ │ - * all the style hash property names containing ${...} strings that have │ │ │ │ │ - * to be replaced using the createLiteral method before returning them. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} hash of property names that need createLiteral parsing. The │ │ │ │ │ - * name of the property is the key, and the value is true; │ │ │ │ │ - */ │ │ │ │ │ - findPropertyStyles: function() { │ │ │ │ │ - var propertyStyles = {}; │ │ │ │ │ - │ │ │ │ │ - // check the default style │ │ │ │ │ - var style = this.defaultStyle; │ │ │ │ │ - this.addPropertyStyles(propertyStyles, style); │ │ │ │ │ - │ │ │ │ │ - // walk through all rules to check for properties in their symbolizer │ │ │ │ │ - var rules = this.rules; │ │ │ │ │ - var symbolizer, value; │ │ │ │ │ - for (var i = 0, len = rules.length; i < len; i++) { │ │ │ │ │ - symbolizer = rules[i].symbolizer; │ │ │ │ │ - for (var key in symbolizer) { │ │ │ │ │ - value = symbolizer[key]; │ │ │ │ │ - if (typeof value == "object") { │ │ │ │ │ - // symbolizer key is "Point", "Line" or "Polygon" │ │ │ │ │ - this.addPropertyStyles(propertyStyles, value); │ │ │ │ │ - } else { │ │ │ │ │ - // symbolizer is a hash of style properties │ │ │ │ │ - this.addPropertyStyles(propertyStyles, symbolizer); │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - return propertyStyles; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: addPropertyStyles │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * propertyStyles - {Object} hash to add new property styles to. Will be │ │ │ │ │ - * modified inline │ │ │ │ │ - * symbolizer - {Object} search this symbolizer for property styles │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} propertyStyles hash │ │ │ │ │ - */ │ │ │ │ │ - addPropertyStyles: function(propertyStyles, symbolizer) { │ │ │ │ │ - var property; │ │ │ │ │ - for (var key in symbolizer) { │ │ │ │ │ - property = symbolizer[key]; │ │ │ │ │ - if (typeof property == "string" && │ │ │ │ │ - property.match(/\$\{\w+\}/)) { │ │ │ │ │ - propertyStyles[key] = true; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - return propertyStyles; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: addRules │ │ │ │ │ - * Adds rules to this style. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * rules - {Array()} │ │ │ │ │ - */ │ │ │ │ │ - addRules: function(rules) { │ │ │ │ │ - Array.prototype.push.apply(this.rules, rules); │ │ │ │ │ - this.propertyStyles = this.findPropertyStyles(); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: setDefaultStyle │ │ │ │ │ - * Sets the default style for this style object. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * style - {Object} Hash of style properties │ │ │ │ │ - */ │ │ │ │ │ - setDefaultStyle: function(style) { │ │ │ │ │ - this.defaultStyle = style; │ │ │ │ │ - this.propertyStyles = this.findPropertyStyles(); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: getSymbolizerPrefix │ │ │ │ │ - * Returns the correct symbolizer prefix according to the │ │ │ │ │ - * geometry type of the passed geometry │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * geometry - {} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} key of the according symbolizer │ │ │ │ │ - */ │ │ │ │ │ - getSymbolizerPrefix: function(geometry) { │ │ │ │ │ - var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES; │ │ │ │ │ - for (var i = 0, len = prefixes.length; i < len; i++) { │ │ │ │ │ - if (geometry.CLASS_NAME.indexOf(prefixes[i]) != -1) { │ │ │ │ │ - return prefixes[i]; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: clone │ │ │ │ │ - * Clones this style. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} Clone of this style. │ │ │ │ │ - */ │ │ │ │ │ - clone: function() { │ │ │ │ │ - var options = OpenLayers.Util.extend({}, this); │ │ │ │ │ - // clone rules │ │ │ │ │ - if (this.rules) { │ │ │ │ │ - options.rules = []; │ │ │ │ │ - for (var i = 0, len = this.rules.length; i < len; ++i) { │ │ │ │ │ - options.rules.push(this.rules[i].clone()); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - // clone context │ │ │ │ │ - options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ │ - //clone default style │ │ │ │ │ - var defaultStyle = OpenLayers.Util.extend({}, this.defaultStyle); │ │ │ │ │ - return new OpenLayers.Style(defaultStyle, options); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Style" │ │ │ │ │ -}); │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Function: createLiteral │ │ │ │ │ - * converts a style value holding a combination of PropertyName and Literal │ │ │ │ │ - * into a Literal, taking the property values from the passed features. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * value - {String} value to parse. If this string contains a construct like │ │ │ │ │ - * "foo ${bar}", then "foo " will be taken as literal, and "${bar}" │ │ │ │ │ - * will be replaced by the value of the "bar" attribute of the passed │ │ │ │ │ - * feature. │ │ │ │ │ - * context - {Object} context to take attribute values from │ │ │ │ │ - * feature - {} optional feature to pass to │ │ │ │ │ - * for evaluating functions in the │ │ │ │ │ - * context. │ │ │ │ │ - * property - {String} optional, name of the property for which the literal is │ │ │ │ │ - * being created for evaluating functions in the context. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} the parsed value. In the example of the value parameter above, the │ │ │ │ │ - * result would be "foo valueOfBar", assuming that the passed feature has an │ │ │ │ │ - * attribute named "bar" with the value "valueOfBar". │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Style.createLiteral = function(value, context, feature, property) { │ │ │ │ │ - if (typeof value == "string" && value.indexOf("${") != -1) { │ │ │ │ │ - value = OpenLayers.String.format(value, context, [feature, property]); │ │ │ │ │ - value = (isNaN(value) || !value) ? value : parseFloat(value); │ │ │ │ │ - } │ │ │ │ │ - return value; │ │ │ │ │ -}; │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Style.SYMBOLIZER_PREFIXES │ │ │ │ │ - * {Array} prefixes of the sld symbolizers. These are the │ │ │ │ │ - * same as the main geometry types │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Style.SYMBOLIZER_PREFIXES = ['Point', 'Line', 'Polygon', 'Text', │ │ │ │ │ - 'Raster' │ │ │ │ │ -]; │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Filter.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ │ - * @requires OpenLayers/Style.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Filter │ │ │ │ │ - * This class represents an OGC Filter. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Filter = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Filter │ │ │ │ │ - * This class represents a generic filter. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ - * instance. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(options) { │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ - * Remove reference to anything added. │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() {}, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: evaluate │ │ │ │ │ - * Evaluates this filter in a specific context. Instances or subclasses │ │ │ │ │ - * are supposed to override this method. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * context - {Object} Context to use in evaluating the filter. If a vector │ │ │ │ │ - * feature is provided, the feature.attributes will be used as context. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The filter applies. │ │ │ │ │ - */ │ │ │ │ │ - evaluate: function(context) { │ │ │ │ │ - return true; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: clone │ │ │ │ │ - * Clones this filter. Should be implemented by subclasses. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} Clone of this filter. │ │ │ │ │ - */ │ │ │ │ │ - clone: function() { │ │ │ │ │ - return null; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: toString │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} Include in your build to get a CQL │ │ │ │ │ - * representation of the filter returned. Otherwise "[Object object]" │ │ │ │ │ - * will be returned. │ │ │ │ │ - */ │ │ │ │ │ - toString: function() { │ │ │ │ │ - var string; │ │ │ │ │ - if (OpenLayers.Format && OpenLayers.Format.CQL) { │ │ │ │ │ - string = OpenLayers.Format.CQL.prototype.write(this); │ │ │ │ │ - } else { │ │ │ │ │ - string = Object.prototype.toString.call(this); │ │ │ │ │ - } │ │ │ │ │ - return string; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Filter" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ OpenLayers/Filter/Spatial.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ @@ -24416,974 +26292,1463 @@ │ │ │ │ │ OpenLayers.Util.extend(this, options); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.WPSProcess.ChainLink" │ │ │ │ │ │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Format/WPSDescribeProcess.js │ │ │ │ │ + OpenLayers/Popup.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Format/XML.js │ │ │ │ │ - * @requires OpenLayers/Format/OWSCommon/v1_1_0.js │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Format.WPSDescribeProcess │ │ │ │ │ - * Read WPS DescribeProcess responses. │ │ │ │ │ + * Class: OpenLayers.Popup │ │ │ │ │ + * A popup is a small div that can opened and closed on the map. │ │ │ │ │ + * Typically opened in response to clicking on a marker. │ │ │ │ │ + * See . Popup's don't require their own │ │ │ │ │ + * layer and are added the the map using the │ │ │ │ │ + * method. │ │ │ │ │ * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * Example: │ │ │ │ │ + * (code) │ │ │ │ │ + * popup = new OpenLayers.Popup("chicken", │ │ │ │ │ + * new OpenLayers.LonLat(5,40), │ │ │ │ │ + * new OpenLayers.Size(200,200), │ │ │ │ │ + * "example popup", │ │ │ │ │ + * true); │ │ │ │ │ + * │ │ │ │ │ + * map.addPopup(popup); │ │ │ │ │ + * (end) │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Format.WPSDescribeProcess = OpenLayers.Class( │ │ │ │ │ - OpenLayers.Format.XML, { │ │ │ │ │ +OpenLayers.Popup = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constant: VERSION │ │ │ │ │ - * {String} 1.0.0 │ │ │ │ │ - */ │ │ │ │ │ - VERSION: "1.0.0", │ │ │ │ │ + /** │ │ │ │ │ + * Property: events │ │ │ │ │ + * {} custom event manager │ │ │ │ │ + */ │ │ │ │ │ + events: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: namespaces │ │ │ │ │ - * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ │ - */ │ │ │ │ │ - namespaces: { │ │ │ │ │ - wps: "http://www.opengis.net/wps/1.0.0", │ │ │ │ │ - ows: "http://www.opengis.net/ows/1.1", │ │ │ │ │ - xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ │ - }, │ │ │ │ │ + /** Property: id │ │ │ │ │ + * {String} the unique identifier assigned to this popup. │ │ │ │ │ + */ │ │ │ │ │ + id: "", │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: schemaLocation │ │ │ │ │ - * {String} Schema location │ │ │ │ │ - */ │ │ │ │ │ - schemaLocation: "http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd", │ │ │ │ │ + /** │ │ │ │ │ + * Property: lonlat │ │ │ │ │ + * {} the position of this popup on the map │ │ │ │ │ + */ │ │ │ │ │ + lonlat: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: defaultPrefix │ │ │ │ │ - */ │ │ │ │ │ - defaultPrefix: "wps", │ │ │ │ │ + /** │ │ │ │ │ + * Property: div │ │ │ │ │ + * {DOMElement} the div that contains this popup. │ │ │ │ │ + */ │ │ │ │ │ + div: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: regExes │ │ │ │ │ - * Compiled regular expressions for manipulating strings. │ │ │ │ │ - */ │ │ │ │ │ - regExes: { │ │ │ │ │ - trimSpace: (/^\s*|\s*$/g), │ │ │ │ │ - removeSpace: (/\s*/g), │ │ │ │ │ - splitSpace: (/\s+/), │ │ │ │ │ - trimComma: (/\s*,\s*/g) │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * Property: contentSize │ │ │ │ │ + * {} the width and height of the content. │ │ │ │ │ + */ │ │ │ │ │ + contentSize: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Format.WPSDescribeProcess │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ │ - * this instance. │ │ │ │ │ - */ │ │ │ │ │ + /** │ │ │ │ │ + * Property: size │ │ │ │ │ + * {} the width and height of the popup. │ │ │ │ │ + */ │ │ │ │ │ + size: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: read │ │ │ │ │ - * Parse a WPS DescribeProcess and return an object with its information. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} │ │ │ │ │ - */ │ │ │ │ │ - read: function(data) { │ │ │ │ │ - if (typeof data == "string") { │ │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ │ - } │ │ │ │ │ - if (data && data.nodeType == 9) { │ │ │ │ │ - data = data.documentElement; │ │ │ │ │ - } │ │ │ │ │ - var info = {}; │ │ │ │ │ - this.readNode(data, info); │ │ │ │ │ - return info; │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * Property: contentHTML │ │ │ │ │ + * {String} An HTML string for this popup to display. │ │ │ │ │ + */ │ │ │ │ │ + contentHTML: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: readers │ │ │ │ │ - * Contains public functions, grouped by namespace prefix, that will │ │ │ │ │ - * be applied when a namespaced node is found matching the function │ │ │ │ │ - * name. The function will be applied in the scope of this parser │ │ │ │ │ - * with two arguments: the node being read and a context object passed │ │ │ │ │ - * from the parent. │ │ │ │ │ - */ │ │ │ │ │ - readers: { │ │ │ │ │ - "wps": { │ │ │ │ │ - "ProcessDescriptions": function(node, obj) { │ │ │ │ │ - obj.processDescriptions = {}; │ │ │ │ │ - this.readChildNodes(node, obj.processDescriptions); │ │ │ │ │ - }, │ │ │ │ │ - "ProcessDescription": function(node, processDescriptions) { │ │ │ │ │ - var processVersion = this.getAttributeNS(node, this.namespaces.wps, "processVersion"); │ │ │ │ │ - var processDescription = { │ │ │ │ │ - processVersion: processVersion, │ │ │ │ │ - statusSupported: (node.getAttribute("statusSupported") === "true"), │ │ │ │ │ - storeSupported: (node.getAttribute("storeSupported") === "true") │ │ │ │ │ - }; │ │ │ │ │ - this.readChildNodes(node, processDescription); │ │ │ │ │ - processDescriptions[processDescription.identifier] = processDescription; │ │ │ │ │ - }, │ │ │ │ │ - "DataInputs": function(node, processDescription) { │ │ │ │ │ - processDescription.dataInputs = []; │ │ │ │ │ - this.readChildNodes(node, processDescription.dataInputs); │ │ │ │ │ - }, │ │ │ │ │ - "ProcessOutputs": function(node, processDescription) { │ │ │ │ │ - processDescription.processOutputs = []; │ │ │ │ │ - this.readChildNodes(node, processDescription.processOutputs); │ │ │ │ │ - }, │ │ │ │ │ - "Output": function(node, processOutputs) { │ │ │ │ │ - var output = {}; │ │ │ │ │ - this.readChildNodes(node, output); │ │ │ │ │ - processOutputs.push(output); │ │ │ │ │ - }, │ │ │ │ │ - "ComplexOutput": function(node, output) { │ │ │ │ │ - output.complexOutput = {}; │ │ │ │ │ - this.readChildNodes(node, output.complexOutput); │ │ │ │ │ - }, │ │ │ │ │ - "LiteralOutput": function(node, output) { │ │ │ │ │ - output.literalOutput = {}; │ │ │ │ │ - this.readChildNodes(node, output.literalOutput); │ │ │ │ │ - }, │ │ │ │ │ - "Input": function(node, dataInputs) { │ │ │ │ │ - var input = { │ │ │ │ │ - maxOccurs: parseInt(node.getAttribute("maxOccurs")), │ │ │ │ │ - minOccurs: parseInt(node.getAttribute("minOccurs")) │ │ │ │ │ - }; │ │ │ │ │ - this.readChildNodes(node, input); │ │ │ │ │ - dataInputs.push(input); │ │ │ │ │ - }, │ │ │ │ │ - "BoundingBoxData": function(node, input) { │ │ │ │ │ - input.boundingBoxData = {}; │ │ │ │ │ - this.readChildNodes(node, input.boundingBoxData); │ │ │ │ │ - }, │ │ │ │ │ - "CRS": function(node, obj) { │ │ │ │ │ - if (!obj.CRSs) { │ │ │ │ │ - obj.CRSs = {}; │ │ │ │ │ - } │ │ │ │ │ - obj.CRSs[this.getChildValue(node)] = true; │ │ │ │ │ - }, │ │ │ │ │ - "LiteralData": function(node, input) { │ │ │ │ │ - input.literalData = {}; │ │ │ │ │ - this.readChildNodes(node, input.literalData); │ │ │ │ │ - }, │ │ │ │ │ - "ComplexData": function(node, input) { │ │ │ │ │ - input.complexData = {}; │ │ │ │ │ - this.readChildNodes(node, input.complexData); │ │ │ │ │ - }, │ │ │ │ │ - "Default": function(node, complexData) { │ │ │ │ │ - complexData["default"] = {}; │ │ │ │ │ - this.readChildNodes(node, complexData["default"]); │ │ │ │ │ - }, │ │ │ │ │ - "Supported": function(node, complexData) { │ │ │ │ │ - complexData["supported"] = {}; │ │ │ │ │ - this.readChildNodes(node, complexData["supported"]); │ │ │ │ │ - }, │ │ │ │ │ - "Format": function(node, obj) { │ │ │ │ │ - var format = {}; │ │ │ │ │ - this.readChildNodes(node, format); │ │ │ │ │ - if (!obj.formats) { │ │ │ │ │ - obj.formats = {}; │ │ │ │ │ - } │ │ │ │ │ - obj.formats[format.mimeType] = true; │ │ │ │ │ - }, │ │ │ │ │ - "MimeType": function(node, format) { │ │ │ │ │ - format.mimeType = this.getChildValue(node); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * Property: backgroundColor │ │ │ │ │ + * {String} the background color used by the popup. │ │ │ │ │ + */ │ │ │ │ │ + backgroundColor: "", │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.WPSDescribeProcess" │ │ │ │ │ + /** │ │ │ │ │ + * Property: opacity │ │ │ │ │ + * {float} the opacity of this popup (between 0.0 and 1.0) │ │ │ │ │ + */ │ │ │ │ │ + opacity: "", │ │ │ │ │ │ │ │ │ │ - }); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/WPSClient.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ + /** │ │ │ │ │ + * Property: border │ │ │ │ │ + * {String} the border size of the popup. (eg 2px) │ │ │ │ │ + */ │ │ │ │ │ + border: "", │ │ │ │ │ │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ + /** │ │ │ │ │ + * Property: contentDiv │ │ │ │ │ + * {DOMElement} a reference to the element that holds the content of │ │ │ │ │ + * the div. │ │ │ │ │ + */ │ │ │ │ │ + contentDiv: null, │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/SingleFile.js │ │ │ │ │ - */ │ │ │ │ │ + /** │ │ │ │ │ + * Property: groupDiv │ │ │ │ │ + * {DOMElement} First and only child of 'div'. The group Div contains the │ │ │ │ │ + * 'contentDiv' and the 'closeDiv'. │ │ │ │ │ + */ │ │ │ │ │ + groupDiv: null, │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Events.js │ │ │ │ │ - * @requires OpenLayers/WPSProcess.js │ │ │ │ │ - * @requires OpenLayers/Format/WPSDescribeProcess.js │ │ │ │ │ - * @requires OpenLayers/Request.js │ │ │ │ │ - */ │ │ │ │ │ + /** │ │ │ │ │ + * Property: closeDiv │ │ │ │ │ + * {DOMElement} the optional closer image │ │ │ │ │ + */ │ │ │ │ │ + closeDiv: null, │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.WPSClient │ │ │ │ │ - * High level API for interaction with Web Processing Services (WPS). │ │ │ │ │ - * An instance is used to create │ │ │ │ │ - * instances for servers known to the WPSClient. The WPSClient also caches │ │ │ │ │ - * DescribeProcess responses to reduce the number of requests sent to servers │ │ │ │ │ - * when processes are created. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.WPSClient = OpenLayers.Class({ │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: autoSize │ │ │ │ │ + * {Boolean} Resize the popup to auto-fit the contents. │ │ │ │ │ + * Default is false. │ │ │ │ │ + */ │ │ │ │ │ + autoSize: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: servers │ │ │ │ │ - * {Object} Service metadata, keyed by a local identifier. │ │ │ │ │ - * │ │ │ │ │ - * Properties: │ │ │ │ │ - * url - {String} the url of the server │ │ │ │ │ - * version - {String} WPS version of the server │ │ │ │ │ - * processDescription - {Object} Cache of raw DescribeProcess │ │ │ │ │ - * responses, keyed by process identifier. │ │ │ │ │ + * APIProperty: minSize │ │ │ │ │ + * {} Minimum size allowed for the popup's contents. │ │ │ │ │ */ │ │ │ │ │ - servers: null, │ │ │ │ │ + minSize: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: version │ │ │ │ │ - * {String} The default WPS version to use if none is configured. Default │ │ │ │ │ - * is '1.0.0'. │ │ │ │ │ + * APIProperty: maxSize │ │ │ │ │ + * {} Maximum size allowed for the popup's contents. │ │ │ │ │ */ │ │ │ │ │ - version: '1.0.0', │ │ │ │ │ + maxSize: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: lazy │ │ │ │ │ - * {Boolean} Should the DescribeProcess be deferred until a process is │ │ │ │ │ - * fully configured? Default is false. │ │ │ │ │ + /** │ │ │ │ │ + * Property: displayClass │ │ │ │ │ + * {String} The CSS class of the popup. │ │ │ │ │ */ │ │ │ │ │ - lazy: false, │ │ │ │ │ + displayClass: "olPopup", │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: events │ │ │ │ │ - * {} │ │ │ │ │ - * │ │ │ │ │ - * Supported event types: │ │ │ │ │ - * describeprocess - Fires when the process description is available. │ │ │ │ │ - * Listeners receive an object with a 'raw' property holding the raw │ │ │ │ │ - * DescribeProcess response, and an 'identifier' property holding the │ │ │ │ │ - * process identifier of the described process. │ │ │ │ │ + /** │ │ │ │ │ + * Property: contentDisplayClass │ │ │ │ │ + * {String} The CSS class of the popup content div. │ │ │ │ │ */ │ │ │ │ │ - events: null, │ │ │ │ │ + contentDisplayClass: "olPopupContent", │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.WPSClient │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} Object whose properties will be set on the instance. │ │ │ │ │ - * │ │ │ │ │ - * Avaliable options: │ │ │ │ │ - * servers - {Object} Mandatory. Service metadata, keyed by a local │ │ │ │ │ - * identifier. Can either be a string with the service url or an │ │ │ │ │ - * object literal with additional metadata: │ │ │ │ │ - * │ │ │ │ │ - * (code) │ │ │ │ │ - * servers: { │ │ │ │ │ - * local: '/geoserver/wps' │ │ │ │ │ - * }, { │ │ │ │ │ - * opengeo: { │ │ │ │ │ - * url: 'http://demo.opengeo.org/geoserver/wps', │ │ │ │ │ - * version: '1.0.0' │ │ │ │ │ - * } │ │ │ │ │ - * } │ │ │ │ │ - * (end) │ │ │ │ │ - * │ │ │ │ │ - * lazy - {Boolean} Optional. Set to true if DescribeProcess should not be │ │ │ │ │ - * requested until a process is fully configured. Default is false. │ │ │ │ │ + /** │ │ │ │ │ + * Property: padding │ │ │ │ │ + * {int or } An extra opportunity to specify internal │ │ │ │ │ + * padding of the content div inside the popup. This was originally │ │ │ │ │ + * confused with the css padding as specified in style.css's │ │ │ │ │ + * 'olPopupContent' class. We would like to get rid of this altogether, │ │ │ │ │ + * except that it does come in handy for the framed and anchoredbubble │ │ │ │ │ + * popups, who need to maintain yet another barrier between their │ │ │ │ │ + * content and the outer border of the popup itself. │ │ │ │ │ + * │ │ │ │ │ + * Note that in order to not break API, we must continue to support │ │ │ │ │ + * this property being set as an integer. Really, though, we'd like to │ │ │ │ │ + * have this specified as a Bounds object so that user can specify │ │ │ │ │ + * distinct left, top, right, bottom paddings. With the 3.0 release │ │ │ │ │ + * we can make this only a bounds. │ │ │ │ │ */ │ │ │ │ │ - initialize: function(options) { │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ - this.events = new OpenLayers.Events(this); │ │ │ │ │ - this.servers = {}; │ │ │ │ │ - for (var s in options.servers) { │ │ │ │ │ - this.servers[s] = typeof options.servers[s] == 'string' ? { │ │ │ │ │ - url: options.servers[s], │ │ │ │ │ - version: this.version, │ │ │ │ │ - processDescription: {} │ │ │ │ │ - } : options.servers[s]; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ + padding: 0, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: execute │ │ │ │ │ - * Shortcut to execute a process with a single function call. This is │ │ │ │ │ - * equivalent to using and then calling execute on the │ │ │ │ │ - * process. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} Options for the execute operation. │ │ │ │ │ - * │ │ │ │ │ - * Available options: │ │ │ │ │ - * server - {String} Mandatory. One of the local identifiers of the │ │ │ │ │ - * configured servers. │ │ │ │ │ - * process - {String} Mandatory. A process identifier known to the │ │ │ │ │ - * server. │ │ │ │ │ - * inputs - {Object} The inputs for the process, keyed by input identifier. │ │ │ │ │ - * For spatial data inputs, the value of an input is usually an │ │ │ │ │ - * , an or an array of │ │ │ │ │ - * geometries or features. │ │ │ │ │ - * output - {String} The identifier of an output to parse. Optional. If not │ │ │ │ │ - * provided, the first output will be parsed. │ │ │ │ │ - * success - {Function} Callback to call when the process is complete. │ │ │ │ │ - * This function is called with an outputs object as argument, which │ │ │ │ │ - * will have a property with the identifier of the requested output │ │ │ │ │ - * (e.g. 'result'). For processes that generate spatial output, the │ │ │ │ │ - * value will either be a single or an │ │ │ │ │ - * array of features. │ │ │ │ │ - * scope - {Object} Optional scope for the success callback. │ │ │ │ │ + /** │ │ │ │ │ + * Property: disableFirefoxOverflowHack │ │ │ │ │ + * {Boolean} The hack for overflow in Firefox causes all elements │ │ │ │ │ + * to be re-drawn, which causes Flash elements to be │ │ │ │ │ + * re-initialized, which is troublesome. │ │ │ │ │ + * With this property the hack can be disabled. │ │ │ │ │ */ │ │ │ │ │ - execute: function(options) { │ │ │ │ │ - var process = this.getProcess(options.server, options.process); │ │ │ │ │ - process.execute({ │ │ │ │ │ - inputs: options.inputs, │ │ │ │ │ - success: options.success, │ │ │ │ │ - scope: options.scope │ │ │ │ │ - }); │ │ │ │ │ - }, │ │ │ │ │ + disableFirefoxOverflowHack: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: getProcess │ │ │ │ │ - * Creates an . │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * serverID - {String} Local identifier from the servers that this instance │ │ │ │ │ - * was constructed with. │ │ │ │ │ - * processID - {String} Process identifier known to the server. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} │ │ │ │ │ + * Method: fixPadding │ │ │ │ │ + * To be removed in 3.0, this function merely helps us to deal with the │ │ │ │ │ + * case where the user may have set an integer value for padding, │ │ │ │ │ + * instead of an object. │ │ │ │ │ */ │ │ │ │ │ - getProcess: function(serverID, processID) { │ │ │ │ │ - var process = new OpenLayers.WPSProcess({ │ │ │ │ │ - client: this, │ │ │ │ │ - server: serverID, │ │ │ │ │ - identifier: processID │ │ │ │ │ - }); │ │ │ │ │ - if (!this.lazy) { │ │ │ │ │ - process.describe(); │ │ │ │ │ + fixPadding: function() { │ │ │ │ │ + if (typeof this.padding == "number") { │ │ │ │ │ + this.padding = new OpenLayers.Bounds( │ │ │ │ │ + this.padding, this.padding, this.padding, this.padding │ │ │ │ │ + ); │ │ │ │ │ } │ │ │ │ │ - return process; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: describeProcess │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * serverID - {String} Identifier of the server │ │ │ │ │ - * processID - {String} Identifier of the requested process │ │ │ │ │ - * callback - {Function} Callback to call when the description is available │ │ │ │ │ - * scope - {Object} Optional execution scope for the callback function │ │ │ │ │ + * APIProperty: panMapIfOutOfView │ │ │ │ │ + * {Boolean} When drawn, pan map such that the entire popup is visible in │ │ │ │ │ + * the current viewport (if necessary). │ │ │ │ │ + * Default is false. │ │ │ │ │ */ │ │ │ │ │ - describeProcess: function(serverID, processID, callback, scope) { │ │ │ │ │ - var server = this.servers[serverID]; │ │ │ │ │ - if (!server.processDescription[processID]) { │ │ │ │ │ - if (!(processID in server.processDescription)) { │ │ │ │ │ - // set to null so we know a describeFeature request is pending │ │ │ │ │ - server.processDescription[processID] = null; │ │ │ │ │ - OpenLayers.Request.GET({ │ │ │ │ │ - url: server.url, │ │ │ │ │ - params: { │ │ │ │ │ - SERVICE: 'WPS', │ │ │ │ │ - VERSION: server.version, │ │ │ │ │ - REQUEST: 'DescribeProcess', │ │ │ │ │ - IDENTIFIER: processID │ │ │ │ │ - }, │ │ │ │ │ - success: function(response) { │ │ │ │ │ - server.processDescription[processID] = response.responseText; │ │ │ │ │ - this.events.triggerEvent('describeprocess', { │ │ │ │ │ - identifier: processID, │ │ │ │ │ - raw: response.responseText │ │ │ │ │ - }); │ │ │ │ │ - }, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ - } else { │ │ │ │ │ - // pending request │ │ │ │ │ - this.events.register('describeprocess', this, function describe(evt) { │ │ │ │ │ - if (evt.identifier === processID) { │ │ │ │ │ - this.events.unregister('describeprocess', this, describe); │ │ │ │ │ - callback.call(scope, evt.raw); │ │ │ │ │ - } │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ - } else { │ │ │ │ │ - window.setTimeout(function() { │ │ │ │ │ - callback.call(scope, server.processDescription[processID]); │ │ │ │ │ - }, 0); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ + panMapIfOutOfView: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: destroy │ │ │ │ │ + * APIProperty: keepInMap │ │ │ │ │ + * {Boolean} If panMapIfOutOfView is false, and this property is true, │ │ │ │ │ + * contrain the popup such that it always fits in the available map │ │ │ │ │ + * space. By default, this is not set on the base class. If you are │ │ │ │ │ + * creating popups that are near map edges and not allowing pannning, │ │ │ │ │ + * and especially if you have a popup which has a │ │ │ │ │ + * fixedRelativePosition, setting this to false may be a smart thing to │ │ │ │ │ + * do. Subclasses may want to override this setting. │ │ │ │ │ + * │ │ │ │ │ + * Default is false. │ │ │ │ │ */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - this.events.destroy(); │ │ │ │ │ - this.events = null; │ │ │ │ │ - this.servers = null; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: 'OpenLayers.WPSClient' │ │ │ │ │ - │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Icon.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Icon │ │ │ │ │ - * │ │ │ │ │ - * The icon represents a graphical icon on the screen. Typically used in │ │ │ │ │ - * conjunction with a to represent markers on a screen. │ │ │ │ │ - * │ │ │ │ │ - * An icon has a url, size and position. It also contains an offset which │ │ │ │ │ - * allows the center point to be represented correctly. This can be │ │ │ │ │ - * provided either as a fixed offset or a function provided to calculate │ │ │ │ │ - * the desired offset. │ │ │ │ │ - * │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Icon = OpenLayers.Class({ │ │ │ │ │ + keepInMap: false, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: url │ │ │ │ │ - * {String} image url │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: closeOnMove │ │ │ │ │ + * {Boolean} When map pans, close the popup. │ │ │ │ │ + * Default is false. │ │ │ │ │ */ │ │ │ │ │ - url: null, │ │ │ │ │ + closeOnMove: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: size │ │ │ │ │ - * {|Object} An OpenLayers.Size or │ │ │ │ │ - * an object with a 'w' and 'h' properties. │ │ │ │ │ + * Property: map │ │ │ │ │ + * {} this gets set in Map.js when the popup is added to the map │ │ │ │ │ */ │ │ │ │ │ - size: null, │ │ │ │ │ + map: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: offset │ │ │ │ │ - * {|Object} distance in pixels to offset the │ │ │ │ │ - * image when being rendered. An OpenLayers.Pixel or an object │ │ │ │ │ - * with a 'x' and 'y' properties. │ │ │ │ │ + * Constructor: OpenLayers.Popup │ │ │ │ │ + * Create a popup. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * id - {String} a unqiue identifier for this popup. If null is passed │ │ │ │ │ + * an identifier will be automatically generated. │ │ │ │ │ + * lonlat - {} The position on the map the popup will │ │ │ │ │ + * be shown. │ │ │ │ │ + * contentSize - {} The size of the content. │ │ │ │ │ + * contentHTML - {String} An HTML string to display inside the │ │ │ │ │ + * popup. │ │ │ │ │ + * closeBox - {Boolean} Whether to display a close box inside │ │ │ │ │ + * the popup. │ │ │ │ │ + * closeBoxCallback - {Function} Function to be called on closeBox click. │ │ │ │ │ */ │ │ │ │ │ - offset: null, │ │ │ │ │ + initialize: function(id, lonlat, contentSize, contentHTML, closeBox, closeBoxCallback) { │ │ │ │ │ + if (id == null) { │ │ │ │ │ + id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: calculateOffset │ │ │ │ │ - * {Function} Function to calculate the offset (based on the size) │ │ │ │ │ - */ │ │ │ │ │ - calculateOffset: null, │ │ │ │ │ + this.id = id; │ │ │ │ │ + this.lonlat = lonlat; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: imageDiv │ │ │ │ │ - * {DOMElement} │ │ │ │ │ - */ │ │ │ │ │ - imageDiv: null, │ │ │ │ │ + this.contentSize = (contentSize != null) ? contentSize : │ │ │ │ │ + new OpenLayers.Size( │ │ │ │ │ + OpenLayers.Popup.WIDTH, │ │ │ │ │ + OpenLayers.Popup.HEIGHT); │ │ │ │ │ + if (contentHTML != null) { │ │ │ │ │ + this.contentHTML = contentHTML; │ │ │ │ │ + } │ │ │ │ │ + this.backgroundColor = OpenLayers.Popup.COLOR; │ │ │ │ │ + this.opacity = OpenLayers.Popup.OPACITY; │ │ │ │ │ + this.border = OpenLayers.Popup.BORDER; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: px │ │ │ │ │ - * {|Object} An OpenLayers.Pixel or an object │ │ │ │ │ - * with a 'x' and 'y' properties. │ │ │ │ │ - */ │ │ │ │ │ - px: null, │ │ │ │ │ + this.div = OpenLayers.Util.createDiv(this.id, null, null, │ │ │ │ │ + null, null, null, "hidden"); │ │ │ │ │ + this.div.className = this.displayClass; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Icon │ │ │ │ │ - * Creates an icon, which is an image tag in a div. │ │ │ │ │ - * │ │ │ │ │ - * url - {String} │ │ │ │ │ - * size - {|Object} An OpenLayers.Size or an │ │ │ │ │ - * object with a 'w' and 'h' │ │ │ │ │ - * properties. │ │ │ │ │ - * offset - {|Object} An OpenLayers.Pixel or an │ │ │ │ │ - * object with a 'x' and 'y' │ │ │ │ │ - * properties. │ │ │ │ │ - * calculateOffset - {Function} │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(url, size, offset, calculateOffset) { │ │ │ │ │ - this.url = url; │ │ │ │ │ - this.size = size || { │ │ │ │ │ - w: 20, │ │ │ │ │ - h: 20 │ │ │ │ │ - }; │ │ │ │ │ - this.offset = offset || { │ │ │ │ │ - x: -(this.size.w / 2), │ │ │ │ │ - y: -(this.size.h / 2) │ │ │ │ │ - }; │ │ │ │ │ - this.calculateOffset = calculateOffset; │ │ │ │ │ + var groupDivId = this.id + "_GroupDiv"; │ │ │ │ │ + this.groupDiv = OpenLayers.Util.createDiv(groupDivId, null, null, │ │ │ │ │ + null, "relative", null, │ │ │ │ │ + "hidden"); │ │ │ │ │ │ │ │ │ │ - var id = OpenLayers.Util.createUniqueID("OL_Icon_"); │ │ │ │ │ - this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id); │ │ │ │ │ + var id = this.div.id + "_contentDiv"; │ │ │ │ │ + this.contentDiv = OpenLayers.Util.createDiv(id, null, this.contentSize.clone(), │ │ │ │ │ + null, "relative"); │ │ │ │ │ + this.contentDiv.className = this.contentDisplayClass; │ │ │ │ │ + this.groupDiv.appendChild(this.contentDiv); │ │ │ │ │ + this.div.appendChild(this.groupDiv); │ │ │ │ │ + │ │ │ │ │ + if (closeBox) { │ │ │ │ │ + this.addCloseBox(closeBoxCallback); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.registerEvents(); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ * Method: destroy │ │ │ │ │ - * Nullify references and remove event listeners to prevent circular │ │ │ │ │ - * references and memory leaks │ │ │ │ │ + * nullify references to prevent circular references and memory leaks │ │ │ │ │ */ │ │ │ │ │ destroy: function() { │ │ │ │ │ - // erase any drawn elements │ │ │ │ │ - this.erase(); │ │ │ │ │ │ │ │ │ │ - OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild); │ │ │ │ │ - this.imageDiv.innerHTML = ""; │ │ │ │ │ - this.imageDiv = null; │ │ │ │ │ + this.id = null; │ │ │ │ │ + this.lonlat = null; │ │ │ │ │ + this.size = null; │ │ │ │ │ + this.contentHTML = null; │ │ │ │ │ + │ │ │ │ │ + this.backgroundColor = null; │ │ │ │ │ + this.opacity = null; │ │ │ │ │ + this.border = null; │ │ │ │ │ + │ │ │ │ │ + if (this.closeOnMove && this.map) { │ │ │ │ │ + this.map.events.unregister("movestart", this, this.hide); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.events.destroy(); │ │ │ │ │ + this.events = null; │ │ │ │ │ + │ │ │ │ │ + if (this.closeDiv) { │ │ │ │ │ + OpenLayers.Event.stopObservingElement(this.closeDiv); │ │ │ │ │ + this.groupDiv.removeChild(this.closeDiv); │ │ │ │ │ + } │ │ │ │ │ + this.closeDiv = null; │ │ │ │ │ + │ │ │ │ │ + this.div.removeChild(this.groupDiv); │ │ │ │ │ + this.groupDiv = null; │ │ │ │ │ + │ │ │ │ │ + if (this.map != null) { │ │ │ │ │ + this.map.removePopup(this); │ │ │ │ │ + } │ │ │ │ │ + this.map = null; │ │ │ │ │ + this.div = null; │ │ │ │ │ + │ │ │ │ │ + this.autoSize = null; │ │ │ │ │ + this.minSize = null; │ │ │ │ │ + this.maxSize = null; │ │ │ │ │ + this.padding = null; │ │ │ │ │ + this.panMapIfOutOfView = null; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: clone │ │ │ │ │ + * Method: draw │ │ │ │ │ + * Constructs the elements that make up the popup. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * px - {} the position the popup in pixels. │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {} A fresh copy of the icon. │ │ │ │ │ + * {DOMElement} Reference to a div that contains the drawn popup │ │ │ │ │ */ │ │ │ │ │ - clone: function() { │ │ │ │ │ - return new OpenLayers.Icon(this.url, │ │ │ │ │ - this.size, │ │ │ │ │ - this.offset, │ │ │ │ │ - this.calculateOffset); │ │ │ │ │ + draw: function(px) { │ │ │ │ │ + if (px == null) { │ │ │ │ │ + if ((this.lonlat != null) && (this.map != null)) { │ │ │ │ │ + px = this.map.getLayerPxFromLonLat(this.lonlat); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // this assumes that this.map already exists, which is okay because │ │ │ │ │ + // this.draw is only called once the popup has been added to the map. │ │ │ │ │ + if (this.closeOnMove) { │ │ │ │ │ + this.map.events.register("movestart", this, this.hide); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + //listen to movestart, moveend to disable overflow (FF bug) │ │ │ │ │ + if (!this.disableFirefoxOverflowHack && OpenLayers.BROWSER_NAME == 'firefox') { │ │ │ │ │ + this.map.events.register("movestart", this, function() { │ │ │ │ │ + var style = document.defaultView.getComputedStyle( │ │ │ │ │ + this.contentDiv, null │ │ │ │ │ + ); │ │ │ │ │ + var currentOverflow = style.getPropertyValue("overflow"); │ │ │ │ │ + if (currentOverflow != "hidden") { │ │ │ │ │ + this.contentDiv._oldOverflow = currentOverflow; │ │ │ │ │ + this.contentDiv.style.overflow = "hidden"; │ │ │ │ │ + } │ │ │ │ │ + }); │ │ │ │ │ + this.map.events.register("moveend", this, function() { │ │ │ │ │ + var oldOverflow = this.contentDiv._oldOverflow; │ │ │ │ │ + if (oldOverflow) { │ │ │ │ │ + this.contentDiv.style.overflow = oldOverflow; │ │ │ │ │ + this.contentDiv._oldOverflow = null; │ │ │ │ │ + } │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.moveTo(px); │ │ │ │ │ + if (!this.autoSize && !this.size) { │ │ │ │ │ + this.setSize(this.contentSize); │ │ │ │ │ + } │ │ │ │ │ + this.setBackgroundColor(); │ │ │ │ │ + this.setOpacity(); │ │ │ │ │ + this.setBorder(); │ │ │ │ │ + this.setContentHTML(); │ │ │ │ │ + │ │ │ │ │ + if (this.panMapIfOutOfView) { │ │ │ │ │ + this.panIntoView(); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + return this.div; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: setSize │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * size - {|Object} An OpenLayers.Size or │ │ │ │ │ - * an object with a 'w' and 'h' properties. │ │ │ │ │ + /** │ │ │ │ │ + * Method: updatePosition │ │ │ │ │ + * if the popup has a lonlat and its map members set, │ │ │ │ │ + * then have it move itself to its proper position │ │ │ │ │ */ │ │ │ │ │ - setSize: function(size) { │ │ │ │ │ - if (size != null) { │ │ │ │ │ - this.size = size; │ │ │ │ │ + updatePosition: function() { │ │ │ │ │ + if ((this.lonlat) && (this.map)) { │ │ │ │ │ + var px = this.map.getLayerPxFromLonLat(this.lonlat); │ │ │ │ │ + if (px) { │ │ │ │ │ + this.moveTo(px); │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ - this.draw(); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: setUrl │ │ │ │ │ + * Method: moveTo │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * url - {String} │ │ │ │ │ + * px - {} the top and left position of the popup div. │ │ │ │ │ */ │ │ │ │ │ - setUrl: function(url) { │ │ │ │ │ - if (url != null) { │ │ │ │ │ - this.url = url; │ │ │ │ │ + moveTo: function(px) { │ │ │ │ │ + if ((px != null) && (this.div != null)) { │ │ │ │ │ + this.div.style.left = px.x + "px"; │ │ │ │ │ + this.div.style.top = px.y + "px"; │ │ │ │ │ } │ │ │ │ │ - this.draw(); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: draw │ │ │ │ │ - * Move the div to the given pixel. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * px - {|Object} An OpenLayers.Pixel or an │ │ │ │ │ - * object with a 'x' and 'y' properties. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {DOMElement} A new DOM Image of this icon set at the location passed-in │ │ │ │ │ + /** │ │ │ │ │ + * Method: visible │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Boolean indicating whether or not the popup is visible │ │ │ │ │ */ │ │ │ │ │ - draw: function(px) { │ │ │ │ │ - OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, │ │ │ │ │ - null, │ │ │ │ │ - null, │ │ │ │ │ - this.size, │ │ │ │ │ - this.url, │ │ │ │ │ - "absolute"); │ │ │ │ │ - this.moveTo(px); │ │ │ │ │ - return this.imageDiv; │ │ │ │ │ + visible: function() { │ │ │ │ │ + return OpenLayers.Element.visible(this.div); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: erase │ │ │ │ │ - * Erase the underlying image element. │ │ │ │ │ + /** │ │ │ │ │ + * Method: toggle │ │ │ │ │ + * Toggles visibility of the popup. │ │ │ │ │ */ │ │ │ │ │ - erase: function() { │ │ │ │ │ - if (this.imageDiv != null && this.imageDiv.parentNode != null) { │ │ │ │ │ - OpenLayers.Element.remove(this.imageDiv); │ │ │ │ │ + toggle: function() { │ │ │ │ │ + if (this.visible()) { │ │ │ │ │ + this.hide(); │ │ │ │ │ + } else { │ │ │ │ │ + this.show(); │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: setOpacity │ │ │ │ │ - * Change the icon's opacity │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * opacity - {float} │ │ │ │ │ + /** │ │ │ │ │ + * Method: show │ │ │ │ │ + * Makes the popup visible. │ │ │ │ │ */ │ │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ │ - OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, │ │ │ │ │ - null, null, null, null, opacity); │ │ │ │ │ + show: function() { │ │ │ │ │ + this.div.style.display = ''; │ │ │ │ │ │ │ │ │ │ + if (this.panMapIfOutOfView) { │ │ │ │ │ + this.panIntoView(); │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: moveTo │ │ │ │ │ - * move icon to passed in px. │ │ │ │ │ + * Method: hide │ │ │ │ │ + * Makes the popup invisible. │ │ │ │ │ + */ │ │ │ │ │ + hide: function() { │ │ │ │ │ + this.div.style.display = 'none'; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: setSize │ │ │ │ │ + * Used to adjust the size of the popup. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * px - {|Object} the pixel position to move to. │ │ │ │ │ - * An OpenLayers.Pixel or an object with a 'x' and 'y' properties. │ │ │ │ │ + * contentSize - {} the new size for the popup's │ │ │ │ │ + * contents div (in pixels). │ │ │ │ │ */ │ │ │ │ │ - moveTo: function(px) { │ │ │ │ │ - //if no px passed in, use stored location │ │ │ │ │ - if (px != null) { │ │ │ │ │ - this.px = px; │ │ │ │ │ + setSize: function(contentSize) { │ │ │ │ │ + this.size = contentSize.clone(); │ │ │ │ │ + │ │ │ │ │ + // if our contentDiv has a css 'padding' set on it by a stylesheet, we │ │ │ │ │ + // must add that to the desired "size". │ │ │ │ │ + var contentDivPadding = this.getContentDivPadding(); │ │ │ │ │ + var wPadding = contentDivPadding.left + contentDivPadding.right; │ │ │ │ │ + var hPadding = contentDivPadding.top + contentDivPadding.bottom; │ │ │ │ │ + │ │ │ │ │ + // take into account the popup's 'padding' property │ │ │ │ │ + this.fixPadding(); │ │ │ │ │ + wPadding += this.padding.left + this.padding.right; │ │ │ │ │ + hPadding += this.padding.top + this.padding.bottom; │ │ │ │ │ + │ │ │ │ │ + // make extra space for the close div │ │ │ │ │ + if (this.closeDiv) { │ │ │ │ │ + var closeDivWidth = parseInt(this.closeDiv.style.width); │ │ │ │ │ + wPadding += closeDivWidth + contentDivPadding.right; │ │ │ │ │ } │ │ │ │ │ │ │ │ │ │ - if (this.imageDiv != null) { │ │ │ │ │ - if (this.px == null) { │ │ │ │ │ - this.display(false); │ │ │ │ │ - } else { │ │ │ │ │ - if (this.calculateOffset) { │ │ │ │ │ - this.offset = this.calculateOffset(this.size); │ │ │ │ │ - } │ │ │ │ │ - OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, { │ │ │ │ │ - x: this.px.x + this.offset.x, │ │ │ │ │ - y: this.px.y + this.offset.y │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ + //increase size of the main popup div to take into account the │ │ │ │ │ + // users's desired padding and close div. │ │ │ │ │ + this.size.w += wPadding; │ │ │ │ │ + this.size.h += hPadding; │ │ │ │ │ + │ │ │ │ │ + //now if our browser is IE, we need to actually make the contents │ │ │ │ │ + // div itself bigger to take its own padding into effect. this makes │ │ │ │ │ + // me want to shoot someone, but so it goes. │ │ │ │ │ + if (OpenLayers.BROWSER_NAME == "msie") { │ │ │ │ │ + this.contentSize.w += │ │ │ │ │ + contentDivPadding.left + contentDivPadding.right; │ │ │ │ │ + this.contentSize.h += │ │ │ │ │ + contentDivPadding.bottom + contentDivPadding.top; │ │ │ │ │ } │ │ │ │ │ - }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: display │ │ │ │ │ - * Hide or show the icon │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * display - {Boolean} │ │ │ │ │ - */ │ │ │ │ │ - display: function(display) { │ │ │ │ │ - this.imageDiv.style.display = (display) ? "" : "none"; │ │ │ │ │ + if (this.div != null) { │ │ │ │ │ + this.div.style.width = this.size.w + "px"; │ │ │ │ │ + this.div.style.height = this.size.h + "px"; │ │ │ │ │ + } │ │ │ │ │ + if (this.contentDiv != null) { │ │ │ │ │ + this.contentDiv.style.width = contentSize.w + "px"; │ │ │ │ │ + this.contentDiv.style.height = contentSize.h + "px"; │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: isDrawn │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} Whether or not the icon is drawn. │ │ │ │ │ + * APIMethod: updateSize │ │ │ │ │ + * Auto size the popup so that it precisely fits its contents (as │ │ │ │ │ + * determined by this.contentDiv.innerHTML). Popup size will, of │ │ │ │ │ + * course, be limited by the available space on the current map │ │ │ │ │ */ │ │ │ │ │ - isDrawn: function() { │ │ │ │ │ - // nodeType 11 for ie, whose nodes *always* have a parentNode │ │ │ │ │ - // (of type document fragment) │ │ │ │ │ - var isDrawn = (this.imageDiv && this.imageDiv.parentNode && │ │ │ │ │ - (this.imageDiv.parentNode.nodeType != 11)); │ │ │ │ │ + updateSize: function() { │ │ │ │ │ │ │ │ │ │ - return isDrawn; │ │ │ │ │ - }, │ │ │ │ │ + // determine actual render dimensions of the contents by putting its │ │ │ │ │ + // contents into a fake contentDiv (for the CSS) and then measuring it │ │ │ │ │ + var preparedHTML = "
" + │ │ │ │ │ + this.contentDiv.innerHTML + │ │ │ │ │ + "
"; │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Icon" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Protocol.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ + var containerElement = (this.map) ? this.map.div : document.body; │ │ │ │ │ + var realSize = OpenLayers.Util.getRenderedDimensions( │ │ │ │ │ + preparedHTML, null, { │ │ │ │ │ + displayClass: this.displayClass, │ │ │ │ │ + containerElement: containerElement │ │ │ │ │ + } │ │ │ │ │ + ); │ │ │ │ │ │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ + // is the "real" size of the div is safe to display in our map? │ │ │ │ │ + var safeSize = this.getSafeContentSize(realSize); │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - */ │ │ │ │ │ + var newSize = null; │ │ │ │ │ + if (safeSize.equals(realSize)) { │ │ │ │ │ + //real size of content is small enough to fit on the map, │ │ │ │ │ + // so we use real size. │ │ │ │ │ + newSize = realSize; │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Protocol │ │ │ │ │ - * Abstract vector layer protocol class. Not to be instantiated directly. Use │ │ │ │ │ - * one of the protocol subclasses instead. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Protocol = OpenLayers.Class({ │ │ │ │ │ + } else { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: format │ │ │ │ │ - * {} The format used by this protocol. │ │ │ │ │ - */ │ │ │ │ │ - format: null, │ │ │ │ │ + // make a new 'size' object with the clipped dimensions │ │ │ │ │ + // set or null if not clipped. │ │ │ │ │ + var fixedSize = { │ │ │ │ │ + w: (safeSize.w < realSize.w) ? safeSize.w : null, │ │ │ │ │ + h: (safeSize.h < realSize.h) ? safeSize.h : null │ │ │ │ │ + }; │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: options │ │ │ │ │ - * {Object} Any options sent to the constructor. │ │ │ │ │ - */ │ │ │ │ │ - options: null, │ │ │ │ │ + if (fixedSize.w && fixedSize.h) { │ │ │ │ │ + //content is too big in both directions, so we will use │ │ │ │ │ + // max popup size (safeSize), knowing well that it will │ │ │ │ │ + // overflow both ways. │ │ │ │ │ + newSize = safeSize; │ │ │ │ │ + } else { │ │ │ │ │ + //content is clipped in only one direction, so we need to │ │ │ │ │ + // run getRenderedDimensions() again with a fixed dimension │ │ │ │ │ + var clippedSize = OpenLayers.Util.getRenderedDimensions( │ │ │ │ │ + preparedHTML, fixedSize, { │ │ │ │ │ + displayClass: this.contentDisplayClass, │ │ │ │ │ + containerElement: containerElement │ │ │ │ │ + } │ │ │ │ │ + ); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: autoDestroy │ │ │ │ │ - * {Boolean} The creator of the protocol can set autoDestroy to false │ │ │ │ │ - * to fully control when the protocol is destroyed. Defaults to │ │ │ │ │ - * true. │ │ │ │ │ - */ │ │ │ │ │ - autoDestroy: true, │ │ │ │ │ + //if the clipped size is still the same as the safeSize, │ │ │ │ │ + // that means that our content must be fixed in the │ │ │ │ │ + // offending direction. If overflow is 'auto', this means │ │ │ │ │ + // we are going to have a scrollbar for sure, so we must │ │ │ │ │ + // adjust for that. │ │ │ │ │ + // │ │ │ │ │ + var currentOverflow = OpenLayers.Element.getStyle( │ │ │ │ │ + this.contentDiv, "overflow" │ │ │ │ │ + ); │ │ │ │ │ + if ((currentOverflow != "hidden") && │ │ │ │ │ + (clippedSize.equals(safeSize))) { │ │ │ │ │ + var scrollBar = OpenLayers.Util.getScrollbarWidth(); │ │ │ │ │ + if (fixedSize.w) { │ │ │ │ │ + clippedSize.h += scrollBar; │ │ │ │ │ + } else { │ │ │ │ │ + clippedSize.w += scrollBar; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: defaultFilter │ │ │ │ │ - * {} Optional default filter to read requests │ │ │ │ │ - */ │ │ │ │ │ - defaultFilter: null, │ │ │ │ │ + newSize = this.getSafeContentSize(clippedSize); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + this.setSize(newSize); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Protocol │ │ │ │ │ - * Abstract class for vector protocols. Create instances of a subclass. │ │ │ │ │ + * Method: setBackgroundColor │ │ │ │ │ + * Sets the background color of the popup. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ - * instance. │ │ │ │ │ + * color - {String} the background color. eg "#FFBBBB" │ │ │ │ │ */ │ │ │ │ │ - initialize: function(options) { │ │ │ │ │ - options = options || {}; │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ - this.options = options; │ │ │ │ │ + setBackgroundColor: function(color) { │ │ │ │ │ + if (color != undefined) { │ │ │ │ │ + this.backgroundColor = color; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (this.div != null) { │ │ │ │ │ + this.div.style.backgroundColor = this.backgroundColor; │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: mergeWithDefaultFilter │ │ │ │ │ - * Merge filter passed to the read method with the default one │ │ │ │ │ - * │ │ │ │ │ + * Method: setOpacity │ │ │ │ │ + * Sets the opacity of the popup. │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * filter - {} │ │ │ │ │ + * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid). │ │ │ │ │ */ │ │ │ │ │ - mergeWithDefaultFilter: function(filter) { │ │ │ │ │ - var merged; │ │ │ │ │ - if (filter && this.defaultFilter) { │ │ │ │ │ - merged = new OpenLayers.Filter.Logical({ │ │ │ │ │ - type: OpenLayers.Filter.Logical.AND, │ │ │ │ │ - filters: [this.defaultFilter, filter] │ │ │ │ │ - }); │ │ │ │ │ - } else { │ │ │ │ │ - merged = filter || this.defaultFilter || undefined; │ │ │ │ │ + setOpacity: function(opacity) { │ │ │ │ │ + if (opacity != undefined) { │ │ │ │ │ + this.opacity = opacity; │ │ │ │ │ } │ │ │ │ │ - return merged; │ │ │ │ │ - }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ - * Clean up the protocol. │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - this.options = null; │ │ │ │ │ - this.format = null; │ │ │ │ │ + if (this.div != null) { │ │ │ │ │ + // for Mozilla and Safari │ │ │ │ │ + this.div.style.opacity = this.opacity; │ │ │ │ │ + │ │ │ │ │ + // for IE │ │ │ │ │ + this.div.style.filter = 'alpha(opacity=' + this.opacity * 100 + ')'; │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: read │ │ │ │ │ - * Construct a request for reading new features. │ │ │ │ │ + * Method: setBorder │ │ │ │ │ + * Sets the border style of the popup. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * options - {Object} Optional object for configuring the request. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} An │ │ │ │ │ - * object, the same object will be passed to the callback function passed │ │ │ │ │ - * if one exists in the options object. │ │ │ │ │ + * border - {String} The border style value. eg 2px │ │ │ │ │ */ │ │ │ │ │ - read: function(options) { │ │ │ │ │ - options = options || {}; │ │ │ │ │ - options.filter = this.mergeWithDefaultFilter(options.filter); │ │ │ │ │ - }, │ │ │ │ │ + setBorder: function(border) { │ │ │ │ │ + if (border != undefined) { │ │ │ │ │ + this.border = border; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ + if (this.div != null) { │ │ │ │ │ + this.div.style.border = this.border; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: create │ │ │ │ │ - * Construct a request for writing newly created features. │ │ │ │ │ + * Method: setContentHTML │ │ │ │ │ + * Allows the user to set the HTML content of the popup. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * features - {Array({})} or │ │ │ │ │ - * {} │ │ │ │ │ - * options - {Object} Optional object for configuring the request. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} An │ │ │ │ │ - * object, the same object will be passed to the callback function passed │ │ │ │ │ - * if one exists in the options object. │ │ │ │ │ + * contentHTML - {String} HTML for the div. │ │ │ │ │ */ │ │ │ │ │ - create: function() {}, │ │ │ │ │ + setContentHTML: function(contentHTML) { │ │ │ │ │ + │ │ │ │ │ + if (contentHTML != null) { │ │ │ │ │ + this.contentHTML = contentHTML; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if ((this.contentDiv != null) && │ │ │ │ │ + (this.contentHTML != null) && │ │ │ │ │ + (this.contentHTML != this.contentDiv.innerHTML)) { │ │ │ │ │ + │ │ │ │ │ + this.contentDiv.innerHTML = this.contentHTML; │ │ │ │ │ + │ │ │ │ │ + if (this.autoSize) { │ │ │ │ │ + │ │ │ │ │ + //if popup has images, listen for when they finish │ │ │ │ │ + // loading and resize accordingly │ │ │ │ │ + this.registerImageListeners(); │ │ │ │ │ + │ │ │ │ │ + //auto size the popup to its current contents │ │ │ │ │ + this.updateSize(); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: update │ │ │ │ │ - * Construct a request updating modified features. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * features - {Array({})} or │ │ │ │ │ - * {} │ │ │ │ │ - * options - {Object} Optional object for configuring the request. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} An │ │ │ │ │ - * object, the same object will be passed to the callback function passed │ │ │ │ │ - * if one exists in the options object. │ │ │ │ │ + * Method: registerImageListeners │ │ │ │ │ + * Called when an image contained by the popup loaded. this function │ │ │ │ │ + * updates the popup size, then unregisters the image load listener. │ │ │ │ │ */ │ │ │ │ │ - update: function() {}, │ │ │ │ │ + registerImageListeners: function() { │ │ │ │ │ + │ │ │ │ │ + // As the images load, this function will call updateSize() to │ │ │ │ │ + // resize the popup to fit the content div (which presumably is now │ │ │ │ │ + // bigger than when the image was not loaded). │ │ │ │ │ + // │ │ │ │ │ + // If the 'panMapIfOutOfView' property is set, we will pan the newly │ │ │ │ │ + // resized popup back into view. │ │ │ │ │ + // │ │ │ │ │ + // Note that this function, when called, will have 'popup' and │ │ │ │ │ + // 'img' properties in the context. │ │ │ │ │ + // │ │ │ │ │ + var onImgLoad = function() { │ │ │ │ │ + if (this.popup.id === null) { // this.popup has been destroyed! │ │ │ │ │ + return; │ │ │ │ │ + } │ │ │ │ │ + this.popup.updateSize(); │ │ │ │ │ + │ │ │ │ │ + if (this.popup.visible() && this.popup.panMapIfOutOfView) { │ │ │ │ │ + this.popup.panIntoView(); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + OpenLayers.Event.stopObserving( │ │ │ │ │ + this.img, "load", this.img._onImgLoad │ │ │ │ │ + ); │ │ │ │ │ + │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ + //cycle through the images and if their size is 0x0, that means that │ │ │ │ │ + // they haven't been loaded yet, so we attach the listener, which │ │ │ │ │ + // will fire when the images finish loading and will resize the │ │ │ │ │ + // popup accordingly to its new size. │ │ │ │ │ + var images = this.contentDiv.getElementsByTagName("img"); │ │ │ │ │ + for (var i = 0, len = images.length; i < len; i++) { │ │ │ │ │ + var img = images[i]; │ │ │ │ │ + if (img.width == 0 || img.height == 0) { │ │ │ │ │ + │ │ │ │ │ + var context = { │ │ │ │ │ + 'popup': this, │ │ │ │ │ + 'img': img │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ + //expando this function to the image itself before registering │ │ │ │ │ + // it. This way we can easily and properly unregister it. │ │ │ │ │ + img._onImgLoad = OpenLayers.Function.bind(onImgLoad, context); │ │ │ │ │ + │ │ │ │ │ + OpenLayers.Event.observe(img, 'load', img._onImgLoad); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: delete │ │ │ │ │ - * Construct a request deleting a removed feature. │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: getSafeContentSize │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * feature - {} │ │ │ │ │ - * options - {Object} Optional object for configuring the request. │ │ │ │ │ - * │ │ │ │ │ + * size - {} Desired size to make the popup. │ │ │ │ │ + * │ │ │ │ │ * Returns: │ │ │ │ │ - * {} An │ │ │ │ │ - * object, the same object will be passed to the callback function passed │ │ │ │ │ - * if one exists in the options object. │ │ │ │ │ + * {} A size to make the popup which is neither smaller │ │ │ │ │ + * than the specified minimum size, nor bigger than the maximum │ │ │ │ │ + * size (which is calculated relative to the size of the viewport). │ │ │ │ │ */ │ │ │ │ │ - "delete": function() {}, │ │ │ │ │ + getSafeContentSize: function(size) { │ │ │ │ │ + │ │ │ │ │ + var safeContentSize = size.clone(); │ │ │ │ │ + │ │ │ │ │ + // if our contentDiv has a css 'padding' set on it by a stylesheet, we │ │ │ │ │ + // must add that to the desired "size". │ │ │ │ │ + var contentDivPadding = this.getContentDivPadding(); │ │ │ │ │ + var wPadding = contentDivPadding.left + contentDivPadding.right; │ │ │ │ │ + var hPadding = contentDivPadding.top + contentDivPadding.bottom; │ │ │ │ │ + │ │ │ │ │ + // take into account the popup's 'padding' property │ │ │ │ │ + this.fixPadding(); │ │ │ │ │ + wPadding += this.padding.left + this.padding.right; │ │ │ │ │ + hPadding += this.padding.top + this.padding.bottom; │ │ │ │ │ + │ │ │ │ │ + if (this.closeDiv) { │ │ │ │ │ + var closeDivWidth = parseInt(this.closeDiv.style.width); │ │ │ │ │ + wPadding += closeDivWidth + contentDivPadding.right; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // prevent the popup from being smaller than a specified minimal size │ │ │ │ │ + if (this.minSize) { │ │ │ │ │ + safeContentSize.w = Math.max(safeContentSize.w, │ │ │ │ │ + (this.minSize.w - wPadding)); │ │ │ │ │ + safeContentSize.h = Math.max(safeContentSize.h, │ │ │ │ │ + (this.minSize.h - hPadding)); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // prevent the popup from being bigger than a specified maximum size │ │ │ │ │ + if (this.maxSize) { │ │ │ │ │ + safeContentSize.w = Math.min(safeContentSize.w, │ │ │ │ │ + (this.maxSize.w - wPadding)); │ │ │ │ │ + safeContentSize.h = Math.min(safeContentSize.h, │ │ │ │ │ + (this.maxSize.h - hPadding)); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + //make sure the desired size to set doesn't result in a popup that │ │ │ │ │ + // is bigger than the map's viewport. │ │ │ │ │ + // │ │ │ │ │ + if (this.map && this.map.size) { │ │ │ │ │ + │ │ │ │ │ + var extraX = 0, │ │ │ │ │ + extraY = 0; │ │ │ │ │ + if (this.keepInMap && !this.panMapIfOutOfView) { │ │ │ │ │ + var px = this.map.getPixelFromLonLat(this.lonlat); │ │ │ │ │ + switch (this.relativePosition) { │ │ │ │ │ + case "tr": │ │ │ │ │ + extraX = px.x; │ │ │ │ │ + extraY = this.map.size.h - px.y; │ │ │ │ │ + break; │ │ │ │ │ + case "tl": │ │ │ │ │ + extraX = this.map.size.w - px.x; │ │ │ │ │ + extraY = this.map.size.h - px.y; │ │ │ │ │ + break; │ │ │ │ │ + case "bl": │ │ │ │ │ + extraX = this.map.size.w - px.x; │ │ │ │ │ + extraY = px.y; │ │ │ │ │ + break; │ │ │ │ │ + case "br": │ │ │ │ │ + extraX = px.x; │ │ │ │ │ + extraY = px.y; │ │ │ │ │ + break; │ │ │ │ │ + default: │ │ │ │ │ + extraX = px.x; │ │ │ │ │ + extraY = this.map.size.h - px.y; │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + var maxY = this.map.size.h - │ │ │ │ │ + this.map.paddingForPopups.top - │ │ │ │ │ + this.map.paddingForPopups.bottom - │ │ │ │ │ + hPadding - extraY; │ │ │ │ │ + │ │ │ │ │ + var maxX = this.map.size.w - │ │ │ │ │ + this.map.paddingForPopups.left - │ │ │ │ │ + this.map.paddingForPopups.right - │ │ │ │ │ + wPadding - extraX; │ │ │ │ │ + │ │ │ │ │ + safeContentSize.w = Math.min(safeContentSize.w, maxX); │ │ │ │ │ + safeContentSize.h = Math.min(safeContentSize.h, maxY); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + return safeContentSize; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: commit │ │ │ │ │ - * Go over the features and for each take action │ │ │ │ │ - * based on the feature state. Possible actions are create, │ │ │ │ │ - * update and delete. │ │ │ │ │ + * Method: getContentDivPadding │ │ │ │ │ + * Glorious, oh glorious hack in order to determine the css 'padding' of │ │ │ │ │ + * the contentDiv. IE/Opera return null here unless we actually add the │ │ │ │ │ + * popup's main 'div' element (which contains contentDiv) to the DOM. │ │ │ │ │ + * So we make it invisible and then add it to the document temporarily. │ │ │ │ │ * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * features - {Array({})} │ │ │ │ │ - * options - {Object} Object whose possible keys are "create", "update", │ │ │ │ │ - * "delete", "callback" and "scope", the values referenced by the │ │ │ │ │ - * first three are objects as passed to the "create", "update", and │ │ │ │ │ - * "delete" methods, the value referenced by the "callback" key is │ │ │ │ │ - * a function which is called when the commit operation is complete │ │ │ │ │ - * using the scope referenced by the "scope" key. │ │ │ │ │ + * Once we've taken the padding readings we need, we then remove it │ │ │ │ │ + * from the DOM (it will actually get added to the DOM in │ │ │ │ │ + * Map.js's addPopup) │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Array({})} An array of │ │ │ │ │ - * objects. │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - commit: function() {}, │ │ │ │ │ + getContentDivPadding: function() { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: abort │ │ │ │ │ - * Abort an ongoing request. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * response - {} │ │ │ │ │ - */ │ │ │ │ │ - abort: function(response) {}, │ │ │ │ │ + //use cached value if we have it │ │ │ │ │ + var contentDivPadding = this._contentDivPadding; │ │ │ │ │ + if (!contentDivPadding) { │ │ │ │ │ + │ │ │ │ │ + if (this.div.parentNode == null) { │ │ │ │ │ + //make the div invisible and add it to the page │ │ │ │ │ + this.div.style.display = "none"; │ │ │ │ │ + document.body.appendChild(this.div); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + //read the padding settings from css, put them in an OL.Bounds │ │ │ │ │ + contentDivPadding = new OpenLayers.Bounds( │ │ │ │ │ + OpenLayers.Element.getStyle(this.contentDiv, "padding-left"), │ │ │ │ │ + OpenLayers.Element.getStyle(this.contentDiv, "padding-bottom"), │ │ │ │ │ + OpenLayers.Element.getStyle(this.contentDiv, "padding-right"), │ │ │ │ │ + OpenLayers.Element.getStyle(this.contentDiv, "padding-top") │ │ │ │ │ + ); │ │ │ │ │ + │ │ │ │ │ + //cache the value │ │ │ │ │ + this._contentDivPadding = contentDivPadding; │ │ │ │ │ + │ │ │ │ │ + if (this.div.parentNode == document.body) { │ │ │ │ │ + //remove the div from the page and make it visible again │ │ │ │ │ + document.body.removeChild(this.div); │ │ │ │ │ + this.div.style.display = ""; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return contentDivPadding; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: createCallback │ │ │ │ │ - * Returns a function that applies the given public method with resp and │ │ │ │ │ - * options arguments. │ │ │ │ │ - * │ │ │ │ │ + * Method: addCloseBox │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * method - {Function} The method to be applied by the callback. │ │ │ │ │ - * response - {} The protocol response object. │ │ │ │ │ - * options - {Object} Options sent to the protocol method │ │ │ │ │ + * callback - {Function} The callback to be called when the close button │ │ │ │ │ + * is clicked. │ │ │ │ │ */ │ │ │ │ │ - createCallback: function(method, response, options) { │ │ │ │ │ - return OpenLayers.Function.bind(function() { │ │ │ │ │ - method.apply(this, [response, options]); │ │ │ │ │ - }, this); │ │ │ │ │ - }, │ │ │ │ │ + addCloseBox: function(callback) { │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol" │ │ │ │ │ -}); │ │ │ │ │ + this.closeDiv = OpenLayers.Util.createDiv( │ │ │ │ │ + this.id + "_close", null, { │ │ │ │ │ + w: 17, │ │ │ │ │ + h: 17 │ │ │ │ │ + } │ │ │ │ │ + ); │ │ │ │ │ + this.closeDiv.className = "olPopupCloseBox"; │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Protocol.Response │ │ │ │ │ - * Protocols return Response objects to their users. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Protocol.Response = OpenLayers.Class({ │ │ │ │ │ - /** │ │ │ │ │ - * Property: code │ │ │ │ │ - * {Number} - OpenLayers.Protocol.Response.SUCCESS or │ │ │ │ │ - * OpenLayers.Protocol.Response.FAILURE │ │ │ │ │ - */ │ │ │ │ │ - code: null, │ │ │ │ │ + // use the content div's css padding to determine if we should │ │ │ │ │ + // padd the close div │ │ │ │ │ + var contentDivPadding = this.getContentDivPadding(); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: requestType │ │ │ │ │ - * {String} The type of request this response corresponds to. Either │ │ │ │ │ - * "create", "read", "update" or "delete". │ │ │ │ │ - */ │ │ │ │ │ - requestType: null, │ │ │ │ │ + this.closeDiv.style.right = contentDivPadding.right + "px"; │ │ │ │ │ + this.closeDiv.style.top = contentDivPadding.top + "px"; │ │ │ │ │ + this.groupDiv.appendChild(this.closeDiv); │ │ │ │ │ + │ │ │ │ │ + var closePopup = callback || function(e) { │ │ │ │ │ + this.hide(); │ │ │ │ │ + OpenLayers.Event.stop(e); │ │ │ │ │ + }; │ │ │ │ │ + OpenLayers.Event.observe(this.closeDiv, "touchend", │ │ │ │ │ + OpenLayers.Function.bindAsEventListener(closePopup, this)); │ │ │ │ │ + OpenLayers.Event.observe(this.closeDiv, "click", │ │ │ │ │ + OpenLayers.Function.bindAsEventListener(closePopup, this)); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: last │ │ │ │ │ - * {Boolean} - true if this is the last response expected in a commit, │ │ │ │ │ - * false otherwise, defaults to true. │ │ │ │ │ + * Method: panIntoView │ │ │ │ │ + * Pans the map such that the popup is totaly viewable (if necessary) │ │ │ │ │ */ │ │ │ │ │ - last: true, │ │ │ │ │ + panIntoView: function() { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: features │ │ │ │ │ - * {Array({})} or {} │ │ │ │ │ - * The features returned in the response by the server. Depending on the │ │ │ │ │ - * protocol's read payload, either features or data will be populated. │ │ │ │ │ + var mapSize = this.map.getSize(); │ │ │ │ │ + │ │ │ │ │ + //start with the top left corner of the popup, in px, │ │ │ │ │ + // relative to the viewport │ │ │ │ │ + var origTL = this.map.getViewPortPxFromLayerPx(new OpenLayers.Pixel( │ │ │ │ │ + parseInt(this.div.style.left), │ │ │ │ │ + parseInt(this.div.style.top) │ │ │ │ │ + )); │ │ │ │ │ + var newTL = origTL.clone(); │ │ │ │ │ + │ │ │ │ │ + //new left (compare to margins, using this.size to calculate right) │ │ │ │ │ + if (origTL.x < this.map.paddingForPopups.left) { │ │ │ │ │ + newTL.x = this.map.paddingForPopups.left; │ │ │ │ │ + } else │ │ │ │ │ + if ((origTL.x + this.size.w) > (mapSize.w - this.map.paddingForPopups.right)) { │ │ │ │ │ + newTL.x = mapSize.w - this.map.paddingForPopups.right - this.size.w; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + //new top (compare to margins, using this.size to calculate bottom) │ │ │ │ │ + if (origTL.y < this.map.paddingForPopups.top) { │ │ │ │ │ + newTL.y = this.map.paddingForPopups.top; │ │ │ │ │ + } else │ │ │ │ │ + if ((origTL.y + this.size.h) > (mapSize.h - this.map.paddingForPopups.bottom)) { │ │ │ │ │ + newTL.y = mapSize.h - this.map.paddingForPopups.bottom - this.size.h; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + var dx = origTL.x - newTL.x; │ │ │ │ │ + var dy = origTL.y - newTL.y; │ │ │ │ │ + │ │ │ │ │ + this.map.pan(dx, dy); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: registerEvents │ │ │ │ │ + * Registers events on the popup. │ │ │ │ │ + * │ │ │ │ │ + * Do this in a separate function so that subclasses can │ │ │ │ │ + * choose to override it if they wish to deal differently │ │ │ │ │ + * with mouse events │ │ │ │ │ + * │ │ │ │ │ + * Note in the following handler functions that some special │ │ │ │ │ + * care is needed to deal correctly with mousing and popups. │ │ │ │ │ + * │ │ │ │ │ + * Because the user might select the zoom-rectangle option and │ │ │ │ │ + * then drag it over a popup, we need a safe way to allow the │ │ │ │ │ + * mousemove and mouseup events to pass through the popup when │ │ │ │ │ + * they are initiated from outside. The same procedure is needed for │ │ │ │ │ + * touchmove and touchend events. │ │ │ │ │ + * │ │ │ │ │ + * Otherwise, we want to essentially kill the event propagation │ │ │ │ │ + * for all other events, though we have to do so carefully, │ │ │ │ │ + * without disabling basic html functionality, like clicking on │ │ │ │ │ + * hyperlinks or drag-selecting text. │ │ │ │ │ */ │ │ │ │ │ - features: null, │ │ │ │ │ + registerEvents: function() { │ │ │ │ │ + this.events = new OpenLayers.Events(this, this.div, null, true); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: data │ │ │ │ │ - * {Object} │ │ │ │ │ - * The data returned in the response by the server. Depending on the │ │ │ │ │ - * protocol's read payload, either features or data will be populated. │ │ │ │ │ + function onTouchstart(evt) { │ │ │ │ │ + OpenLayers.Event.stop(evt, true); │ │ │ │ │ + } │ │ │ │ │ + this.events.on({ │ │ │ │ │ + "mousedown": this.onmousedown, │ │ │ │ │ + "mousemove": this.onmousemove, │ │ │ │ │ + "mouseup": this.onmouseup, │ │ │ │ │ + "click": this.onclick, │ │ │ │ │ + "mouseout": this.onmouseout, │ │ │ │ │ + "dblclick": this.ondblclick, │ │ │ │ │ + "touchstart": onTouchstart, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: onmousedown │ │ │ │ │ + * When mouse goes down within the popup, make a note of │ │ │ │ │ + * it locally, and then do not propagate the mousedown │ │ │ │ │ + * (but do so safely so that user can select text inside) │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {Event} │ │ │ │ │ */ │ │ │ │ │ - data: null, │ │ │ │ │ + onmousedown: function(evt) { │ │ │ │ │ + this.mousedown = true; │ │ │ │ │ + OpenLayers.Event.stop(evt, true); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: reqFeatures │ │ │ │ │ - * {Array({})} or {} │ │ │ │ │ - * The features provided by the user and placed in the request by the │ │ │ │ │ - * protocol. │ │ │ │ │ + /** │ │ │ │ │ + * Method: onmousemove │ │ │ │ │ + * If the drag was started within the popup, then │ │ │ │ │ + * do not propagate the mousemove (but do so safely │ │ │ │ │ + * so that user can select text inside) │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {Event} │ │ │ │ │ */ │ │ │ │ │ - reqFeatures: null, │ │ │ │ │ + onmousemove: function(evt) { │ │ │ │ │ + if (this.mousedown) { │ │ │ │ │ + OpenLayers.Event.stop(evt, true); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: priv │ │ │ │ │ + /** │ │ │ │ │ + * Method: onmouseup │ │ │ │ │ + * When mouse comes up within the popup, after going down │ │ │ │ │ + * in it, reset the flag, and then (once again) do not │ │ │ │ │ + * propagate the event, but do so safely so that user can │ │ │ │ │ + * select text inside │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {Event} │ │ │ │ │ */ │ │ │ │ │ - priv: null, │ │ │ │ │ + onmouseup: function(evt) { │ │ │ │ │ + if (this.mousedown) { │ │ │ │ │ + this.mousedown = false; │ │ │ │ │ + OpenLayers.Event.stop(evt, true); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: error │ │ │ │ │ - * {Object} The error object in case a service exception was encountered. │ │ │ │ │ + * Method: onclick │ │ │ │ │ + * Ignore clicks, but allowing default browser handling │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {Event} │ │ │ │ │ */ │ │ │ │ │ - error: null, │ │ │ │ │ + onclick: function(evt) { │ │ │ │ │ + OpenLayers.Event.stop(evt, true); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Protocol.Response │ │ │ │ │ - * │ │ │ │ │ + /** │ │ │ │ │ + * Method: onmouseout │ │ │ │ │ + * When mouse goes out of the popup set the flag to false so that │ │ │ │ │ + * if they let go and then drag back in, we won't be confused. │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ - * instance. │ │ │ │ │ + * evt - {Event} │ │ │ │ │ */ │ │ │ │ │ - initialize: function(options) { │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ + onmouseout: function(evt) { │ │ │ │ │ + this.mousedown = false; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: success │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} - true on success, false otherwise │ │ │ │ │ + /** │ │ │ │ │ + * Method: ondblclick │ │ │ │ │ + * Ignore double-clicks, but allowing default browser handling │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {Event} │ │ │ │ │ */ │ │ │ │ │ - success: function() { │ │ │ │ │ - return this.code > 0; │ │ │ │ │ + ondblclick: function(evt) { │ │ │ │ │ + OpenLayers.Event.stop(evt, true); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Protocol.Response" │ │ │ │ │ + CLASS_NAME: "OpenLayers.Popup" │ │ │ │ │ }); │ │ │ │ │ │ │ │ │ │ -OpenLayers.Protocol.Response.SUCCESS = 1; │ │ │ │ │ -OpenLayers.Protocol.Response.FAILURE = 0; │ │ │ │ │ +OpenLayers.Popup.WIDTH = 200; │ │ │ │ │ +OpenLayers.Popup.HEIGHT = 200; │ │ │ │ │ +OpenLayers.Popup.COLOR = "white"; │ │ │ │ │ +OpenLayers.Popup.OPACITY = 1; │ │ │ │ │ +OpenLayers.Popup.BORDER = "0px"; │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Renderer.js │ │ │ │ │ + OpenLayers/Control.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control │ │ │ │ │ + * Controls affect the display or behavior of the map. They allow everything │ │ │ │ │ + * from panning and zooming to displaying a scale indicator. Controls by │ │ │ │ │ + * default are added to the map they are contained within however it is │ │ │ │ │ + * possible to add a control to an external div by passing the div in the │ │ │ │ │ + * options parameter. │ │ │ │ │ + * │ │ │ │ │ + * Example: │ │ │ │ │ + * The following example shows how to add many of the common controls │ │ │ │ │ + * to a map. │ │ │ │ │ + * │ │ │ │ │ + * > var map = new OpenLayers.Map('map', { controls: [] }); │ │ │ │ │ + * > │ │ │ │ │ + * > map.addControl(new OpenLayers.Control.PanZoomBar()); │ │ │ │ │ + * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false})); │ │ │ │ │ + * > map.addControl(new OpenLayers.Control.Permalink()); │ │ │ │ │ + * > map.addControl(new OpenLayers.Control.Permalink('permalink')); │ │ │ │ │ + * > map.addControl(new OpenLayers.Control.MousePosition()); │ │ │ │ │ + * > map.addControl(new OpenLayers.Control.OverviewMap()); │ │ │ │ │ + * > map.addControl(new OpenLayers.Control.KeyboardDefaults()); │ │ │ │ │ + * │ │ │ │ │ + * The next code fragment is a quick example of how to intercept │ │ │ │ │ + * shift-mouse click to display the extent of the bounding box │ │ │ │ │ + * dragged out by the user. Usually controls are not created │ │ │ │ │ + * in exactly this manner. See the source for a more complete │ │ │ │ │ + * example: │ │ │ │ │ + * │ │ │ │ │ + * > var control = new OpenLayers.Control(); │ │ │ │ │ + * > OpenLayers.Util.extend(control, { │ │ │ │ │ + * > draw: function () { │ │ │ │ │ + * > // this Handler.Box will intercept the shift-mousedown │ │ │ │ │ + * > // before Control.MouseDefault gets to see it │ │ │ │ │ + * > this.box = new OpenLayers.Handler.Box( control, │ │ │ │ │ + * > {"done": this.notice}, │ │ │ │ │ + * > {keyMask: OpenLayers.Handler.MOD_SHIFT}); │ │ │ │ │ + * > this.box.activate(); │ │ │ │ │ + * > }, │ │ │ │ │ + * > │ │ │ │ │ + * > notice: function (bounds) { │ │ │ │ │ + * > OpenLayers.Console.userError(bounds); │ │ │ │ │ + * > } │ │ │ │ │ + * > }); │ │ │ │ │ + * > map.addControl(control); │ │ │ │ │ + * │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control = OpenLayers.Class({ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: id │ │ │ │ │ + * {String} │ │ │ │ │ + */ │ │ │ │ │ + id: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: map │ │ │ │ │ + * {} this gets set in the addControl() function in │ │ │ │ │ + * OpenLayers.Map │ │ │ │ │ + */ │ │ │ │ │ + map: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: div │ │ │ │ │ + * {DOMElement} The element that contains the control, if not present the │ │ │ │ │ + * control is placed inside the map. │ │ │ │ │ + */ │ │ │ │ │ + div: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: type │ │ │ │ │ + * {Number} Controls can have a 'type'. The type determines the type of │ │ │ │ │ + * interactions which are possible with them when they are placed in an │ │ │ │ │ + * . │ │ │ │ │ + */ │ │ │ │ │ + type: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: allowSelection │ │ │ │ │ + * {Boolean} By default, controls do not allow selection, because │ │ │ │ │ + * it may interfere with map dragging. If this is true, OpenLayers │ │ │ │ │ + * will not prevent selection of the control. │ │ │ │ │ + * Default is false. │ │ │ │ │ + */ │ │ │ │ │ + allowSelection: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: displayClass │ │ │ │ │ + * {string} This property is used for CSS related to the drawing of the │ │ │ │ │ + * Control. │ │ │ │ │ + */ │ │ │ │ │ + displayClass: "", │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: title │ │ │ │ │ + * {string} This property is used for showing a tooltip over the │ │ │ │ │ + * Control. │ │ │ │ │ + */ │ │ │ │ │ + title: "", │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: autoActivate │ │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ │ + * false. │ │ │ │ │ + */ │ │ │ │ │ + autoActivate: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: active │ │ │ │ │ + * {Boolean} The control is active (read-only). Use and │ │ │ │ │ + * to change control state. │ │ │ │ │ + */ │ │ │ │ │ + active: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: handlerOptions │ │ │ │ │ + * {Object} Used to set non-default properties on the control's handler │ │ │ │ │ + */ │ │ │ │ │ + handlerOptions: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: handler │ │ │ │ │ + * {} null │ │ │ │ │ + */ │ │ │ │ │ + handler: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: eventListeners │ │ │ │ │ + * {Object} If set as an option at construction, the eventListeners │ │ │ │ │ + * object will be registered with . Object │ │ │ │ │ + * structure must be a listeners object as shown in the example for │ │ │ │ │ + * the events.on method. │ │ │ │ │ + */ │ │ │ │ │ + eventListeners: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: events │ │ │ │ │ + * {} Events instance for listeners and triggering │ │ │ │ │ + * control specific events. │ │ │ │ │ + * │ │ │ │ │ + * Register a listener for a particular event with the following syntax: │ │ │ │ │ + * (code) │ │ │ │ │ + * control.events.register(type, obj, listener); │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Listeners will be called with a reference to an event object. The │ │ │ │ │ + * properties of this event depends on exactly what happened. │ │ │ │ │ + * │ │ │ │ │ + * All event objects have at least the following properties: │ │ │ │ │ + * object - {Object} A reference to control.events.object (a reference │ │ │ │ │ + * to the control). │ │ │ │ │ + * element - {DOMElement} A reference to control.events.element (which │ │ │ │ │ + * will be null unless documented otherwise). │ │ │ │ │ + * │ │ │ │ │ + * Supported map event types: │ │ │ │ │ + * activate - Triggered when activated. │ │ │ │ │ + * deactivate - Triggered when deactivated. │ │ │ │ │ + */ │ │ │ │ │ + events: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Control │ │ │ │ │ + * Create an OpenLayers Control. The options passed as a parameter │ │ │ │ │ + * directly extend the control. For example passing the following: │ │ │ │ │ + * │ │ │ │ │ + * > var control = new OpenLayers.Control({div: myDiv}); │ │ │ │ │ + * │ │ │ │ │ + * Overrides the default div attribute value of null. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + // We do this before the extend so that instances can override │ │ │ │ │ + // className in options. │ │ │ │ │ + this.displayClass = │ │ │ │ │ + this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, ""); │ │ │ │ │ + │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + │ │ │ │ │ + this.events = new OpenLayers.Events(this); │ │ │ │ │ + if (this.eventListeners instanceof Object) { │ │ │ │ │ + this.events.on(this.eventListeners); │ │ │ │ │ + } │ │ │ │ │ + if (this.id == null) { │ │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroy │ │ │ │ │ + * The destroy method is used to perform any clean up before the control │ │ │ │ │ + * is dereferenced. Typically this is where event listeners are removed │ │ │ │ │ + * to prevent memory leaks. │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + if (this.events) { │ │ │ │ │ + if (this.eventListeners) { │ │ │ │ │ + this.events.un(this.eventListeners); │ │ │ │ │ + } │ │ │ │ │ + this.events.destroy(); │ │ │ │ │ + this.events = null; │ │ │ │ │ + } │ │ │ │ │ + this.eventListeners = null; │ │ │ │ │ + │ │ │ │ │ + // eliminate circular references │ │ │ │ │ + if (this.handler) { │ │ │ │ │ + this.handler.destroy(); │ │ │ │ │ + this.handler = null; │ │ │ │ │ + } │ │ │ │ │ + if (this.handlers) { │ │ │ │ │ + for (var key in this.handlers) { │ │ │ │ │ + if (this.handlers.hasOwnProperty(key) && │ │ │ │ │ + typeof this.handlers[key].destroy == "function") { │ │ │ │ │ + this.handlers[key].destroy(); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + this.handlers = null; │ │ │ │ │ + } │ │ │ │ │ + if (this.map) { │ │ │ │ │ + this.map.removeControl(this); │ │ │ │ │ + this.map = null; │ │ │ │ │ + } │ │ │ │ │ + this.div = null; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: setMap │ │ │ │ │ + * Set the map property for the control. This is done through an accessor │ │ │ │ │ + * so that subclasses can override this and take special action once │ │ │ │ │ + * they have their map variable set. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * map - {} │ │ │ │ │ + */ │ │ │ │ │ + setMap: function(map) { │ │ │ │ │ + this.map = map; │ │ │ │ │ + if (this.handler) { │ │ │ │ │ + this.handler.setMap(map); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: draw │ │ │ │ │ + * The draw method is called when the control is ready to be displayed │ │ │ │ │ + * on the page. If a div has not been created one is created. Controls │ │ │ │ │ + * with a visual component will almost always want to override this method │ │ │ │ │ + * to customize the look of control. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * px - {} The top-left pixel position of the control │ │ │ │ │ + * or null. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {DOMElement} A reference to the DIV DOMElement containing the control │ │ │ │ │ + */ │ │ │ │ │ + draw: function(px) { │ │ │ │ │ + if (this.div == null) { │ │ │ │ │ + this.div = OpenLayers.Util.createDiv(this.id); │ │ │ │ │ + this.div.className = this.displayClass; │ │ │ │ │ + if (!this.allowSelection) { │ │ │ │ │ + this.div.className += " olControlNoSelect"; │ │ │ │ │ + this.div.setAttribute("unselectable", "on", 0); │ │ │ │ │ + this.div.onselectstart = OpenLayers.Function.False; │ │ │ │ │ + } │ │ │ │ │ + if (this.title != "") { │ │ │ │ │ + this.div.title = this.title; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + if (px != null) { │ │ │ │ │ + this.position = px.clone(); │ │ │ │ │ + } │ │ │ │ │ + this.moveTo(this.position); │ │ │ │ │ + return this.div; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: moveTo │ │ │ │ │ + * Sets the left and top style attributes to the passed in pixel │ │ │ │ │ + * coordinates. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * px - {} │ │ │ │ │ + */ │ │ │ │ │ + moveTo: function(px) { │ │ │ │ │ + if ((px != null) && (this.div != null)) { │ │ │ │ │ + this.div.style.left = px.x + "px"; │ │ │ │ │ + this.div.style.top = px.y + "px"; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: activate │ │ │ │ │ + * Explicitly activates a control and it's associated │ │ │ │ │ + * handler if one has been set. Controls can be │ │ │ │ │ + * deactivated by calling the deactivate() method. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} True if the control was successfully activated or │ │ │ │ │ + * false if the control was already active. │ │ │ │ │ + */ │ │ │ │ │ + activate: function() { │ │ │ │ │ + if (this.active) { │ │ │ │ │ + return false; │ │ │ │ │ + } │ │ │ │ │ + if (this.handler) { │ │ │ │ │ + this.handler.activate(); │ │ │ │ │ + } │ │ │ │ │ + this.active = true; │ │ │ │ │ + if (this.map) { │ │ │ │ │ + OpenLayers.Element.addClass( │ │ │ │ │ + this.map.viewPortDiv, │ │ │ │ │ + this.displayClass.replace(/ /g, "") + "Active" │ │ │ │ │ + ); │ │ │ │ │ + } │ │ │ │ │ + this.events.triggerEvent("activate"); │ │ │ │ │ + return true; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: deactivate │ │ │ │ │ + * Deactivates a control and it's associated handler if any. The exact │ │ │ │ │ + * effect of this depends on the control itself. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} True if the control was effectively deactivated or false │ │ │ │ │ + * if the control was already inactive. │ │ │ │ │ + */ │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + if (this.active) { │ │ │ │ │ + if (this.handler) { │ │ │ │ │ + this.handler.deactivate(); │ │ │ │ │ + } │ │ │ │ │ + this.active = false; │ │ │ │ │ + if (this.map) { │ │ │ │ │ + OpenLayers.Element.removeClass( │ │ │ │ │ + this.map.viewPortDiv, │ │ │ │ │ + this.displayClass.replace(/ /g, "") + "Active" │ │ │ │ │ + ); │ │ │ │ │ + } │ │ │ │ │ + this.events.triggerEvent("deactivate"); │ │ │ │ │ + return true; │ │ │ │ │ + } │ │ │ │ │ + return false; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control" │ │ │ │ │ +}); │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Constant: OpenLayers.Control.TYPE_BUTTON │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.TYPE_BUTTON = 1; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Constant: OpenLayers.Control.TYPE_TOGGLE │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.TYPE_TOGGLE = 2; │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Constant: OpenLayers.Control.TYPE_TOOL │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.TYPE_TOOL = 3; │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Renderer.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ @@ -25817,14 +28182,917 @@ │ │ │ │ │ 4, 0 │ │ │ │ │ ], │ │ │ │ │ "x": [0, 0, 25, 0, 50, 35, 75, 0, 100, 0, 65, 50, 100, 100, 75, 100, 50, 65, 25, 100, 0, 100, 35, 50, 0, 0], │ │ │ │ │ "square": [0, 0, 0, 1, 1, 1, 1, 0, 0, 0], │ │ │ │ │ "triangle": [0, 10, 10, 10, 5, 0, 0, 10] │ │ │ │ │ }; │ │ │ │ │ /* ====================================================================== │ │ │ │ │ + OpenLayers/Symbolizer.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Symbolizer │ │ │ │ │ + * Base class representing a symbolizer used for feature rendering. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Symbolizer = OpenLayers.Class({ │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: zIndex │ │ │ │ │ + * {Number} The zIndex determines the rendering order for a symbolizer. │ │ │ │ │ + * Symbolizers with larger zIndex values are rendered over symbolizers │ │ │ │ │ + * with smaller zIndex values. Default is 0. │ │ │ │ │ + */ │ │ │ │ │ + zIndex: 0, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Symbolizer │ │ │ │ │ + * Instances of this class are not useful. See one of the subclasses. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ │ + * construction. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * A new symbolizer. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(config) { │ │ │ │ │ + OpenLayers.Util.extend(this, config); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: clone │ │ │ │ │ + * Create a copy of this symbolizer. │ │ │ │ │ + * │ │ │ │ │ + * Returns a symbolizer of the same type with the same properties. │ │ │ │ │ + */ │ │ │ │ │ + clone: function() { │ │ │ │ │ + var Type = eval(this.CLASS_NAME); │ │ │ │ │ + return new Type(OpenLayers.Util.extend({}, this)); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer" │ │ │ │ │ + │ │ │ │ │ +}); │ │ │ │ │ + │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Rule.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ │ + * @requires OpenLayers/Style.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Rule │ │ │ │ │ + * This class represents an SLD Rule, as being used for rule-based SLD styling. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Rule = OpenLayers.Class({ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: id │ │ │ │ │ + * {String} A unique id for this session. │ │ │ │ │ + */ │ │ │ │ │ + id: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: name │ │ │ │ │ + * {String} name of this rule │ │ │ │ │ + */ │ │ │ │ │ + name: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: title │ │ │ │ │ + * {String} Title of this rule (set if included in SLD) │ │ │ │ │ + */ │ │ │ │ │ + title: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: description │ │ │ │ │ + * {String} Description of this rule (set if abstract is included in SLD) │ │ │ │ │ + */ │ │ │ │ │ + description: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: context │ │ │ │ │ + * {Object} An optional object with properties that the rule should be │ │ │ │ │ + * evaluated against. If no context is specified, feature.attributes will │ │ │ │ │ + * be used. │ │ │ │ │ + */ │ │ │ │ │ + context: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: filter │ │ │ │ │ + * {} Optional filter for the rule. │ │ │ │ │ + */ │ │ │ │ │ + filter: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: elseFilter │ │ │ │ │ + * {Boolean} Determines whether this rule is only to be applied only if │ │ │ │ │ + * no other rules match (ElseFilter according to the SLD specification). │ │ │ │ │ + * Default is false. For instances of OpenLayers.Rule, if elseFilter is │ │ │ │ │ + * false, the rule will always apply. For subclasses, the else property is │ │ │ │ │ + * ignored. │ │ │ │ │ + */ │ │ │ │ │ + elseFilter: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: symbolizer │ │ │ │ │ + * {Object} Symbolizer or hash of symbolizers for this rule. If hash of │ │ │ │ │ + * symbolizers, keys are one or more of ["Point", "Line", "Polygon"]. The │ │ │ │ │ + * latter if useful if it is required to style e.g. vertices of a line │ │ │ │ │ + * with a point symbolizer. Note, however, that this is not implemented │ │ │ │ │ + * yet in OpenLayers, but it is the way how symbolizers are defined in │ │ │ │ │ + * SLD. │ │ │ │ │ + */ │ │ │ │ │ + symbolizer: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: symbolizers │ │ │ │ │ + * {Array} Collection of symbolizers associated with this rule. If │ │ │ │ │ + * provided at construction, the symbolizers array has precedence │ │ │ │ │ + * over the deprecated symbolizer property. Note that multiple │ │ │ │ │ + * symbolizers are not currently supported by the vector renderers. │ │ │ │ │ + * Rules with multiple symbolizers are currently only useful for │ │ │ │ │ + * maintaining elements in an SLD document. │ │ │ │ │ + */ │ │ │ │ │ + symbolizers: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: minScaleDenominator │ │ │ │ │ + * {Number} or {String} minimum scale at which to draw the feature. │ │ │ │ │ + * In the case of a String, this can be a combination of text and │ │ │ │ │ + * propertyNames in the form "literal ${propertyName}" │ │ │ │ │ + */ │ │ │ │ │ + minScaleDenominator: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: maxScaleDenominator │ │ │ │ │ + * {Number} or {String} maximum scale at which to draw the feature. │ │ │ │ │ + * In the case of a String, this can be a combination of text and │ │ │ │ │ + * propertyNames in the form "literal ${propertyName}" │ │ │ │ │ + */ │ │ │ │ │ + maxScaleDenominator: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Rule │ │ │ │ │ + * Creates a Rule. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} An optional object with properties to set on the │ │ │ │ │ + * rule │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + this.symbolizer = {}; │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + if (this.symbolizers) { │ │ │ │ │ + delete this.symbolizer; │ │ │ │ │ + } │ │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ + * nullify references to prevent circular references and memory leaks │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + for (var i in this.symbolizer) { │ │ │ │ │ + this.symbolizer[i] = null; │ │ │ │ │ + } │ │ │ │ │ + this.symbolizer = null; │ │ │ │ │ + delete this.symbolizers; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: evaluate │ │ │ │ │ + * evaluates this rule for a specific feature │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * feature - {} feature to apply the rule to. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} true if the rule applies, false if it does not. │ │ │ │ │ + * This rule is the default rule and always returns true. │ │ │ │ │ + */ │ │ │ │ │ + evaluate: function(feature) { │ │ │ │ │ + var context = this.getContext(feature); │ │ │ │ │ + var applies = true; │ │ │ │ │ + │ │ │ │ │ + if (this.minScaleDenominator || this.maxScaleDenominator) { │ │ │ │ │ + var scale = feature.layer.map.getScale(); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // check if within minScale/maxScale bounds │ │ │ │ │ + if (this.minScaleDenominator) { │ │ │ │ │ + applies = scale >= OpenLayers.Style.createLiteral( │ │ │ │ │ + this.minScaleDenominator, context); │ │ │ │ │ + } │ │ │ │ │ + if (applies && this.maxScaleDenominator) { │ │ │ │ │ + applies = scale < OpenLayers.Style.createLiteral( │ │ │ │ │ + this.maxScaleDenominator, context); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // check if optional filter applies │ │ │ │ │ + if (applies && this.filter) { │ │ │ │ │ + // feature id filters get the feature, others get the context │ │ │ │ │ + if (this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") { │ │ │ │ │ + applies = this.filter.evaluate(feature); │ │ │ │ │ + } else { │ │ │ │ │ + applies = this.filter.evaluate(context); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + return applies; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: getContext │ │ │ │ │ + * Gets the context for evaluating this rule │ │ │ │ │ + * │ │ │ │ │ + * Paramters: │ │ │ │ │ + * feature - {} feature to take the context from if │ │ │ │ │ + * none is specified. │ │ │ │ │ + */ │ │ │ │ │ + getContext: function(feature) { │ │ │ │ │ + var context = this.context; │ │ │ │ │ + if (!context) { │ │ │ │ │ + context = feature.attributes || feature.data; │ │ │ │ │ + } │ │ │ │ │ + if (typeof this.context == "function") { │ │ │ │ │ + context = this.context(feature); │ │ │ │ │ + } │ │ │ │ │ + return context; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: clone │ │ │ │ │ + * Clones this rule. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} Clone of this rule. │ │ │ │ │ + */ │ │ │ │ │ + clone: function() { │ │ │ │ │ + var options = OpenLayers.Util.extend({}, this); │ │ │ │ │ + if (this.symbolizers) { │ │ │ │ │ + // clone symbolizers │ │ │ │ │ + var len = this.symbolizers.length; │ │ │ │ │ + options.symbolizers = new Array(len); │ │ │ │ │ + for (var i = 0; i < len; ++i) { │ │ │ │ │ + options.symbolizers[i] = this.symbolizers[i].clone(); │ │ │ │ │ + } │ │ │ │ │ + } else { │ │ │ │ │ + // clone symbolizer │ │ │ │ │ + options.symbolizer = {}; │ │ │ │ │ + var value, type; │ │ │ │ │ + for (var key in this.symbolizer) { │ │ │ │ │ + value = this.symbolizer[key]; │ │ │ │ │ + type = typeof value; │ │ │ │ │ + if (type === "object") { │ │ │ │ │ + options.symbolizer[key] = OpenLayers.Util.extend({}, value); │ │ │ │ │ + } else if (type === "string") { │ │ │ │ │ + options.symbolizer[key] = value; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + // clone filter │ │ │ │ │ + options.filter = this.filter && this.filter.clone(); │ │ │ │ │ + // clone context │ │ │ │ │ + options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ │ + return new OpenLayers.Rule(options); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Rule" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Format/WPSDescribeProcess.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Format/XML.js │ │ │ │ │ + * @requires OpenLayers/Format/OWSCommon/v1_1_0.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Format.WPSDescribeProcess │ │ │ │ │ + * Read WPS DescribeProcess responses. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Format.WPSDescribeProcess = OpenLayers.Class( │ │ │ │ │ + OpenLayers.Format.XML, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constant: VERSION │ │ │ │ │ + * {String} 1.0.0 │ │ │ │ │ + */ │ │ │ │ │ + VERSION: "1.0.0", │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: namespaces │ │ │ │ │ + * {Object} Mapping of namespace aliases to namespace URIs. │ │ │ │ │ + */ │ │ │ │ │ + namespaces: { │ │ │ │ │ + wps: "http://www.opengis.net/wps/1.0.0", │ │ │ │ │ + ows: "http://www.opengis.net/ows/1.1", │ │ │ │ │ + xsi: "http://www.w3.org/2001/XMLSchema-instance" │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: schemaLocation │ │ │ │ │ + * {String} Schema location │ │ │ │ │ + */ │ │ │ │ │ + schemaLocation: "http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd", │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: defaultPrefix │ │ │ │ │ + */ │ │ │ │ │ + defaultPrefix: "wps", │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: regExes │ │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ │ + */ │ │ │ │ │ + regExes: { │ │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Format.WPSDescribeProcess │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ │ + * this instance. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: read │ │ │ │ │ + * Parse a WPS DescribeProcess and return an object with its information. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Object} │ │ │ │ │ + */ │ │ │ │ │ + read: function(data) { │ │ │ │ │ + if (typeof data == "string") { │ │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ │ + } │ │ │ │ │ + if (data && data.nodeType == 9) { │ │ │ │ │ + data = data.documentElement; │ │ │ │ │ + } │ │ │ │ │ + var info = {}; │ │ │ │ │ + this.readNode(data, info); │ │ │ │ │ + return info; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: readers │ │ │ │ │ + * Contains public functions, grouped by namespace prefix, that will │ │ │ │ │ + * be applied when a namespaced node is found matching the function │ │ │ │ │ + * name. The function will be applied in the scope of this parser │ │ │ │ │ + * with two arguments: the node being read and a context object passed │ │ │ │ │ + * from the parent. │ │ │ │ │ + */ │ │ │ │ │ + readers: { │ │ │ │ │ + "wps": { │ │ │ │ │ + "ProcessDescriptions": function(node, obj) { │ │ │ │ │ + obj.processDescriptions = {}; │ │ │ │ │ + this.readChildNodes(node, obj.processDescriptions); │ │ │ │ │ + }, │ │ │ │ │ + "ProcessDescription": function(node, processDescriptions) { │ │ │ │ │ + var processVersion = this.getAttributeNS(node, this.namespaces.wps, "processVersion"); │ │ │ │ │ + var processDescription = { │ │ │ │ │ + processVersion: processVersion, │ │ │ │ │ + statusSupported: (node.getAttribute("statusSupported") === "true"), │ │ │ │ │ + storeSupported: (node.getAttribute("storeSupported") === "true") │ │ │ │ │ + }; │ │ │ │ │ + this.readChildNodes(node, processDescription); │ │ │ │ │ + processDescriptions[processDescription.identifier] = processDescription; │ │ │ │ │ + }, │ │ │ │ │ + "DataInputs": function(node, processDescription) { │ │ │ │ │ + processDescription.dataInputs = []; │ │ │ │ │ + this.readChildNodes(node, processDescription.dataInputs); │ │ │ │ │ + }, │ │ │ │ │ + "ProcessOutputs": function(node, processDescription) { │ │ │ │ │ + processDescription.processOutputs = []; │ │ │ │ │ + this.readChildNodes(node, processDescription.processOutputs); │ │ │ │ │ + }, │ │ │ │ │ + "Output": function(node, processOutputs) { │ │ │ │ │ + var output = {}; │ │ │ │ │ + this.readChildNodes(node, output); │ │ │ │ │ + processOutputs.push(output); │ │ │ │ │ + }, │ │ │ │ │ + "ComplexOutput": function(node, output) { │ │ │ │ │ + output.complexOutput = {}; │ │ │ │ │ + this.readChildNodes(node, output.complexOutput); │ │ │ │ │ + }, │ │ │ │ │ + "LiteralOutput": function(node, output) { │ │ │ │ │ + output.literalOutput = {}; │ │ │ │ │ + this.readChildNodes(node, output.literalOutput); │ │ │ │ │ + }, │ │ │ │ │ + "Input": function(node, dataInputs) { │ │ │ │ │ + var input = { │ │ │ │ │ + maxOccurs: parseInt(node.getAttribute("maxOccurs")), │ │ │ │ │ + minOccurs: parseInt(node.getAttribute("minOccurs")) │ │ │ │ │ + }; │ │ │ │ │ + this.readChildNodes(node, input); │ │ │ │ │ + dataInputs.push(input); │ │ │ │ │ + }, │ │ │ │ │ + "BoundingBoxData": function(node, input) { │ │ │ │ │ + input.boundingBoxData = {}; │ │ │ │ │ + this.readChildNodes(node, input.boundingBoxData); │ │ │ │ │ + }, │ │ │ │ │ + "CRS": function(node, obj) { │ │ │ │ │ + if (!obj.CRSs) { │ │ │ │ │ + obj.CRSs = {}; │ │ │ │ │ + } │ │ │ │ │ + obj.CRSs[this.getChildValue(node)] = true; │ │ │ │ │ + }, │ │ │ │ │ + "LiteralData": function(node, input) { │ │ │ │ │ + input.literalData = {}; │ │ │ │ │ + this.readChildNodes(node, input.literalData); │ │ │ │ │ + }, │ │ │ │ │ + "ComplexData": function(node, input) { │ │ │ │ │ + input.complexData = {}; │ │ │ │ │ + this.readChildNodes(node, input.complexData); │ │ │ │ │ + }, │ │ │ │ │ + "Default": function(node, complexData) { │ │ │ │ │ + complexData["default"] = {}; │ │ │ │ │ + this.readChildNodes(node, complexData["default"]); │ │ │ │ │ + }, │ │ │ │ │ + "Supported": function(node, complexData) { │ │ │ │ │ + complexData["supported"] = {}; │ │ │ │ │ + this.readChildNodes(node, complexData["supported"]); │ │ │ │ │ + }, │ │ │ │ │ + "Format": function(node, obj) { │ │ │ │ │ + var format = {}; │ │ │ │ │ + this.readChildNodes(node, format); │ │ │ │ │ + if (!obj.formats) { │ │ │ │ │ + obj.formats = {}; │ │ │ │ │ + } │ │ │ │ │ + obj.formats[format.mimeType] = true; │ │ │ │ │ + }, │ │ │ │ │ + "MimeType": function(node, format) { │ │ │ │ │ + format.mimeType = this.getChildValue(node); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + "ows": OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers["ows"] │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WPSDescribeProcess" │ │ │ │ │ + │ │ │ │ │ + }); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/WPSClient.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/SingleFile.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Events.js │ │ │ │ │ + * @requires OpenLayers/WPSProcess.js │ │ │ │ │ + * @requires OpenLayers/Format/WPSDescribeProcess.js │ │ │ │ │ + * @requires OpenLayers/Request.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.WPSClient │ │ │ │ │ + * High level API for interaction with Web Processing Services (WPS). │ │ │ │ │ + * An instance is used to create │ │ │ │ │ + * instances for servers known to the WPSClient. The WPSClient also caches │ │ │ │ │ + * DescribeProcess responses to reduce the number of requests sent to servers │ │ │ │ │ + * when processes are created. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.WPSClient = OpenLayers.Class({ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: servers │ │ │ │ │ + * {Object} Service metadata, keyed by a local identifier. │ │ │ │ │ + * │ │ │ │ │ + * Properties: │ │ │ │ │ + * url - {String} the url of the server │ │ │ │ │ + * version - {String} WPS version of the server │ │ │ │ │ + * processDescription - {Object} Cache of raw DescribeProcess │ │ │ │ │ + * responses, keyed by process identifier. │ │ │ │ │ + */ │ │ │ │ │ + servers: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: version │ │ │ │ │ + * {String} The default WPS version to use if none is configured. Default │ │ │ │ │ + * is '1.0.0'. │ │ │ │ │ + */ │ │ │ │ │ + version: '1.0.0', │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: lazy │ │ │ │ │ + * {Boolean} Should the DescribeProcess be deferred until a process is │ │ │ │ │ + * fully configured? Default is false. │ │ │ │ │ + */ │ │ │ │ │ + lazy: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: events │ │ │ │ │ + * {} │ │ │ │ │ + * │ │ │ │ │ + * Supported event types: │ │ │ │ │ + * describeprocess - Fires when the process description is available. │ │ │ │ │ + * Listeners receive an object with a 'raw' property holding the raw │ │ │ │ │ + * DescribeProcess response, and an 'identifier' property holding the │ │ │ │ │ + * process identifier of the described process. │ │ │ │ │ + */ │ │ │ │ │ + events: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.WPSClient │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} Object whose properties will be set on the instance. │ │ │ │ │ + * │ │ │ │ │ + * Avaliable options: │ │ │ │ │ + * servers - {Object} Mandatory. Service metadata, keyed by a local │ │ │ │ │ + * identifier. Can either be a string with the service url or an │ │ │ │ │ + * object literal with additional metadata: │ │ │ │ │ + * │ │ │ │ │ + * (code) │ │ │ │ │ + * servers: { │ │ │ │ │ + * local: '/geoserver/wps' │ │ │ │ │ + * }, { │ │ │ │ │ + * opengeo: { │ │ │ │ │ + * url: 'http://demo.opengeo.org/geoserver/wps', │ │ │ │ │ + * version: '1.0.0' │ │ │ │ │ + * } │ │ │ │ │ + * } │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * lazy - {Boolean} Optional. Set to true if DescribeProcess should not be │ │ │ │ │ + * requested until a process is fully configured. Default is false. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + this.events = new OpenLayers.Events(this); │ │ │ │ │ + this.servers = {}; │ │ │ │ │ + for (var s in options.servers) { │ │ │ │ │ + this.servers[s] = typeof options.servers[s] == 'string' ? { │ │ │ │ │ + url: options.servers[s], │ │ │ │ │ + version: this.version, │ │ │ │ │ + processDescription: {} │ │ │ │ │ + } : options.servers[s]; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: execute │ │ │ │ │ + * Shortcut to execute a process with a single function call. This is │ │ │ │ │ + * equivalent to using and then calling execute on the │ │ │ │ │ + * process. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} Options for the execute operation. │ │ │ │ │ + * │ │ │ │ │ + * Available options: │ │ │ │ │ + * server - {String} Mandatory. One of the local identifiers of the │ │ │ │ │ + * configured servers. │ │ │ │ │ + * process - {String} Mandatory. A process identifier known to the │ │ │ │ │ + * server. │ │ │ │ │ + * inputs - {Object} The inputs for the process, keyed by input identifier. │ │ │ │ │ + * For spatial data inputs, the value of an input is usually an │ │ │ │ │ + * , an or an array of │ │ │ │ │ + * geometries or features. │ │ │ │ │ + * output - {String} The identifier of an output to parse. Optional. If not │ │ │ │ │ + * provided, the first output will be parsed. │ │ │ │ │ + * success - {Function} Callback to call when the process is complete. │ │ │ │ │ + * This function is called with an outputs object as argument, which │ │ │ │ │ + * will have a property with the identifier of the requested output │ │ │ │ │ + * (e.g. 'result'). For processes that generate spatial output, the │ │ │ │ │ + * value will either be a single or an │ │ │ │ │ + * array of features. │ │ │ │ │ + * scope - {Object} Optional scope for the success callback. │ │ │ │ │ + */ │ │ │ │ │ + execute: function(options) { │ │ │ │ │ + var process = this.getProcess(options.server, options.process); │ │ │ │ │ + process.execute({ │ │ │ │ │ + inputs: options.inputs, │ │ │ │ │ + success: options.success, │ │ │ │ │ + scope: options.scope │ │ │ │ │ + }); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: getProcess │ │ │ │ │ + * Creates an . │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * serverID - {String} Local identifier from the servers that this instance │ │ │ │ │ + * was constructed with. │ │ │ │ │ + * processID - {String} Process identifier known to the server. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} │ │ │ │ │ + */ │ │ │ │ │ + getProcess: function(serverID, processID) { │ │ │ │ │ + var process = new OpenLayers.WPSProcess({ │ │ │ │ │ + client: this, │ │ │ │ │ + server: serverID, │ │ │ │ │ + identifier: processID │ │ │ │ │ + }); │ │ │ │ │ + if (!this.lazy) { │ │ │ │ │ + process.describe(); │ │ │ │ │ + } │ │ │ │ │ + return process; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: describeProcess │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * serverID - {String} Identifier of the server │ │ │ │ │ + * processID - {String} Identifier of the requested process │ │ │ │ │ + * callback - {Function} Callback to call when the description is available │ │ │ │ │ + * scope - {Object} Optional execution scope for the callback function │ │ │ │ │ + */ │ │ │ │ │ + describeProcess: function(serverID, processID, callback, scope) { │ │ │ │ │ + var server = this.servers[serverID]; │ │ │ │ │ + if (!server.processDescription[processID]) { │ │ │ │ │ + if (!(processID in server.processDescription)) { │ │ │ │ │ + // set to null so we know a describeFeature request is pending │ │ │ │ │ + server.processDescription[processID] = null; │ │ │ │ │ + OpenLayers.Request.GET({ │ │ │ │ │ + url: server.url, │ │ │ │ │ + params: { │ │ │ │ │ + SERVICE: 'WPS', │ │ │ │ │ + VERSION: server.version, │ │ │ │ │ + REQUEST: 'DescribeProcess', │ │ │ │ │ + IDENTIFIER: processID │ │ │ │ │ + }, │ │ │ │ │ + success: function(response) { │ │ │ │ │ + server.processDescription[processID] = response.responseText; │ │ │ │ │ + this.events.triggerEvent('describeprocess', { │ │ │ │ │ + identifier: processID, │ │ │ │ │ + raw: response.responseText │ │ │ │ │ + }); │ │ │ │ │ + }, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + } else { │ │ │ │ │ + // pending request │ │ │ │ │ + this.events.register('describeprocess', this, function describe(evt) { │ │ │ │ │ + if (evt.identifier === processID) { │ │ │ │ │ + this.events.unregister('describeprocess', this, describe); │ │ │ │ │ + callback.call(scope, evt.raw); │ │ │ │ │ + } │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + } else { │ │ │ │ │ + window.setTimeout(function() { │ │ │ │ │ + callback.call(scope, server.processDescription[processID]); │ │ │ │ │ + }, 0); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroy │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + this.events.destroy(); │ │ │ │ │ + this.events = null; │ │ │ │ │ + this.servers = null; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: 'OpenLayers.WPSClient' │ │ │ │ │ + │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Kinetic.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Animation.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +OpenLayers.Kinetic = OpenLayers.Class({ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: threshold │ │ │ │ │ + * In most cases changing the threshold isn't needed. │ │ │ │ │ + * In px/ms, default to 0. │ │ │ │ │ + */ │ │ │ │ │ + threshold: 0, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: deceleration │ │ │ │ │ + * {Float} the deseleration in px/ms², default to 0.0035. │ │ │ │ │ + */ │ │ │ │ │ + deceleration: 0.0035, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: nbPoints │ │ │ │ │ + * {Integer} the number of points we use to calculate the kinetic │ │ │ │ │ + * initial values. │ │ │ │ │ + */ │ │ │ │ │ + nbPoints: 100, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: delay │ │ │ │ │ + * {Float} time to consider to calculate the kinetic initial values. │ │ │ │ │ + * In ms, default to 200. │ │ │ │ │ + */ │ │ │ │ │ + delay: 200, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: points │ │ │ │ │ + * List of points use to calculate the kinetic initial values. │ │ │ │ │ + */ │ │ │ │ │ + points: undefined, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: timerId │ │ │ │ │ + * ID of the timer. │ │ │ │ │ + */ │ │ │ │ │ + timerId: undefined, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Kinetic │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + OpenLayers.Util.extend(this, options); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: begin │ │ │ │ │ + * Begins the dragging. │ │ │ │ │ + */ │ │ │ │ │ + begin: function() { │ │ │ │ │ + OpenLayers.Animation.stop(this.timerId); │ │ │ │ │ + this.timerId = undefined; │ │ │ │ │ + this.points = []; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: update │ │ │ │ │ + * Updates during the dragging. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * xy - {} The new position. │ │ │ │ │ + */ │ │ │ │ │ + update: function(xy) { │ │ │ │ │ + this.points.unshift({ │ │ │ │ │ + xy: xy, │ │ │ │ │ + tick: new Date().getTime() │ │ │ │ │ + }); │ │ │ │ │ + if (this.points.length > this.nbPoints) { │ │ │ │ │ + this.points.pop(); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: end │ │ │ │ │ + * Ends the dragging, start the kinetic. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * xy - {} The last position. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Object} An object with two properties: "speed", and "theta". The │ │ │ │ │ + * "speed" and "theta" values are to be passed to the move │ │ │ │ │ + * function when starting the animation. │ │ │ │ │ + */ │ │ │ │ │ + end: function(xy) { │ │ │ │ │ + var last, now = new Date().getTime(); │ │ │ │ │ + for (var i = 0, l = this.points.length, point; i < l; i++) { │ │ │ │ │ + point = this.points[i]; │ │ │ │ │ + if (now - point.tick > this.delay) { │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + last = point; │ │ │ │ │ + } │ │ │ │ │ + if (!last) { │ │ │ │ │ + return; │ │ │ │ │ + } │ │ │ │ │ + var time = new Date().getTime() - last.tick; │ │ │ │ │ + var dist = Math.sqrt(Math.pow(xy.x - last.xy.x, 2) + │ │ │ │ │ + Math.pow(xy.y - last.xy.y, 2)); │ │ │ │ │ + var speed = dist / time; │ │ │ │ │ + if (speed == 0 || speed < this.threshold) { │ │ │ │ │ + return; │ │ │ │ │ + } │ │ │ │ │ + var theta = Math.asin((xy.y - last.xy.y) / dist); │ │ │ │ │ + if (last.xy.x <= xy.x) { │ │ │ │ │ + theta = Math.PI - theta; │ │ │ │ │ + } │ │ │ │ │ + return { │ │ │ │ │ + speed: speed, │ │ │ │ │ + theta: theta │ │ │ │ │ + }; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: move │ │ │ │ │ + * Launch the kinetic move pan. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * info - {Object} An object with two properties, "speed", and "theta". │ │ │ │ │ + * These values are those returned from the "end" call. │ │ │ │ │ + * callback - {Function} Function called on every step of the animation, │ │ │ │ │ + * receives x, y (values to pan), end (is the last point). │ │ │ │ │ + */ │ │ │ │ │ + move: function(info, callback) { │ │ │ │ │ + var v0 = info.speed; │ │ │ │ │ + var fx = Math.cos(info.theta); │ │ │ │ │ + var fy = -Math.sin(info.theta); │ │ │ │ │ + │ │ │ │ │ + var initialTime = new Date().getTime(); │ │ │ │ │ + │ │ │ │ │ + var lastX = 0; │ │ │ │ │ + var lastY = 0; │ │ │ │ │ + │ │ │ │ │ + var timerCallback = function() { │ │ │ │ │ + if (this.timerId == null) { │ │ │ │ │ + return; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + var t = new Date().getTime() - initialTime; │ │ │ │ │ + │ │ │ │ │ + var p = (-this.deceleration * Math.pow(t, 2)) / 2.0 + v0 * t; │ │ │ │ │ + var x = p * fx; │ │ │ │ │ + var y = p * fy; │ │ │ │ │ + │ │ │ │ │ + var args = {}; │ │ │ │ │ + args.end = false; │ │ │ │ │ + var v = -this.deceleration * t + v0; │ │ │ │ │ + │ │ │ │ │ + if (v <= 0) { │ │ │ │ │ + OpenLayers.Animation.stop(this.timerId); │ │ │ │ │ + this.timerId = null; │ │ │ │ │ + args.end = true; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + args.x = x - lastX; │ │ │ │ │ + args.y = y - lastY; │ │ │ │ │ + lastX = x; │ │ │ │ │ + lastY = y; │ │ │ │ │ + callback(args.x, args.y, args.end); │ │ │ │ │ + }; │ │ │ │ │ + │ │ │ │ │ + this.timerId = OpenLayers.Animation.start( │ │ │ │ │ + OpenLayers.Function.bind(timerCallback, this) │ │ │ │ │ + ); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Kinetic" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ OpenLayers/Layer.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ @@ -27200,14 +30468,573 @@ │ │ │ │ │ } │ │ │ │ │ return bounds; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Layer" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ + OpenLayers/Symbolizer/Point.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Symbolizer.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Symbolizer.Point │ │ │ │ │ + * A symbolizer used to render point features. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Symbolizer.Point = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: strokeColor │ │ │ │ │ + * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ │ + * for red). │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: strokeOpacity │ │ │ │ │ + * {Number} Stroke opacity (0-1). │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: strokeWidth │ │ │ │ │ + * {Number} Pixel stroke width. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: strokeLinecap │ │ │ │ │ + * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: strokeDashstyle │ │ │ │ │ + * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ │ + * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ │ + * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ │ + * most SLD patterns will render correctly in OpenLayers. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: fillColor │ │ │ │ │ + * {String} RGB hex fill color (e.g. "#ff0000" for red). │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: fillOpacity │ │ │ │ │ + * {Number} Fill opacity (0-1). │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: pointRadius │ │ │ │ │ + * {Number} Pixel point radius. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: externalGraphic │ │ │ │ │ + * {String} Url to an external graphic that will be used for rendering │ │ │ │ │ + * points. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: graphicWidth │ │ │ │ │ + * {Number} Pixel width for sizing an external graphic. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: graphicHeight │ │ │ │ │ + * {Number} Pixel height for sizing an external graphic. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: graphicOpacity │ │ │ │ │ + * {Number} Opacity (0-1) for an external graphic. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: graphicXOffset │ │ │ │ │ + * {Number} Pixel offset along the positive x axis for displacing an │ │ │ │ │ + * external graphic. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: graphicYOffset │ │ │ │ │ + * {Number} Pixel offset along the positive y axis for displacing an │ │ │ │ │ + * external graphic. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: rotation │ │ │ │ │ + * {Number} The rotation of a graphic in the clockwise direction about its │ │ │ │ │ + * center point (or any point off center as specified by │ │ │ │ │ + * and ). │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: graphicName │ │ │ │ │ + * {String} Named graphic to use when rendering points. Supported values │ │ │ │ │ + * include "circle", "square", "star", "x", "cross", and "triangle". │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Symbolizer.Point │ │ │ │ │ + * Create a symbolizer for rendering points. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ │ + * construction. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * A new point symbolizer. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(config) { │ │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Point" │ │ │ │ │ + │ │ │ │ │ +}); │ │ │ │ │ + │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Symbolizer/Line.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Symbolizer.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Symbolizer.Line │ │ │ │ │ + * A symbolizer used to render line features. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Symbolizer.Line = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: strokeColor │ │ │ │ │ + * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ │ + * for red). │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: strokeOpacity │ │ │ │ │ + * {Number} Stroke opacity (0-1). │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: strokeWidth │ │ │ │ │ + * {Number} Pixel stroke width. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: strokeLinecap │ │ │ │ │ + * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: strokeDashstyle │ │ │ │ │ + * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ │ + * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ │ + * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ │ + * most SLD patterns will render correctly in OpenLayers. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Symbolizer.Line │ │ │ │ │ + * Create a symbolizer for rendering lines. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ │ + * construction. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * A new line symbolizer. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(config) { │ │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Line" │ │ │ │ │ + │ │ │ │ │ +}); │ │ │ │ │ + │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Symbolizer/Polygon.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Symbolizer.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Symbolizer.Polygon │ │ │ │ │ + * A symbolizer used to render line features. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Symbolizer.Polygon = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: strokeColor │ │ │ │ │ + * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ │ + * for red). │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: strokeOpacity │ │ │ │ │ + * {Number} Stroke opacity (0-1). │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: strokeWidth │ │ │ │ │ + * {Number} Pixel stroke width. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: strokeLinecap │ │ │ │ │ + * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: strokeDashstyle │ │ │ │ │ + * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ │ + * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ │ + * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ │ + * most SLD patterns will render correctly in OpenLayers. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: fillColor │ │ │ │ │ + * {String} RGB hex fill color (e.g. "#ff0000" for red). │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: fillOpacity │ │ │ │ │ + * {Number} Fill opacity (0-1). │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Symbolizer.Polygon │ │ │ │ │ + * Create a symbolizer for rendering polygons. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ │ + * construction. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * A new polygon symbolizer. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(config) { │ │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Polygon" │ │ │ │ │ + │ │ │ │ │ +}); │ │ │ │ │ + │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Symbolizer/Text.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Symbolizer.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Symbolizer.Text │ │ │ │ │ + * A symbolizer used to render text labels for features. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: label │ │ │ │ │ + * {String} The text for the label. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: fontFamily │ │ │ │ │ + * {String} The font family for the label. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: fontSize │ │ │ │ │ + * {String} The font size for the label. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: fontWeight │ │ │ │ │ + * {String} The font weight for the label. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: fontStyle │ │ │ │ │ + * {String} The font style for the label. │ │ │ │ │ + * │ │ │ │ │ + * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Symbolizer.Text │ │ │ │ │ + * Create a symbolizer for rendering text labels. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ │ + * construction. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * A new text symbolizer. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(config) { │ │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Text" │ │ │ │ │ + │ │ │ │ │ +}); │ │ │ │ │ + │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Symbolizer/Raster.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Symbolizer.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Symbolizer.Raster │ │ │ │ │ + * A symbolizer used to render raster images. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Symbolizer.Raster = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Symbolizer.Raster │ │ │ │ │ + * Create a symbolizer for rendering rasters. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ │ + * symbolizer. Any documented symbolizer property can be set at │ │ │ │ │ + * construction. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * A new raster symbolizer. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(config) { │ │ │ │ │ + OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Symbolizer.Raster" │ │ │ │ │ + │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Style2.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Rule.js │ │ │ │ │ + * @requires OpenLayers/Symbolizer/Point.js │ │ │ │ │ + * @requires OpenLayers/Symbolizer/Line.js │ │ │ │ │ + * @requires OpenLayers/Symbolizer/Polygon.js │ │ │ │ │ + * @requires OpenLayers/Symbolizer/Text.js │ │ │ │ │ + * @requires OpenLayers/Symbolizer/Raster.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Style2 │ │ │ │ │ + * This class represents a collection of rules for rendering features. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Style2 = OpenLayers.Class({ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: id │ │ │ │ │ + * {String} A unique id for this session. │ │ │ │ │ + */ │ │ │ │ │ + id: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: name │ │ │ │ │ + * {String} Style identifier. │ │ │ │ │ + */ │ │ │ │ │ + name: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: title │ │ │ │ │ + * {String} Title of this style. │ │ │ │ │ + */ │ │ │ │ │ + title: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: description │ │ │ │ │ + * {String} Description of this style. │ │ │ │ │ + */ │ │ │ │ │ + description: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: layerName │ │ │ │ │ + * {} Name of the layer that this style belongs to, usually │ │ │ │ │ + * according to the NamedLayer attribute of an SLD document. │ │ │ │ │ + */ │ │ │ │ │ + layerName: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: isDefault │ │ │ │ │ + * {Boolean} │ │ │ │ │ + */ │ │ │ │ │ + isDefault: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: rules │ │ │ │ │ + * {Array()} Collection of rendering rules. │ │ │ │ │ + */ │ │ │ │ │ + rules: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Style2 │ │ │ │ │ + * Creates a style representing a collection of rendering rules. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * config - {Object} An object containing properties to be set on the │ │ │ │ │ + * style. Any documented properties may be set at construction. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} A new style object. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(config) { │ │ │ │ │ + OpenLayers.Util.extend(this, config); │ │ │ │ │ + this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ + * nullify references to prevent circular references and memory leaks │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + for (var i = 0, len = this.rules.length; i < len; i++) { │ │ │ │ │ + this.rules[i].destroy(); │ │ │ │ │ + } │ │ │ │ │ + delete this.rules; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: clone │ │ │ │ │ + * Clones this style. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} Clone of this style. │ │ │ │ │ + */ │ │ │ │ │ + clone: function() { │ │ │ │ │ + var config = OpenLayers.Util.extend({}, this); │ │ │ │ │ + // clone rules │ │ │ │ │ + if (this.rules) { │ │ │ │ │ + config.rules = []; │ │ │ │ │ + for (var i = 0, len = this.rules.length; i < len; ++i) { │ │ │ │ │ + config.rules.push(this.rules[i].clone()); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return new OpenLayers.Style2(config); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Style2" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ OpenLayers/Layer/HTTPRequest.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ @@ -27436,313 +31263,14 @@ │ │ │ │ │ │ │ │ │ │ return OpenLayers.Util.urlAppend(url, paramsString); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Layer.HTTPRequest" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Tile.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Tile │ │ │ │ │ - * This is a class designed to designate a single tile, however │ │ │ │ │ - * it is explicitly designed to do relatively little. Tiles store │ │ │ │ │ - * information about themselves -- such as the URL that they are related │ │ │ │ │ - * to, and their size - but do not add themselves to the layer div │ │ │ │ │ - * automatically, for example. Create a new tile with the │ │ │ │ │ - * constructor, or a subclass. │ │ │ │ │ - * │ │ │ │ │ - * TBD 3.0 - remove reference to url in above paragraph │ │ │ │ │ - * │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Tile = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: events │ │ │ │ │ - * {} An events object that handles all │ │ │ │ │ - * events on the tile. │ │ │ │ │ - * │ │ │ │ │ - * Register a listener for a particular event with the following syntax: │ │ │ │ │ - * (code) │ │ │ │ │ - * tile.events.register(type, obj, listener); │ │ │ │ │ - * (end) │ │ │ │ │ - * │ │ │ │ │ - * Supported event types: │ │ │ │ │ - * beforedraw - Triggered before the tile is drawn. Used to defer │ │ │ │ │ - * drawing to an animation queue. To defer drawing, listeners need │ │ │ │ │ - * to return false, which will abort drawing. The queue handler needs │ │ │ │ │ - * to call (true) to actually draw the tile. │ │ │ │ │ - * loadstart - Triggered when tile loading starts. │ │ │ │ │ - * loadend - Triggered when tile loading ends. │ │ │ │ │ - * loaderror - Triggered before the loadend event (i.e. when the tile is │ │ │ │ │ - * still hidden) if the tile could not be loaded. │ │ │ │ │ - * reload - Triggered when an already loading tile is reloaded. │ │ │ │ │ - * unload - Triggered before a tile is unloaded. │ │ │ │ │ - */ │ │ │ │ │ - events: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: eventListeners │ │ │ │ │ - * {Object} If set as an option at construction, the eventListeners │ │ │ │ │ - * object will be registered with . Object │ │ │ │ │ - * structure must be a listeners object as shown in the example for │ │ │ │ │ - * the events.on method. │ │ │ │ │ - * │ │ │ │ │ - * This options can be set in the ``tileOptions`` option from │ │ │ │ │ - * . For example, to be notified of the │ │ │ │ │ - * ``loadend`` event of each tiles: │ │ │ │ │ - * (code) │ │ │ │ │ - * new OpenLayers.Layer.OSM('osm', 'http://tile.openstreetmap.org/${z}/${x}/${y}.png', { │ │ │ │ │ - * tileOptions: { │ │ │ │ │ - * eventListeners: { │ │ │ │ │ - * 'loadend': function(evt) { │ │ │ │ │ - * // do something on loadend │ │ │ │ │ - * } │ │ │ │ │ - * } │ │ │ │ │ - * } │ │ │ │ │ - * }); │ │ │ │ │ - * (end) │ │ │ │ │ - */ │ │ │ │ │ - eventListeners: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: id │ │ │ │ │ - * {String} null │ │ │ │ │ - */ │ │ │ │ │ - id: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: layer │ │ │ │ │ - * {} layer the tile is attached to │ │ │ │ │ - */ │ │ │ │ │ - layer: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: url │ │ │ │ │ - * {String} url of the request. │ │ │ │ │ - * │ │ │ │ │ - * TBD 3.0 │ │ │ │ │ - * Deprecated. The base tile class does not need an url. This should be │ │ │ │ │ - * handled in subclasses. Does not belong here. │ │ │ │ │ - */ │ │ │ │ │ - url: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: bounds │ │ │ │ │ - * {} null │ │ │ │ │ - */ │ │ │ │ │ - bounds: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: size │ │ │ │ │ - * {} null │ │ │ │ │ - */ │ │ │ │ │ - size: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: position │ │ │ │ │ - * {} Top Left pixel of the tile │ │ │ │ │ - */ │ │ │ │ │ - position: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: isLoading │ │ │ │ │ - * {Boolean} Is the tile loading? │ │ │ │ │ - */ │ │ │ │ │ - isLoading: false, │ │ │ │ │ - │ │ │ │ │ - /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor. │ │ │ │ │ - * there is no need for the base tile class to have a url. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Tile │ │ │ │ │ - * Constructor for a new instance. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * layer - {} layer that the tile will go in. │ │ │ │ │ - * position - {} │ │ │ │ │ - * bounds - {} │ │ │ │ │ - * url - {} │ │ │ │ │ - * size - {} │ │ │ │ │ - * options - {Object} │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(layer, position, bounds, url, size, options) { │ │ │ │ │ - this.layer = layer; │ │ │ │ │ - this.position = position.clone(); │ │ │ │ │ - this.setBounds(bounds); │ │ │ │ │ - this.url = url; │ │ │ │ │ - if (size) { │ │ │ │ │ - this.size = size.clone(); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - //give the tile a unique id based on its BBOX. │ │ │ │ │ - this.id = OpenLayers.Util.createUniqueID("Tile_"); │ │ │ │ │ - │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ - │ │ │ │ │ - this.events = new OpenLayers.Events(this); │ │ │ │ │ - if (this.eventListeners instanceof Object) { │ │ │ │ │ - this.events.on(this.eventListeners); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: unload │ │ │ │ │ - * Call immediately before destroying if you are listening to tile │ │ │ │ │ - * events, so that counters are properly handled if tile is still │ │ │ │ │ - * loading at destroy-time. Will only fire an event if the tile is │ │ │ │ │ - * still loading. │ │ │ │ │ - */ │ │ │ │ │ - unload: function() { │ │ │ │ │ - if (this.isLoading) { │ │ │ │ │ - this.isLoading = false; │ │ │ │ │ - this.events.triggerEvent("unload"); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ - * Nullify references to prevent circular references and memory leaks. │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - this.layer = null; │ │ │ │ │ - this.bounds = null; │ │ │ │ │ - this.size = null; │ │ │ │ │ - this.position = null; │ │ │ │ │ - │ │ │ │ │ - if (this.eventListeners) { │ │ │ │ │ - this.events.un(this.eventListeners); │ │ │ │ │ - } │ │ │ │ │ - this.events.destroy(); │ │ │ │ │ - this.eventListeners = null; │ │ │ │ │ - this.events = null; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: draw │ │ │ │ │ - * Clear whatever is currently in the tile, then return whether or not │ │ │ │ │ - * it should actually be re-drawn. This is an example implementation │ │ │ │ │ - * that can be overridden by subclasses. The minimum thing to do here │ │ │ │ │ - * is to call and return the result from . │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * force - {Boolean} If true, the tile will not be cleared and no beforedraw │ │ │ │ │ - * event will be fired. This is used for drawing tiles asynchronously │ │ │ │ │ - * after drawing has been cancelled by returning false from a beforedraw │ │ │ │ │ - * listener. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} Whether or not the tile should actually be drawn. Returns null │ │ │ │ │ - * if a beforedraw listener returned false. │ │ │ │ │ - */ │ │ │ │ │ - draw: function(force) { │ │ │ │ │ - if (!force) { │ │ │ │ │ - //clear tile's contents and mark as not drawn │ │ │ │ │ - this.clear(); │ │ │ │ │ - } │ │ │ │ │ - var draw = this.shouldDraw(); │ │ │ │ │ - if (draw && !force && this.events.triggerEvent("beforedraw") === false) { │ │ │ │ │ - draw = null; │ │ │ │ │ - } │ │ │ │ │ - return draw; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: shouldDraw │ │ │ │ │ - * Return whether or not the tile should actually be (re-)drawn. The only │ │ │ │ │ - * case where we *wouldn't* want to draw the tile is if the tile is outside │ │ │ │ │ - * its layer's maxExtent │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} Whether or not the tile should actually be drawn. │ │ │ │ │ - */ │ │ │ │ │ - shouldDraw: function() { │ │ │ │ │ - var withinMaxExtent = false, │ │ │ │ │ - maxExtent = this.layer.maxExtent; │ │ │ │ │ - if (maxExtent) { │ │ │ │ │ - var map = this.layer.map; │ │ │ │ │ - var worldBounds = map.baseLayer.wrapDateLine && map.getMaxExtent(); │ │ │ │ │ - if (this.bounds.intersectsBounds(maxExtent, { │ │ │ │ │ - inclusive: false, │ │ │ │ │ - worldBounds: worldBounds │ │ │ │ │ - })) { │ │ │ │ │ - withinMaxExtent = true; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - return withinMaxExtent || this.layer.displayOutsideMaxExtent; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: setBounds │ │ │ │ │ - * Sets the bounds on this instance │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * bounds {} │ │ │ │ │ - */ │ │ │ │ │ - setBounds: function(bounds) { │ │ │ │ │ - bounds = bounds.clone(); │ │ │ │ │ - if (this.layer.map.baseLayer.wrapDateLine) { │ │ │ │ │ - var worldExtent = this.layer.map.getMaxExtent(), │ │ │ │ │ - tolerance = this.layer.map.getResolution(); │ │ │ │ │ - bounds = bounds.wrapDateLine(worldExtent, { │ │ │ │ │ - leftTolerance: tolerance, │ │ │ │ │ - rightTolerance: tolerance │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ - this.bounds = bounds; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: moveTo │ │ │ │ │ - * Reposition the tile. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * bounds - {} │ │ │ │ │ - * position - {} │ │ │ │ │ - * redraw - {Boolean} Call draw method on tile after moving. │ │ │ │ │ - * Default is true │ │ │ │ │ - */ │ │ │ │ │ - moveTo: function(bounds, position, redraw) { │ │ │ │ │ - if (redraw == null) { │ │ │ │ │ - redraw = true; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - this.setBounds(bounds); │ │ │ │ │ - this.position = position.clone(); │ │ │ │ │ - if (redraw) { │ │ │ │ │ - this.draw(); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: clear │ │ │ │ │ - * Clear the tile of any bounds/position-related data so that it can │ │ │ │ │ - * be reused in a new location. │ │ │ │ │ - */ │ │ │ │ │ - clear: function(draw) { │ │ │ │ │ - // to be extended by subclasses │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Tile" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ OpenLayers/Tile/Image.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ @@ -30087,3127 +33615,1704 @@ │ │ │ │ │ this.tileCache = null; │ │ │ │ │ this.tileCacheIndex = null; │ │ │ │ │ this._destroyed = true; │ │ │ │ │ } │ │ │ │ │ │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Marker.js │ │ │ │ │ + OpenLayers/Marker/Box.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Events.js │ │ │ │ │ - * @requires OpenLayers/Icon.js │ │ │ │ │ + * @requires OpenLayers/Marker.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Marker │ │ │ │ │ - * Instances of OpenLayers.Marker are a combination of a │ │ │ │ │ - * and an . │ │ │ │ │ - * │ │ │ │ │ - * Markers are generally added to a special layer called │ │ │ │ │ - * . │ │ │ │ │ - * │ │ │ │ │ - * Example: │ │ │ │ │ - * (code) │ │ │ │ │ - * var markers = new OpenLayers.Layer.Markers( "Markers" ); │ │ │ │ │ - * map.addLayer(markers); │ │ │ │ │ - * │ │ │ │ │ - * var size = new OpenLayers.Size(21,25); │ │ │ │ │ - * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h); │ │ │ │ │ - * var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset); │ │ │ │ │ - * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon)); │ │ │ │ │ - * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone())); │ │ │ │ │ - * │ │ │ │ │ - * (end) │ │ │ │ │ + * Class: OpenLayers.Marker.Box │ │ │ │ │ * │ │ │ │ │ - * Note that if you pass an icon into the Marker constructor, it will take │ │ │ │ │ - * that icon and use it. This means that you should not share icons between │ │ │ │ │ - * markers -- you use them once, but you should clone() for any additional │ │ │ │ │ - * markers using that same icon. │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Marker = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: icon │ │ │ │ │ - * {} The icon used by this marker. │ │ │ │ │ - */ │ │ │ │ │ - icon: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: lonlat │ │ │ │ │ - * {} location of object │ │ │ │ │ - */ │ │ │ │ │ - lonlat: null, │ │ │ │ │ +OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, { │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: events │ │ │ │ │ - * {} the event handler. │ │ │ │ │ + * Property: bounds │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - events: null, │ │ │ │ │ + bounds: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: map │ │ │ │ │ - * {} the map this marker is attached to │ │ │ │ │ + * Property: div │ │ │ │ │ + * {DOMElement} │ │ │ │ │ */ │ │ │ │ │ - map: null, │ │ │ │ │ + div: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Marker │ │ │ │ │ + * Constructor: OpenLayers.Marker.Box │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * lonlat - {} the position of this marker │ │ │ │ │ - * icon - {} the icon for this marker │ │ │ │ │ + * bounds - {} │ │ │ │ │ + * borderColor - {String} │ │ │ │ │ + * borderWidth - {int} │ │ │ │ │ */ │ │ │ │ │ - initialize: function(lonlat, icon) { │ │ │ │ │ - this.lonlat = lonlat; │ │ │ │ │ - │ │ │ │ │ - var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon(); │ │ │ │ │ - if (this.icon == null) { │ │ │ │ │ - this.icon = newIcon; │ │ │ │ │ - } else { │ │ │ │ │ - this.icon.url = newIcon.url; │ │ │ │ │ - this.icon.size = newIcon.size; │ │ │ │ │ - this.icon.offset = newIcon.offset; │ │ │ │ │ - this.icon.calculateOffset = newIcon.calculateOffset; │ │ │ │ │ - } │ │ │ │ │ - this.events = new OpenLayers.Events(this, this.icon.imageDiv); │ │ │ │ │ + initialize: function(bounds, borderColor, borderWidth) { │ │ │ │ │ + this.bounds = bounds; │ │ │ │ │ + this.div = OpenLayers.Util.createDiv(); │ │ │ │ │ + this.div.style.overflow = 'hidden'; │ │ │ │ │ + this.events = new OpenLayers.Events(this, this.div); │ │ │ │ │ + this.setBorder(borderColor, borderWidth); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ - * Destroy the marker. You must first remove the marker from any │ │ │ │ │ - * layer which it has been added to, or you will get buggy behavior. │ │ │ │ │ - * (This can not be done within the marker since the marker does not │ │ │ │ │ - * know which layer it is attached to.) │ │ │ │ │ + * Method: destroy │ │ │ │ │ */ │ │ │ │ │ destroy: function() { │ │ │ │ │ - // erase any drawn features │ │ │ │ │ - this.erase(); │ │ │ │ │ │ │ │ │ │ - this.map = null; │ │ │ │ │ - │ │ │ │ │ - this.events.destroy(); │ │ │ │ │ - this.events = null; │ │ │ │ │ + this.bounds = null; │ │ │ │ │ + this.div = null; │ │ │ │ │ │ │ │ │ │ - if (this.icon != null) { │ │ │ │ │ - this.icon.destroy(); │ │ │ │ │ - this.icon = null; │ │ │ │ │ - } │ │ │ │ │ + OpenLayers.Marker.prototype.destroy.apply(this, arguments); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: draw │ │ │ │ │ - * Calls draw on the icon, and returns that output. │ │ │ │ │ + * Method: setBorder │ │ │ │ │ + * Allow the user to change the box's color and border width │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * px - {} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {DOMElement} A new DOM Image with this marker's icon set at the │ │ │ │ │ - * location passed-in │ │ │ │ │ - */ │ │ │ │ │ - draw: function(px) { │ │ │ │ │ - return this.icon.draw(px); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: erase │ │ │ │ │ - * Erases any drawn elements for this marker. │ │ │ │ │ + * color - {String} Default is "red" │ │ │ │ │ + * width - {int} Default is 2 │ │ │ │ │ */ │ │ │ │ │ - erase: function() { │ │ │ │ │ - if (this.icon != null) { │ │ │ │ │ - this.icon.erase(); │ │ │ │ │ + setBorder: function(color, width) { │ │ │ │ │ + if (!color) { │ │ │ │ │ + color = "red"; │ │ │ │ │ } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: moveTo │ │ │ │ │ - * Move the marker to the new location. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * px - {|Object} the pixel position to move to. │ │ │ │ │ - * An OpenLayers.Pixel or an object with a 'x' and 'y' properties. │ │ │ │ │ - */ │ │ │ │ │ - moveTo: function(px) { │ │ │ │ │ - if ((px != null) && (this.icon != null)) { │ │ │ │ │ - this.icon.moveTo(px); │ │ │ │ │ + if (!width) { │ │ │ │ │ + width = 2; │ │ │ │ │ } │ │ │ │ │ - this.lonlat = this.map.getLonLatFromLayerPx(px); │ │ │ │ │ + this.div.style.border = width + "px solid " + color; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: isDrawn │ │ │ │ │ + /** │ │ │ │ │ + * Method: draw │ │ │ │ │ * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} Whether or not the marker is drawn. │ │ │ │ │ + * Parameters: │ │ │ │ │ + * px - {} │ │ │ │ │ + * sz - {} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {DOMElement} A new DOM Image with this marker's icon set at the │ │ │ │ │ + * location passed-in │ │ │ │ │ */ │ │ │ │ │ - isDrawn: function() { │ │ │ │ │ - var isDrawn = (this.icon && this.icon.isDrawn()); │ │ │ │ │ - return isDrawn; │ │ │ │ │ + draw: function(px, sz) { │ │ │ │ │ + OpenLayers.Util.modifyDOMElement(this.div, null, px, sz); │ │ │ │ │ + return this.div; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ * Method: onScreen │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ + * │ │ │ │ │ + * Rreturn: │ │ │ │ │ * {Boolean} Whether or not the marker is currently visible on screen. │ │ │ │ │ */ │ │ │ │ │ onScreen: function() { │ │ │ │ │ - │ │ │ │ │ var onScreen = false; │ │ │ │ │ if (this.map) { │ │ │ │ │ var screenBounds = this.map.getExtent(); │ │ │ │ │ - onScreen = screenBounds.containsLonLat(this.lonlat); │ │ │ │ │ + onScreen = screenBounds.containsBounds(this.bounds, true, true); │ │ │ │ │ } │ │ │ │ │ return onScreen; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: inflate │ │ │ │ │ - * Englarges the markers icon by the specified ratio. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * inflate - {float} the ratio to enlarge the marker by (passing 2 │ │ │ │ │ - * will double the size). │ │ │ │ │ - */ │ │ │ │ │ - inflate: function(inflate) { │ │ │ │ │ - if (this.icon) { │ │ │ │ │ - this.icon.setSize({ │ │ │ │ │ - w: this.icon.size.w * inflate, │ │ │ │ │ - h: this.icon.size.h * inflate │ │ │ │ │ - }); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: setOpacity │ │ │ │ │ - * Change the opacity of the marker by changin the opacity of │ │ │ │ │ - * its icon │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * opacity - {float} Specified as fraction (0.4, etc) │ │ │ │ │ - */ │ │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ │ - this.icon.setOpacity(opacity); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: setUrl │ │ │ │ │ - * Change URL of the Icon Image. │ │ │ │ │ - * │ │ │ │ │ - * url - {String} │ │ │ │ │ - */ │ │ │ │ │ - setUrl: function(url) { │ │ │ │ │ - this.icon.setUrl(url); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ * Method: display │ │ │ │ │ * Hide or show the icon │ │ │ │ │ * │ │ │ │ │ + * Parameters: │ │ │ │ │ * display - {Boolean} │ │ │ │ │ */ │ │ │ │ │ display: function(display) { │ │ │ │ │ - this.icon.display(display); │ │ │ │ │ + this.div.style.display = (display) ? "" : "none"; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Marker" │ │ │ │ │ + CLASS_NAME: "OpenLayers.Marker.Box" │ │ │ │ │ }); │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Function: defaultIcon │ │ │ │ │ - * Creates a default . │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} A default OpenLayers.Icon to use for a marker │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Marker.defaultIcon = function() { │ │ │ │ │ - return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"), { │ │ │ │ │ - w: 21, │ │ │ │ │ - h: 25 │ │ │ │ │ - }, { │ │ │ │ │ - x: -10.5, │ │ │ │ │ - y: -25 │ │ │ │ │ - }); │ │ │ │ │ -}; │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Strategy.js │ │ │ │ │ + OpenLayers/Strategy/Paging.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Strategy.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Strategy │ │ │ │ │ - * Abstract vector layer strategy class. Not to be instantiated directly. Use │ │ │ │ │ - * one of the strategy subclasses instead. │ │ │ │ │ + * Class: OpenLayers.Strategy.Paging │ │ │ │ │ + * Strategy for vector feature paging │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Strategy = OpenLayers.Class({ │ │ │ │ │ +OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: layer │ │ │ │ │ - * {} The layer this strategy belongs to. │ │ │ │ │ + * Property: features │ │ │ │ │ + * {Array()} Cached features. │ │ │ │ │ */ │ │ │ │ │ - layer: null, │ │ │ │ │ + features: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: options │ │ │ │ │ - * {Object} Any options sent to the constructor. │ │ │ │ │ - */ │ │ │ │ │ - options: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: active │ │ │ │ │ - * {Boolean} The control is active. │ │ │ │ │ + * Property: length │ │ │ │ │ + * {Integer} Number of features per page. Default is 10. │ │ │ │ │ */ │ │ │ │ │ - active: null, │ │ │ │ │ + length: 10, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: autoActivate │ │ │ │ │ - * {Boolean} The creator of the strategy can set autoActivate to false │ │ │ │ │ - * to fully control when the protocol is activated and deactivated. │ │ │ │ │ - * Defaults to true. │ │ │ │ │ + * Property: num │ │ │ │ │ + * {Integer} The currently displayed page number. │ │ │ │ │ */ │ │ │ │ │ - autoActivate: true, │ │ │ │ │ + num: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: autoDestroy │ │ │ │ │ - * {Boolean} The creator of the strategy can set autoDestroy to false │ │ │ │ │ - * to fully control when the strategy is destroyed. Defaults to │ │ │ │ │ - * true. │ │ │ │ │ + * Property: paging │ │ │ │ │ + * {Boolean} The strategy is currently changing pages. │ │ │ │ │ */ │ │ │ │ │ - autoDestroy: true, │ │ │ │ │ + paging: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Strategy │ │ │ │ │ - * Abstract class for vector strategies. Create instances of a subclass. │ │ │ │ │ + * Constructor: OpenLayers.Strategy.Paging │ │ │ │ │ + * Create a new paging strategy. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ * instance. │ │ │ │ │ */ │ │ │ │ │ - initialize: function(options) { │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ - this.options = options; │ │ │ │ │ - // set the active property here, so that user cannot override it │ │ │ │ │ - this.active = false; │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: activate │ │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The strategy was successfully activated. │ │ │ │ │ + */ │ │ │ │ │ + activate: function() { │ │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ │ + if (activated) { │ │ │ │ │ + this.layer.events.on({ │ │ │ │ │ + "beforefeaturesadded": this.cacheFeatures, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + return activated; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ - * Clean up the strategy. │ │ │ │ │ + * APIMethod: deactivate │ │ │ │ │ + * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ │ + * tear-down. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The strategy was successfully deactivated. │ │ │ │ │ */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - this.deactivate(); │ │ │ │ │ - this.layer = null; │ │ │ │ │ - this.options = null; │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ │ + if (deactivated) { │ │ │ │ │ + this.clearCache(); │ │ │ │ │ + this.layer.events.un({ │ │ │ │ │ + "beforefeaturesadded": this.cacheFeatures, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + return deactivated; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: setLayer │ │ │ │ │ - * Called to set the property. │ │ │ │ │ + * Method: cacheFeatures │ │ │ │ │ + * Cache features before they are added to the layer. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * layer - {} │ │ │ │ │ + * event - {Object} The event that this was listening for. This will come │ │ │ │ │ + * with a batch of features to be paged. │ │ │ │ │ */ │ │ │ │ │ - setLayer: function(layer) { │ │ │ │ │ - this.layer = layer; │ │ │ │ │ + cacheFeatures: function(event) { │ │ │ │ │ + if (!this.paging) { │ │ │ │ │ + this.clearCache(); │ │ │ │ │ + this.features = event.features; │ │ │ │ │ + this.pageNext(event); │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: activate │ │ │ │ │ - * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ │ + * Method: clearCache │ │ │ │ │ + * Clear out the cached features. This destroys features, assuming │ │ │ │ │ + * nothing else has a reference. │ │ │ │ │ + */ │ │ │ │ │ + clearCache: function() { │ │ │ │ │ + if (this.features) { │ │ │ │ │ + for (var i = 0; i < this.features.length; ++i) { │ │ │ │ │ + this.features[i].destroy(); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + this.features = null; │ │ │ │ │ + this.num = null; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: pageCount │ │ │ │ │ + * Get the total count of pages given the current cache of features. │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Boolean} True if the strategy was successfully activated or false if │ │ │ │ │ - * the strategy was already active. │ │ │ │ │ + * {Integer} The page count. │ │ │ │ │ */ │ │ │ │ │ - activate: function() { │ │ │ │ │ - if (!this.active) { │ │ │ │ │ - this.active = true; │ │ │ │ │ - return true; │ │ │ │ │ + pageCount: function() { │ │ │ │ │ + var numFeatures = this.features ? this.features.length : 0; │ │ │ │ │ + return Math.ceil(numFeatures / this.length); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: pageNum │ │ │ │ │ + * Get the zero based page number. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Integer} The current page number being displayed. │ │ │ │ │ + */ │ │ │ │ │ + pageNum: function() { │ │ │ │ │ + return this.num; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: pageLength │ │ │ │ │ + * Gets or sets page length. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * newLength - {Integer} Optional length to be set. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Integer} The length of a page (number of features per page). │ │ │ │ │ + */ │ │ │ │ │ + pageLength: function(newLength) { │ │ │ │ │ + if (newLength && newLength > 0) { │ │ │ │ │ + this.length = newLength; │ │ │ │ │ } │ │ │ │ │ - return false; │ │ │ │ │ + return this.length; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: deactivate │ │ │ │ │ - * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ │ - * tear-down. │ │ │ │ │ + * APIMethod: pageNext │ │ │ │ │ + * Display the next page of features. │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Boolean} True if the strategy was successfully deactivated or false if │ │ │ │ │ - * the strategy was already inactive. │ │ │ │ │ + * {Boolean} A new page was displayed. │ │ │ │ │ */ │ │ │ │ │ - deactivate: function() { │ │ │ │ │ - if (this.active) { │ │ │ │ │ - this.active = false; │ │ │ │ │ - return true; │ │ │ │ │ + pageNext: function(event) { │ │ │ │ │ + var changed = false; │ │ │ │ │ + if (this.features) { │ │ │ │ │ + if (this.num === null) { │ │ │ │ │ + this.num = -1; │ │ │ │ │ + } │ │ │ │ │ + var start = (this.num + 1) * this.length; │ │ │ │ │ + changed = this.page(start, event); │ │ │ │ │ } │ │ │ │ │ - return false; │ │ │ │ │ + return changed; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Strategy" │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: pagePrevious │ │ │ │ │ + * Display the previous page of features. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} A new page was displayed. │ │ │ │ │ + */ │ │ │ │ │ + pagePrevious: function() { │ │ │ │ │ + var changed = false; │ │ │ │ │ + if (this.features) { │ │ │ │ │ + if (this.num === null) { │ │ │ │ │ + this.num = this.pageCount(); │ │ │ │ │ + } │ │ │ │ │ + var start = (this.num - 1) * this.length; │ │ │ │ │ + changed = this.page(start); │ │ │ │ │ + } │ │ │ │ │ + return changed; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: page │ │ │ │ │ + * Display the page starting at the given index from the cache. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} A new page was displayed. │ │ │ │ │ + */ │ │ │ │ │ + page: function(start, event) { │ │ │ │ │ + var changed = false; │ │ │ │ │ + if (this.features) { │ │ │ │ │ + if (start >= 0 && start < this.features.length) { │ │ │ │ │ + var num = Math.floor(start / this.length); │ │ │ │ │ + if (num != this.num) { │ │ │ │ │ + this.paging = true; │ │ │ │ │ + var features = this.features.slice(start, start + this.length); │ │ │ │ │ + this.layer.removeFeatures(this.layer.features); │ │ │ │ │ + this.num = num; │ │ │ │ │ + // modify the event if any │ │ │ │ │ + if (event && event.features) { │ │ │ │ │ + // this.was called by an event listener │ │ │ │ │ + event.features = features; │ │ │ │ │ + } else { │ │ │ │ │ + // this was called directly on the strategy │ │ │ │ │ + this.layer.addFeatures(features); │ │ │ │ │ + } │ │ │ │ │ + this.paging = false; │ │ │ │ │ + changed = true; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return changed; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Paging" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Popup.js │ │ │ │ │ + OpenLayers/Strategy/Filter.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ + * @requires OpenLayers/Strategy.js │ │ │ │ │ + * @requires OpenLayers/Filter.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Popup │ │ │ │ │ - * A popup is a small div that can opened and closed on the map. │ │ │ │ │ - * Typically opened in response to clicking on a marker. │ │ │ │ │ - * See . Popup's don't require their own │ │ │ │ │ - * layer and are added the the map using the │ │ │ │ │ - * method. │ │ │ │ │ + * Class: OpenLayers.Strategy.Filter │ │ │ │ │ + * Strategy for limiting features that get added to a layer by │ │ │ │ │ + * evaluating a filter. The strategy maintains a cache of │ │ │ │ │ + * all features until removeFeatures is called on the layer. │ │ │ │ │ * │ │ │ │ │ - * Example: │ │ │ │ │ - * (code) │ │ │ │ │ - * popup = new OpenLayers.Popup("chicken", │ │ │ │ │ - * new OpenLayers.LonLat(5,40), │ │ │ │ │ - * new OpenLayers.Size(200,200), │ │ │ │ │ - * "example popup", │ │ │ │ │ - * true); │ │ │ │ │ - * │ │ │ │ │ - * map.addPopup(popup); │ │ │ │ │ - * (end) │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Popup = OpenLayers.Class({ │ │ │ │ │ +OpenLayers.Strategy.Filter = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: events │ │ │ │ │ - * {} custom event manager │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: filter │ │ │ │ │ + * {} Filter for limiting features sent to the layer. │ │ │ │ │ + * Use the method to update this filter after construction. │ │ │ │ │ */ │ │ │ │ │ - events: null, │ │ │ │ │ + filter: null, │ │ │ │ │ │ │ │ │ │ - /** Property: id │ │ │ │ │ - * {String} the unique identifier assigned to this popup. │ │ │ │ │ + /** │ │ │ │ │ + * Property: cache │ │ │ │ │ + * {Array()} List of currently cached │ │ │ │ │ + * features. │ │ │ │ │ */ │ │ │ │ │ - id: "", │ │ │ │ │ + cache: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: lonlat │ │ │ │ │ - * {} the position of this popup on the map │ │ │ │ │ + /** │ │ │ │ │ + * Property: caching │ │ │ │ │ + * {Boolean} The filter is currently caching features. │ │ │ │ │ */ │ │ │ │ │ - lonlat: null, │ │ │ │ │ + caching: false, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: div │ │ │ │ │ - * {DOMElement} the div that contains this popup. │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Strategy.Filter │ │ │ │ │ + * Create a new filter strategy. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ + * instance. │ │ │ │ │ */ │ │ │ │ │ - div: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: contentSize │ │ │ │ │ - * {} the width and height of the content. │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: activate │ │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ │ + * By default, this strategy automatically activates itself when a layer │ │ │ │ │ + * is added to a map. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} True if the strategy was successfully activated or false if │ │ │ │ │ + * the strategy was already active. │ │ │ │ │ */ │ │ │ │ │ - contentSize: null, │ │ │ │ │ + activate: function() { │ │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments); │ │ │ │ │ + if (activated) { │ │ │ │ │ + this.cache = []; │ │ │ │ │ + this.layer.events.on({ │ │ │ │ │ + "beforefeaturesadded": this.handleAdd, │ │ │ │ │ + "beforefeaturesremoved": this.handleRemove, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + return activated; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: size │ │ │ │ │ - * {} the width and height of the popup. │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: deactivate │ │ │ │ │ + * Deactivate the strategy. Clear the feature cache. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} True if the strategy was successfully deactivated or false if │ │ │ │ │ + * the strategy was already inactive. │ │ │ │ │ */ │ │ │ │ │ - size: null, │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + this.cache = null; │ │ │ │ │ + if (this.layer && this.layer.events) { │ │ │ │ │ + this.layer.events.un({ │ │ │ │ │ + "beforefeaturesadded": this.handleAdd, │ │ │ │ │ + "beforefeaturesremoved": this.handleRemove, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + return OpenLayers.Strategy.prototype.deactivate.apply(this, arguments); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: contentHTML │ │ │ │ │ - * {String} An HTML string for this popup to display. │ │ │ │ │ + /** │ │ │ │ │ + * Method: handleAdd │ │ │ │ │ */ │ │ │ │ │ - contentHTML: null, │ │ │ │ │ + handleAdd: function(event) { │ │ │ │ │ + if (!this.caching && this.filter) { │ │ │ │ │ + var features = event.features; │ │ │ │ │ + event.features = []; │ │ │ │ │ + var feature; │ │ │ │ │ + for (var i = 0, ii = features.length; i < ii; ++i) { │ │ │ │ │ + feature = features[i]; │ │ │ │ │ + if (this.filter.evaluate(feature)) { │ │ │ │ │ + event.features.push(feature); │ │ │ │ │ + } else { │ │ │ │ │ + this.cache.push(feature); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: backgroundColor │ │ │ │ │ - * {String} the background color used by the popup. │ │ │ │ │ + /** │ │ │ │ │ + * Method: handleRemove │ │ │ │ │ */ │ │ │ │ │ - backgroundColor: "", │ │ │ │ │ + handleRemove: function(event) { │ │ │ │ │ + if (!this.caching) { │ │ │ │ │ + this.cache = []; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: opacity │ │ │ │ │ - * {float} the opacity of this popup (between 0.0 and 1.0) │ │ │ │ │ + * APIMethod: setFilter │ │ │ │ │ + * Update the filter for this strategy. This will re-evaluate │ │ │ │ │ + * any features on the layer and in the cache. Only features │ │ │ │ │ + * for which filter.evalute(feature) returns true will be │ │ │ │ │ + * added to the layer. Others will be cached by the strategy. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * filter - {} A filter for evaluating features. │ │ │ │ │ */ │ │ │ │ │ - opacity: "", │ │ │ │ │ + setFilter: function(filter) { │ │ │ │ │ + this.filter = filter; │ │ │ │ │ + var previousCache = this.cache; │ │ │ │ │ + this.cache = []; │ │ │ │ │ + // look through layer for features to remove from layer │ │ │ │ │ + this.handleAdd({ │ │ │ │ │ + features: this.layer.features │ │ │ │ │ + }); │ │ │ │ │ + // cache now contains features to remove from layer │ │ │ │ │ + if (this.cache.length > 0) { │ │ │ │ │ + this.caching = true; │ │ │ │ │ + this.layer.removeFeatures(this.cache.slice()); │ │ │ │ │ + this.caching = false; │ │ │ │ │ + } │ │ │ │ │ + // now look through previous cache for features to add to layer │ │ │ │ │ + if (previousCache.length > 0) { │ │ │ │ │ + var event = { │ │ │ │ │ + features: previousCache │ │ │ │ │ + }; │ │ │ │ │ + this.handleAdd(event); │ │ │ │ │ + if (event.features.length > 0) { │ │ │ │ │ + // event has features to add to layer │ │ │ │ │ + this.caching = true; │ │ │ │ │ + this.layer.addFeatures(event.features); │ │ │ │ │ + this.caching = false; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: border │ │ │ │ │ - * {String} the border size of the popup. (eg 2px) │ │ │ │ │ - */ │ │ │ │ │ - border: "", │ │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Filter" │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: contentDiv │ │ │ │ │ - * {DOMElement} a reference to the element that holds the content of │ │ │ │ │ - * the div. │ │ │ │ │ - */ │ │ │ │ │ - contentDiv: null, │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Strategy/Save.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: groupDiv │ │ │ │ │ - * {DOMElement} First and only child of 'div'. The group Div contains the │ │ │ │ │ - * 'contentDiv' and the 'closeDiv'. │ │ │ │ │ - */ │ │ │ │ │ - groupDiv: null, │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: closeDiv │ │ │ │ │ - * {DOMElement} the optional closer image │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Strategy.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Strategy.Save │ │ │ │ │ + * A strategy that commits newly created or modified features. By default │ │ │ │ │ + * the strategy waits for a call to before persisting changes. By │ │ │ │ │ + * configuring the strategy with the option, changes can be saved │ │ │ │ │ + * automatically. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Strategy.Save = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: events │ │ │ │ │ + * {} An events object that handles all │ │ │ │ │ + * events on the strategy object. │ │ │ │ │ + * │ │ │ │ │ + * Register a listener for a particular event with the following syntax: │ │ │ │ │ + * (code) │ │ │ │ │ + * strategy.events.register(type, obj, listener); │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Supported event types: │ │ │ │ │ + * start - Triggered before saving │ │ │ │ │ + * success - Triggered after a successful transaction │ │ │ │ │ + * fail - Triggered after a failed transaction │ │ │ │ │ + * │ │ │ │ │ */ │ │ │ │ │ - closeDiv: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: autoSize │ │ │ │ │ - * {Boolean} Resize the popup to auto-fit the contents. │ │ │ │ │ - * Default is false. │ │ │ │ │ + * Property: events │ │ │ │ │ + * {} Events instance for triggering this protocol │ │ │ │ │ + * events. │ │ │ │ │ */ │ │ │ │ │ - autoSize: false, │ │ │ │ │ + events: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: minSize │ │ │ │ │ - * {} Minimum size allowed for the popup's contents. │ │ │ │ │ + * APIProperty: auto │ │ │ │ │ + * {Boolean | Number} Auto-save. Default is false. If true, features will be │ │ │ │ │ + * saved immediately after being added to the layer and with each │ │ │ │ │ + * modification or deletion. If auto is a number, features will be │ │ │ │ │ + * saved on an interval provided by the value (in seconds). │ │ │ │ │ */ │ │ │ │ │ - minSize: null, │ │ │ │ │ + auto: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: maxSize │ │ │ │ │ - * {} Maximum size allowed for the popup's contents. │ │ │ │ │ + * Property: timer │ │ │ │ │ + * {Number} The id of the timer. │ │ │ │ │ */ │ │ │ │ │ - maxSize: null, │ │ │ │ │ + timer: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: displayClass │ │ │ │ │ - * {String} The CSS class of the popup. │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Strategy.Save │ │ │ │ │ + * Create a new Save strategy. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ + * instance. │ │ │ │ │ */ │ │ │ │ │ - displayClass: "olPopup", │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + OpenLayers.Strategy.prototype.initialize.apply(this, [options]); │ │ │ │ │ + this.events = new OpenLayers.Events(this); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: contentDisplayClass │ │ │ │ │ - * {String} The CSS class of the popup content div. │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: activate │ │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The strategy was successfully activated. │ │ │ │ │ */ │ │ │ │ │ - contentDisplayClass: "olPopupContent", │ │ │ │ │ + activate: function() { │ │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ │ + if (activated) { │ │ │ │ │ + if (this.auto) { │ │ │ │ │ + if (typeof this.auto === "number") { │ │ │ │ │ + this.timer = window.setInterval( │ │ │ │ │ + OpenLayers.Function.bind(this.save, this), │ │ │ │ │ + this.auto * 1000 │ │ │ │ │ + ); │ │ │ │ │ + } else { │ │ │ │ │ + this.layer.events.on({ │ │ │ │ │ + "featureadded": this.triggerSave, │ │ │ │ │ + "afterfeaturemodified": this.triggerSave, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return activated; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: padding │ │ │ │ │ - * {int or } An extra opportunity to specify internal │ │ │ │ │ - * padding of the content div inside the popup. This was originally │ │ │ │ │ - * confused with the css padding as specified in style.css's │ │ │ │ │ - * 'olPopupContent' class. We would like to get rid of this altogether, │ │ │ │ │ - * except that it does come in handy for the framed and anchoredbubble │ │ │ │ │ - * popups, who need to maintain yet another barrier between their │ │ │ │ │ - * content and the outer border of the popup itself. │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: deactivate │ │ │ │ │ + * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ │ + * tear-down. │ │ │ │ │ * │ │ │ │ │ - * Note that in order to not break API, we must continue to support │ │ │ │ │ - * this property being set as an integer. Really, though, we'd like to │ │ │ │ │ - * have this specified as a Bounds object so that user can specify │ │ │ │ │ - * distinct left, top, right, bottom paddings. With the 3.0 release │ │ │ │ │ - * we can make this only a bounds. │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The strategy was successfully deactivated. │ │ │ │ │ */ │ │ │ │ │ - padding: 0, │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ │ + if (deactivated) { │ │ │ │ │ + if (this.auto) { │ │ │ │ │ + if (typeof this.auto === "number") { │ │ │ │ │ + window.clearInterval(this.timer); │ │ │ │ │ + } else { │ │ │ │ │ + this.layer.events.un({ │ │ │ │ │ + "featureadded": this.triggerSave, │ │ │ │ │ + "afterfeaturemodified": this.triggerSave, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return deactivated; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: disableFirefoxOverflowHack │ │ │ │ │ - * {Boolean} The hack for overflow in Firefox causes all elements │ │ │ │ │ - * to be re-drawn, which causes Flash elements to be │ │ │ │ │ - * re-initialized, which is troublesome. │ │ │ │ │ - * With this property the hack can be disabled. │ │ │ │ │ + /** │ │ │ │ │ + * Method: triggerSave │ │ │ │ │ + * Registered as a listener. Calls save if a feature has insert, update, │ │ │ │ │ + * or delete state. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * event - {Object} The event this function is listening for. │ │ │ │ │ */ │ │ │ │ │ - disableFirefoxOverflowHack: false, │ │ │ │ │ + triggerSave: function(event) { │ │ │ │ │ + var feature = event.feature; │ │ │ │ │ + if (feature.state === OpenLayers.State.INSERT || │ │ │ │ │ + feature.state === OpenLayers.State.UPDATE || │ │ │ │ │ + feature.state === OpenLayers.State.DELETE) { │ │ │ │ │ + this.save([event.feature]); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: fixPadding │ │ │ │ │ - * To be removed in 3.0, this function merely helps us to deal with the │ │ │ │ │ - * case where the user may have set an integer value for padding, │ │ │ │ │ - * instead of an object. │ │ │ │ │ + * APIMethod: save │ │ │ │ │ + * Tell the layer protocol to commit unsaved features. If the layer │ │ │ │ │ + * projection differs from the map projection, features will be │ │ │ │ │ + * transformed into the layer projection before being committed. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * features - {Array} Features to be saved. If null, then default is all │ │ │ │ │ + * features in the layer. Features are assumed to be in the map │ │ │ │ │ + * projection. │ │ │ │ │ */ │ │ │ │ │ - fixPadding: function() { │ │ │ │ │ - if (typeof this.padding == "number") { │ │ │ │ │ - this.padding = new OpenLayers.Bounds( │ │ │ │ │ - this.padding, this.padding, this.padding, this.padding │ │ │ │ │ - ); │ │ │ │ │ + save: function(features) { │ │ │ │ │ + if (!features) { │ │ │ │ │ + features = this.layer.features; │ │ │ │ │ } │ │ │ │ │ + this.events.triggerEvent("start", { │ │ │ │ │ + features: features │ │ │ │ │ + }); │ │ │ │ │ + var remote = this.layer.projection; │ │ │ │ │ + var local = this.layer.map.getProjectionObject(); │ │ │ │ │ + if (!local.equals(remote)) { │ │ │ │ │ + var len = features.length; │ │ │ │ │ + var clones = new Array(len); │ │ │ │ │ + var orig, clone; │ │ │ │ │ + for (var i = 0; i < len; ++i) { │ │ │ │ │ + orig = features[i]; │ │ │ │ │ + clone = orig.clone(); │ │ │ │ │ + clone.fid = orig.fid; │ │ │ │ │ + clone.state = orig.state; │ │ │ │ │ + if (orig.url) { │ │ │ │ │ + clone.url = orig.url; │ │ │ │ │ + } │ │ │ │ │ + clone._original = orig; │ │ │ │ │ + clone.geometry.transform(local, remote); │ │ │ │ │ + clones[i] = clone; │ │ │ │ │ + } │ │ │ │ │ + features = clones; │ │ │ │ │ + } │ │ │ │ │ + this.layer.protocol.commit(features, { │ │ │ │ │ + callback: this.onCommit, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: panMapIfOutOfView │ │ │ │ │ - * {Boolean} When drawn, pan map such that the entire popup is visible in │ │ │ │ │ - * the current viewport (if necessary). │ │ │ │ │ - * Default is false. │ │ │ │ │ + * Method: onCommit │ │ │ │ │ + * Called after protocol commit. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * response - {} A response object. │ │ │ │ │ */ │ │ │ │ │ - panMapIfOutOfView: false, │ │ │ │ │ + onCommit: function(response) { │ │ │ │ │ + var evt = { │ │ │ │ │ + "response": response │ │ │ │ │ + }; │ │ │ │ │ + if (response.success()) { │ │ │ │ │ + var features = response.reqFeatures; │ │ │ │ │ + // deal with inserts, updates, and deletes │ │ │ │ │ + var state, feature; │ │ │ │ │ + var destroys = []; │ │ │ │ │ + var insertIds = response.insertIds || []; │ │ │ │ │ + var j = 0; │ │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ │ + feature = features[i]; │ │ │ │ │ + // if projection was different, we may be dealing with clones │ │ │ │ │ + feature = feature._original || feature; │ │ │ │ │ + state = feature.state; │ │ │ │ │ + if (state) { │ │ │ │ │ + if (state == OpenLayers.State.DELETE) { │ │ │ │ │ + destroys.push(feature); │ │ │ │ │ + } else if (state == OpenLayers.State.INSERT) { │ │ │ │ │ + feature.fid = insertIds[j]; │ │ │ │ │ + ++j; │ │ │ │ │ + } │ │ │ │ │ + feature.state = null; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (destroys.length > 0) { │ │ │ │ │ + this.layer.destroyFeatures(destroys); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.events.triggerEvent("success", evt); │ │ │ │ │ + │ │ │ │ │ + } else { │ │ │ │ │ + this.events.triggerEvent("fail", evt); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Save" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Strategy/Fixed.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Strategy.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Strategy.Fixed │ │ │ │ │ + * A simple strategy that requests features once and never requests new data. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: keepInMap │ │ │ │ │ - * {Boolean} If panMapIfOutOfView is false, and this property is true, │ │ │ │ │ - * contrain the popup such that it always fits in the available map │ │ │ │ │ - * space. By default, this is not set on the base class. If you are │ │ │ │ │ - * creating popups that are near map edges and not allowing pannning, │ │ │ │ │ - * and especially if you have a popup which has a │ │ │ │ │ - * fixedRelativePosition, setting this to false may be a smart thing to │ │ │ │ │ - * do. Subclasses may want to override this setting. │ │ │ │ │ - * │ │ │ │ │ - * Default is false. │ │ │ │ │ + * APIProperty: preload │ │ │ │ │ + * {Boolean} Load data before layer made visible. Enabling this may result │ │ │ │ │ + * in considerable overhead if your application loads many data layers │ │ │ │ │ + * that are not visible by default. Default is false. │ │ │ │ │ */ │ │ │ │ │ - keepInMap: false, │ │ │ │ │ + preload: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: closeOnMove │ │ │ │ │ - * {Boolean} When map pans, close the popup. │ │ │ │ │ - * Default is false. │ │ │ │ │ + * Constructor: OpenLayers.Strategy.Fixed │ │ │ │ │ + * Create a new Fixed strategy. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ + * instance. │ │ │ │ │ */ │ │ │ │ │ - closeOnMove: false, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: map │ │ │ │ │ - * {} this gets set in Map.js when the popup is added to the map │ │ │ │ │ + /** │ │ │ │ │ + * Method: activate │ │ │ │ │ + * Activate the strategy: load data or add listener to load when visible │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} True if the strategy was successfully activated or false if │ │ │ │ │ + * the strategy was already active. │ │ │ │ │ */ │ │ │ │ │ - map: null, │ │ │ │ │ + activate: function() { │ │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments); │ │ │ │ │ + if (activated) { │ │ │ │ │ + this.layer.events.on({ │ │ │ │ │ + "refresh": this.load, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + if (this.layer.visibility == true || this.preload) { │ │ │ │ │ + this.load(); │ │ │ │ │ + } else { │ │ │ │ │ + this.layer.events.on({ │ │ │ │ │ + "visibilitychanged": this.load, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return activated; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Popup │ │ │ │ │ - * Create a popup. │ │ │ │ │ + /** │ │ │ │ │ + * Method: deactivate │ │ │ │ │ + * Deactivate the strategy. Undo what is done in . │ │ │ │ │ * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * id - {String} a unqiue identifier for this popup. If null is passed │ │ │ │ │ - * an identifier will be automatically generated. │ │ │ │ │ - * lonlat - {} The position on the map the popup will │ │ │ │ │ - * be shown. │ │ │ │ │ - * contentSize - {} The size of the content. │ │ │ │ │ - * contentHTML - {String} An HTML string to display inside the │ │ │ │ │ - * popup. │ │ │ │ │ - * closeBox - {Boolean} Whether to display a close box inside │ │ │ │ │ - * the popup. │ │ │ │ │ - * closeBoxCallback - {Function} Function to be called on closeBox click. │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The strategy was successfully deactivated. │ │ │ │ │ */ │ │ │ │ │ - initialize: function(id, lonlat, contentSize, contentHTML, closeBox, closeBoxCallback) { │ │ │ │ │ - if (id == null) { │ │ │ │ │ - id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ │ + if (deactivated) { │ │ │ │ │ + this.layer.events.un({ │ │ │ │ │ + "refresh": this.load, │ │ │ │ │ + "visibilitychanged": this.load, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ } │ │ │ │ │ + return deactivated; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - this.id = id; │ │ │ │ │ - this.lonlat = lonlat; │ │ │ │ │ + /** │ │ │ │ │ + * Method: load │ │ │ │ │ + * Tells protocol to load data and unhooks the visibilitychanged event │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} options to pass to protocol read. │ │ │ │ │ + */ │ │ │ │ │ + load: function(options) { │ │ │ │ │ + var layer = this.layer; │ │ │ │ │ + layer.events.triggerEvent("loadstart", { │ │ │ │ │ + filter: layer.filter │ │ │ │ │ + }); │ │ │ │ │ + layer.protocol.read(OpenLayers.Util.applyDefaults({ │ │ │ │ │ + callback: this.merge, │ │ │ │ │ + filter: layer.filter, │ │ │ │ │ + scope: this │ │ │ │ │ + }, options)); │ │ │ │ │ + layer.events.un({ │ │ │ │ │ + "visibilitychanged": this.load, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - this.contentSize = (contentSize != null) ? contentSize : │ │ │ │ │ - new OpenLayers.Size( │ │ │ │ │ - OpenLayers.Popup.WIDTH, │ │ │ │ │ - OpenLayers.Popup.HEIGHT); │ │ │ │ │ - if (contentHTML != null) { │ │ │ │ │ - this.contentHTML = contentHTML; │ │ │ │ │ + /** │ │ │ │ │ + * Method: merge │ │ │ │ │ + * Add all features to the layer. │ │ │ │ │ + * If the layer projection differs from the map projection, features │ │ │ │ │ + * will be transformed from the layer projection to the map projection. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * resp - {} The response object passed │ │ │ │ │ + * by the protocol. │ │ │ │ │ + */ │ │ │ │ │ + merge: function(resp) { │ │ │ │ │ + var layer = this.layer; │ │ │ │ │ + layer.destroyFeatures(); │ │ │ │ │ + var features = resp.features; │ │ │ │ │ + if (features && features.length > 0) { │ │ │ │ │ + var remote = layer.projection; │ │ │ │ │ + var local = layer.map.getProjectionObject(); │ │ │ │ │ + if (!local.equals(remote)) { │ │ │ │ │ + var geom; │ │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ │ + geom = features[i].geometry; │ │ │ │ │ + if (geom) { │ │ │ │ │ + geom.transform(remote, local); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + layer.addFeatures(features); │ │ │ │ │ } │ │ │ │ │ - this.backgroundColor = OpenLayers.Popup.COLOR; │ │ │ │ │ - this.opacity = OpenLayers.Popup.OPACITY; │ │ │ │ │ - this.border = OpenLayers.Popup.BORDER; │ │ │ │ │ + layer.events.triggerEvent("loadend", { │ │ │ │ │ + response: resp │ │ │ │ │ + }); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - this.div = OpenLayers.Util.createDiv(this.id, null, null, │ │ │ │ │ - null, null, null, "hidden"); │ │ │ │ │ - this.div.className = this.displayClass; │ │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Fixed" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Strategy/BBOX.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - var groupDivId = this.id + "_GroupDiv"; │ │ │ │ │ - this.groupDiv = OpenLayers.Util.createDiv(groupDivId, null, null, │ │ │ │ │ - null, "relative", null, │ │ │ │ │ - "hidden"); │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - var id = this.div.id + "_contentDiv"; │ │ │ │ │ - this.contentDiv = OpenLayers.Util.createDiv(id, null, this.contentSize.clone(), │ │ │ │ │ - null, "relative"); │ │ │ │ │ - this.contentDiv.className = this.contentDisplayClass; │ │ │ │ │ - this.groupDiv.appendChild(this.contentDiv); │ │ │ │ │ - this.div.appendChild(this.groupDiv); │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Strategy.js │ │ │ │ │ + * @requires OpenLayers/Filter/Spatial.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - if (closeBox) { │ │ │ │ │ - this.addCloseBox(closeBoxCallback); │ │ │ │ │ - } │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Strategy.BBOX │ │ │ │ │ + * A simple strategy that reads new features when the viewport invalidates │ │ │ │ │ + * some bounds. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ │ │ - this.registerEvents(); │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * Property: bounds │ │ │ │ │ + * {} The current data bounds (in the same projection │ │ │ │ │ + * as the layer - not always the same projection as the map). │ │ │ │ │ + */ │ │ │ │ │ + bounds: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: destroy │ │ │ │ │ - * nullify references to prevent circular references and memory leaks │ │ │ │ │ + * Property: resolution │ │ │ │ │ + * {Float} The current data resolution. │ │ │ │ │ */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - │ │ │ │ │ - this.id = null; │ │ │ │ │ - this.lonlat = null; │ │ │ │ │ - this.size = null; │ │ │ │ │ - this.contentHTML = null; │ │ │ │ │ - │ │ │ │ │ - this.backgroundColor = null; │ │ │ │ │ - this.opacity = null; │ │ │ │ │ - this.border = null; │ │ │ │ │ - │ │ │ │ │ - if (this.closeOnMove && this.map) { │ │ │ │ │ - this.map.events.unregister("movestart", this, this.hide); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - this.events.destroy(); │ │ │ │ │ - this.events = null; │ │ │ │ │ - │ │ │ │ │ - if (this.closeDiv) { │ │ │ │ │ - OpenLayers.Event.stopObservingElement(this.closeDiv); │ │ │ │ │ - this.groupDiv.removeChild(this.closeDiv); │ │ │ │ │ - } │ │ │ │ │ - this.closeDiv = null; │ │ │ │ │ + resolution: null, │ │ │ │ │ │ │ │ │ │ - this.div.removeChild(this.groupDiv); │ │ │ │ │ - this.groupDiv = null; │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: ratio │ │ │ │ │ + * {Float} The ratio of the data bounds to the viewport bounds (in each │ │ │ │ │ + * dimension). Default is 2. │ │ │ │ │ + */ │ │ │ │ │ + ratio: 2, │ │ │ │ │ │ │ │ │ │ - if (this.map != null) { │ │ │ │ │ - this.map.removePopup(this); │ │ │ │ │ - } │ │ │ │ │ - this.map = null; │ │ │ │ │ - this.div = null; │ │ │ │ │ + /** │ │ │ │ │ + * Property: resFactor │ │ │ │ │ + * {Float} Optional factor used to determine when previously requested │ │ │ │ │ + * features are invalid. If set, the resFactor will be compared to the │ │ │ │ │ + * resolution of the previous request to the current map resolution. │ │ │ │ │ + * If resFactor > (old / new) and 1/resFactor < (old / new). If you │ │ │ │ │ + * set a resFactor of 1, data will be requested every time the │ │ │ │ │ + * resolution changes. If you set a resFactor of 3, data will be │ │ │ │ │ + * requested if the old resolution is 3 times the new, or if the new is │ │ │ │ │ + * 3 times the old. If the old bounds do not contain the new bounds │ │ │ │ │ + * new data will always be requested (with or without considering │ │ │ │ │ + * resFactor). │ │ │ │ │ + */ │ │ │ │ │ + resFactor: null, │ │ │ │ │ │ │ │ │ │ - this.autoSize = null; │ │ │ │ │ - this.minSize = null; │ │ │ │ │ - this.maxSize = null; │ │ │ │ │ - this.padding = null; │ │ │ │ │ - this.panMapIfOutOfView = null; │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * Property: response │ │ │ │ │ + * {} The protocol response object returned │ │ │ │ │ + * by the layer protocol. │ │ │ │ │ + */ │ │ │ │ │ + response: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: draw │ │ │ │ │ - * Constructs the elements that make up the popup. │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Strategy.BBOX │ │ │ │ │ + * Create a new BBOX strategy. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * px - {} the position the popup in pixels. │ │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ + * instance. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: activate │ │ │ │ │ + * Set up strategy with regard to reading new batches of remote data. │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {DOMElement} Reference to a div that contains the drawn popup │ │ │ │ │ + * {Boolean} The strategy was successfully activated. │ │ │ │ │ */ │ │ │ │ │ - draw: function(px) { │ │ │ │ │ - if (px == null) { │ │ │ │ │ - if ((this.lonlat != null) && (this.map != null)) { │ │ │ │ │ - px = this.map.getLayerPxFromLonLat(this.lonlat); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // this assumes that this.map already exists, which is okay because │ │ │ │ │ - // this.draw is only called once the popup has been added to the map. │ │ │ │ │ - if (this.closeOnMove) { │ │ │ │ │ - this.map.events.register("movestart", this, this.hide); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - //listen to movestart, moveend to disable overflow (FF bug) │ │ │ │ │ - if (!this.disableFirefoxOverflowHack && OpenLayers.BROWSER_NAME == 'firefox') { │ │ │ │ │ - this.map.events.register("movestart", this, function() { │ │ │ │ │ - var style = document.defaultView.getComputedStyle( │ │ │ │ │ - this.contentDiv, null │ │ │ │ │ - ); │ │ │ │ │ - var currentOverflow = style.getPropertyValue("overflow"); │ │ │ │ │ - if (currentOverflow != "hidden") { │ │ │ │ │ - this.contentDiv._oldOverflow = currentOverflow; │ │ │ │ │ - this.contentDiv.style.overflow = "hidden"; │ │ │ │ │ - } │ │ │ │ │ - }); │ │ │ │ │ - this.map.events.register("moveend", this, function() { │ │ │ │ │ - var oldOverflow = this.contentDiv._oldOverflow; │ │ │ │ │ - if (oldOverflow) { │ │ │ │ │ - this.contentDiv.style.overflow = oldOverflow; │ │ │ │ │ - this.contentDiv._oldOverflow = null; │ │ │ │ │ - } │ │ │ │ │ + activate: function() { │ │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ │ + if (activated) { │ │ │ │ │ + this.layer.events.on({ │ │ │ │ │ + "moveend": this.update, │ │ │ │ │ + "refresh": this.update, │ │ │ │ │ + "visibilitychanged": this.update, │ │ │ │ │ + scope: this │ │ │ │ │ }); │ │ │ │ │ + this.update(); │ │ │ │ │ } │ │ │ │ │ - │ │ │ │ │ - this.moveTo(px); │ │ │ │ │ - if (!this.autoSize && !this.size) { │ │ │ │ │ - this.setSize(this.contentSize); │ │ │ │ │ - } │ │ │ │ │ - this.setBackgroundColor(); │ │ │ │ │ - this.setOpacity(); │ │ │ │ │ - this.setBorder(); │ │ │ │ │ - this.setContentHTML(); │ │ │ │ │ - │ │ │ │ │ - if (this.panMapIfOutOfView) { │ │ │ │ │ - this.panIntoView(); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - return this.div; │ │ │ │ │ + return activated; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: updatePosition │ │ │ │ │ - * if the popup has a lonlat and its map members set, │ │ │ │ │ - * then have it move itself to its proper position │ │ │ │ │ + /** │ │ │ │ │ + * Method: deactivate │ │ │ │ │ + * Tear down strategy with regard to reading new batches of remote data. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The strategy was successfully deactivated. │ │ │ │ │ */ │ │ │ │ │ - updatePosition: function() { │ │ │ │ │ - if ((this.lonlat) && (this.map)) { │ │ │ │ │ - var px = this.map.getLayerPxFromLonLat(this.lonlat); │ │ │ │ │ - if (px) { │ │ │ │ │ - this.moveTo(px); │ │ │ │ │ - } │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ │ + if (deactivated) { │ │ │ │ │ + this.layer.events.un({ │ │ │ │ │ + "moveend": this.update, │ │ │ │ │ + "refresh": this.update, │ │ │ │ │ + "visibilitychanged": this.update, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ } │ │ │ │ │ + return deactivated; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: moveTo │ │ │ │ │ - * │ │ │ │ │ + * Method: update │ │ │ │ │ + * Callback function called on "moveend" or "refresh" layer events. │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * px - {} the top and left position of the popup div. │ │ │ │ │ + * options - {Object} Optional object whose properties will determine │ │ │ │ │ + * the behaviour of this Strategy │ │ │ │ │ + * │ │ │ │ │ + * Valid options include: │ │ │ │ │ + * force - {Boolean} if true, new data must be unconditionally read. │ │ │ │ │ + * noAbort - {Boolean} if true, do not abort previous requests. │ │ │ │ │ */ │ │ │ │ │ - moveTo: function(px) { │ │ │ │ │ - if ((px != null) && (this.div != null)) { │ │ │ │ │ - this.div.style.left = px.x + "px"; │ │ │ │ │ - this.div.style.top = px.y + "px"; │ │ │ │ │ + update: function(options) { │ │ │ │ │ + var mapBounds = this.getMapBounds(); │ │ │ │ │ + if (mapBounds !== null && ((options && options.force) || │ │ │ │ │ + (this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds)))) { │ │ │ │ │ + this.calculateBounds(mapBounds); │ │ │ │ │ + this.resolution = this.layer.map.getResolution(); │ │ │ │ │ + this.triggerRead(options); │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: visible │ │ │ │ │ + * Method: getMapBounds │ │ │ │ │ + * Get the map bounds expressed in the same projection as this layer. │ │ │ │ │ * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} Boolean indicating whether or not the popup is visible │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} Map bounds in the projection of the layer. │ │ │ │ │ */ │ │ │ │ │ - visible: function() { │ │ │ │ │ - return OpenLayers.Element.visible(this.div); │ │ │ │ │ + getMapBounds: function() { │ │ │ │ │ + if (this.layer.map === null) { │ │ │ │ │ + return null; │ │ │ │ │ + } │ │ │ │ │ + var bounds = this.layer.map.getExtent(); │ │ │ │ │ + if (bounds && !this.layer.projection.equals( │ │ │ │ │ + this.layer.map.getProjectionObject())) { │ │ │ │ │ + bounds = bounds.clone().transform( │ │ │ │ │ + this.layer.map.getProjectionObject(), this.layer.projection │ │ │ │ │ + ); │ │ │ │ │ + } │ │ │ │ │ + return bounds; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: toggle │ │ │ │ │ - * Toggles visibility of the popup. │ │ │ │ │ + * Method: invalidBounds │ │ │ │ │ + * Determine whether the previously requested set of features is invalid. │ │ │ │ │ + * This occurs when the new map bounds do not contain the previously │ │ │ │ │ + * requested bounds. In addition, if is set, it will be │ │ │ │ │ + * considered. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * mapBounds - {} the current map extent, will be │ │ │ │ │ + * retrieved from the map object if not provided │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} │ │ │ │ │ */ │ │ │ │ │ - toggle: function() { │ │ │ │ │ - if (this.visible()) { │ │ │ │ │ - this.hide(); │ │ │ │ │ - } else { │ │ │ │ │ - this.show(); │ │ │ │ │ + invalidBounds: function(mapBounds) { │ │ │ │ │ + if (!mapBounds) { │ │ │ │ │ + mapBounds = this.getMapBounds(); │ │ │ │ │ + } │ │ │ │ │ + var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds); │ │ │ │ │ + if (!invalid && this.resFactor) { │ │ │ │ │ + var ratio = this.resolution / this.layer.map.getResolution(); │ │ │ │ │ + invalid = (ratio >= this.resFactor || ratio <= (1 / this.resFactor)); │ │ │ │ │ } │ │ │ │ │ + return invalid; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: show │ │ │ │ │ - * Makes the popup visible. │ │ │ │ │ + * Method: calculateBounds │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * mapBounds - {} the current map extent, will be │ │ │ │ │ + * retrieved from the map object if not provided │ │ │ │ │ */ │ │ │ │ │ - show: function() { │ │ │ │ │ - this.div.style.display = ''; │ │ │ │ │ + calculateBounds: function(mapBounds) { │ │ │ │ │ + if (!mapBounds) { │ │ │ │ │ + mapBounds = this.getMapBounds(); │ │ │ │ │ + } │ │ │ │ │ + var center = mapBounds.getCenterLonLat(); │ │ │ │ │ + var dataWidth = mapBounds.getWidth() * this.ratio; │ │ │ │ │ + var dataHeight = mapBounds.getHeight() * this.ratio; │ │ │ │ │ + this.bounds = new OpenLayers.Bounds( │ │ │ │ │ + center.lon - (dataWidth / 2), │ │ │ │ │ + center.lat - (dataHeight / 2), │ │ │ │ │ + center.lon + (dataWidth / 2), │ │ │ │ │ + center.lat + (dataHeight / 2) │ │ │ │ │ + ); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (this.panMapIfOutOfView) { │ │ │ │ │ - this.panIntoView(); │ │ │ │ │ + /** │ │ │ │ │ + * Method: triggerRead │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} Additional options for the protocol's read method │ │ │ │ │ + * (optional) │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} The protocol response object │ │ │ │ │ + * returned by the layer protocol. │ │ │ │ │ + */ │ │ │ │ │ + triggerRead: function(options) { │ │ │ │ │ + if (this.response && !(options && options.noAbort === true)) { │ │ │ │ │ + this.layer.protocol.abort(this.response); │ │ │ │ │ + this.layer.events.triggerEvent("loadend"); │ │ │ │ │ } │ │ │ │ │ + var evt = { │ │ │ │ │ + filter: this.createFilter() │ │ │ │ │ + }; │ │ │ │ │ + this.layer.events.triggerEvent("loadstart", evt); │ │ │ │ │ + this.response = this.layer.protocol.read( │ │ │ │ │ + OpenLayers.Util.applyDefaults({ │ │ │ │ │ + filter: evt.filter, │ │ │ │ │ + callback: this.merge, │ │ │ │ │ + scope: this │ │ │ │ │ + }, options)); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: hide │ │ │ │ │ - * Makes the popup invisible. │ │ │ │ │ + * Method: createFilter │ │ │ │ │ + * Creates a spatial BBOX filter. If the layer that this strategy belongs │ │ │ │ │ + * to has a filter property, this filter will be combined with the BBOX │ │ │ │ │ + * filter. │ │ │ │ │ + * │ │ │ │ │ + * Returns │ │ │ │ │ + * {} The filter object. │ │ │ │ │ */ │ │ │ │ │ - hide: function() { │ │ │ │ │ - this.div.style.display = 'none'; │ │ │ │ │ + createFilter: function() { │ │ │ │ │ + var filter = new OpenLayers.Filter.Spatial({ │ │ │ │ │ + type: OpenLayers.Filter.Spatial.BBOX, │ │ │ │ │ + value: this.bounds, │ │ │ │ │ + projection: this.layer.projection │ │ │ │ │ + }); │ │ │ │ │ + if (this.layer.filter) { │ │ │ │ │ + filter = new OpenLayers.Filter.Logical({ │ │ │ │ │ + type: OpenLayers.Filter.Logical.AND, │ │ │ │ │ + filters: [this.layer.filter, filter] │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + return filter; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: setSize │ │ │ │ │ - * Used to adjust the size of the popup. │ │ │ │ │ + * Method: merge │ │ │ │ │ + * Given a list of features, determine which ones to add to the layer. │ │ │ │ │ + * If the layer projection differs from the map projection, features │ │ │ │ │ + * will be transformed from the layer projection to the map projection. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * contentSize - {} the new size for the popup's │ │ │ │ │ - * contents div (in pixels). │ │ │ │ │ + * resp - {} The response object passed │ │ │ │ │ + * by the protocol. │ │ │ │ │ */ │ │ │ │ │ - setSize: function(contentSize) { │ │ │ │ │ - this.size = contentSize.clone(); │ │ │ │ │ - │ │ │ │ │ - // if our contentDiv has a css 'padding' set on it by a stylesheet, we │ │ │ │ │ - // must add that to the desired "size". │ │ │ │ │ - var contentDivPadding = this.getContentDivPadding(); │ │ │ │ │ - var wPadding = contentDivPadding.left + contentDivPadding.right; │ │ │ │ │ - var hPadding = contentDivPadding.top + contentDivPadding.bottom; │ │ │ │ │ - │ │ │ │ │ - // take into account the popup's 'padding' property │ │ │ │ │ - this.fixPadding(); │ │ │ │ │ - wPadding += this.padding.left + this.padding.right; │ │ │ │ │ - hPadding += this.padding.top + this.padding.bottom; │ │ │ │ │ - │ │ │ │ │ - // make extra space for the close div │ │ │ │ │ - if (this.closeDiv) { │ │ │ │ │ - var closeDivWidth = parseInt(this.closeDiv.style.width); │ │ │ │ │ - wPadding += closeDivWidth + contentDivPadding.right; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - //increase size of the main popup div to take into account the │ │ │ │ │ - // users's desired padding and close div. │ │ │ │ │ - this.size.w += wPadding; │ │ │ │ │ - this.size.h += hPadding; │ │ │ │ │ - │ │ │ │ │ - //now if our browser is IE, we need to actually make the contents │ │ │ │ │ - // div itself bigger to take its own padding into effect. this makes │ │ │ │ │ - // me want to shoot someone, but so it goes. │ │ │ │ │ - if (OpenLayers.BROWSER_NAME == "msie") { │ │ │ │ │ - this.contentSize.w += │ │ │ │ │ - contentDivPadding.left + contentDivPadding.right; │ │ │ │ │ - this.contentSize.h += │ │ │ │ │ - contentDivPadding.bottom + contentDivPadding.top; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (this.div != null) { │ │ │ │ │ - this.div.style.width = this.size.w + "px"; │ │ │ │ │ - this.div.style.height = this.size.h + "px"; │ │ │ │ │ - } │ │ │ │ │ - if (this.contentDiv != null) { │ │ │ │ │ - this.contentDiv.style.width = contentSize.w + "px"; │ │ │ │ │ - this.contentDiv.style.height = contentSize.h + "px"; │ │ │ │ │ + merge: function(resp) { │ │ │ │ │ + this.layer.destroyFeatures(); │ │ │ │ │ + if (resp.success()) { │ │ │ │ │ + var features = resp.features; │ │ │ │ │ + if (features && features.length > 0) { │ │ │ │ │ + var remote = this.layer.projection; │ │ │ │ │ + var local = this.layer.map.getProjectionObject(); │ │ │ │ │ + if (!local.equals(remote)) { │ │ │ │ │ + var geom; │ │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ │ + geom = features[i].geometry; │ │ │ │ │ + if (geom) { │ │ │ │ │ + geom.transform(remote, local); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + this.layer.addFeatures(features); │ │ │ │ │ + } │ │ │ │ │ + } else { │ │ │ │ │ + this.bounds = null; │ │ │ │ │ } │ │ │ │ │ + this.response = null; │ │ │ │ │ + this.layer.events.triggerEvent("loadend", { │ │ │ │ │ + response: resp │ │ │ │ │ + }); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: updateSize │ │ │ │ │ - * Auto size the popup so that it precisely fits its contents (as │ │ │ │ │ - * determined by this.contentDiv.innerHTML). Popup size will, of │ │ │ │ │ - * course, be limited by the available space on the current map │ │ │ │ │ - */ │ │ │ │ │ - updateSize: function() { │ │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.BBOX" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Strategy/Cluster.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - // determine actual render dimensions of the contents by putting its │ │ │ │ │ - // contents into a fake contentDiv (for the CSS) and then measuring it │ │ │ │ │ - var preparedHTML = "
" + │ │ │ │ │ - this.contentDiv.innerHTML + │ │ │ │ │ - "
"; │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - var containerElement = (this.map) ? this.map.div : document.body; │ │ │ │ │ - var realSize = OpenLayers.Util.getRenderedDimensions( │ │ │ │ │ - preparedHTML, null, { │ │ │ │ │ - displayClass: this.displayClass, │ │ │ │ │ - containerElement: containerElement │ │ │ │ │ - } │ │ │ │ │ - ); │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Strategy.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - // is the "real" size of the div is safe to display in our map? │ │ │ │ │ - var safeSize = this.getSafeContentSize(realSize); │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Strategy.Cluster │ │ │ │ │ + * Strategy for vector feature clustering. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ │ │ - var newSize = null; │ │ │ │ │ - if (safeSize.equals(realSize)) { │ │ │ │ │ - //real size of content is small enough to fit on the map, │ │ │ │ │ - // so we use real size. │ │ │ │ │ - newSize = realSize; │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: distance │ │ │ │ │ + * {Integer} Pixel distance between features that should be considered a │ │ │ │ │ + * single cluster. Default is 20 pixels. │ │ │ │ │ + */ │ │ │ │ │ + distance: 20, │ │ │ │ │ │ │ │ │ │ - } else { │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: threshold │ │ │ │ │ + * {Integer} Optional threshold below which original features will be │ │ │ │ │ + * added to the layer instead of clusters. For example, a threshold │ │ │ │ │ + * of 3 would mean that any time there are 2 or fewer features in │ │ │ │ │ + * a cluster, those features will be added directly to the layer instead │ │ │ │ │ + * of a cluster representing those features. Default is null (which is │ │ │ │ │ + * equivalent to 1 - meaning that clusters may contain just one feature). │ │ │ │ │ + */ │ │ │ │ │ + threshold: null, │ │ │ │ │ │ │ │ │ │ - // make a new 'size' object with the clipped dimensions │ │ │ │ │ - // set or null if not clipped. │ │ │ │ │ - var fixedSize = { │ │ │ │ │ - w: (safeSize.w < realSize.w) ? safeSize.w : null, │ │ │ │ │ - h: (safeSize.h < realSize.h) ? safeSize.h : null │ │ │ │ │ - }; │ │ │ │ │ + /** │ │ │ │ │ + * Property: features │ │ │ │ │ + * {Array()} Cached features. │ │ │ │ │ + */ │ │ │ │ │ + features: null, │ │ │ │ │ │ │ │ │ │ - if (fixedSize.w && fixedSize.h) { │ │ │ │ │ - //content is too big in both directions, so we will use │ │ │ │ │ - // max popup size (safeSize), knowing well that it will │ │ │ │ │ - // overflow both ways. │ │ │ │ │ - newSize = safeSize; │ │ │ │ │ - } else { │ │ │ │ │ - //content is clipped in only one direction, so we need to │ │ │ │ │ - // run getRenderedDimensions() again with a fixed dimension │ │ │ │ │ - var clippedSize = OpenLayers.Util.getRenderedDimensions( │ │ │ │ │ - preparedHTML, fixedSize, { │ │ │ │ │ - displayClass: this.contentDisplayClass, │ │ │ │ │ - containerElement: containerElement │ │ │ │ │ - } │ │ │ │ │ - ); │ │ │ │ │ + /** │ │ │ │ │ + * Property: clusters │ │ │ │ │ + * {Array()} Calculated clusters. │ │ │ │ │ + */ │ │ │ │ │ + clusters: null, │ │ │ │ │ │ │ │ │ │ - //if the clipped size is still the same as the safeSize, │ │ │ │ │ - // that means that our content must be fixed in the │ │ │ │ │ - // offending direction. If overflow is 'auto', this means │ │ │ │ │ - // we are going to have a scrollbar for sure, so we must │ │ │ │ │ - // adjust for that. │ │ │ │ │ - // │ │ │ │ │ - var currentOverflow = OpenLayers.Element.getStyle( │ │ │ │ │ - this.contentDiv, "overflow" │ │ │ │ │ - ); │ │ │ │ │ - if ((currentOverflow != "hidden") && │ │ │ │ │ - (clippedSize.equals(safeSize))) { │ │ │ │ │ - var scrollBar = OpenLayers.Util.getScrollbarWidth(); │ │ │ │ │ - if (fixedSize.w) { │ │ │ │ │ - clippedSize.h += scrollBar; │ │ │ │ │ - } else { │ │ │ │ │ - clippedSize.w += scrollBar; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Property: clustering │ │ │ │ │ + * {Boolean} The strategy is currently clustering features. │ │ │ │ │ + */ │ │ │ │ │ + clustering: false, │ │ │ │ │ │ │ │ │ │ - newSize = this.getSafeContentSize(clippedSize); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - this.setSize(newSize); │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * Property: resolution │ │ │ │ │ + * {Float} The resolution (map units per pixel) of the current cluster set. │ │ │ │ │ + */ │ │ │ │ │ + resolution: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: setBackgroundColor │ │ │ │ │ - * Sets the background color of the popup. │ │ │ │ │ + * Constructor: OpenLayers.Strategy.Cluster │ │ │ │ │ + * Create a new clustering strategy. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * color - {String} the background color. eg "#FFBBBB" │ │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ + * instance. │ │ │ │ │ */ │ │ │ │ │ - setBackgroundColor: function(color) { │ │ │ │ │ - if (color != undefined) { │ │ │ │ │ - this.backgroundColor = color; │ │ │ │ │ - } │ │ │ │ │ │ │ │ │ │ - if (this.div != null) { │ │ │ │ │ - this.div.style.backgroundColor = this.backgroundColor; │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: activate │ │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The strategy was successfully activated. │ │ │ │ │ + */ │ │ │ │ │ + activate: function() { │ │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ │ + if (activated) { │ │ │ │ │ + this.layer.events.on({ │ │ │ │ │ + "beforefeaturesadded": this.cacheFeatures, │ │ │ │ │ + "featuresremoved": this.clearCache, │ │ │ │ │ + "moveend": this.cluster, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ } │ │ │ │ │ + return activated; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: setOpacity │ │ │ │ │ - * Sets the opacity of the popup. │ │ │ │ │ + * APIMethod: deactivate │ │ │ │ │ + * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ │ + * tear-down. │ │ │ │ │ * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid). │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The strategy was successfully deactivated. │ │ │ │ │ */ │ │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ │ - if (opacity != undefined) { │ │ │ │ │ - this.opacity = opacity; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (this.div != null) { │ │ │ │ │ - // for Mozilla and Safari │ │ │ │ │ - this.div.style.opacity = this.opacity; │ │ │ │ │ - │ │ │ │ │ - // for IE │ │ │ │ │ - this.div.style.filter = 'alpha(opacity=' + this.opacity * 100 + ')'; │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ │ + if (deactivated) { │ │ │ │ │ + this.clearCache(); │ │ │ │ │ + this.layer.events.un({ │ │ │ │ │ + "beforefeaturesadded": this.cacheFeatures, │ │ │ │ │ + "featuresremoved": this.clearCache, │ │ │ │ │ + "moveend": this.cluster, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ } │ │ │ │ │ + return deactivated; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: setBorder │ │ │ │ │ - * Sets the border style of the popup. │ │ │ │ │ + * Method: cacheFeatures │ │ │ │ │ + * Cache features before they are added to the layer. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * border - {String} The border style value. eg 2px │ │ │ │ │ + * event - {Object} The event that this was listening for. This will come │ │ │ │ │ + * with a batch of features to be clustered. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} False to stop features from being added to the layer. │ │ │ │ │ */ │ │ │ │ │ - setBorder: function(border) { │ │ │ │ │ - if (border != undefined) { │ │ │ │ │ - this.border = border; │ │ │ │ │ + cacheFeatures: function(event) { │ │ │ │ │ + var propagate = true; │ │ │ │ │ + if (!this.clustering) { │ │ │ │ │ + this.clearCache(); │ │ │ │ │ + this.features = event.features; │ │ │ │ │ + this.cluster(); │ │ │ │ │ + propagate = false; │ │ │ │ │ } │ │ │ │ │ + return propagate; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (this.div != null) { │ │ │ │ │ - this.div.style.border = this.border; │ │ │ │ │ + /** │ │ │ │ │ + * Method: clearCache │ │ │ │ │ + * Clear out the cached features. │ │ │ │ │ + */ │ │ │ │ │ + clearCache: function() { │ │ │ │ │ + if (!this.clustering) { │ │ │ │ │ + this.features = null; │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: setContentHTML │ │ │ │ │ - * Allows the user to set the HTML content of the popup. │ │ │ │ │ + * Method: cluster │ │ │ │ │ + * Cluster features based on some threshold distance. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * contentHTML - {String} HTML for the div. │ │ │ │ │ + * event - {Object} The event received when cluster is called as a │ │ │ │ │ + * result of a moveend event. │ │ │ │ │ */ │ │ │ │ │ - setContentHTML: function(contentHTML) { │ │ │ │ │ - │ │ │ │ │ - if (contentHTML != null) { │ │ │ │ │ - this.contentHTML = contentHTML; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if ((this.contentDiv != null) && │ │ │ │ │ - (this.contentHTML != null) && │ │ │ │ │ - (this.contentHTML != this.contentDiv.innerHTML)) { │ │ │ │ │ - │ │ │ │ │ - this.contentDiv.innerHTML = this.contentHTML; │ │ │ │ │ - │ │ │ │ │ - if (this.autoSize) { │ │ │ │ │ - │ │ │ │ │ - //if popup has images, listen for when they finish │ │ │ │ │ - // loading and resize accordingly │ │ │ │ │ - this.registerImageListeners(); │ │ │ │ │ - │ │ │ │ │ - //auto size the popup to its current contents │ │ │ │ │ - this.updateSize(); │ │ │ │ │ + cluster: function(event) { │ │ │ │ │ + if ((!event || event.zoomChanged) && this.features) { │ │ │ │ │ + var resolution = this.layer.map.getResolution(); │ │ │ │ │ + if (resolution != this.resolution || !this.clustersExist()) { │ │ │ │ │ + this.resolution = resolution; │ │ │ │ │ + var clusters = []; │ │ │ │ │ + var feature, clustered, cluster; │ │ │ │ │ + for (var i = 0; i < this.features.length; ++i) { │ │ │ │ │ + feature = this.features[i]; │ │ │ │ │ + if (feature.geometry) { │ │ │ │ │ + clustered = false; │ │ │ │ │ + for (var j = clusters.length - 1; j >= 0; --j) { │ │ │ │ │ + cluster = clusters[j]; │ │ │ │ │ + if (this.shouldCluster(cluster, feature)) { │ │ │ │ │ + this.addToCluster(cluster, feature); │ │ │ │ │ + clustered = true; │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + if (!clustered) { │ │ │ │ │ + clusters.push(this.createCluster(this.features[i])); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + this.clustering = true; │ │ │ │ │ + this.layer.removeAllFeatures(); │ │ │ │ │ + this.clustering = false; │ │ │ │ │ + if (clusters.length > 0) { │ │ │ │ │ + if (this.threshold > 1) { │ │ │ │ │ + var clone = clusters.slice(); │ │ │ │ │ + clusters = []; │ │ │ │ │ + var candidate; │ │ │ │ │ + for (var i = 0, len = clone.length; i < len; ++i) { │ │ │ │ │ + candidate = clone[i]; │ │ │ │ │ + if (candidate.attributes.count < this.threshold) { │ │ │ │ │ + Array.prototype.push.apply(clusters, candidate.cluster); │ │ │ │ │ + } else { │ │ │ │ │ + clusters.push(candidate); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + this.clustering = true; │ │ │ │ │ + // A legitimate feature addition could occur during this │ │ │ │ │ + // addFeatures call. For clustering to behave well, features │ │ │ │ │ + // should be removed from a layer before requesting a new batch. │ │ │ │ │ + this.layer.addFeatures(clusters); │ │ │ │ │ + this.clustering = false; │ │ │ │ │ + } │ │ │ │ │ + this.clusters = clusters; │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ - │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: registerImageListeners │ │ │ │ │ - * Called when an image contained by the popup loaded. this function │ │ │ │ │ - * updates the popup size, then unregisters the image load listener. │ │ │ │ │ + * Method: clustersExist │ │ │ │ │ + * Determine whether calculated clusters are already on the layer. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The calculated clusters are already on the layer. │ │ │ │ │ */ │ │ │ │ │ - registerImageListeners: function() { │ │ │ │ │ - │ │ │ │ │ - // As the images load, this function will call updateSize() to │ │ │ │ │ - // resize the popup to fit the content div (which presumably is now │ │ │ │ │ - // bigger than when the image was not loaded). │ │ │ │ │ - // │ │ │ │ │ - // If the 'panMapIfOutOfView' property is set, we will pan the newly │ │ │ │ │ - // resized popup back into view. │ │ │ │ │ - // │ │ │ │ │ - // Note that this function, when called, will have 'popup' and │ │ │ │ │ - // 'img' properties in the context. │ │ │ │ │ - // │ │ │ │ │ - var onImgLoad = function() { │ │ │ │ │ - if (this.popup.id === null) { // this.popup has been destroyed! │ │ │ │ │ - return; │ │ │ │ │ - } │ │ │ │ │ - this.popup.updateSize(); │ │ │ │ │ - │ │ │ │ │ - if (this.popup.visible() && this.popup.panMapIfOutOfView) { │ │ │ │ │ - this.popup.panIntoView(); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - OpenLayers.Event.stopObserving( │ │ │ │ │ - this.img, "load", this.img._onImgLoad │ │ │ │ │ - ); │ │ │ │ │ - │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - //cycle through the images and if their size is 0x0, that means that │ │ │ │ │ - // they haven't been loaded yet, so we attach the listener, which │ │ │ │ │ - // will fire when the images finish loading and will resize the │ │ │ │ │ - // popup accordingly to its new size. │ │ │ │ │ - var images = this.contentDiv.getElementsByTagName("img"); │ │ │ │ │ - for (var i = 0, len = images.length; i < len; i++) { │ │ │ │ │ - var img = images[i]; │ │ │ │ │ - if (img.width == 0 || img.height == 0) { │ │ │ │ │ - │ │ │ │ │ - var context = { │ │ │ │ │ - 'popup': this, │ │ │ │ │ - 'img': img │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - //expando this function to the image itself before registering │ │ │ │ │ - // it. This way we can easily and properly unregister it. │ │ │ │ │ - img._onImgLoad = OpenLayers.Function.bind(onImgLoad, context); │ │ │ │ │ - │ │ │ │ │ - OpenLayers.Event.observe(img, 'load', img._onImgLoad); │ │ │ │ │ + clustersExist: function() { │ │ │ │ │ + var exist = false; │ │ │ │ │ + if (this.clusters && this.clusters.length > 0 && │ │ │ │ │ + this.clusters.length == this.layer.features.length) { │ │ │ │ │ + exist = true; │ │ │ │ │ + for (var i = 0; i < this.clusters.length; ++i) { │ │ │ │ │ + if (this.clusters[i] != this.layer.features[i]) { │ │ │ │ │ + exist = false; │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ + return exist; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: getSafeContentSize │ │ │ │ │ - * │ │ │ │ │ + * Method: shouldCluster │ │ │ │ │ + * Determine whether to include a feature in a given cluster. │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * size - {} Desired size to make the popup. │ │ │ │ │ - * │ │ │ │ │ + * cluster - {} A cluster. │ │ │ │ │ + * feature - {} A feature. │ │ │ │ │ + * │ │ │ │ │ * Returns: │ │ │ │ │ - * {} A size to make the popup which is neither smaller │ │ │ │ │ - * than the specified minimum size, nor bigger than the maximum │ │ │ │ │ - * size (which is calculated relative to the size of the viewport). │ │ │ │ │ + * {Boolean} The feature should be included in the cluster. │ │ │ │ │ */ │ │ │ │ │ - getSafeContentSize: function(size) { │ │ │ │ │ - │ │ │ │ │ - var safeContentSize = size.clone(); │ │ │ │ │ + shouldCluster: function(cluster, feature) { │ │ │ │ │ + var cc = cluster.geometry.getBounds().getCenterLonLat(); │ │ │ │ │ + var fc = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ │ + var distance = ( │ │ │ │ │ + Math.sqrt( │ │ │ │ │ + Math.pow((cc.lon - fc.lon), 2) + Math.pow((cc.lat - fc.lat), 2) │ │ │ │ │ + ) / this.resolution │ │ │ │ │ + ); │ │ │ │ │ + return (distance <= this.distance); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // if our contentDiv has a css 'padding' set on it by a stylesheet, we │ │ │ │ │ - // must add that to the desired "size". │ │ │ │ │ - var contentDivPadding = this.getContentDivPadding(); │ │ │ │ │ - var wPadding = contentDivPadding.left + contentDivPadding.right; │ │ │ │ │ - var hPadding = contentDivPadding.top + contentDivPadding.bottom; │ │ │ │ │ - │ │ │ │ │ - // take into account the popup's 'padding' property │ │ │ │ │ - this.fixPadding(); │ │ │ │ │ - wPadding += this.padding.left + this.padding.right; │ │ │ │ │ - hPadding += this.padding.top + this.padding.bottom; │ │ │ │ │ - │ │ │ │ │ - if (this.closeDiv) { │ │ │ │ │ - var closeDivWidth = parseInt(this.closeDiv.style.width); │ │ │ │ │ - wPadding += closeDivWidth + contentDivPadding.right; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // prevent the popup from being smaller than a specified minimal size │ │ │ │ │ - if (this.minSize) { │ │ │ │ │ - safeContentSize.w = Math.max(safeContentSize.w, │ │ │ │ │ - (this.minSize.w - wPadding)); │ │ │ │ │ - safeContentSize.h = Math.max(safeContentSize.h, │ │ │ │ │ - (this.minSize.h - hPadding)); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // prevent the popup from being bigger than a specified maximum size │ │ │ │ │ - if (this.maxSize) { │ │ │ │ │ - safeContentSize.w = Math.min(safeContentSize.w, │ │ │ │ │ - (this.maxSize.w - wPadding)); │ │ │ │ │ - safeContentSize.h = Math.min(safeContentSize.h, │ │ │ │ │ - (this.maxSize.h - hPadding)); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - //make sure the desired size to set doesn't result in a popup that │ │ │ │ │ - // is bigger than the map's viewport. │ │ │ │ │ - // │ │ │ │ │ - if (this.map && this.map.size) { │ │ │ │ │ - │ │ │ │ │ - var extraX = 0, │ │ │ │ │ - extraY = 0; │ │ │ │ │ - if (this.keepInMap && !this.panMapIfOutOfView) { │ │ │ │ │ - var px = this.map.getPixelFromLonLat(this.lonlat); │ │ │ │ │ - switch (this.relativePosition) { │ │ │ │ │ - case "tr": │ │ │ │ │ - extraX = px.x; │ │ │ │ │ - extraY = this.map.size.h - px.y; │ │ │ │ │ - break; │ │ │ │ │ - case "tl": │ │ │ │ │ - extraX = this.map.size.w - px.x; │ │ │ │ │ - extraY = this.map.size.h - px.y; │ │ │ │ │ - break; │ │ │ │ │ - case "bl": │ │ │ │ │ - extraX = this.map.size.w - px.x; │ │ │ │ │ - extraY = px.y; │ │ │ │ │ - break; │ │ │ │ │ - case "br": │ │ │ │ │ - extraX = px.x; │ │ │ │ │ - extraY = px.y; │ │ │ │ │ - break; │ │ │ │ │ - default: │ │ │ │ │ - extraX = px.x; │ │ │ │ │ - extraY = this.map.size.h - px.y; │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - var maxY = this.map.size.h - │ │ │ │ │ - this.map.paddingForPopups.top - │ │ │ │ │ - this.map.paddingForPopups.bottom - │ │ │ │ │ - hPadding - extraY; │ │ │ │ │ - │ │ │ │ │ - var maxX = this.map.size.w - │ │ │ │ │ - this.map.paddingForPopups.left - │ │ │ │ │ - this.map.paddingForPopups.right - │ │ │ │ │ - wPadding - extraX; │ │ │ │ │ - │ │ │ │ │ - safeContentSize.w = Math.min(safeContentSize.w, maxX); │ │ │ │ │ - safeContentSize.h = Math.min(safeContentSize.h, maxY); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - return safeContentSize; │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * Method: addToCluster │ │ │ │ │ + * Add a feature to a cluster. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * cluster - {} A cluster. │ │ │ │ │ + * feature - {} A feature. │ │ │ │ │ + */ │ │ │ │ │ + addToCluster: function(cluster, feature) { │ │ │ │ │ + cluster.cluster.push(feature); │ │ │ │ │ + cluster.attributes.count += 1; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getContentDivPadding │ │ │ │ │ - * Glorious, oh glorious hack in order to determine the css 'padding' of │ │ │ │ │ - * the contentDiv. IE/Opera return null here unless we actually add the │ │ │ │ │ - * popup's main 'div' element (which contains contentDiv) to the DOM. │ │ │ │ │ - * So we make it invisible and then add it to the document temporarily. │ │ │ │ │ + * Method: createCluster │ │ │ │ │ + * Given a feature, create a cluster. │ │ │ │ │ * │ │ │ │ │ - * Once we've taken the padding readings we need, we then remove it │ │ │ │ │ - * from the DOM (it will actually get added to the DOM in │ │ │ │ │ - * Map.js's addPopup) │ │ │ │ │ + * Parameters: │ │ │ │ │ + * feature - {} │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - getContentDivPadding: function() { │ │ │ │ │ - │ │ │ │ │ - //use cached value if we have it │ │ │ │ │ - var contentDivPadding = this._contentDivPadding; │ │ │ │ │ - if (!contentDivPadding) { │ │ │ │ │ - │ │ │ │ │ - if (this.div.parentNode == null) { │ │ │ │ │ - //make the div invisible and add it to the page │ │ │ │ │ - this.div.style.display = "none"; │ │ │ │ │ - document.body.appendChild(this.div); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - //read the padding settings from css, put them in an OL.Bounds │ │ │ │ │ - contentDivPadding = new OpenLayers.Bounds( │ │ │ │ │ - OpenLayers.Element.getStyle(this.contentDiv, "padding-left"), │ │ │ │ │ - OpenLayers.Element.getStyle(this.contentDiv, "padding-bottom"), │ │ │ │ │ - OpenLayers.Element.getStyle(this.contentDiv, "padding-right"), │ │ │ │ │ - OpenLayers.Element.getStyle(this.contentDiv, "padding-top") │ │ │ │ │ - ); │ │ │ │ │ - │ │ │ │ │ - //cache the value │ │ │ │ │ - this._contentDivPadding = contentDivPadding; │ │ │ │ │ - │ │ │ │ │ - if (this.div.parentNode == document.body) { │ │ │ │ │ - //remove the div from the page and make it visible again │ │ │ │ │ - document.body.removeChild(this.div); │ │ │ │ │ - this.div.style.display = ""; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - return contentDivPadding; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: addCloseBox │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * callback - {Function} The callback to be called when the close button │ │ │ │ │ - * is clicked. │ │ │ │ │ + * {} A cluster. │ │ │ │ │ */ │ │ │ │ │ - addCloseBox: function(callback) { │ │ │ │ │ - │ │ │ │ │ - this.closeDiv = OpenLayers.Util.createDiv( │ │ │ │ │ - this.id + "_close", null, { │ │ │ │ │ - w: 17, │ │ │ │ │ - h: 17 │ │ │ │ │ + createCluster: function(feature) { │ │ │ │ │ + var center = feature.geometry.getBounds().getCenterLonLat(); │ │ │ │ │ + var cluster = new OpenLayers.Feature.Vector( │ │ │ │ │ + new OpenLayers.Geometry.Point(center.lon, center.lat), { │ │ │ │ │ + count: 1 │ │ │ │ │ } │ │ │ │ │ ); │ │ │ │ │ - this.closeDiv.className = "olPopupCloseBox"; │ │ │ │ │ - │ │ │ │ │ - // use the content div's css padding to determine if we should │ │ │ │ │ - // padd the close div │ │ │ │ │ - var contentDivPadding = this.getContentDivPadding(); │ │ │ │ │ - │ │ │ │ │ - this.closeDiv.style.right = contentDivPadding.right + "px"; │ │ │ │ │ - this.closeDiv.style.top = contentDivPadding.top + "px"; │ │ │ │ │ - this.groupDiv.appendChild(this.closeDiv); │ │ │ │ │ - │ │ │ │ │ - var closePopup = callback || function(e) { │ │ │ │ │ - this.hide(); │ │ │ │ │ - OpenLayers.Event.stop(e); │ │ │ │ │ - }; │ │ │ │ │ - OpenLayers.Event.observe(this.closeDiv, "touchend", │ │ │ │ │ - OpenLayers.Function.bindAsEventListener(closePopup, this)); │ │ │ │ │ - OpenLayers.Event.observe(this.closeDiv, "click", │ │ │ │ │ - OpenLayers.Function.bindAsEventListener(closePopup, this)); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: panIntoView │ │ │ │ │ - * Pans the map such that the popup is totaly viewable (if necessary) │ │ │ │ │ - */ │ │ │ │ │ - panIntoView: function() { │ │ │ │ │ - │ │ │ │ │ - var mapSize = this.map.getSize(); │ │ │ │ │ - │ │ │ │ │ - //start with the top left corner of the popup, in px, │ │ │ │ │ - // relative to the viewport │ │ │ │ │ - var origTL = this.map.getViewPortPxFromLayerPx(new OpenLayers.Pixel( │ │ │ │ │ - parseInt(this.div.style.left), │ │ │ │ │ - parseInt(this.div.style.top) │ │ │ │ │ - )); │ │ │ │ │ - var newTL = origTL.clone(); │ │ │ │ │ - │ │ │ │ │ - //new left (compare to margins, using this.size to calculate right) │ │ │ │ │ - if (origTL.x < this.map.paddingForPopups.left) { │ │ │ │ │ - newTL.x = this.map.paddingForPopups.left; │ │ │ │ │ - } else │ │ │ │ │ - if ((origTL.x + this.size.w) > (mapSize.w - this.map.paddingForPopups.right)) { │ │ │ │ │ - newTL.x = mapSize.w - this.map.paddingForPopups.right - this.size.w; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - //new top (compare to margins, using this.size to calculate bottom) │ │ │ │ │ - if (origTL.y < this.map.paddingForPopups.top) { │ │ │ │ │ - newTL.y = this.map.paddingForPopups.top; │ │ │ │ │ - } else │ │ │ │ │ - if ((origTL.y + this.size.h) > (mapSize.h - this.map.paddingForPopups.bottom)) { │ │ │ │ │ - newTL.y = mapSize.h - this.map.paddingForPopups.bottom - this.size.h; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - var dx = origTL.x - newTL.x; │ │ │ │ │ - var dy = origTL.y - newTL.y; │ │ │ │ │ - │ │ │ │ │ - this.map.pan(dx, dy); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: registerEvents │ │ │ │ │ - * Registers events on the popup. │ │ │ │ │ - * │ │ │ │ │ - * Do this in a separate function so that subclasses can │ │ │ │ │ - * choose to override it if they wish to deal differently │ │ │ │ │ - * with mouse events │ │ │ │ │ - * │ │ │ │ │ - * Note in the following handler functions that some special │ │ │ │ │ - * care is needed to deal correctly with mousing and popups. │ │ │ │ │ - * │ │ │ │ │ - * Because the user might select the zoom-rectangle option and │ │ │ │ │ - * then drag it over a popup, we need a safe way to allow the │ │ │ │ │ - * mousemove and mouseup events to pass through the popup when │ │ │ │ │ - * they are initiated from outside. The same procedure is needed for │ │ │ │ │ - * touchmove and touchend events. │ │ │ │ │ - * │ │ │ │ │ - * Otherwise, we want to essentially kill the event propagation │ │ │ │ │ - * for all other events, though we have to do so carefully, │ │ │ │ │ - * without disabling basic html functionality, like clicking on │ │ │ │ │ - * hyperlinks or drag-selecting text. │ │ │ │ │ - */ │ │ │ │ │ - registerEvents: function() { │ │ │ │ │ - this.events = new OpenLayers.Events(this, this.div, null, true); │ │ │ │ │ - │ │ │ │ │ - function onTouchstart(evt) { │ │ │ │ │ - OpenLayers.Event.stop(evt, true); │ │ │ │ │ - } │ │ │ │ │ - this.events.on({ │ │ │ │ │ - "mousedown": this.onmousedown, │ │ │ │ │ - "mousemove": this.onmousemove, │ │ │ │ │ - "mouseup": this.onmouseup, │ │ │ │ │ - "click": this.onclick, │ │ │ │ │ - "mouseout": this.onmouseout, │ │ │ │ │ - "dblclick": this.ondblclick, │ │ │ │ │ - "touchstart": onTouchstart, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ - │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: onmousedown │ │ │ │ │ - * When mouse goes down within the popup, make a note of │ │ │ │ │ - * it locally, and then do not propagate the mousedown │ │ │ │ │ - * (but do so safely so that user can select text inside) │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - */ │ │ │ │ │ - onmousedown: function(evt) { │ │ │ │ │ - this.mousedown = true; │ │ │ │ │ - OpenLayers.Event.stop(evt, true); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: onmousemove │ │ │ │ │ - * If the drag was started within the popup, then │ │ │ │ │ - * do not propagate the mousemove (but do so safely │ │ │ │ │ - * so that user can select text inside) │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - */ │ │ │ │ │ - onmousemove: function(evt) { │ │ │ │ │ - if (this.mousedown) { │ │ │ │ │ - OpenLayers.Event.stop(evt, true); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: onmouseup │ │ │ │ │ - * When mouse comes up within the popup, after going down │ │ │ │ │ - * in it, reset the flag, and then (once again) do not │ │ │ │ │ - * propagate the event, but do so safely so that user can │ │ │ │ │ - * select text inside │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - */ │ │ │ │ │ - onmouseup: function(evt) { │ │ │ │ │ - if (this.mousedown) { │ │ │ │ │ - this.mousedown = false; │ │ │ │ │ - OpenLayers.Event.stop(evt, true); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: onclick │ │ │ │ │ - * Ignore clicks, but allowing default browser handling │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - */ │ │ │ │ │ - onclick: function(evt) { │ │ │ │ │ - OpenLayers.Event.stop(evt, true); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: onmouseout │ │ │ │ │ - * When mouse goes out of the popup set the flag to false so that │ │ │ │ │ - * if they let go and then drag back in, we won't be confused. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - */ │ │ │ │ │ - onmouseout: function(evt) { │ │ │ │ │ - this.mousedown = false; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: ondblclick │ │ │ │ │ - * Ignore double-clicks, but allowing default browser handling │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - */ │ │ │ │ │ - ondblclick: function(evt) { │ │ │ │ │ - OpenLayers.Event.stop(evt, true); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Popup" │ │ │ │ │ -}); │ │ │ │ │ - │ │ │ │ │ -OpenLayers.Popup.WIDTH = 200; │ │ │ │ │ -OpenLayers.Popup.HEIGHT = 200; │ │ │ │ │ -OpenLayers.Popup.COLOR = "white"; │ │ │ │ │ -OpenLayers.Popup.OPACITY = 1; │ │ │ │ │ -OpenLayers.Popup.BORDER = "0px"; │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/StyleMap.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Style.js │ │ │ │ │ - * @requires OpenLayers/Feature/Vector.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.StyleMap │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.StyleMap = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: styles │ │ │ │ │ - * {Object} Hash of {}, keyed by names of well known │ │ │ │ │ - * rendering intents (e.g. "default", "temporary", "select", "delete"). │ │ │ │ │ - */ │ │ │ │ │ - styles: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: extendDefault │ │ │ │ │ - * {Boolean} if true, every render intent will extend the symbolizers │ │ │ │ │ - * specified for the "default" intent at rendering time. Otherwise, every │ │ │ │ │ - * rendering intent will be treated as a completely independent style. │ │ │ │ │ - */ │ │ │ │ │ - extendDefault: true, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.StyleMap │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * style - {Object} Optional. Either a style hash, or a style object, or │ │ │ │ │ - * a hash of style objects (style hashes) keyed by rendering │ │ │ │ │ - * intent. If just one style hash or style object is passed, │ │ │ │ │ - * this will be used for all known render intents (default, │ │ │ │ │ - * select, temporary) │ │ │ │ │ - * options - {Object} optional hash of additional options for this │ │ │ │ │ - * instance │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(style, options) { │ │ │ │ │ - this.styles = { │ │ │ │ │ - "default": new OpenLayers.Style( │ │ │ │ │ - OpenLayers.Feature.Vector.style["default"]), │ │ │ │ │ - "select": new OpenLayers.Style( │ │ │ │ │ - OpenLayers.Feature.Vector.style["select"]), │ │ │ │ │ - "temporary": new OpenLayers.Style( │ │ │ │ │ - OpenLayers.Feature.Vector.style["temporary"]), │ │ │ │ │ - "delete": new OpenLayers.Style( │ │ │ │ │ - OpenLayers.Feature.Vector.style["delete"]) │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - // take whatever the user passed as style parameter and convert it │ │ │ │ │ - // into parts of stylemap. │ │ │ │ │ - if (style instanceof OpenLayers.Style) { │ │ │ │ │ - // user passed a style object │ │ │ │ │ - this.styles["default"] = style; │ │ │ │ │ - this.styles["select"] = style; │ │ │ │ │ - this.styles["temporary"] = style; │ │ │ │ │ - this.styles["delete"] = style; │ │ │ │ │ - } else if (typeof style == "object") { │ │ │ │ │ - for (var key in style) { │ │ │ │ │ - if (style[key] instanceof OpenLayers.Style) { │ │ │ │ │ - // user passed a hash of style objects │ │ │ │ │ - this.styles[key] = style[key]; │ │ │ │ │ - } else if (typeof style[key] == "object") { │ │ │ │ │ - // user passsed a hash of style hashes │ │ │ │ │ - this.styles[key] = new OpenLayers.Style(style[key]); │ │ │ │ │ - } else { │ │ │ │ │ - // user passed a style hash (i.e. symbolizer) │ │ │ │ │ - this.styles["default"] = new OpenLayers.Style(style); │ │ │ │ │ - this.styles["select"] = new OpenLayers.Style(style); │ │ │ │ │ - this.styles["temporary"] = new OpenLayers.Style(style); │ │ │ │ │ - this.styles["delete"] = new OpenLayers.Style(style); │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: destroy │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - for (var key in this.styles) { │ │ │ │ │ - this.styles[key].destroy(); │ │ │ │ │ - } │ │ │ │ │ - this.styles = null; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: createSymbolizer │ │ │ │ │ - * Creates the symbolizer for a feature for a render intent. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * feature - {} The feature to evaluate the rules │ │ │ │ │ - * of the intended style against. │ │ │ │ │ - * intent - {String} The intent determines the symbolizer that will be │ │ │ │ │ - * used to draw the feature. Well known intents are "default" │ │ │ │ │ - * (for just drawing the features), "select" (for selected │ │ │ │ │ - * features) and "temporary" (for drawing features). │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} symbolizer hash │ │ │ │ │ - */ │ │ │ │ │ - createSymbolizer: function(feature, intent) { │ │ │ │ │ - if (!feature) { │ │ │ │ │ - feature = new OpenLayers.Feature.Vector(); │ │ │ │ │ - } │ │ │ │ │ - if (!this.styles[intent]) { │ │ │ │ │ - intent = "default"; │ │ │ │ │ - } │ │ │ │ │ - feature.renderIntent = intent; │ │ │ │ │ - var defaultSymbolizer = {}; │ │ │ │ │ - if (this.extendDefault && intent != "default") { │ │ │ │ │ - defaultSymbolizer = this.styles["default"].createSymbolizer(feature); │ │ │ │ │ - } │ │ │ │ │ - return OpenLayers.Util.extend(defaultSymbolizer, │ │ │ │ │ - this.styles[intent].createSymbolizer(feature)); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: addUniqueValueRules │ │ │ │ │ - * Convenience method to create comparison rules for unique values of a │ │ │ │ │ - * property. The rules will be added to the style object for a specified │ │ │ │ │ - * rendering intent. This method is a shortcut for creating something like │ │ │ │ │ - * the "unique value legends" familiar from well known desktop GIS systems │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * renderIntent - {String} rendering intent to add the rules to │ │ │ │ │ - * property - {String} values of feature attributes to create the │ │ │ │ │ - * rules for │ │ │ │ │ - * symbolizers - {Object} Hash of symbolizers, keyed by the desired │ │ │ │ │ - * property values │ │ │ │ │ - * context - {Object} An optional object with properties that │ │ │ │ │ - * symbolizers' property values should be evaluated │ │ │ │ │ - * against. If no context is specified, feature.attributes │ │ │ │ │ - * will be used │ │ │ │ │ - */ │ │ │ │ │ - addUniqueValueRules: function(renderIntent, property, symbolizers, context) { │ │ │ │ │ - var rules = []; │ │ │ │ │ - for (var value in symbolizers) { │ │ │ │ │ - rules.push(new OpenLayers.Rule({ │ │ │ │ │ - symbolizer: symbolizers[value], │ │ │ │ │ - context: context, │ │ │ │ │ - filter: new OpenLayers.Filter.Comparison({ │ │ │ │ │ - type: OpenLayers.Filter.Comparison.EQUAL_TO, │ │ │ │ │ - property: property, │ │ │ │ │ - value: value │ │ │ │ │ - }) │ │ │ │ │ - })); │ │ │ │ │ - } │ │ │ │ │ - this.styles[renderIntent].addRules(rules); │ │ │ │ │ + cluster.cluster = [feature]; │ │ │ │ │ + return cluster; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.StyleMap" │ │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Cluster" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Handler.js │ │ │ │ │ + OpenLayers/Strategy/Refresh.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Events.js │ │ │ │ │ + * @requires OpenLayers/Strategy.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Handler │ │ │ │ │ - * Base class to construct a higher-level handler for event sequences. All │ │ │ │ │ - * handlers have activate and deactivate methods. In addition, they have │ │ │ │ │ - * methods named like browser events. When a handler is activated, any │ │ │ │ │ - * additional methods named like a browser event is registered as a │ │ │ │ │ - * listener for the corresponding event. When a handler is deactivated, │ │ │ │ │ - * those same methods are unregistered as event listeners. │ │ │ │ │ + * Class: OpenLayers.Strategy.Refresh │ │ │ │ │ + * A strategy that refreshes the layer. By default the strategy waits for a │ │ │ │ │ + * call to before refreshing. By configuring the strategy with │ │ │ │ │ + * the option, refreshing can take place automatically. │ │ │ │ │ * │ │ │ │ │ - * Handlers also typically have a callbacks object with keys named like │ │ │ │ │ - * the abstracted events or event sequences that they are in charge of │ │ │ │ │ - * handling. The controls that wrap handlers define the methods that │ │ │ │ │ - * correspond to these abstract events - so instead of listening for │ │ │ │ │ - * individual browser events, they only listen for the abstract events │ │ │ │ │ - * defined by the handler. │ │ │ │ │ - * │ │ │ │ │ - * Handlers are created by controls, which ultimately have the responsibility │ │ │ │ │ - * of making changes to the the state of the application. Handlers │ │ │ │ │ - * themselves may make temporary changes, but in general are expected to │ │ │ │ │ - * return the application in the same state that they found it. │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Handler = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: id │ │ │ │ │ - * {String} │ │ │ │ │ - */ │ │ │ │ │ - id: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: control │ │ │ │ │ - * {}. The control that initialized this handler. The │ │ │ │ │ - * control is assumed to have a valid map property - that map is used │ │ │ │ │ - * in the handler's own setMap method. │ │ │ │ │ - */ │ │ │ │ │ - control: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: map │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - map: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: keyMask │ │ │ │ │ - * {Integer} Use bitwise operators and one or more of the OpenLayers.Handler │ │ │ │ │ - * constants to construct a keyMask. The keyMask is used by │ │ │ │ │ - * . If the keyMask matches the combination of keys │ │ │ │ │ - * down on an event, checkModifiers returns true. │ │ │ │ │ - * │ │ │ │ │ - * Example: │ │ │ │ │ - * (code) │ │ │ │ │ - * // handler only responds if the Shift key is down │ │ │ │ │ - * handler.keyMask = OpenLayers.Handler.MOD_SHIFT; │ │ │ │ │ - * │ │ │ │ │ - * // handler only responds if Ctrl-Shift is down │ │ │ │ │ - * handler.keyMask = OpenLayers.Handler.MOD_SHIFT | │ │ │ │ │ - * OpenLayers.Handler.MOD_CTRL; │ │ │ │ │ - * (end) │ │ │ │ │ - */ │ │ │ │ │ - keyMask: null, │ │ │ │ │ +OpenLayers.Strategy.Refresh = OpenLayers.Class(OpenLayers.Strategy, { │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: active │ │ │ │ │ - * {Boolean} │ │ │ │ │ + * Property: force │ │ │ │ │ + * {Boolean} Force a refresh on the layer. Default is false. │ │ │ │ │ */ │ │ │ │ │ - active: false, │ │ │ │ │ + force: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: evt │ │ │ │ │ - * {Event} This property references the last event handled by the handler. │ │ │ │ │ - * Note that this property is not part of the stable API. Use of the │ │ │ │ │ - * evt property should be restricted to controls in the library │ │ │ │ │ - * or other applications that are willing to update with changes to │ │ │ │ │ - * the OpenLayers code. │ │ │ │ │ + * Property: interval │ │ │ │ │ + * {Number} Auto-refresh. Default is 0. If > 0, layer will be refreshed │ │ │ │ │ + * every N milliseconds. │ │ │ │ │ */ │ │ │ │ │ - evt: null, │ │ │ │ │ + interval: 0, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: touch │ │ │ │ │ - * {Boolean} Indicates the support of touch events. When touch events are │ │ │ │ │ - * started touch will be true and all mouse related listeners will do │ │ │ │ │ - * nothing. │ │ │ │ │ + * Property: timer │ │ │ │ │ + * {Number} The id of the timer. │ │ │ │ │ */ │ │ │ │ │ - touch: false, │ │ │ │ │ + timer: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Handler │ │ │ │ │ - * Construct a handler. │ │ │ │ │ + * Constructor: OpenLayers.Strategy.Refresh │ │ │ │ │ + * Create a new Refresh strategy. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * control - {} The control that initialized this │ │ │ │ │ - * handler. The control is assumed to have a valid map property; that │ │ │ │ │ - * map is used in the handler's own setMap method. If a map property │ │ │ │ │ - * is present in the options argument it will be used instead. │ │ │ │ │ - * callbacks - {Object} An object whose properties correspond to abstracted │ │ │ │ │ - * events or sequences of browser events. The values for these │ │ │ │ │ - * properties are functions defined by the control that get called by │ │ │ │ │ - * the handler. │ │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ │ - * the handler. │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ - this.control = control; │ │ │ │ │ - this.callbacks = callbacks; │ │ │ │ │ - │ │ │ │ │ - var map = this.map || control.map; │ │ │ │ │ - if (map) { │ │ │ │ │ - this.setMap(map); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: setMap │ │ │ │ │ - */ │ │ │ │ │ - setMap: function(map) { │ │ │ │ │ - this.map = map; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: checkModifiers │ │ │ │ │ - * Check the keyMask on the handler. If no is set, this always │ │ │ │ │ - * returns true. If a is set and it matches the combination │ │ │ │ │ - * of keys down on an event, this returns true. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The keyMask matches the keys down on an event. │ │ │ │ │ + * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ + * instance. │ │ │ │ │ */ │ │ │ │ │ - checkModifiers: function(evt) { │ │ │ │ │ - if (this.keyMask == null) { │ │ │ │ │ - return true; │ │ │ │ │ - } │ │ │ │ │ - /* calculate the keyboard modifier mask for this event */ │ │ │ │ │ - var keyModifiers = │ │ │ │ │ - (evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) | │ │ │ │ │ - (evt.ctrlKey ? OpenLayers.Handler.MOD_CTRL : 0) | │ │ │ │ │ - (evt.altKey ? OpenLayers.Handler.MOD_ALT : 0) | │ │ │ │ │ - (evt.metaKey ? OpenLayers.Handler.MOD_META : 0); │ │ │ │ │ - │ │ │ │ │ - /* if it differs from the handler object's key mask, │ │ │ │ │ - bail out of the event handler */ │ │ │ │ │ - return (keyModifiers == this.keyMask); │ │ │ │ │ - }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ * APIMethod: activate │ │ │ │ │ - * Turn on the handler. Returns false if the handler was already active. │ │ │ │ │ + * Activate the strategy. Register any listeners, do appropriate setup. │ │ │ │ │ * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The handler was activated. │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} True if the strategy was successfully activated. │ │ │ │ │ */ │ │ │ │ │ activate: function() { │ │ │ │ │ - if (this.active) { │ │ │ │ │ - return false; │ │ │ │ │ - } │ │ │ │ │ - // register for event handlers defined on this class. │ │ │ │ │ - var events = OpenLayers.Events.prototype.BROWSER_EVENTS; │ │ │ │ │ - for (var i = 0, len = events.length; i < len; i++) { │ │ │ │ │ - if (this[events[i]]) { │ │ │ │ │ - this.register(events[i], this[events[i]]); │ │ │ │ │ + var activated = OpenLayers.Strategy.prototype.activate.call(this); │ │ │ │ │ + if (activated) { │ │ │ │ │ + if (this.layer.visibility === true) { │ │ │ │ │ + this.start(); │ │ │ │ │ } │ │ │ │ │ + this.layer.events.on({ │ │ │ │ │ + "visibilitychanged": this.reset, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ } │ │ │ │ │ - this.active = true; │ │ │ │ │ - return true; │ │ │ │ │ + return activated; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ * APIMethod: deactivate │ │ │ │ │ - * Turn off the handler. Returns false if the handler was already inactive. │ │ │ │ │ + * Deactivate the strategy. Unregister any listeners, do appropriate │ │ │ │ │ + * tear-down. │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Boolean} The handler was deactivated. │ │ │ │ │ + * {Boolean} True if the strategy was successfully deactivated. │ │ │ │ │ */ │ │ │ │ │ deactivate: function() { │ │ │ │ │ - if (!this.active) { │ │ │ │ │ - return false; │ │ │ │ │ - } │ │ │ │ │ - // unregister event handlers defined on this class. │ │ │ │ │ - var events = OpenLayers.Events.prototype.BROWSER_EVENTS; │ │ │ │ │ - for (var i = 0, len = events.length; i < len; i++) { │ │ │ │ │ - if (this[events[i]]) { │ │ │ │ │ - this.unregister(events[i], this[events[i]]); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - this.touch = false; │ │ │ │ │ - this.active = false; │ │ │ │ │ - return true; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: startTouch │ │ │ │ │ - * Start touch events, this method must be called by subclasses in │ │ │ │ │ - * "touchstart" method. When touch events are started will be │ │ │ │ │ - * true and all mouse related listeners will do nothing. │ │ │ │ │ - */ │ │ │ │ │ - startTouch: function() { │ │ │ │ │ - if (!this.touch) { │ │ │ │ │ - this.touch = true; │ │ │ │ │ - var events = [ │ │ │ │ │ - "mousedown", "mouseup", "mousemove", "click", "dblclick", │ │ │ │ │ - "mouseout" │ │ │ │ │ - ]; │ │ │ │ │ - for (var i = 0, len = events.length; i < len; i++) { │ │ │ │ │ - if (this[events[i]]) { │ │ │ │ │ - this.unregister(events[i], this[events[i]]); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: callback │ │ │ │ │ - * Trigger the control's named callback with the given arguments │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * name - {String} The key for the callback that is one of the properties │ │ │ │ │ - * of the handler's callbacks object. │ │ │ │ │ - * args - {Array(*)} An array of arguments (any type) with which to call │ │ │ │ │ - * the callback (defined by the control). │ │ │ │ │ - */ │ │ │ │ │ - callback: function(name, args) { │ │ │ │ │ - if (name && this.callbacks[name]) { │ │ │ │ │ - this.callbacks[name].apply(this.control, args); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: register │ │ │ │ │ - * register an event on the map │ │ │ │ │ - */ │ │ │ │ │ - register: function(name, method) { │ │ │ │ │ - // TODO: deal with registerPriority in 3.0 │ │ │ │ │ - this.map.events.registerPriority(name, this, method); │ │ │ │ │ - this.map.events.registerPriority(name, this, this.setEvent); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: unregister │ │ │ │ │ - * unregister an event from the map │ │ │ │ │ - */ │ │ │ │ │ - unregister: function(name, method) { │ │ │ │ │ - this.map.events.unregister(name, this, method); │ │ │ │ │ - this.map.events.unregister(name, this, this.setEvent); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: setEvent │ │ │ │ │ - * With each registered browser event, the handler sets its own evt │ │ │ │ │ - * property. This property can be accessed by controls if needed │ │ │ │ │ - * to get more information about the event that the handler is │ │ │ │ │ - * processing. │ │ │ │ │ - * │ │ │ │ │ - * This allows modifier keys on the event to be checked (alt, shift, ctrl, │ │ │ │ │ - * and meta cannot be checked with the keyboard handler). For a │ │ │ │ │ - * control to determine which modifier keys are associated with the │ │ │ │ │ - * event that a handler is currently processing, it should access │ │ │ │ │ - * (code)handler.evt.altKey || handler.evt.shiftKey || │ │ │ │ │ - * handler.evt.ctrlKey || handler.evt.metaKey(end). │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} The browser event. │ │ │ │ │ - */ │ │ │ │ │ - setEvent: function(evt) { │ │ │ │ │ - this.evt = evt; │ │ │ │ │ - return true; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: destroy │ │ │ │ │ - * Deconstruct the handler. │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - // unregister event listeners │ │ │ │ │ - this.deactivate(); │ │ │ │ │ - // eliminate circular references │ │ │ │ │ - this.control = this.map = null; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler" │ │ │ │ │ -}); │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Handler.MOD_NONE │ │ │ │ │ - * If set as the , returns false if any key is down. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Handler.MOD_NONE = 0; │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Handler.MOD_SHIFT │ │ │ │ │ - * If set as the , returns false if Shift is down. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Handler.MOD_SHIFT = 1; │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Handler.MOD_CTRL │ │ │ │ │ - * If set as the , returns false if Ctrl is down. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Handler.MOD_CTRL = 2; │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Handler.MOD_ALT │ │ │ │ │ - * If set as the , returns false if Alt is down. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Handler.MOD_ALT = 4; │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Handler.MOD_META │ │ │ │ │ - * If set as the , returns false if Cmd is down. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Handler.MOD_META = 8; │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Spherical.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/SingleFile.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Namespace: Spherical │ │ │ │ │ - * The OpenLayers.Spherical namespace includes utility functions for │ │ │ │ │ - * calculations on the basis of a spherical earth (ignoring ellipsoidal │ │ │ │ │ - * effects), which is accurate enough for most purposes. │ │ │ │ │ - * │ │ │ │ │ - * Relevant links: │ │ │ │ │ - * * http://www.movable-type.co.uk/scripts/latlong.html │ │ │ │ │ - * * http://code.google.com/apis/maps/documentation/javascript/reference.html#spherical │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -OpenLayers.Spherical = OpenLayers.Spherical || {}; │ │ │ │ │ - │ │ │ │ │ -OpenLayers.Spherical.DEFAULT_RADIUS = 6378137; │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * APIFunction: computeDistanceBetween │ │ │ │ │ - * Computes the distance between two LonLats. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * from - {} or {Object} Starting point. A LonLat or │ │ │ │ │ - * a JavaScript literal with lon lat properties. │ │ │ │ │ - * to - {} or {Object} Ending point. A LonLat or a │ │ │ │ │ - * JavaScript literal with lon lat properties. │ │ │ │ │ - * radius - {Float} The radius. Optional. Defaults to 6378137 meters. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Float} The distance in meters. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Spherical.computeDistanceBetween = function(from, to, radius) { │ │ │ │ │ - var R = radius || OpenLayers.Spherical.DEFAULT_RADIUS; │ │ │ │ │ - var sinHalfDeltaLon = Math.sin(Math.PI * (to.lon - from.lon) / 360); │ │ │ │ │ - var sinHalfDeltaLat = Math.sin(Math.PI * (to.lat - from.lat) / 360); │ │ │ │ │ - var a = sinHalfDeltaLat * sinHalfDeltaLat + │ │ │ │ │ - sinHalfDeltaLon * sinHalfDeltaLon * Math.cos(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ │ - return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); │ │ │ │ │ -}; │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * APIFunction: computeHeading │ │ │ │ │ - * Computes the heading from one LonLat to another LonLat. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * from - {} or {Object} Starting point. A LonLat or │ │ │ │ │ - * a JavaScript literal with lon lat properties. │ │ │ │ │ - * to - {} or {Object} Ending point. A LonLat or a │ │ │ │ │ - * JavaScript literal with lon lat properties. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Float} The heading in degrees. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Spherical.computeHeading = function(from, to) { │ │ │ │ │ - var y = Math.sin(Math.PI * (from.lon - to.lon) / 180) * Math.cos(Math.PI * to.lat / 180); │ │ │ │ │ - var x = Math.cos(Math.PI * from.lat / 180) * Math.sin(Math.PI * to.lat / 180) - │ │ │ │ │ - Math.sin(Math.PI * from.lat / 180) * Math.cos(Math.PI * to.lat / 180) * Math.cos(Math.PI * (from.lon - to.lon) / 180); │ │ │ │ │ - return 180 * Math.atan2(y, x) / Math.PI; │ │ │ │ │ -}; │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Symbolizer.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Symbolizer │ │ │ │ │ - * Base class representing a symbolizer used for feature rendering. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Symbolizer = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: zIndex │ │ │ │ │ - * {Number} The zIndex determines the rendering order for a symbolizer. │ │ │ │ │ - * Symbolizers with larger zIndex values are rendered over symbolizers │ │ │ │ │ - * with smaller zIndex values. Default is 0. │ │ │ │ │ - */ │ │ │ │ │ - zIndex: 0, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Symbolizer │ │ │ │ │ - * Instances of this class are not useful. See one of the subclasses. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ │ - * construction. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * A new symbolizer. │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(config) { │ │ │ │ │ - OpenLayers.Util.extend(this, config); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: clone │ │ │ │ │ - * Create a copy of this symbolizer. │ │ │ │ │ - * │ │ │ │ │ - * Returns a symbolizer of the same type with the same properties. │ │ │ │ │ - */ │ │ │ │ │ - clone: function() { │ │ │ │ │ - var Type = eval(this.CLASS_NAME); │ │ │ │ │ - return new Type(OpenLayers.Util.extend({}, this)); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer" │ │ │ │ │ - │ │ │ │ │ -}); │ │ │ │ │ - │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Rule.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ │ - * @requires OpenLayers/Style.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Rule │ │ │ │ │ - * This class represents an SLD Rule, as being used for rule-based SLD styling. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Rule = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: id │ │ │ │ │ - * {String} A unique id for this session. │ │ │ │ │ - */ │ │ │ │ │ - id: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: name │ │ │ │ │ - * {String} name of this rule │ │ │ │ │ - */ │ │ │ │ │ - name: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: title │ │ │ │ │ - * {String} Title of this rule (set if included in SLD) │ │ │ │ │ - */ │ │ │ │ │ - title: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: description │ │ │ │ │ - * {String} Description of this rule (set if abstract is included in SLD) │ │ │ │ │ - */ │ │ │ │ │ - description: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: context │ │ │ │ │ - * {Object} An optional object with properties that the rule should be │ │ │ │ │ - * evaluated against. If no context is specified, feature.attributes will │ │ │ │ │ - * be used. │ │ │ │ │ - */ │ │ │ │ │ - context: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: filter │ │ │ │ │ - * {} Optional filter for the rule. │ │ │ │ │ - */ │ │ │ │ │ - filter: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: elseFilter │ │ │ │ │ - * {Boolean} Determines whether this rule is only to be applied only if │ │ │ │ │ - * no other rules match (ElseFilter according to the SLD specification). │ │ │ │ │ - * Default is false. For instances of OpenLayers.Rule, if elseFilter is │ │ │ │ │ - * false, the rule will always apply. For subclasses, the else property is │ │ │ │ │ - * ignored. │ │ │ │ │ - */ │ │ │ │ │ - elseFilter: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: symbolizer │ │ │ │ │ - * {Object} Symbolizer or hash of symbolizers for this rule. If hash of │ │ │ │ │ - * symbolizers, keys are one or more of ["Point", "Line", "Polygon"]. The │ │ │ │ │ - * latter if useful if it is required to style e.g. vertices of a line │ │ │ │ │ - * with a point symbolizer. Note, however, that this is not implemented │ │ │ │ │ - * yet in OpenLayers, but it is the way how symbolizers are defined in │ │ │ │ │ - * SLD. │ │ │ │ │ - */ │ │ │ │ │ - symbolizer: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: symbolizers │ │ │ │ │ - * {Array} Collection of symbolizers associated with this rule. If │ │ │ │ │ - * provided at construction, the symbolizers array has precedence │ │ │ │ │ - * over the deprecated symbolizer property. Note that multiple │ │ │ │ │ - * symbolizers are not currently supported by the vector renderers. │ │ │ │ │ - * Rules with multiple symbolizers are currently only useful for │ │ │ │ │ - * maintaining elements in an SLD document. │ │ │ │ │ - */ │ │ │ │ │ - symbolizers: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: minScaleDenominator │ │ │ │ │ - * {Number} or {String} minimum scale at which to draw the feature. │ │ │ │ │ - * In the case of a String, this can be a combination of text and │ │ │ │ │ - * propertyNames in the form "literal ${propertyName}" │ │ │ │ │ - */ │ │ │ │ │ - minScaleDenominator: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: maxScaleDenominator │ │ │ │ │ - * {Number} or {String} maximum scale at which to draw the feature. │ │ │ │ │ - * In the case of a String, this can be a combination of text and │ │ │ │ │ - * propertyNames in the form "literal ${propertyName}" │ │ │ │ │ - */ │ │ │ │ │ - maxScaleDenominator: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Rule │ │ │ │ │ - * Creates a Rule. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * options - {Object} An optional object with properties to set on the │ │ │ │ │ - * rule │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(options) { │ │ │ │ │ - this.symbolizer = {}; │ │ │ │ │ - OpenLayers.Util.extend(this, options); │ │ │ │ │ - if (this.symbolizers) { │ │ │ │ │ - delete this.symbolizer; │ │ │ │ │ - } │ │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ - * nullify references to prevent circular references and memory leaks │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - for (var i in this.symbolizer) { │ │ │ │ │ - this.symbolizer[i] = null; │ │ │ │ │ - } │ │ │ │ │ - this.symbolizer = null; │ │ │ │ │ - delete this.symbolizers; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: evaluate │ │ │ │ │ - * evaluates this rule for a specific feature │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * feature - {} feature to apply the rule to. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} true if the rule applies, false if it does not. │ │ │ │ │ - * This rule is the default rule and always returns true. │ │ │ │ │ - */ │ │ │ │ │ - evaluate: function(feature) { │ │ │ │ │ - var context = this.getContext(feature); │ │ │ │ │ - var applies = true; │ │ │ │ │ - │ │ │ │ │ - if (this.minScaleDenominator || this.maxScaleDenominator) { │ │ │ │ │ - var scale = feature.layer.map.getScale(); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // check if within minScale/maxScale bounds │ │ │ │ │ - if (this.minScaleDenominator) { │ │ │ │ │ - applies = scale >= OpenLayers.Style.createLiteral( │ │ │ │ │ - this.minScaleDenominator, context); │ │ │ │ │ - } │ │ │ │ │ - if (applies && this.maxScaleDenominator) { │ │ │ │ │ - applies = scale < OpenLayers.Style.createLiteral( │ │ │ │ │ - this.maxScaleDenominator, context); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // check if optional filter applies │ │ │ │ │ - if (applies && this.filter) { │ │ │ │ │ - // feature id filters get the feature, others get the context │ │ │ │ │ - if (this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") { │ │ │ │ │ - applies = this.filter.evaluate(feature); │ │ │ │ │ - } else { │ │ │ │ │ - applies = this.filter.evaluate(context); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - return applies; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: getContext │ │ │ │ │ - * Gets the context for evaluating this rule │ │ │ │ │ - * │ │ │ │ │ - * Paramters: │ │ │ │ │ - * feature - {} feature to take the context from if │ │ │ │ │ - * none is specified. │ │ │ │ │ - */ │ │ │ │ │ - getContext: function(feature) { │ │ │ │ │ - var context = this.context; │ │ │ │ │ - if (!context) { │ │ │ │ │ - context = feature.attributes || feature.data; │ │ │ │ │ - } │ │ │ │ │ - if (typeof this.context == "function") { │ │ │ │ │ - context = this.context(feature); │ │ │ │ │ + var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this); │ │ │ │ │ + if (deactivated) { │ │ │ │ │ + this.stop(); │ │ │ │ │ + this.layer.events.un({ │ │ │ │ │ + "visibilitychanged": this.reset, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ } │ │ │ │ │ - return context; │ │ │ │ │ + return deactivated; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: clone │ │ │ │ │ - * Clones this rule. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} Clone of this rule. │ │ │ │ │ + * Method: reset │ │ │ │ │ + * Start or cancel the refresh interval depending on the visibility of │ │ │ │ │ + * the layer. │ │ │ │ │ */ │ │ │ │ │ - clone: function() { │ │ │ │ │ - var options = OpenLayers.Util.extend({}, this); │ │ │ │ │ - if (this.symbolizers) { │ │ │ │ │ - // clone symbolizers │ │ │ │ │ - var len = this.symbolizers.length; │ │ │ │ │ - options.symbolizers = new Array(len); │ │ │ │ │ - for (var i = 0; i < len; ++i) { │ │ │ │ │ - options.symbolizers[i] = this.symbolizers[i].clone(); │ │ │ │ │ - } │ │ │ │ │ + reset: function() { │ │ │ │ │ + if (this.layer.visibility === true) { │ │ │ │ │ + this.start(); │ │ │ │ │ } else { │ │ │ │ │ - // clone symbolizer │ │ │ │ │ - options.symbolizer = {}; │ │ │ │ │ - var value, type; │ │ │ │ │ - for (var key in this.symbolizer) { │ │ │ │ │ - value = this.symbolizer[key]; │ │ │ │ │ - type = typeof value; │ │ │ │ │ - if (type === "object") { │ │ │ │ │ - options.symbolizer[key] = OpenLayers.Util.extend({}, value); │ │ │ │ │ - } else if (type === "string") { │ │ │ │ │ - options.symbolizer[key] = value; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ + this.stop(); │ │ │ │ │ } │ │ │ │ │ - // clone filter │ │ │ │ │ - options.filter = this.filter && this.filter.clone(); │ │ │ │ │ - // clone context │ │ │ │ │ - options.context = this.context && OpenLayers.Util.extend({}, this.context); │ │ │ │ │ - return new OpenLayers.Rule(options); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Rule" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Symbolizer/Point.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Symbolizer.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Symbolizer.Point │ │ │ │ │ - * A symbolizer used to render point features. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Symbolizer.Point = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: strokeColor │ │ │ │ │ - * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ │ - * for red). │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: strokeOpacity │ │ │ │ │ - * {Number} Stroke opacity (0-1). │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: strokeWidth │ │ │ │ │ - * {Number} Pixel stroke width. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: strokeLinecap │ │ │ │ │ - * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: strokeDashstyle │ │ │ │ │ - * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ │ - * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ │ - * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ │ - * most SLD patterns will render correctly in OpenLayers. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: fillColor │ │ │ │ │ - * {String} RGB hex fill color (e.g. "#ff0000" for red). │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: fillOpacity │ │ │ │ │ - * {Number} Fill opacity (0-1). │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: pointRadius │ │ │ │ │ - * {Number} Pixel point radius. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: externalGraphic │ │ │ │ │ - * {String} Url to an external graphic that will be used for rendering │ │ │ │ │ - * points. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: graphicWidth │ │ │ │ │ - * {Number} Pixel width for sizing an external graphic. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: graphicHeight │ │ │ │ │ - * {Number} Pixel height for sizing an external graphic. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: graphicOpacity │ │ │ │ │ - * {Number} Opacity (0-1) for an external graphic. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: graphicXOffset │ │ │ │ │ - * {Number} Pixel offset along the positive x axis for displacing an │ │ │ │ │ - * external graphic. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: graphicYOffset │ │ │ │ │ - * {Number} Pixel offset along the positive y axis for displacing an │ │ │ │ │ - * external graphic. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: rotation │ │ │ │ │ - * {Number} The rotation of a graphic in the clockwise direction about its │ │ │ │ │ - * center point (or any point off center as specified by │ │ │ │ │ - * and ). │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: graphicName │ │ │ │ │ - * {String} Named graphic to use when rendering points. Supported values │ │ │ │ │ - * include "circle", "square", "star", "x", "cross", and "triangle". │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Symbolizer.Point │ │ │ │ │ - * Create a symbolizer for rendering points. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ │ - * construction. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * A new point symbolizer. │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(config) { │ │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Point" │ │ │ │ │ - │ │ │ │ │ -}); │ │ │ │ │ - │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Symbolizer/Line.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Symbolizer.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Symbolizer.Line │ │ │ │ │ - * A symbolizer used to render line features. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Symbolizer.Line = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: strokeColor │ │ │ │ │ - * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ │ - * for red). │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: strokeOpacity │ │ │ │ │ - * {Number} Stroke opacity (0-1). │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: strokeWidth │ │ │ │ │ - * {Number} Pixel stroke width. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: strokeLinecap │ │ │ │ │ - * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: strokeDashstyle │ │ │ │ │ - * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ │ - * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ │ - * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ │ - * most SLD patterns will render correctly in OpenLayers. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Symbolizer.Line │ │ │ │ │ - * Create a symbolizer for rendering lines. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ │ - * construction. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * A new line symbolizer. │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(config) { │ │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Line" │ │ │ │ │ - │ │ │ │ │ -}); │ │ │ │ │ - │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Symbolizer/Polygon.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Symbolizer.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Symbolizer.Polygon │ │ │ │ │ - * A symbolizer used to render line features. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Symbolizer.Polygon = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: strokeColor │ │ │ │ │ - * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000" │ │ │ │ │ - * for red). │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: strokeOpacity │ │ │ │ │ - * {Number} Stroke opacity (0-1). │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: strokeWidth │ │ │ │ │ - * {Number} Pixel stroke width. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: strokeLinecap │ │ │ │ │ - * {String} Stroke cap type ("butt", "round", or "square"). │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: strokeDashstyle │ │ │ │ │ - * {String} Stroke dash style according to the SLD spec. Note that the │ │ │ │ │ - * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot", │ │ │ │ │ - * "longdash", "longdashdot", or "solid") will not work in SLD, but │ │ │ │ │ - * most SLD patterns will render correctly in OpenLayers. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: fillColor │ │ │ │ │ - * {String} RGB hex fill color (e.g. "#ff0000" for red). │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: fillOpacity │ │ │ │ │ - * {Number} Fill opacity (0-1). │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Symbolizer.Polygon │ │ │ │ │ - * Create a symbolizer for rendering polygons. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ │ - * construction. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * A new polygon symbolizer. │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(config) { │ │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Polygon" │ │ │ │ │ - │ │ │ │ │ -}); │ │ │ │ │ - │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Symbolizer/Text.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Symbolizer.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Symbolizer.Text │ │ │ │ │ - * A symbolizer used to render text labels for features. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: label │ │ │ │ │ - * {String} The text for the label. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: fontFamily │ │ │ │ │ - * {String} The font family for the label. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: fontSize │ │ │ │ │ - * {String} The font size for the label. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: fontWeight │ │ │ │ │ - * {String} The font weight for the label. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ /** │ │ │ │ │ - * Property: fontStyle │ │ │ │ │ - * {String} The font style for the label. │ │ │ │ │ - * │ │ │ │ │ - * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Symbolizer.Text │ │ │ │ │ - * Create a symbolizer for rendering text labels. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ │ - * construction. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * A new text symbolizer. │ │ │ │ │ + * Method: start │ │ │ │ │ + * Start the refresh interval. │ │ │ │ │ */ │ │ │ │ │ - initialize: function(config) { │ │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Text" │ │ │ │ │ - │ │ │ │ │ -}); │ │ │ │ │ - │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Symbolizer/Raster.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Symbolizer.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Symbolizer.Raster │ │ │ │ │ - * A symbolizer used to render raster images. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Symbolizer.Raster = OpenLayers.Class(OpenLayers.Symbolizer, { │ │ │ │ │ + start: function() { │ │ │ │ │ + if (this.interval && typeof this.interval === "number" && │ │ │ │ │ + this.interval > 0) { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Symbolizer.Raster │ │ │ │ │ - * Create a symbolizer for rendering rasters. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ │ - * symbolizer. Any documented symbolizer property can be set at │ │ │ │ │ - * construction. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * A new raster symbolizer. │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(config) { │ │ │ │ │ - OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments); │ │ │ │ │ + this.timer = window.setInterval( │ │ │ │ │ + OpenLayers.Function.bind(this.refresh, this), │ │ │ │ │ + this.interval); │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Symbolizer.Raster" │ │ │ │ │ - │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Style2.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/BaseTypes/Class.js │ │ │ │ │ - * @requires OpenLayers/Rule.js │ │ │ │ │ - * @requires OpenLayers/Symbolizer/Point.js │ │ │ │ │ - * @requires OpenLayers/Symbolizer/Line.js │ │ │ │ │ - * @requires OpenLayers/Symbolizer/Polygon.js │ │ │ │ │ - * @requires OpenLayers/Symbolizer/Text.js │ │ │ │ │ - * @requires OpenLayers/Symbolizer/Raster.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Style2 │ │ │ │ │ - * This class represents a collection of rules for rendering features. │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Style2 = OpenLayers.Class({ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: id │ │ │ │ │ - * {String} A unique id for this session. │ │ │ │ │ - */ │ │ │ │ │ - id: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: name │ │ │ │ │ - * {String} Style identifier. │ │ │ │ │ - */ │ │ │ │ │ - name: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: title │ │ │ │ │ - * {String} Title of this style. │ │ │ │ │ - */ │ │ │ │ │ - title: null, │ │ │ │ │ - │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: description │ │ │ │ │ - * {String} Description of this style. │ │ │ │ │ - */ │ │ │ │ │ - description: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: layerName │ │ │ │ │ - * {} Name of the layer that this style belongs to, usually │ │ │ │ │ - * according to the NamedLayer attribute of an SLD document. │ │ │ │ │ - */ │ │ │ │ │ - layerName: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: isDefault │ │ │ │ │ - * {Boolean} │ │ │ │ │ - */ │ │ │ │ │ - isDefault: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: rules │ │ │ │ │ - * {Array()} Collection of rendering rules. │ │ │ │ │ - */ │ │ │ │ │ - rules: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Style2 │ │ │ │ │ - * Creates a style representing a collection of rendering rules. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * config - {Object} An object containing properties to be set on the │ │ │ │ │ - * style. Any documented properties may be set at construction. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} A new style object. │ │ │ │ │ + * APIMethod: refresh │ │ │ │ │ + * Tell the strategy to refresh which will refresh the layer. │ │ │ │ │ */ │ │ │ │ │ - initialize: function(config) { │ │ │ │ │ - OpenLayers.Util.extend(this, config); │ │ │ │ │ - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); │ │ │ │ │ - }, │ │ │ │ │ + refresh: function() { │ │ │ │ │ + if (this.layer && this.layer.refresh && │ │ │ │ │ + typeof this.layer.refresh == "function") { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ - * nullify references to prevent circular references and memory leaks │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - for (var i = 0, len = this.rules.length; i < len; i++) { │ │ │ │ │ - this.rules[i].destroy(); │ │ │ │ │ + this.layer.refresh({ │ │ │ │ │ + force: this.force │ │ │ │ │ + }); │ │ │ │ │ } │ │ │ │ │ - delete this.rules; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: clone │ │ │ │ │ - * Clones this style. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} Clone of this style. │ │ │ │ │ + * Method: stop │ │ │ │ │ + * Cancels the refresh interval. │ │ │ │ │ */ │ │ │ │ │ - clone: function() { │ │ │ │ │ - var config = OpenLayers.Util.extend({}, this); │ │ │ │ │ - // clone rules │ │ │ │ │ - if (this.rules) { │ │ │ │ │ - config.rules = []; │ │ │ │ │ - for (var i = 0, len = this.rules.length; i < len; ++i) { │ │ │ │ │ - config.rules.push(this.rules[i].clone()); │ │ │ │ │ - } │ │ │ │ │ + stop: function() { │ │ │ │ │ + if (this.timer !== null) { │ │ │ │ │ + window.clearInterval(this.timer); │ │ │ │ │ + this.timer = null; │ │ │ │ │ } │ │ │ │ │ - return new OpenLayers.Style2(config); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Style2" │ │ │ │ │ + CLASS_NAME: "OpenLayers.Strategy.Refresh" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Handler/Pinch.js │ │ │ │ │ + OpenLayers/Control/Button.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Handler.js │ │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Handler.Pinch │ │ │ │ │ - * The pinch handler is used to deal with sequences of browser events related │ │ │ │ │ - * to pinch gestures. The handler is used by controls that want to know │ │ │ │ │ - * when a pinch sequence begins, when a pinch is happening, and when it has │ │ │ │ │ - * finished. │ │ │ │ │ - * │ │ │ │ │ - * Controls that use the pinch handler typically construct it with callbacks │ │ │ │ │ - * for 'start', 'move', and 'done'. Callbacks for these keys are │ │ │ │ │ - * called when the pinch begins, with each change, and when the pinch is │ │ │ │ │ - * done. │ │ │ │ │ - * │ │ │ │ │ - * Create a new pinch handler with the constructor. │ │ │ │ │ - * │ │ │ │ │ + * Class: OpenLayers.Control.Button │ │ │ │ │ + * The Button control is a very simple push-button, for use with │ │ │ │ │ + * . │ │ │ │ │ + * When clicked, the function trigger() is executed. │ │ │ │ │ + * │ │ │ │ │ * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * - │ │ │ │ │ + * │ │ │ │ │ + * Use: │ │ │ │ │ + * (code) │ │ │ │ │ + * var button = new OpenLayers.Control.Button({ │ │ │ │ │ + * displayClass: "MyButton", trigger: myFunction │ │ │ │ │ + * }); │ │ │ │ │ + * panel.addControls([button]); │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Will create a button with CSS class MyButtonItemInactive, that │ │ │ │ │ + * will call the function MyFunction() when clicked. │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Handler.Pinch = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: started │ │ │ │ │ - * {Boolean} When a touchstart event is received, we want to record it, │ │ │ │ │ - * but not set 'pinching' until the touchmove get started after │ │ │ │ │ - * starting. │ │ │ │ │ - */ │ │ │ │ │ - started: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: stopDown │ │ │ │ │ - * {Boolean} Stop propagation of touchstart events from getting to │ │ │ │ │ - * listeners on the same element. Default is false. │ │ │ │ │ - */ │ │ │ │ │ - stopDown: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: pinching │ │ │ │ │ - * {Boolean} │ │ │ │ │ - */ │ │ │ │ │ - pinching: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: last │ │ │ │ │ - * {Object} Object that store informations related to pinch last touch. │ │ │ │ │ - */ │ │ │ │ │ - last: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: start │ │ │ │ │ - * {Object} Object that store informations related to pinch touchstart. │ │ │ │ │ - */ │ │ │ │ │ - start: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Handler.Pinch │ │ │ │ │ - * Returns OpenLayers.Handler.Pinch │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * control - {} The control that is making use of │ │ │ │ │ - * this handler. If a handler is being used without a control, the │ │ │ │ │ - * handlers setMap method must be overridden to deal properly with │ │ │ │ │ - * the map. │ │ │ │ │ - * callbacks - {Object} An object containing functions to be called when │ │ │ │ │ - * the pinch operation start, change, or is finished. The callbacks │ │ │ │ │ - * should expect to receive an object argument, which contains │ │ │ │ │ - * information about scale, distance, and position of touch points. │ │ │ │ │ - * options - {Object} │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: touchstart │ │ │ │ │ - * Handle touchstart events │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ │ - */ │ │ │ │ │ - touchstart: function(evt) { │ │ │ │ │ - var propagate = true; │ │ │ │ │ - this.pinching = false; │ │ │ │ │ - if (OpenLayers.Event.isMultiTouch(evt)) { │ │ │ │ │ - this.started = true; │ │ │ │ │ - this.last = this.start = { │ │ │ │ │ - distance: this.getDistance(evt.touches), │ │ │ │ │ - delta: 0, │ │ │ │ │ - scale: 1 │ │ │ │ │ - }; │ │ │ │ │ - this.callback("start", [evt, this.start]); │ │ │ │ │ - propagate = !this.stopDown; │ │ │ │ │ - } else if (this.started) { │ │ │ │ │ - // Some webkit versions send fake single-touch events during │ │ │ │ │ - // multitouch, which cause the drag handler to trigger │ │ │ │ │ - return false; │ │ │ │ │ - } else { │ │ │ │ │ - this.started = false; │ │ │ │ │ - this.start = null; │ │ │ │ │ - this.last = null; │ │ │ │ │ - } │ │ │ │ │ - // prevent document dragging │ │ │ │ │ - OpenLayers.Event.preventDefault(evt); │ │ │ │ │ - return propagate; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: touchmove │ │ │ │ │ - * Handle touchmove events │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ │ - */ │ │ │ │ │ - touchmove: function(evt) { │ │ │ │ │ - if (this.started && OpenLayers.Event.isMultiTouch(evt)) { │ │ │ │ │ - this.pinching = true; │ │ │ │ │ - var current = this.getPinchData(evt); │ │ │ │ │ - this.callback("move", [evt, current]); │ │ │ │ │ - this.last = current; │ │ │ │ │ - // prevent document dragging │ │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ │ - } else if (this.started) { │ │ │ │ │ - // Some webkit versions send fake single-touch events during │ │ │ │ │ - // multitouch, which cause the drag handler to trigger │ │ │ │ │ - return false; │ │ │ │ │ - } │ │ │ │ │ - return true; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: touchend │ │ │ │ │ - * Handle touchend events │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ │ - */ │ │ │ │ │ - touchend: function(evt) { │ │ │ │ │ - if (this.started && !OpenLayers.Event.isMultiTouch(evt)) { │ │ │ │ │ - this.started = false; │ │ │ │ │ - this.pinching = false; │ │ │ │ │ - this.callback("done", [evt, this.start, this.last]); │ │ │ │ │ - this.start = null; │ │ │ │ │ - this.last = null; │ │ │ │ │ - return false; │ │ │ │ │ - } │ │ │ │ │ - return true; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: activate │ │ │ │ │ - * Activate the handler. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The handler was successfully activated. │ │ │ │ │ - */ │ │ │ │ │ - activate: function() { │ │ │ │ │ - var activated = false; │ │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ │ - this.pinching = false; │ │ │ │ │ - activated = true; │ │ │ │ │ - } │ │ │ │ │ - return activated; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: deactivate │ │ │ │ │ - * Deactivate the handler. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The handler was successfully deactivated. │ │ │ │ │ - */ │ │ │ │ │ - deactivate: function() { │ │ │ │ │ - var deactivated = false; │ │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ │ - this.started = false; │ │ │ │ │ - this.pinching = false; │ │ │ │ │ - this.start = null; │ │ │ │ │ - this.last = null; │ │ │ │ │ - deactivated = true; │ │ │ │ │ - } │ │ │ │ │ - return deactivated; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ +OpenLayers.Control.Button = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ /** │ │ │ │ │ - * Method: getDistance │ │ │ │ │ - * Get the distance in pixels between two touches. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * touches - {Array(Object)} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Number} The distance in pixels. │ │ │ │ │ + * Property: type │ │ │ │ │ + * {Integer} OpenLayers.Control.TYPE_BUTTON. │ │ │ │ │ */ │ │ │ │ │ - getDistance: function(touches) { │ │ │ │ │ - var t0 = touches[0]; │ │ │ │ │ - var t1 = touches[1]; │ │ │ │ │ - return Math.sqrt( │ │ │ │ │ - Math.pow(t0.olClientX - t1.olClientX, 2) + │ │ │ │ │ - Math.pow(t0.olClientY - t1.olClientY, 2) │ │ │ │ │ - ); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ + type: OpenLayers.Control.TYPE_BUTTON, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getPinchData │ │ │ │ │ - * Get informations about the pinch event. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} Object that contains data about the current pinch. │ │ │ │ │ + * Method: trigger │ │ │ │ │ + * Called by a control panel when the button is clicked. │ │ │ │ │ */ │ │ │ │ │ - getPinchData: function(evt) { │ │ │ │ │ - var distance = this.getDistance(evt.touches); │ │ │ │ │ - var scale = distance / this.start.distance; │ │ │ │ │ - return { │ │ │ │ │ - distance: distance, │ │ │ │ │ - delta: this.last.distance - distance, │ │ │ │ │ - scale: scale │ │ │ │ │ - }; │ │ │ │ │ - }, │ │ │ │ │ + trigger: function() {}, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Pinch" │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Button" │ │ │ │ │ }); │ │ │ │ │ - │ │ │ │ │ /* ====================================================================== │ │ │ │ │ OpenLayers/Handler/Click.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ @@ -33710,14 +35815,1043 @@ │ │ │ │ │ } │ │ │ │ │ return deactivated; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Handler.Click" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ + OpenLayers/Handler/Hover.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Handler.Hover │ │ │ │ │ + * The hover handler is to be used to emulate mouseovers on objects │ │ │ │ │ + * on the map that aren't DOM elements. For example one can use │ │ │ │ │ + * this handler to send WMS/GetFeatureInfo requests as the user │ │ │ │ │ + * moves the mouve over the map. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: delay │ │ │ │ │ + * {Integer} - Number of milliseconds between mousemoves before │ │ │ │ │ + * the event is considered a hover. Default is 500. │ │ │ │ │ + */ │ │ │ │ │ + delay: 500, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: pixelTolerance │ │ │ │ │ + * {Integer} - Maximum number of pixels between mousemoves for │ │ │ │ │ + * an event to be considered a hover. Default is null. │ │ │ │ │ + */ │ │ │ │ │ + pixelTolerance: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: stopMove │ │ │ │ │ + * {Boolean} - Stop other listeners from being notified on mousemoves. │ │ │ │ │ + * Default is false. │ │ │ │ │ + */ │ │ │ │ │ + stopMove: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: px │ │ │ │ │ + * {} - The location of the last mousemove, expressed │ │ │ │ │ + * in pixels. │ │ │ │ │ + */ │ │ │ │ │ + px: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: timerId │ │ │ │ │ + * {Number} - The id of the timer. │ │ │ │ │ + */ │ │ │ │ │ + timerId: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Handler.Hover │ │ │ │ │ + * Construct a hover handler. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * control - {} The control that initialized this │ │ │ │ │ + * handler. The control is assumed to have a valid map property; that │ │ │ │ │ + * map is used in the handler's own setMap method. │ │ │ │ │ + * callbacks - {Object} An object with keys corresponding to callbacks │ │ │ │ │ + * that will be called by the handler. The callbacks should │ │ │ │ │ + * expect to receive a single argument, the event. Callbacks for │ │ │ │ │ + * 'move', the mouse is moving, and 'pause', the mouse is pausing, │ │ │ │ │ + * are supported. │ │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ │ + * the handler. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: mousemove │ │ │ │ │ + * Called when the mouse moves on the map. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Continue propagating this event. │ │ │ │ │ + */ │ │ │ │ │ + mousemove: function(evt) { │ │ │ │ │ + if (this.passesTolerance(evt.xy)) { │ │ │ │ │ + this.clearTimer(); │ │ │ │ │ + this.callback('move', [evt]); │ │ │ │ │ + this.px = evt.xy; │ │ │ │ │ + // clone the evt so original properties can be accessed even │ │ │ │ │ + // if the browser deletes them during the delay │ │ │ │ │ + evt = OpenLayers.Util.extend({}, evt); │ │ │ │ │ + this.timerId = window.setTimeout( │ │ │ │ │ + OpenLayers.Function.bind(this.delayedCall, this, evt), │ │ │ │ │ + this.delay │ │ │ │ │ + ); │ │ │ │ │ + } │ │ │ │ │ + return !this.stopMove; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: mouseout │ │ │ │ │ + * Called when the mouse goes out of the map. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Continue propagating this event. │ │ │ │ │ + */ │ │ │ │ │ + mouseout: function(evt) { │ │ │ │ │ + if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ │ + this.clearTimer(); │ │ │ │ │ + this.callback('move', [evt]); │ │ │ │ │ + } │ │ │ │ │ + return true; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: passesTolerance │ │ │ │ │ + * Determine whether the mouse move is within the optional pixel tolerance. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * px - {} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The mouse move is within the pixel tolerance. │ │ │ │ │ + */ │ │ │ │ │ + passesTolerance: function(px) { │ │ │ │ │ + var passes = true; │ │ │ │ │ + if (this.pixelTolerance && this.px) { │ │ │ │ │ + var dpx = Math.sqrt( │ │ │ │ │ + Math.pow(this.px.x - px.x, 2) + │ │ │ │ │ + Math.pow(this.px.y - px.y, 2) │ │ │ │ │ + ); │ │ │ │ │ + if (dpx < this.pixelTolerance) { │ │ │ │ │ + passes = false; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return passes; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: clearTimer │ │ │ │ │ + * Clear the timer and set to null. │ │ │ │ │ + */ │ │ │ │ │ + clearTimer: function() { │ │ │ │ │ + if (this.timerId != null) { │ │ │ │ │ + window.clearTimeout(this.timerId); │ │ │ │ │ + this.timerId = null; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: delayedCall │ │ │ │ │ + * Triggers pause callback. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {} │ │ │ │ │ + */ │ │ │ │ │ + delayedCall: function(evt) { │ │ │ │ │ + this.callback('pause', [evt]); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: deactivate │ │ │ │ │ + * Deactivate the handler. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The handler was successfully deactivated. │ │ │ │ │ + */ │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + var deactivated = false; │ │ │ │ │ + if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ │ + this.clearTimer(); │ │ │ │ │ + deactivated = true; │ │ │ │ │ + } │ │ │ │ │ + return deactivated; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Hover" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Format/WMSGetFeatureInfo.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Format/XML.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Format.WMSGetFeatureInfo │ │ │ │ │ + * Class to read GetFeatureInfo responses from Web Mapping Services │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Format.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: layerIdentifier │ │ │ │ │ + * {String} All xml nodes containing this search criteria will populate an │ │ │ │ │ + * internal array of layer nodes. │ │ │ │ │ + */ │ │ │ │ │ + layerIdentifier: '_layer', │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: featureIdentifier │ │ │ │ │ + * {String} All xml nodes containing this search criteria will populate an │ │ │ │ │ + * internal array of feature nodes for each layer node found. │ │ │ │ │ + */ │ │ │ │ │ + featureIdentifier: '_feature', │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: regExes │ │ │ │ │ + * Compiled regular expressions for manipulating strings. │ │ │ │ │ + */ │ │ │ │ │ + regExes: { │ │ │ │ │ + trimSpace: (/^\s*|\s*$/g), │ │ │ │ │ + removeSpace: (/\s*/g), │ │ │ │ │ + splitSpace: (/\s+/), │ │ │ │ │ + trimComma: (/\s*,\s*/g) │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: gmlFormat │ │ │ │ │ + * {} internal GML format for parsing geometries │ │ │ │ │ + * in msGMLOutput │ │ │ │ │ + */ │ │ │ │ │ + gmlFormat: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Format.WMSGetFeatureInfo │ │ │ │ │ + * Create a new parser for WMS GetFeatureInfo responses │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ │ + * this instance. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: read │ │ │ │ │ + * Read WMS GetFeatureInfo data from a string, and return an array of features │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * data - {String} or {DOMElement} data to read/parse. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Array()} An array of features. │ │ │ │ │ + */ │ │ │ │ │ + read: function(data) { │ │ │ │ │ + var result; │ │ │ │ │ + if (typeof data == "string") { │ │ │ │ │ + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ │ + } │ │ │ │ │ + var root = data.documentElement; │ │ │ │ │ + if (root) { │ │ │ │ │ + var scope = this; │ │ │ │ │ + var read = this["read_" + root.nodeName]; │ │ │ │ │ + if (read) { │ │ │ │ │ + result = read.call(this, root); │ │ │ │ │ + } else { │ │ │ │ │ + // fall-back to GML since this is a common output format for WMS │ │ │ │ │ + // GetFeatureInfo responses │ │ │ │ │ + result = new OpenLayers.Format.GML((this.options ? this.options : {})).read(data); │ │ │ │ │ + } │ │ │ │ │ + } else { │ │ │ │ │ + result = data; │ │ │ │ │ + } │ │ │ │ │ + return result; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: read_msGMLOutput │ │ │ │ │ + * Parse msGMLOutput nodes. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * data - {DOMElement} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Array} │ │ │ │ │ + */ │ │ │ │ │ + read_msGMLOutput: function(data) { │ │ │ │ │ + var response = []; │ │ │ │ │ + var layerNodes = this.getSiblingNodesByTagCriteria(data, │ │ │ │ │ + this.layerIdentifier); │ │ │ │ │ + if (layerNodes) { │ │ │ │ │ + for (var i = 0, len = layerNodes.length; i < len; ++i) { │ │ │ │ │ + var node = layerNodes[i]; │ │ │ │ │ + var layerName = node.nodeName; │ │ │ │ │ + if (node.prefix) { │ │ │ │ │ + layerName = layerName.split(':')[1]; │ │ │ │ │ + } │ │ │ │ │ + var layerName = layerName.replace(this.layerIdentifier, ''); │ │ │ │ │ + var featureNodes = this.getSiblingNodesByTagCriteria(node, │ │ │ │ │ + this.featureIdentifier); │ │ │ │ │ + if (featureNodes) { │ │ │ │ │ + for (var j = 0; j < featureNodes.length; j++) { │ │ │ │ │ + var featureNode = featureNodes[j]; │ │ │ │ │ + var geomInfo = this.parseGeometry(featureNode); │ │ │ │ │ + var attributes = this.parseAttributes(featureNode); │ │ │ │ │ + var feature = new OpenLayers.Feature.Vector(geomInfo.geometry, │ │ │ │ │ + attributes, null); │ │ │ │ │ + feature.bounds = geomInfo.bounds; │ │ │ │ │ + feature.type = layerName; │ │ │ │ │ + response.push(feature); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return response; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: read_FeatureInfoResponse │ │ │ │ │ + * Parse FeatureInfoResponse nodes. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * data - {DOMElement} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Array} │ │ │ │ │ + */ │ │ │ │ │ + read_FeatureInfoResponse: function(data) { │ │ │ │ │ + var response = []; │ │ │ │ │ + var featureNodes = this.getElementsByTagNameNS(data, '*', │ │ │ │ │ + 'FIELDS'); │ │ │ │ │ + │ │ │ │ │ + for (var i = 0, len = featureNodes.length; i < len; i++) { │ │ │ │ │ + var featureNode = featureNodes[i]; │ │ │ │ │ + var geom = null; │ │ │ │ │ + │ │ │ │ │ + // attributes can be actual attributes on the FIELDS tag, │ │ │ │ │ + // or FIELD children │ │ │ │ │ + var attributes = {}; │ │ │ │ │ + var j; │ │ │ │ │ + var jlen = featureNode.attributes.length; │ │ │ │ │ + if (jlen > 0) { │ │ │ │ │ + for (j = 0; j < jlen; j++) { │ │ │ │ │ + var attribute = featureNode.attributes[j]; │ │ │ │ │ + attributes[attribute.nodeName] = attribute.nodeValue; │ │ │ │ │ + } │ │ │ │ │ + } else { │ │ │ │ │ + var nodes = featureNode.childNodes; │ │ │ │ │ + for (j = 0, jlen = nodes.length; j < jlen; ++j) { │ │ │ │ │ + var node = nodes[j]; │ │ │ │ │ + if (node.nodeType != 3) { │ │ │ │ │ + attributes[node.getAttribute("name")] = │ │ │ │ │ + node.getAttribute("value"); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + response.push( │ │ │ │ │ + new OpenLayers.Feature.Vector(geom, attributes, null) │ │ │ │ │ + ); │ │ │ │ │ + } │ │ │ │ │ + return response; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: getSiblingNodesByTagCriteria │ │ │ │ │ + * Recursively searches passed xml node and all it's descendant levels for │ │ │ │ │ + * nodes whose tagName contains the passed search string. This returns an │ │ │ │ │ + * array of all sibling nodes which match the criteria from the highest │ │ │ │ │ + * hierarchial level from which a match is found. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * node - {DOMElement} An xml node │ │ │ │ │ + * criteria - {String} Search string which will match some part of a tagName │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * Array({DOMElement}) An array of sibling xml nodes │ │ │ │ │ + */ │ │ │ │ │ + getSiblingNodesByTagCriteria: function(node, criteria) { │ │ │ │ │ + var nodes = []; │ │ │ │ │ + var children, tagName, n, matchNodes, child; │ │ │ │ │ + if (node && node.hasChildNodes()) { │ │ │ │ │ + children = node.childNodes; │ │ │ │ │ + n = children.length; │ │ │ │ │ + │ │ │ │ │ + for (var k = 0; k < n; k++) { │ │ │ │ │ + child = children[k]; │ │ │ │ │ + while (child && child.nodeType != 1) { │ │ │ │ │ + child = child.nextSibling; │ │ │ │ │ + k++; │ │ │ │ │ + } │ │ │ │ │ + tagName = (child ? child.nodeName : ''); │ │ │ │ │ + if (tagName.length > 0 && tagName.indexOf(criteria) > -1) { │ │ │ │ │ + nodes.push(child); │ │ │ │ │ + } else { │ │ │ │ │ + matchNodes = this.getSiblingNodesByTagCriteria( │ │ │ │ │ + child, criteria); │ │ │ │ │ + │ │ │ │ │ + if (matchNodes.length > 0) { │ │ │ │ │ + (nodes.length == 0) ? │ │ │ │ │ + nodes = matchNodes: nodes.push(matchNodes); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + } │ │ │ │ │ + return nodes; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: parseAttributes │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * node - {} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Object} An attributes object. │ │ │ │ │ + * │ │ │ │ │ + * Notes: │ │ │ │ │ + * Assumes that attributes are direct child xml nodes of the passed node │ │ │ │ │ + * and contain only a single text node. │ │ │ │ │ + */ │ │ │ │ │ + parseAttributes: function(node) { │ │ │ │ │ + var attributes = {}; │ │ │ │ │ + if (node.nodeType == 1) { │ │ │ │ │ + var children = node.childNodes; │ │ │ │ │ + var n = children.length; │ │ │ │ │ + for (var i = 0; i < n; ++i) { │ │ │ │ │ + var child = children[i]; │ │ │ │ │ + if (child.nodeType == 1) { │ │ │ │ │ + var grandchildren = child.childNodes; │ │ │ │ │ + var name = (child.prefix) ? │ │ │ │ │ + child.nodeName.split(":")[1] : child.nodeName; │ │ │ │ │ + if (grandchildren.length == 0) { │ │ │ │ │ + attributes[name] = null; │ │ │ │ │ + } else if (grandchildren.length == 1) { │ │ │ │ │ + var grandchild = grandchildren[0]; │ │ │ │ │ + if (grandchild.nodeType == 3 || │ │ │ │ │ + grandchild.nodeType == 4) { │ │ │ │ │ + var value = grandchild.nodeValue.replace( │ │ │ │ │ + this.regExes.trimSpace, ""); │ │ │ │ │ + attributes[name] = value; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return attributes; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: parseGeometry │ │ │ │ │ + * Parse the geometry and the feature bounds out of the node using │ │ │ │ │ + * Format.GML │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * node - {} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Object} An object containing the geometry and the feature bounds │ │ │ │ │ + */ │ │ │ │ │ + parseGeometry: function(node) { │ │ │ │ │ + // we need to use the old Format.GML parser since we do not know the │ │ │ │ │ + // geometry name │ │ │ │ │ + if (!this.gmlFormat) { │ │ │ │ │ + this.gmlFormat = new OpenLayers.Format.GML(); │ │ │ │ │ + } │ │ │ │ │ + var feature = this.gmlFormat.parseFeature(node); │ │ │ │ │ + var geometry, bounds = null; │ │ │ │ │ + if (feature) { │ │ │ │ │ + geometry = feature.geometry && feature.geometry.clone(); │ │ │ │ │ + bounds = feature.bounds && feature.bounds.clone(); │ │ │ │ │ + feature.destroy(); │ │ │ │ │ + } │ │ │ │ │ + return { │ │ │ │ │ + geometry: geometry, │ │ │ │ │ + bounds: bounds │ │ │ │ │ + }; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Format.WMSGetFeatureInfo" │ │ │ │ │ + │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Control/WMSGetFeatureInfo.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ │ + * @requires OpenLayers/Handler/Click.js │ │ │ │ │ + * @requires OpenLayers/Handler/Hover.js │ │ │ │ │ + * @requires OpenLayers/Request.js │ │ │ │ │ + * @requires OpenLayers/Format/WMSGetFeatureInfo.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.WMSGetFeatureInfo │ │ │ │ │ + * The WMSGetFeatureInfo control uses a WMS query to get information about a point on the map. The │ │ │ │ │ + * information may be in a display-friendly format such as HTML, or a machine-friendly format such │ │ │ │ │ + * as GML, depending on the server's capabilities and the client's configuration. This control │ │ │ │ │ + * handles click or hover events, attempts to parse the results using an OpenLayers.Format, and │ │ │ │ │ + * fires a 'getfeatureinfo' event with the click position, the raw body of the response, and an │ │ │ │ │ + * array of features if it successfully read the response. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: hover │ │ │ │ │ + * {Boolean} Send GetFeatureInfo requests when mouse stops moving. │ │ │ │ │ + * Default is false. │ │ │ │ │ + */ │ │ │ │ │ + hover: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: drillDown │ │ │ │ │ + * {Boolean} Drill down over all WMS layers in the map. When │ │ │ │ │ + * using drillDown mode, hover is not possible, and an infoFormat that │ │ │ │ │ + * returns parseable features is required. Default is false. │ │ │ │ │ + */ │ │ │ │ │ + drillDown: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: maxFeatures │ │ │ │ │ + * {Integer} Maximum number of features to return from a WMS query. This │ │ │ │ │ + * sets the feature_count parameter on WMS GetFeatureInfo │ │ │ │ │ + * requests. │ │ │ │ │ + */ │ │ │ │ │ + maxFeatures: 10, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: clickCallback │ │ │ │ │ + * {String} The click callback to register in the │ │ │ │ │ + * {} object created when the hover │ │ │ │ │ + * option is set to false. Default is "click". │ │ │ │ │ + */ │ │ │ │ │ + clickCallback: "click", │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: output │ │ │ │ │ + * {String} Either "features" or "object". When triggering a getfeatureinfo │ │ │ │ │ + * request should we pass on an array of features or an object with with │ │ │ │ │ + * a "features" property and other properties (such as the url of the │ │ │ │ │ + * WMS). Default is "features". │ │ │ │ │ + */ │ │ │ │ │ + output: "features", │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: layers │ │ │ │ │ + * {Array()} The layers to query for feature info. │ │ │ │ │ + * If omitted, all map WMS layers with a url that matches this or │ │ │ │ │ + * will be considered. │ │ │ │ │ + */ │ │ │ │ │ + layers: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: queryVisible │ │ │ │ │ + * {Boolean} If true, filter out hidden layers when searching the map for │ │ │ │ │ + * layers to query. Default is false. │ │ │ │ │ + */ │ │ │ │ │ + queryVisible: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: url │ │ │ │ │ + * {String} The URL of the WMS service to use. If not provided, the url │ │ │ │ │ + * of the first eligible layer will be used. │ │ │ │ │ + */ │ │ │ │ │ + url: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: layerUrls │ │ │ │ │ + * {Array(String)} Optional list of urls for layers that should be queried. │ │ │ │ │ + * This can be used when the layer url differs from the url used for │ │ │ │ │ + * making GetFeatureInfo requests (in the case of a layer using cached │ │ │ │ │ + * tiles). │ │ │ │ │ + */ │ │ │ │ │ + layerUrls: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: infoFormat │ │ │ │ │ + * {String} The mimetype to request from the server. If you are using │ │ │ │ │ + * drillDown mode and have multiple servers that do not share a common │ │ │ │ │ + * infoFormat, you can override the control's infoFormat by providing an │ │ │ │ │ + * INFO_FORMAT parameter in your instance(s). │ │ │ │ │ + */ │ │ │ │ │ + infoFormat: 'text/html', │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: vendorParams │ │ │ │ │ + * {Object} Additional parameters that will be added to the request, for │ │ │ │ │ + * WMS implementations that support them. This could e.g. look like │ │ │ │ │ + * (start code) │ │ │ │ │ + * { │ │ │ │ │ + * radius: 5 │ │ │ │ │ + * } │ │ │ │ │ + * (end) │ │ │ │ │ + */ │ │ │ │ │ + vendorParams: {}, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: format │ │ │ │ │ + * {} A format for parsing GetFeatureInfo responses. │ │ │ │ │ + * Default is . │ │ │ │ │ + */ │ │ │ │ │ + format: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: formatOptions │ │ │ │ │ + * {Object} Optional properties to set on the format (if one is not provided │ │ │ │ │ + * in the property. │ │ │ │ │ + */ │ │ │ │ │ + formatOptions: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: handlerOptions │ │ │ │ │ + * {Object} Additional options for the handlers used by this control, e.g. │ │ │ │ │ + * (start code) │ │ │ │ │ + * { │ │ │ │ │ + * "click": {delay: 100}, │ │ │ │ │ + * "hover": {delay: 300} │ │ │ │ │ + * } │ │ │ │ │ + * (end) │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: handler │ │ │ │ │ + * {Object} Reference to the for this control │ │ │ │ │ + */ │ │ │ │ │ + handler: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: hoverRequest │ │ │ │ │ + * {} contains the currently running hover request │ │ │ │ │ + * (if any). │ │ │ │ │ + */ │ │ │ │ │ + hoverRequest: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: events │ │ │ │ │ + * {} Events instance for listeners and triggering │ │ │ │ │ + * control specific events. │ │ │ │ │ + * │ │ │ │ │ + * Register a listener for a particular event with the following syntax: │ │ │ │ │ + * (code) │ │ │ │ │ + * control.events.register(type, obj, listener); │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Supported event types (in addition to those from ): │ │ │ │ │ + * beforegetfeatureinfo - Triggered before the request is sent. │ │ │ │ │ + * The event object has an *xy* property with the position of the │ │ │ │ │ + * mouse click or hover event that triggers the request. │ │ │ │ │ + * nogetfeatureinfo - no queryable layers were found. │ │ │ │ │ + * getfeatureinfo - Triggered when a GetFeatureInfo response is received. │ │ │ │ │ + * The event object has a *text* property with the body of the │ │ │ │ │ + * response (String), a *features* property with an array of the │ │ │ │ │ + * parsed features, an *xy* property with the position of the mouse │ │ │ │ │ + * click or hover event that triggered the request, and a *request* │ │ │ │ │ + * property with the request itself. If drillDown is set to true and │ │ │ │ │ + * multiple requests were issued to collect feature info from all │ │ │ │ │ + * layers, *text* and *request* will only contain the response body │ │ │ │ │ + * and request object of the last request. │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + options = options || {}; │ │ │ │ │ + options.handlerOptions = options.handlerOptions || {}; │ │ │ │ │ + │ │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ │ + │ │ │ │ │ + if (!this.format) { │ │ │ │ │ + this.format = new OpenLayers.Format.WMSGetFeatureInfo( │ │ │ │ │ + options.formatOptions │ │ │ │ │ + ); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (this.drillDown === true) { │ │ │ │ │ + this.hover = false; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (this.hover) { │ │ │ │ │ + this.handler = new OpenLayers.Handler.Hover( │ │ │ │ │ + this, { │ │ │ │ │ + 'move': this.cancelHover, │ │ │ │ │ + 'pause': this.getInfoForHover │ │ │ │ │ + }, │ │ │ │ │ + OpenLayers.Util.extend(this.handlerOptions.hover || {}, { │ │ │ │ │ + 'delay': 250 │ │ │ │ │ + })); │ │ │ │ │ + } else { │ │ │ │ │ + var callbacks = {}; │ │ │ │ │ + callbacks[this.clickCallback] = this.getInfoForClick; │ │ │ │ │ + this.handler = new OpenLayers.Handler.Click( │ │ │ │ │ + this, callbacks, this.handlerOptions.click || {}); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: getInfoForClick │ │ │ │ │ + * Called on click │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {} │ │ │ │ │ + */ │ │ │ │ │ + getInfoForClick: function(evt) { │ │ │ │ │ + this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ │ + xy: evt.xy │ │ │ │ │ + }); │ │ │ │ │ + // Set the cursor to "wait" to tell the user we're working on their │ │ │ │ │ + // click. │ │ │ │ │ + OpenLayers.Element.addClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ │ + this.request(evt.xy, {}); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: getInfoForHover │ │ │ │ │ + * Pause callback for the hover handler │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {Object} │ │ │ │ │ + */ │ │ │ │ │ + getInfoForHover: function(evt) { │ │ │ │ │ + this.events.triggerEvent("beforegetfeatureinfo", { │ │ │ │ │ + xy: evt.xy │ │ │ │ │ + }); │ │ │ │ │ + this.request(evt.xy, { │ │ │ │ │ + hover: true │ │ │ │ │ + }); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: cancelHover │ │ │ │ │ + * Cancel callback for the hover handler │ │ │ │ │ + */ │ │ │ │ │ + cancelHover: function() { │ │ │ │ │ + if (this.hoverRequest) { │ │ │ │ │ + this.hoverRequest.abort(); │ │ │ │ │ + this.hoverRequest = null; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: findLayers │ │ │ │ │ + * Internal method to get the layers, independent of whether we are │ │ │ │ │ + * inspecting the map or using a client-provided array │ │ │ │ │ + */ │ │ │ │ │ + findLayers: function() { │ │ │ │ │ + │ │ │ │ │ + var candidates = this.layers || this.map.layers; │ │ │ │ │ + var layers = []; │ │ │ │ │ + var layer, url; │ │ │ │ │ + for (var i = candidates.length - 1; i >= 0; --i) { │ │ │ │ │ + layer = candidates[i]; │ │ │ │ │ + if (layer instanceof OpenLayers.Layer.WMS && │ │ │ │ │ + (!this.queryVisible || layer.getVisibility())) { │ │ │ │ │ + url = OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url; │ │ │ │ │ + // if the control was not configured with a url, set it │ │ │ │ │ + // to the first layer url │ │ │ │ │ + if (this.drillDown === false && !this.url) { │ │ │ │ │ + this.url = url; │ │ │ │ │ + } │ │ │ │ │ + if (this.drillDown === true || this.urlMatches(url)) { │ │ │ │ │ + layers.push(layer); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return layers; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: urlMatches │ │ │ │ │ + * Test to see if the provided url matches either the control or one │ │ │ │ │ + * of the . │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * url - {String} The url to test. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The provided url matches the control or one of the │ │ │ │ │ + * . │ │ │ │ │ + */ │ │ │ │ │ + urlMatches: function(url) { │ │ │ │ │ + var matches = OpenLayers.Util.isEquivalentUrl(this.url, url); │ │ │ │ │ + if (!matches && this.layerUrls) { │ │ │ │ │ + for (var i = 0, len = this.layerUrls.length; i < len; ++i) { │ │ │ │ │ + if (OpenLayers.Util.isEquivalentUrl(this.layerUrls[i], url)) { │ │ │ │ │ + matches = true; │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return matches; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: buildWMSOptions │ │ │ │ │ + * Build an object with the relevant WMS options for the GetFeatureInfo request │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * url - {String} The url to be used for sending the request │ │ │ │ │ + * layers - {Array(} The position on the map where the mouse │ │ │ │ │ + * event occurred. │ │ │ │ │ + * format - {String} The format from the corresponding GetMap request │ │ │ │ │ + */ │ │ │ │ │ + buildWMSOptions: function(url, layers, clickPosition, format) { │ │ │ │ │ + var layerNames = [], │ │ │ │ │ + styleNames = []; │ │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ │ + if (layers[i].params.LAYERS != null) { │ │ │ │ │ + layerNames = layerNames.concat(layers[i].params.LAYERS); │ │ │ │ │ + styleNames = styleNames.concat(this.getStyleNames(layers[i])); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + var firstLayer = layers[0]; │ │ │ │ │ + // use the firstLayer's projection if it matches the map projection - │ │ │ │ │ + // this assumes that all layers will be available in this projection │ │ │ │ │ + var projection = this.map.getProjection(); │ │ │ │ │ + var layerProj = firstLayer.projection; │ │ │ │ │ + if (layerProj && layerProj.equals(this.map.getProjectionObject())) { │ │ │ │ │ + projection = layerProj.getCode(); │ │ │ │ │ + } │ │ │ │ │ + var params = OpenLayers.Util.extend({ │ │ │ │ │ + service: "WMS", │ │ │ │ │ + version: firstLayer.params.VERSION, │ │ │ │ │ + request: "GetFeatureInfo", │ │ │ │ │ + exceptions: firstLayer.params.EXCEPTIONS, │ │ │ │ │ + bbox: this.map.getExtent().toBBOX(null, │ │ │ │ │ + firstLayer.reverseAxisOrder()), │ │ │ │ │ + feature_count: this.maxFeatures, │ │ │ │ │ + height: this.map.getSize().h, │ │ │ │ │ + width: this.map.getSize().w, │ │ │ │ │ + format: format, │ │ │ │ │ + info_format: firstLayer.params.INFO_FORMAT || this.infoFormat │ │ │ │ │ + }, (parseFloat(firstLayer.params.VERSION) >= 1.3) ? { │ │ │ │ │ + crs: projection, │ │ │ │ │ + i: parseInt(clickPosition.x), │ │ │ │ │ + j: parseInt(clickPosition.y) │ │ │ │ │ + } : { │ │ │ │ │ + srs: projection, │ │ │ │ │ + x: parseInt(clickPosition.x), │ │ │ │ │ + y: parseInt(clickPosition.y) │ │ │ │ │ + }); │ │ │ │ │ + if (layerNames.length != 0) { │ │ │ │ │ + params = OpenLayers.Util.extend({ │ │ │ │ │ + layers: layerNames, │ │ │ │ │ + query_layers: layerNames, │ │ │ │ │ + styles: styleNames │ │ │ │ │ + }, params); │ │ │ │ │ + } │ │ │ │ │ + OpenLayers.Util.applyDefaults(params, this.vendorParams); │ │ │ │ │ + return { │ │ │ │ │ + url: url, │ │ │ │ │ + params: OpenLayers.Util.upperCaseObject(params), │ │ │ │ │ + callback: function(request) { │ │ │ │ │ + this.handleResponse(clickPosition, request, url); │ │ │ │ │ + }, │ │ │ │ │ + scope: this │ │ │ │ │ + }; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: getStyleNames │ │ │ │ │ + * Gets the STYLES parameter for the layer. Make sure the STYLES parameter │ │ │ │ │ + * matches the LAYERS parameter │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * layer - {} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Array(String)} The STYLES parameter │ │ │ │ │ + */ │ │ │ │ │ + getStyleNames: function(layer) { │ │ │ │ │ + // in the event of a WMS layer bundling multiple layers but not │ │ │ │ │ + // specifying styles,we need the same number of commas to specify │ │ │ │ │ + // the default style for each of the layers. We can't just leave it │ │ │ │ │ + // blank as we may be including other layers that do specify styles. │ │ │ │ │ + var styleNames; │ │ │ │ │ + if (layer.params.STYLES) { │ │ │ │ │ + styleNames = layer.params.STYLES; │ │ │ │ │ + } else { │ │ │ │ │ + if (OpenLayers.Util.isArray(layer.params.LAYERS)) { │ │ │ │ │ + styleNames = new Array(layer.params.LAYERS.length); │ │ │ │ │ + } else { // Assume it's a String │ │ │ │ │ + styleNames = layer.params.LAYERS.replace(/[^,]/g, ""); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return styleNames; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: request │ │ │ │ │ + * Sends a GetFeatureInfo request to the WMS │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * clickPosition - {} The position on the map where the │ │ │ │ │ + * mouse event occurred. │ │ │ │ │ + * options - {Object} additional options for this method. │ │ │ │ │ + * │ │ │ │ │ + * Valid options: │ │ │ │ │ + * - *hover* {Boolean} true if we do the request for the hover handler │ │ │ │ │ + */ │ │ │ │ │ + request: function(clickPosition, options) { │ │ │ │ │ + var layers = this.findLayers(); │ │ │ │ │ + if (layers.length == 0) { │ │ │ │ │ + this.events.triggerEvent("nogetfeatureinfo"); │ │ │ │ │ + // Reset the cursor. │ │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ │ + return; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + options = options || {}; │ │ │ │ │ + if (this.drillDown === false) { │ │ │ │ │ + var wmsOptions = this.buildWMSOptions(this.url, layers, │ │ │ │ │ + clickPosition, layers[0].params.FORMAT); │ │ │ │ │ + var request = OpenLayers.Request.GET(wmsOptions); │ │ │ │ │ + │ │ │ │ │ + if (options.hover === true) { │ │ │ │ │ + this.hoverRequest = request; │ │ │ │ │ + } │ │ │ │ │ + } else { │ │ │ │ │ + this._requestCount = 0; │ │ │ │ │ + this._numRequests = 0; │ │ │ │ │ + this.features = []; │ │ │ │ │ + // group according to service url to combine requests │ │ │ │ │ + var services = {}, │ │ │ │ │ + url; │ │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ │ + var layer = layers[i]; │ │ │ │ │ + var service, found = false; │ │ │ │ │ + url = OpenLayers.Util.isArray(layer.url) ? layer.url[0] : layer.url; │ │ │ │ │ + if (url in services) { │ │ │ │ │ + services[url].push(layer); │ │ │ │ │ + } else { │ │ │ │ │ + this._numRequests++; │ │ │ │ │ + services[url] = [layer]; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + var layers; │ │ │ │ │ + for (var url in services) { │ │ │ │ │ + layers = services[url]; │ │ │ │ │ + var wmsOptions = this.buildWMSOptions(url, layers, │ │ │ │ │ + clickPosition, layers[0].params.FORMAT); │ │ │ │ │ + OpenLayers.Request.GET(wmsOptions); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: triggerGetFeatureInfo │ │ │ │ │ + * Trigger the getfeatureinfo event when all is done │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * request - {XMLHttpRequest} The request object │ │ │ │ │ + * xy - {} The position on the map where the │ │ │ │ │ + * mouse event occurred. │ │ │ │ │ + * features - {Array()} or │ │ │ │ │ + * {Array({Object}) when output is "object". The object has a url and a │ │ │ │ │ + * features property which contains an array of features. │ │ │ │ │ + */ │ │ │ │ │ + triggerGetFeatureInfo: function(request, xy, features) { │ │ │ │ │ + this.events.triggerEvent("getfeatureinfo", { │ │ │ │ │ + text: request.responseText, │ │ │ │ │ + features: features, │ │ │ │ │ + request: request, │ │ │ │ │ + xy: xy │ │ │ │ │ + }); │ │ │ │ │ + │ │ │ │ │ + // Reset the cursor. │ │ │ │ │ + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: handleResponse │ │ │ │ │ + * Handler for the GetFeatureInfo response. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * xy - {} The position on the map where the │ │ │ │ │ + * mouse event occurred. │ │ │ │ │ + * request - {XMLHttpRequest} The request object. │ │ │ │ │ + * url - {String} The url which was used for this request. │ │ │ │ │ + */ │ │ │ │ │ + handleResponse: function(xy, request, url) { │ │ │ │ │ + │ │ │ │ │ + var doc = request.responseXML; │ │ │ │ │ + if (!doc || !doc.documentElement) { │ │ │ │ │ + doc = request.responseText; │ │ │ │ │ + } │ │ │ │ │ + var features = this.format.read(doc); │ │ │ │ │ + if (this.drillDown === false) { │ │ │ │ │ + this.triggerGetFeatureInfo(request, xy, features); │ │ │ │ │ + } else { │ │ │ │ │ + this._requestCount++; │ │ │ │ │ + if (this.output === "object") { │ │ │ │ │ + this._features = (this._features || []).concat({ │ │ │ │ │ + url: url, │ │ │ │ │ + features: features │ │ │ │ │ + }); │ │ │ │ │ + } else { │ │ │ │ │ + this._features = (this._features || []).concat(features); │ │ │ │ │ + } │ │ │ │ │ + if (this._requestCount === this._numRequests) { │ │ │ │ │ + this.triggerGetFeatureInfo(request, xy, this._features.concat()); │ │ │ │ │ + delete this._features; │ │ │ │ │ + delete this._requestCount; │ │ │ │ │ + delete this._numRequests; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.WMSGetFeatureInfo" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ OpenLayers/Handler/Drag.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ @@ -34265,134 +37399,828 @@ │ │ │ │ │ OpenLayers.Event.stopObserving(document, "mousemove", this._docMove); │ │ │ │ │ OpenLayers.Event.stopObserving(document, "mouseup", this._docUp); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Handler.Drag" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Handler/Keyboard.js │ │ │ │ │ + OpenLayers/Handler/Box.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ * @requires OpenLayers/Handler.js │ │ │ │ │ - * @requires OpenLayers/Events.js │ │ │ │ │ + * @requires OpenLayers/Handler/Drag.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.handler.Keyboard │ │ │ │ │ - * A handler for keyboard events. Create a new instance with the │ │ │ │ │ - * constructor. │ │ │ │ │ - * │ │ │ │ │ + * Class: OpenLayers.Handler.Box │ │ │ │ │ + * Handler for dragging a rectangle across the map. Box is displayed │ │ │ │ │ + * on mouse down, moves on mouse move, and is finished on mouse up. │ │ │ │ │ + * │ │ │ │ │ * Inherits from: │ │ │ │ │ * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Handler.Keyboard = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ - │ │ │ │ │ - /* http://www.quirksmode.org/js/keys.html explains key x-browser │ │ │ │ │ - key handling quirks in pretty nice detail */ │ │ │ │ │ +OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constant: KEY_EVENTS │ │ │ │ │ - * keydown, keypress, keyup │ │ │ │ │ + * Property: dragHandler │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - KEY_EVENTS: ["keydown", "keyup"], │ │ │ │ │ + dragHandler: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Property: eventListener │ │ │ │ │ - * {Function} │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: boxDivClassName │ │ │ │ │ + * {String} The CSS class to use for drawing the box. Default is │ │ │ │ │ + * olHandlerBoxZoomBox │ │ │ │ │ */ │ │ │ │ │ - eventListener: null, │ │ │ │ │ + boxDivClassName: 'olHandlerBoxZoomBox', │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: observeElement │ │ │ │ │ - * {DOMElement|String} The DOM element on which we listen for │ │ │ │ │ - * key events. Default to the document. │ │ │ │ │ + * Property: boxOffsets │ │ │ │ │ + * {Object} Caches box offsets from css. This is used by the getBoxOffsets │ │ │ │ │ + * method. │ │ │ │ │ */ │ │ │ │ │ - observeElement: null, │ │ │ │ │ + boxOffsets: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Handler.Keyboard │ │ │ │ │ - * Returns a new keyboard handler. │ │ │ │ │ - * │ │ │ │ │ + * Constructor: OpenLayers.Handler.Box │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * control - {} The control that is making use of │ │ │ │ │ - * this handler. If a handler is being used without a control, the │ │ │ │ │ - * handlers setMap method must be overridden to deal properly with │ │ │ │ │ - * the map. │ │ │ │ │ - * callbacks - {Object} An object containing a single function to be │ │ │ │ │ - * called when the drag operation is finished. The callback should │ │ │ │ │ - * expect to recieve a single argument, the pixel location of the event. │ │ │ │ │ - * Callbacks for 'keydown', 'keypress', and 'keyup' are supported. │ │ │ │ │ - * options - {Object} Optional object whose properties will be set on the │ │ │ │ │ - * handler. │ │ │ │ │ + * control - {} │ │ │ │ │ + * callbacks - {Object} An object with a properties whose values are │ │ │ │ │ + * functions. Various callbacks described below. │ │ │ │ │ + * options - {Object} │ │ │ │ │ + * │ │ │ │ │ + * Named callbacks: │ │ │ │ │ + * start - Called when the box drag operation starts. │ │ │ │ │ + * done - Called when the box drag operation is finished. │ │ │ │ │ + * The callback should expect to receive a single argument, the box │ │ │ │ │ + * bounds or a pixel. If the box dragging didn't span more than a 5 │ │ │ │ │ + * pixel distance, a pixel will be returned instead of a bounds object. │ │ │ │ │ */ │ │ │ │ │ initialize: function(control, callbacks, options) { │ │ │ │ │ OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ │ - // cache the bound event listener method so it can be unobserved later │ │ │ │ │ - this.eventListener = OpenLayers.Function.bindAsEventListener( │ │ │ │ │ - this.handleKeyEvent, this │ │ │ │ │ + this.dragHandler = new OpenLayers.Handler.Drag( │ │ │ │ │ + this, { │ │ │ │ │ + down: this.startBox, │ │ │ │ │ + move: this.moveBox, │ │ │ │ │ + out: this.removeBox, │ │ │ │ │ + up: this.endBox │ │ │ │ │ + }, { │ │ │ │ │ + keyMask: this.keyMask │ │ │ │ │ + } │ │ │ │ │ ); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ * Method: destroy │ │ │ │ │ */ │ │ │ │ │ destroy: function() { │ │ │ │ │ - this.deactivate(); │ │ │ │ │ - this.eventListener = null; │ │ │ │ │ OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ │ + if (this.dragHandler) { │ │ │ │ │ + this.dragHandler.destroy(); │ │ │ │ │ + this.dragHandler = null; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: setMap │ │ │ │ │ + */ │ │ │ │ │ + setMap: function(map) { │ │ │ │ │ + OpenLayers.Handler.prototype.setMap.apply(this, arguments); │ │ │ │ │ + if (this.dragHandler) { │ │ │ │ │ + this.dragHandler.setMap(map); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: startBox │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * xy - {} │ │ │ │ │ + */ │ │ │ │ │ + startBox: function(xy) { │ │ │ │ │ + this.callback("start", []); │ │ │ │ │ + this.zoomBox = OpenLayers.Util.createDiv('zoomBox', { │ │ │ │ │ + x: -9999, │ │ │ │ │ + y: -9999 │ │ │ │ │ + }); │ │ │ │ │ + this.zoomBox.className = this.boxDivClassName; │ │ │ │ │ + this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1; │ │ │ │ │ + │ │ │ │ │ + this.map.viewPortDiv.appendChild(this.zoomBox); │ │ │ │ │ + │ │ │ │ │ + OpenLayers.Element.addClass( │ │ │ │ │ + this.map.viewPortDiv, "olDrawBox" │ │ │ │ │ + ); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: moveBox │ │ │ │ │ + */ │ │ │ │ │ + moveBox: function(xy) { │ │ │ │ │ + var startX = this.dragHandler.start.x; │ │ │ │ │ + var startY = this.dragHandler.start.y; │ │ │ │ │ + var deltaX = Math.abs(startX - xy.x); │ │ │ │ │ + var deltaY = Math.abs(startY - xy.y); │ │ │ │ │ + │ │ │ │ │ + var offset = this.getBoxOffsets(); │ │ │ │ │ + this.zoomBox.style.width = (deltaX + offset.width + 1) + "px"; │ │ │ │ │ + this.zoomBox.style.height = (deltaY + offset.height + 1) + "px"; │ │ │ │ │ + this.zoomBox.style.left = (xy.x < startX ? │ │ │ │ │ + startX - deltaX - offset.left : startX - offset.left) + "px"; │ │ │ │ │ + this.zoomBox.style.top = (xy.y < startY ? │ │ │ │ │ + startY - deltaY - offset.top : startY - offset.top) + "px"; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: endBox │ │ │ │ │ + */ │ │ │ │ │ + endBox: function(end) { │ │ │ │ │ + var result; │ │ │ │ │ + if (Math.abs(this.dragHandler.start.x - end.x) > 5 || │ │ │ │ │ + Math.abs(this.dragHandler.start.y - end.y) > 5) { │ │ │ │ │ + var start = this.dragHandler.start; │ │ │ │ │ + var top = Math.min(start.y, end.y); │ │ │ │ │ + var bottom = Math.max(start.y, end.y); │ │ │ │ │ + var left = Math.min(start.x, end.x); │ │ │ │ │ + var right = Math.max(start.x, end.x); │ │ │ │ │ + result = new OpenLayers.Bounds(left, bottom, right, top); │ │ │ │ │ + } else { │ │ │ │ │ + result = this.dragHandler.start.clone(); // i.e. OL.Pixel │ │ │ │ │ + } │ │ │ │ │ + this.removeBox(); │ │ │ │ │ + │ │ │ │ │ + this.callback("done", [result]); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: removeBox │ │ │ │ │ + * Remove the zoombox from the screen and nullify our reference to it. │ │ │ │ │ + */ │ │ │ │ │ + removeBox: function() { │ │ │ │ │ + this.map.viewPortDiv.removeChild(this.zoomBox); │ │ │ │ │ + this.zoomBox = null; │ │ │ │ │ + this.boxOffsets = null; │ │ │ │ │ + OpenLayers.Element.removeClass( │ │ │ │ │ + this.map.viewPortDiv, "olDrawBox" │ │ │ │ │ + ); │ │ │ │ │ + │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ * Method: activate │ │ │ │ │ */ │ │ │ │ │ activate: function() { │ │ │ │ │ if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ │ - this.observeElement = this.observeElement || document; │ │ │ │ │ - for (var i = 0, len = this.KEY_EVENTS.length; i < len; i++) { │ │ │ │ │ - OpenLayers.Event.observe( │ │ │ │ │ - this.observeElement, this.KEY_EVENTS[i], this.eventListener); │ │ │ │ │ - } │ │ │ │ │ + this.dragHandler.activate(); │ │ │ │ │ return true; │ │ │ │ │ } else { │ │ │ │ │ return false; │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ * Method: deactivate │ │ │ │ │ */ │ │ │ │ │ deactivate: function() { │ │ │ │ │ - var deactivated = false; │ │ │ │ │ if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ │ - for (var i = 0, len = this.KEY_EVENTS.length; i < len; i++) { │ │ │ │ │ - OpenLayers.Event.stopObserving( │ │ │ │ │ - this.observeElement, this.KEY_EVENTS[i], this.eventListener); │ │ │ │ │ + if (this.dragHandler.deactivate()) { │ │ │ │ │ + if (this.zoomBox) { │ │ │ │ │ + this.removeBox(); │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ - deactivated = true; │ │ │ │ │ + return true; │ │ │ │ │ + } else { │ │ │ │ │ + return false; │ │ │ │ │ } │ │ │ │ │ - return deactivated; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: handleKeyEvent │ │ │ │ │ + * Method: getBoxOffsets │ │ │ │ │ + * Determines border offsets for a box, according to the box model. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Object} an object with the following offsets: │ │ │ │ │ + * - left │ │ │ │ │ + * - right │ │ │ │ │ + * - top │ │ │ │ │ + * - bottom │ │ │ │ │ + * - width │ │ │ │ │ + * - height │ │ │ │ │ */ │ │ │ │ │ - handleKeyEvent: function(evt) { │ │ │ │ │ - if (this.checkModifiers(evt)) { │ │ │ │ │ - this.callback(evt.type, [evt]); │ │ │ │ │ + getBoxOffsets: function() { │ │ │ │ │ + if (!this.boxOffsets) { │ │ │ │ │ + // Determine the box model. If the testDiv's clientWidth is 3, then │ │ │ │ │ + // the borders are outside and we are dealing with the w3c box │ │ │ │ │ + // model. Otherwise, the browser uses the traditional box model and │ │ │ │ │ + // the borders are inside the box bounds, leaving us with a │ │ │ │ │ + // clientWidth of 1. │ │ │ │ │ + var testDiv = document.createElement("div"); │ │ │ │ │ + //testDiv.style.visibility = "hidden"; │ │ │ │ │ + testDiv.style.position = "absolute"; │ │ │ │ │ + testDiv.style.border = "1px solid black"; │ │ │ │ │ + testDiv.style.width = "3px"; │ │ │ │ │ + document.body.appendChild(testDiv); │ │ │ │ │ + var w3cBoxModel = testDiv.clientWidth == 3; │ │ │ │ │ + document.body.removeChild(testDiv); │ │ │ │ │ + │ │ │ │ │ + var left = parseInt(OpenLayers.Element.getStyle(this.zoomBox, │ │ │ │ │ + "border-left-width")); │ │ │ │ │ + var right = parseInt(OpenLayers.Element.getStyle( │ │ │ │ │ + this.zoomBox, "border-right-width")); │ │ │ │ │ + var top = parseInt(OpenLayers.Element.getStyle(this.zoomBox, │ │ │ │ │ + "border-top-width")); │ │ │ │ │ + var bottom = parseInt(OpenLayers.Element.getStyle( │ │ │ │ │ + this.zoomBox, "border-bottom-width")); │ │ │ │ │ + this.boxOffsets = { │ │ │ │ │ + left: left, │ │ │ │ │ + right: right, │ │ │ │ │ + top: top, │ │ │ │ │ + bottom: bottom, │ │ │ │ │ + width: w3cBoxModel === false ? left + right : 0, │ │ │ │ │ + height: w3cBoxModel === false ? top + bottom : 0 │ │ │ │ │ + }; │ │ │ │ │ } │ │ │ │ │ + return this.boxOffsets; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Keyboard" │ │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Box" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Control/ZoomBox.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ │ + * @requires OpenLayers/Handler/Box.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.ZoomBox │ │ │ │ │ + * The ZoomBox control enables zooming directly to a given extent, by drawing │ │ │ │ │ + * a box on the map. The box is drawn by holding down shift, whilst dragging │ │ │ │ │ + * the mouse. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ + /** │ │ │ │ │ + * Property: type │ │ │ │ │ + * {OpenLayers.Control.TYPE} │ │ │ │ │ + */ │ │ │ │ │ + type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: out │ │ │ │ │ + * {Boolean} Should the control be used for zooming out? │ │ │ │ │ + */ │ │ │ │ │ + out: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: keyMask │ │ │ │ │ + * {Integer} Zoom only occurs if the keyMask matches the combination of │ │ │ │ │ + * keys down. Use bitwise operators and one or more of the │ │ │ │ │ + * constants to construct a keyMask. Leave null if │ │ │ │ │ + * not used mask. Default is null. │ │ │ │ │ + */ │ │ │ │ │ + keyMask: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: alwaysZoom │ │ │ │ │ + * {Boolean} Always zoom in/out when box drawn, even if the zoom level does │ │ │ │ │ + * not change. │ │ │ │ │ + */ │ │ │ │ │ + alwaysZoom: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: zoomOnClick │ │ │ │ │ + * {Boolean} Should we zoom when no box was dragged, i.e. the user only │ │ │ │ │ + * clicked? Default is true. │ │ │ │ │ + */ │ │ │ │ │ + zoomOnClick: true, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: draw │ │ │ │ │ + */ │ │ │ │ │ + draw: function() { │ │ │ │ │ + this.handler = new OpenLayers.Handler.Box(this, { │ │ │ │ │ + done: this.zoomBox │ │ │ │ │ + }, { │ │ │ │ │ + keyMask: this.keyMask │ │ │ │ │ + }); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: zoomBox │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * position - {} or {} │ │ │ │ │ + */ │ │ │ │ │ + zoomBox: function(position) { │ │ │ │ │ + if (position instanceof OpenLayers.Bounds) { │ │ │ │ │ + var bounds, │ │ │ │ │ + targetCenterPx = position.getCenterPixel(); │ │ │ │ │ + if (!this.out) { │ │ │ │ │ + var minXY = this.map.getLonLatFromPixel({ │ │ │ │ │ + x: position.left, │ │ │ │ │ + y: position.bottom │ │ │ │ │ + }); │ │ │ │ │ + var maxXY = this.map.getLonLatFromPixel({ │ │ │ │ │ + x: position.right, │ │ │ │ │ + y: position.top │ │ │ │ │ + }); │ │ │ │ │ + bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat, │ │ │ │ │ + maxXY.lon, maxXY.lat); │ │ │ │ │ + } else { │ │ │ │ │ + var pixWidth = position.right - position.left; │ │ │ │ │ + var pixHeight = position.bottom - position.top; │ │ │ │ │ + var zoomFactor = Math.min((this.map.size.h / pixHeight), │ │ │ │ │ + (this.map.size.w / pixWidth)); │ │ │ │ │ + var extent = this.map.getExtent(); │ │ │ │ │ + var center = this.map.getLonLatFromPixel(targetCenterPx); │ │ │ │ │ + var xmin = center.lon - (extent.getWidth() / 2) * zoomFactor; │ │ │ │ │ + var xmax = center.lon + (extent.getWidth() / 2) * zoomFactor; │ │ │ │ │ + var ymin = center.lat - (extent.getHeight() / 2) * zoomFactor; │ │ │ │ │ + var ymax = center.lat + (extent.getHeight() / 2) * zoomFactor; │ │ │ │ │ + bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax); │ │ │ │ │ + } │ │ │ │ │ + // always zoom in/out │ │ │ │ │ + var lastZoom = this.map.getZoom(), │ │ │ │ │ + size = this.map.getSize(), │ │ │ │ │ + centerPx = { │ │ │ │ │ + x: size.w / 2, │ │ │ │ │ + y: size.h / 2 │ │ │ │ │ + }, │ │ │ │ │ + zoom = this.map.getZoomForExtent(bounds), │ │ │ │ │ + oldRes = this.map.getResolution(), │ │ │ │ │ + newRes = this.map.getResolutionForZoom(zoom); │ │ │ │ │ + if (oldRes == newRes) { │ │ │ │ │ + this.map.setCenter(this.map.getLonLatFromPixel(targetCenterPx)); │ │ │ │ │ + } else { │ │ │ │ │ + var zoomOriginPx = { │ │ │ │ │ + x: (oldRes * targetCenterPx.x - newRes * centerPx.x) / │ │ │ │ │ + (oldRes - newRes), │ │ │ │ │ + y: (oldRes * targetCenterPx.y - newRes * centerPx.y) / │ │ │ │ │ + (oldRes - newRes) │ │ │ │ │ + }; │ │ │ │ │ + this.map.zoomTo(zoom, zoomOriginPx); │ │ │ │ │ + } │ │ │ │ │ + if (lastZoom == this.map.getZoom() && this.alwaysZoom == true) { │ │ │ │ │ + this.map.zoomTo(lastZoom + (this.out ? -1 : 1)); │ │ │ │ │ + } │ │ │ │ │ + } else if (this.zoomOnClick) { // it's a pixel │ │ │ │ │ + if (!this.out) { │ │ │ │ │ + this.map.zoomTo(this.map.getZoom() + 1, position); │ │ │ │ │ + } else { │ │ │ │ │ + this.map.zoomTo(this.map.getZoom() - 1, position); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomBox" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Control/NavigationHistory.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ │ + * @requires OpenLayers/Control/Button.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.NavigationHistory │ │ │ │ │ + * A navigation history control. This is a meta-control, that creates two │ │ │ │ │ + * dependent controls: and . Call the trigger method │ │ │ │ │ + * on the and controls to restore previous and next │ │ │ │ │ + * history states. The previous and next controls will become active │ │ │ │ │ + * when there are available states to restore and will become deactive │ │ │ │ │ + * when there are no states to restore. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.NavigationHistory = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: type │ │ │ │ │ + * {String} Note that this control is not intended to be added directly │ │ │ │ │ + * to a control panel. Instead, add the sub-controls previous and │ │ │ │ │ + * next. These sub-controls are button type controls that activate │ │ │ │ │ + * and deactivate themselves. If this parent control is added to │ │ │ │ │ + * a panel, it will act as a toggle. │ │ │ │ │ + */ │ │ │ │ │ + type: OpenLayers.Control.TYPE_TOGGLE, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: previous │ │ │ │ │ + * {} A button type control whose trigger method restores │ │ │ │ │ + * the previous state managed by this control. │ │ │ │ │ + */ │ │ │ │ │ + previous: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: previousOptions │ │ │ │ │ + * {Object} Set this property on the options argument of the constructor │ │ │ │ │ + * to set optional properties on the control. │ │ │ │ │ + */ │ │ │ │ │ + previousOptions: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: next │ │ │ │ │ + * {} A button type control whose trigger method restores │ │ │ │ │ + * the next state managed by this control. │ │ │ │ │ + */ │ │ │ │ │ + next: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: nextOptions │ │ │ │ │ + * {Object} Set this property on the options argument of the constructor │ │ │ │ │ + * to set optional properties on the control. │ │ │ │ │ + */ │ │ │ │ │ + nextOptions: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: limit │ │ │ │ │ + * {Integer} Optional limit on the number of history items to retain. If │ │ │ │ │ + * null, there is no limit. Default is 50. │ │ │ │ │ + */ │ │ │ │ │ + limit: 50, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: autoActivate │ │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ │ + * true. │ │ │ │ │ + */ │ │ │ │ │ + autoActivate: true, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: clearOnDeactivate │ │ │ │ │ + * {Boolean} Clear the history when the control is deactivated. Default │ │ │ │ │ + * is false. │ │ │ │ │ + */ │ │ │ │ │ + clearOnDeactivate: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: registry │ │ │ │ │ + * {Object} An object with keys corresponding to event types. Values │ │ │ │ │ + * are functions that return an object representing the current state. │ │ │ │ │ + */ │ │ │ │ │ + registry: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: nextStack │ │ │ │ │ + * {Array} Array of items in the history. │ │ │ │ │ + */ │ │ │ │ │ + nextStack: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: previousStack │ │ │ │ │ + * {Array} List of items in the history. First item represents the current │ │ │ │ │ + * state. │ │ │ │ │ + */ │ │ │ │ │ + previousStack: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: listeners │ │ │ │ │ + * {Object} An object containing properties corresponding to event types. │ │ │ │ │ + * This object is used to configure the control and is modified on │ │ │ │ │ + * construction. │ │ │ │ │ + */ │ │ │ │ │ + listeners: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: restoring │ │ │ │ │ + * {Boolean} Currently restoring a history state. This is set to true │ │ │ │ │ + * before calling restore and set to false after restore returns. │ │ │ │ │ + */ │ │ │ │ │ + restoring: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Control.NavigationHistory │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} An optional object whose properties will be used │ │ │ │ │ + * to extend the control. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ │ + │ │ │ │ │ + this.registry = OpenLayers.Util.extend({ │ │ │ │ │ + "moveend": this.getState │ │ │ │ │ + }, this.registry); │ │ │ │ │ + │ │ │ │ │ + var previousOptions = { │ │ │ │ │ + trigger: OpenLayers.Function.bind(this.previousTrigger, this), │ │ │ │ │ + displayClass: this.displayClass + " " + this.displayClass + "Previous" │ │ │ │ │ + }; │ │ │ │ │ + OpenLayers.Util.extend(previousOptions, this.previousOptions); │ │ │ │ │ + this.previous = new OpenLayers.Control.Button(previousOptions); │ │ │ │ │ + │ │ │ │ │ + var nextOptions = { │ │ │ │ │ + trigger: OpenLayers.Function.bind(this.nextTrigger, this), │ │ │ │ │ + displayClass: this.displayClass + " " + this.displayClass + "Next" │ │ │ │ │ + }; │ │ │ │ │ + OpenLayers.Util.extend(nextOptions, this.nextOptions); │ │ │ │ │ + this.next = new OpenLayers.Control.Button(nextOptions); │ │ │ │ │ + │ │ │ │ │ + this.clear(); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: onPreviousChange │ │ │ │ │ + * Called when the previous history stack changes. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * state - {Object} An object representing the state to be restored │ │ │ │ │ + * if previous is triggered again or null if no previous states remain. │ │ │ │ │ + * length - {Integer} The number of remaining previous states that can │ │ │ │ │ + * be restored. │ │ │ │ │ + */ │ │ │ │ │ + onPreviousChange: function(state, length) { │ │ │ │ │ + if (state && !this.previous.active) { │ │ │ │ │ + this.previous.activate(); │ │ │ │ │ + } else if (!state && this.previous.active) { │ │ │ │ │ + this.previous.deactivate(); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: onNextChange │ │ │ │ │ + * Called when the next history stack changes. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * state - {Object} An object representing the state to be restored │ │ │ │ │ + * if next is triggered again or null if no next states remain. │ │ │ │ │ + * length - {Integer} The number of remaining next states that can │ │ │ │ │ + * be restored. │ │ │ │ │ + */ │ │ │ │ │ + onNextChange: function(state, length) { │ │ │ │ │ + if (state && !this.next.active) { │ │ │ │ │ + this.next.activate(); │ │ │ │ │ + } else if (!state && this.next.active) { │ │ │ │ │ + this.next.deactivate(); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ + * Destroy the control. │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this); │ │ │ │ │ + this.previous.destroy(); │ │ │ │ │ + this.next.destroy(); │ │ │ │ │ + this.deactivate(); │ │ │ │ │ + for (var prop in this) { │ │ │ │ │ + this[prop] = null; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: setMap │ │ │ │ │ + * Set the map property for the control and and child │ │ │ │ │ + * controls. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * map - {} │ │ │ │ │ + */ │ │ │ │ │ + setMap: function(map) { │ │ │ │ │ + this.map = map; │ │ │ │ │ + this.next.setMap(map); │ │ │ │ │ + this.previous.setMap(map); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: draw │ │ │ │ │ + * Called when the control is added to the map. │ │ │ │ │ + */ │ │ │ │ │ + draw: function() { │ │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ │ + this.next.draw(); │ │ │ │ │ + this.previous.draw(); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: previousTrigger │ │ │ │ │ + * Restore the previous state. If no items are in the previous history │ │ │ │ │ + * stack, this has no effect. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Object} Item representing state that was restored. Undefined if no │ │ │ │ │ + * items are in the previous history stack. │ │ │ │ │ + */ │ │ │ │ │ + previousTrigger: function() { │ │ │ │ │ + var current = this.previousStack.shift(); │ │ │ │ │ + var state = this.previousStack.shift(); │ │ │ │ │ + if (state != undefined) { │ │ │ │ │ + this.nextStack.unshift(current); │ │ │ │ │ + this.previousStack.unshift(state); │ │ │ │ │ + this.restoring = true; │ │ │ │ │ + this.restore(state); │ │ │ │ │ + this.restoring = false; │ │ │ │ │ + this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ │ + this.onPreviousChange( │ │ │ │ │ + this.previousStack[1], this.previousStack.length - 1 │ │ │ │ │ + ); │ │ │ │ │ + } else { │ │ │ │ │ + this.previousStack.unshift(current); │ │ │ │ │ + } │ │ │ │ │ + return state; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: nextTrigger │ │ │ │ │ + * Restore the next state. If no items are in the next history │ │ │ │ │ + * stack, this has no effect. The next history stack is populated │ │ │ │ │ + * as states are restored from the previous history stack. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Object} Item representing state that was restored. Undefined if no │ │ │ │ │ + * items are in the next history stack. │ │ │ │ │ + */ │ │ │ │ │ + nextTrigger: function() { │ │ │ │ │ + var state = this.nextStack.shift(); │ │ │ │ │ + if (state != undefined) { │ │ │ │ │ + this.previousStack.unshift(state); │ │ │ │ │ + this.restoring = true; │ │ │ │ │ + this.restore(state); │ │ │ │ │ + this.restoring = false; │ │ │ │ │ + this.onNextChange(this.nextStack[0], this.nextStack.length); │ │ │ │ │ + this.onPreviousChange( │ │ │ │ │ + this.previousStack[1], this.previousStack.length - 1 │ │ │ │ │ + ); │ │ │ │ │ + } │ │ │ │ │ + return state; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: clear │ │ │ │ │ + * Clear history. │ │ │ │ │ + */ │ │ │ │ │ + clear: function() { │ │ │ │ │ + this.previousStack = []; │ │ │ │ │ + this.previous.deactivate(); │ │ │ │ │ + this.nextStack = []; │ │ │ │ │ + this.next.deactivate(); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: getState │ │ │ │ │ + * Get the current state and return it. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Object} An object representing the current state. │ │ │ │ │ + */ │ │ │ │ │ + getState: function() { │ │ │ │ │ + return { │ │ │ │ │ + center: this.map.getCenter(), │ │ │ │ │ + resolution: this.map.getResolution(), │ │ │ │ │ + projection: this.map.getProjectionObject(), │ │ │ │ │ + units: this.map.getProjectionObject().getUnits() || │ │ │ │ │ + this.map.units || this.map.baseLayer.units │ │ │ │ │ + }; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: restore │ │ │ │ │ + * Update the state with the given object. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * state - {Object} An object representing the state to restore. │ │ │ │ │ + */ │ │ │ │ │ + restore: function(state) { │ │ │ │ │ + var center, zoom; │ │ │ │ │ + if (this.map.getProjectionObject() == state.projection) { │ │ │ │ │ + zoom = this.map.getZoomForResolution(state.resolution); │ │ │ │ │ + center = state.center; │ │ │ │ │ + } else { │ │ │ │ │ + center = state.center.clone(); │ │ │ │ │ + center.transform(state.projection, this.map.getProjectionObject()); │ │ │ │ │ + var sourceUnits = state.units; │ │ │ │ │ + var targetUnits = this.map.getProjectionObject().getUnits() || │ │ │ │ │ + this.map.units || this.map.baseLayer.units; │ │ │ │ │ + var resolutionFactor = sourceUnits && targetUnits ? │ │ │ │ │ + OpenLayers.INCHES_PER_UNIT[sourceUnits] / OpenLayers.INCHES_PER_UNIT[targetUnits] : 1; │ │ │ │ │ + zoom = this.map.getZoomForResolution(resolutionFactor * state.resolution); │ │ │ │ │ + } │ │ │ │ │ + this.map.setCenter(center, zoom); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: setListeners │ │ │ │ │ + * Sets functions to be registered in the listeners object. │ │ │ │ │ + */ │ │ │ │ │ + setListeners: function() { │ │ │ │ │ + this.listeners = {}; │ │ │ │ │ + for (var type in this.registry) { │ │ │ │ │ + this.listeners[type] = OpenLayers.Function.bind(function() { │ │ │ │ │ + if (!this.restoring) { │ │ │ │ │ + var state = this.registry[type].apply(this, arguments); │ │ │ │ │ + this.previousStack.unshift(state); │ │ │ │ │ + if (this.previousStack.length > 1) { │ │ │ │ │ + this.onPreviousChange( │ │ │ │ │ + this.previousStack[1], this.previousStack.length - 1 │ │ │ │ │ + ); │ │ │ │ │ + } │ │ │ │ │ + if (this.previousStack.length > (this.limit + 1)) { │ │ │ │ │ + this.previousStack.pop(); │ │ │ │ │ + } │ │ │ │ │ + if (this.nextStack.length > 0) { │ │ │ │ │ + this.nextStack = []; │ │ │ │ │ + this.onNextChange(null, 0); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return true; │ │ │ │ │ + }, this); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: activate │ │ │ │ │ + * Activate the control. This registers any listeners. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Control successfully activated. │ │ │ │ │ + */ │ │ │ │ │ + activate: function() { │ │ │ │ │ + var activated = false; │ │ │ │ │ + if (this.map) { │ │ │ │ │ + if (OpenLayers.Control.prototype.activate.apply(this)) { │ │ │ │ │ + if (this.listeners == null) { │ │ │ │ │ + this.setListeners(); │ │ │ │ │ + } │ │ │ │ │ + for (var type in this.listeners) { │ │ │ │ │ + this.map.events.register(type, this, this.listeners[type]); │ │ │ │ │ + } │ │ │ │ │ + activated = true; │ │ │ │ │ + if (this.previousStack.length == 0) { │ │ │ │ │ + this.initStack(); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return activated; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: initStack │ │ │ │ │ + * Called after the control is activated if the previous history stack is │ │ │ │ │ + * empty. │ │ │ │ │ + */ │ │ │ │ │ + initStack: function() { │ │ │ │ │ + if (this.map.getCenter()) { │ │ │ │ │ + this.listeners.moveend(); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: deactivate │ │ │ │ │ + * Deactivate the control. This unregisters any listeners. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Control successfully deactivated. │ │ │ │ │ + */ │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + var deactivated = false; │ │ │ │ │ + if (this.map) { │ │ │ │ │ + if (OpenLayers.Control.prototype.deactivate.apply(this)) { │ │ │ │ │ + for (var type in this.listeners) { │ │ │ │ │ + this.map.events.unregister( │ │ │ │ │ + type, this, this.listeners[type] │ │ │ │ │ + ); │ │ │ │ │ + } │ │ │ │ │ + if (this.clearOnDeactivate) { │ │ │ │ │ + this.clear(); │ │ │ │ │ + } │ │ │ │ │ + deactivated = true; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return deactivated; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.NavigationHistory" │ │ │ │ │ }); │ │ │ │ │ + │ │ │ │ │ /* ====================================================================== │ │ │ │ │ OpenLayers/Handler/Point.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ @@ -35498,2145 +39326,234 @@ │ │ │ │ │ } │ │ │ │ │ return false; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Handler.Path" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Handler/MouseWheel.js │ │ │ │ │ + OpenLayers/Layer/Vector.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Handler.js │ │ │ │ │ + * @requires OpenLayers/Layer.js │ │ │ │ │ + * @requires OpenLayers/Renderer.js │ │ │ │ │ + * @requires OpenLayers/StyleMap.js │ │ │ │ │ + * @requires OpenLayers/Feature/Vector.js │ │ │ │ │ + * @requires OpenLayers/Console.js │ │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Handler.MouseWheel │ │ │ │ │ - * Handler for wheel up/down events. │ │ │ │ │ - * │ │ │ │ │ + * Class: OpenLayers.Layer.Vector │ │ │ │ │ + * Instances of OpenLayers.Layer.Vector are used to render vector data from │ │ │ │ │ + * a variety of sources. Create a new vector layer with the │ │ │ │ │ + * constructor. │ │ │ │ │ + * │ │ │ │ │ * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ - /** │ │ │ │ │ - * Property: wheelListener │ │ │ │ │ - * {function} │ │ │ │ │ +OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: events │ │ │ │ │ + * {} │ │ │ │ │ + * │ │ │ │ │ + * Register a listener for a particular event with the following syntax: │ │ │ │ │ + * (code) │ │ │ │ │ + * layer.events.register(type, obj, listener); │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Listeners will be called with a reference to an event object. The │ │ │ │ │ + * properties of this event depends on exactly what happened. │ │ │ │ │ + * │ │ │ │ │ + * All event objects have at least the following properties: │ │ │ │ │ + * object - {Object} A reference to layer.events.object. │ │ │ │ │ + * element - {DOMElement} A reference to layer.events.element. │ │ │ │ │ + * │ │ │ │ │ + * Supported map event types (in addition to those from ): │ │ │ │ │ + * beforefeatureadded - Triggered before a feature is added. Listeners │ │ │ │ │ + * will receive an object with a *feature* property referencing the │ │ │ │ │ + * feature to be added. To stop the feature from being added, a │ │ │ │ │ + * listener should return false. │ │ │ │ │ + * beforefeaturesadded - Triggered before an array of features is added. │ │ │ │ │ + * Listeners will receive an object with a *features* property │ │ │ │ │ + * referencing the feature to be added. To stop the features from │ │ │ │ │ + * being added, a listener should return false. │ │ │ │ │ + * featureadded - Triggered after a feature is added. The event │ │ │ │ │ + * object passed to listeners will have a *feature* property with a │ │ │ │ │ + * reference to the added feature. │ │ │ │ │ + * featuresadded - Triggered after features are added. The event │ │ │ │ │ + * object passed to listeners will have a *features* property with a │ │ │ │ │ + * reference to an array of added features. │ │ │ │ │ + * beforefeatureremoved - Triggered before a feature is removed. Listeners │ │ │ │ │ + * will receive an object with a *feature* property referencing the │ │ │ │ │ + * feature to be removed. │ │ │ │ │ + * beforefeaturesremoved - Triggered before multiple features are removed. │ │ │ │ │ + * Listeners will receive an object with a *features* property │ │ │ │ │ + * referencing the features to be removed. │ │ │ │ │ + * featureremoved - Triggerd after a feature is removed. The event │ │ │ │ │ + * object passed to listeners will have a *feature* property with a │ │ │ │ │ + * reference to the removed feature. │ │ │ │ │ + * featuresremoved - Triggered after features are removed. The event │ │ │ │ │ + * object passed to listeners will have a *features* property with a │ │ │ │ │ + * reference to an array of removed features. │ │ │ │ │ + * beforefeatureselected - Triggered before a feature is selected. Listeners │ │ │ │ │ + * will receive an object with a *feature* property referencing the │ │ │ │ │ + * feature to be selected. To stop the feature from being selectd, a │ │ │ │ │ + * listener should return false. │ │ │ │ │ + * featureselected - Triggered after a feature is selected. Listeners │ │ │ │ │ + * will receive an object with a *feature* property referencing the │ │ │ │ │ + * selected feature. │ │ │ │ │ + * featureunselected - Triggered after a feature is unselected. │ │ │ │ │ + * Listeners will receive an object with a *feature* property │ │ │ │ │ + * referencing the unselected feature. │ │ │ │ │ + * beforefeaturemodified - Triggered when a feature is selected to │ │ │ │ │ + * be modified. Listeners will receive an object with a *feature* │ │ │ │ │ + * property referencing the selected feature. │ │ │ │ │ + * featuremodified - Triggered when a feature has been modified. │ │ │ │ │ + * Listeners will receive an object with a *feature* property referencing │ │ │ │ │ + * the modified feature. │ │ │ │ │ + * afterfeaturemodified - Triggered when a feature is finished being modified. │ │ │ │ │ + * Listeners will receive an object with a *feature* property referencing │ │ │ │ │ + * the modified feature. │ │ │ │ │ + * vertexmodified - Triggered when a vertex within any feature geometry │ │ │ │ │ + * has been modified. Listeners will receive an object with a │ │ │ │ │ + * *feature* property referencing the modified feature, a *vertex* │ │ │ │ │ + * property referencing the vertex modified (always a point geometry), │ │ │ │ │ + * and a *pixel* property referencing the pixel location of the │ │ │ │ │ + * modification. │ │ │ │ │ + * vertexremoved - Triggered when a vertex within any feature geometry │ │ │ │ │ + * has been deleted. Listeners will receive an object with a │ │ │ │ │ + * *feature* property referencing the modified feature, a *vertex* │ │ │ │ │ + * property referencing the vertex modified (always a point geometry), │ │ │ │ │ + * and a *pixel* property referencing the pixel location of the │ │ │ │ │ + * removal. │ │ │ │ │ + * sketchstarted - Triggered when a feature sketch bound for this layer │ │ │ │ │ + * is started. Listeners will receive an object with a *feature* │ │ │ │ │ + * property referencing the new sketch feature and a *vertex* property │ │ │ │ │ + * referencing the creation point. │ │ │ │ │ + * sketchmodified - Triggered when a feature sketch bound for this layer │ │ │ │ │ + * is modified. Listeners will receive an object with a *vertex* │ │ │ │ │ + * property referencing the modified vertex and a *feature* property │ │ │ │ │ + * referencing the sketch feature. │ │ │ │ │ + * sketchcomplete - Triggered when a feature sketch bound for this layer │ │ │ │ │ + * is complete. Listeners will receive an object with a *feature* │ │ │ │ │ + * property referencing the sketch feature. By returning false, a │ │ │ │ │ + * listener can stop the sketch feature from being added to the layer. │ │ │ │ │ + * refresh - Triggered when something wants a strategy to ask the protocol │ │ │ │ │ + * for a new set of features. │ │ │ │ │ */ │ │ │ │ │ - wheelListener: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: interval │ │ │ │ │ - * {Integer} In order to increase server performance, an interval (in │ │ │ │ │ - * milliseconds) can be set to reduce the number of up/down events │ │ │ │ │ - * called. If set, a new up/down event will not be set until the │ │ │ │ │ - * interval has passed. │ │ │ │ │ - * Defaults to 0, meaning no interval. │ │ │ │ │ + * APIProperty: isBaseLayer │ │ │ │ │ + * {Boolean} The layer is a base layer. Default is false. Set this property │ │ │ │ │ + * in the layer options. │ │ │ │ │ */ │ │ │ │ │ - interval: 0, │ │ │ │ │ + isBaseLayer: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: isFixed │ │ │ │ │ + * {Boolean} Whether the layer remains in one place while dragging the │ │ │ │ │ + * map. Note that setting this to true will move the layer to the bottom │ │ │ │ │ + * of the layer stack. │ │ │ │ │ + */ │ │ │ │ │ + isFixed: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: features │ │ │ │ │ + * {Array()} │ │ │ │ │ + */ │ │ │ │ │ + features: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: filter │ │ │ │ │ + * {} The filter set in this layer, │ │ │ │ │ + * a strategy launching read requests can combined │ │ │ │ │ + * this filter with its own filter. │ │ │ │ │ + */ │ │ │ │ │ + filter: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: selectedFeatures │ │ │ │ │ + * {Array()} │ │ │ │ │ + */ │ │ │ │ │ + selectedFeatures: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: maxDelta │ │ │ │ │ - * {Integer} Maximum delta to collect before breaking from the current │ │ │ │ │ - * interval. In cumulative mode, this also limits the maximum delta │ │ │ │ │ - * returned from the handler. Default is Number.POSITIVE_INFINITY. │ │ │ │ │ + * Property: unrenderedFeatures │ │ │ │ │ + * {Object} hash of features, keyed by feature.id, that the renderer │ │ │ │ │ + * failed to draw │ │ │ │ │ */ │ │ │ │ │ - maxDelta: Number.POSITIVE_INFINITY, │ │ │ │ │ + unrenderedFeatures: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: delta │ │ │ │ │ - * {Integer} When interval is set, delta collects the mousewheel z-deltas │ │ │ │ │ - * of the events that occur within the interval. │ │ │ │ │ - * See also the cumulative option │ │ │ │ │ + * APIProperty: reportError │ │ │ │ │ + * {Boolean} report friendly error message when loading of renderer │ │ │ │ │ + * fails. │ │ │ │ │ */ │ │ │ │ │ - delta: 0, │ │ │ │ │ + reportError: true, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: style │ │ │ │ │ + * {Object} Default style for the layer │ │ │ │ │ + */ │ │ │ │ │ + style: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: cumulative │ │ │ │ │ - * {Boolean} When interval is set: true to collect all the mousewheel │ │ │ │ │ - * z-deltas, false to only record the delta direction (positive or │ │ │ │ │ - * negative) │ │ │ │ │ + * Property: styleMap │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - cumulative: true, │ │ │ │ │ + styleMap: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Handler.MouseWheel │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * control - {} │ │ │ │ │ - * callbacks - {Object} An object containing a single function to be │ │ │ │ │ - * called when the drag operation is finished. │ │ │ │ │ - * The callback should expect to recieve a single │ │ │ │ │ - * argument, the point geometry. │ │ │ │ │ - * options - {Object} │ │ │ │ │ + * Property: strategies │ │ │ │ │ + * {Array(})} Optional list of strategies for the layer. │ │ │ │ │ */ │ │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ │ - this.wheelListener = OpenLayers.Function.bindAsEventListener( │ │ │ │ │ - this.onWheelEvent, this │ │ │ │ │ - ); │ │ │ │ │ - }, │ │ │ │ │ + strategies: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: destroy │ │ │ │ │ + * Property: protocol │ │ │ │ │ + * {} Optional protocol for the layer. │ │ │ │ │ */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ │ - this.wheelListener = null; │ │ │ │ │ - }, │ │ │ │ │ + protocol: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/ │ │ │ │ │ + * Property: renderers │ │ │ │ │ + * {Array(String)} List of supported Renderer classes. Add to this list to │ │ │ │ │ + * add support for additional renderers. This list is ordered: │ │ │ │ │ + * the first renderer which returns true for the 'supported()' │ │ │ │ │ + * method will be used, if not defined in the 'renderer' option. │ │ │ │ │ */ │ │ │ │ │ + renderers: ['SVG', 'VML', 'Canvas'], │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: onWheelEvent │ │ │ │ │ - * Catch the wheel event and handle it xbrowserly │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * e - {Event} │ │ │ │ │ + * Property: renderer │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - onWheelEvent: function(e) { │ │ │ │ │ - │ │ │ │ │ - // make sure we have a map and check keyboard modifiers │ │ │ │ │ - if (!this.map || !this.checkModifiers(e)) { │ │ │ │ │ - return; │ │ │ │ │ - } │ │ │ │ │ + renderer: null, │ │ │ │ │ │ │ │ │ │ - // Ride up the element's DOM hierarchy to determine if it or any of │ │ │ │ │ - // its ancestors was: │ │ │ │ │ - // * specifically marked as scrollable (CSS overflow property) │ │ │ │ │ - // * one of our layer divs or a div marked as scrollable │ │ │ │ │ - // ('olScrollable' CSS class) │ │ │ │ │ - // * the map div │ │ │ │ │ - // │ │ │ │ │ - var overScrollableDiv = false; │ │ │ │ │ - var allowScroll = false; │ │ │ │ │ - var overMapDiv = false; │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: rendererOptions │ │ │ │ │ + * {Object} Options for the renderer. See {} for │ │ │ │ │ + * supported options. │ │ │ │ │ + */ │ │ │ │ │ + rendererOptions: null, │ │ │ │ │ │ │ │ │ │ - var elem = OpenLayers.Event.element(e); │ │ │ │ │ - while ((elem != null) && !overMapDiv && !overScrollableDiv) { │ │ │ │ │ - │ │ │ │ │ - if (!overScrollableDiv) { │ │ │ │ │ - try { │ │ │ │ │ - var overflow; │ │ │ │ │ - if (elem.currentStyle) { │ │ │ │ │ - overflow = elem.currentStyle["overflow"]; │ │ │ │ │ - } else { │ │ │ │ │ - var style = │ │ │ │ │ - document.defaultView.getComputedStyle(elem, null); │ │ │ │ │ - overflow = style.getPropertyValue("overflow"); │ │ │ │ │ - } │ │ │ │ │ - overScrollableDiv = (overflow && │ │ │ │ │ - (overflow == "auto") || (overflow == "scroll")); │ │ │ │ │ - } catch (err) { │ │ │ │ │ - //sometimes when scrolling in a popup, this causes │ │ │ │ │ - // obscure browser error │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (!allowScroll) { │ │ │ │ │ - allowScroll = OpenLayers.Element.hasClass(elem, 'olScrollable'); │ │ │ │ │ - if (!allowScroll) { │ │ │ │ │ - for (var i = 0, len = this.map.layers.length; i < len; i++) { │ │ │ │ │ - // Are we in the layer div? Note that we have two cases │ │ │ │ │ - // here: one is to catch EventPane layers, which have a │ │ │ │ │ - // pane above the layer (layer.pane) │ │ │ │ │ - var layer = this.map.layers[i]; │ │ │ │ │ - if (elem == layer.div || elem == layer.pane) { │ │ │ │ │ - allowScroll = true; │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - overMapDiv = (elem == this.map.div); │ │ │ │ │ - │ │ │ │ │ - elem = elem.parentNode; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // Logic below is the following: │ │ │ │ │ - // │ │ │ │ │ - // If we are over a scrollable div or not over the map div: │ │ │ │ │ - // * do nothing (let the browser handle scrolling) │ │ │ │ │ - // │ │ │ │ │ - // otherwise │ │ │ │ │ - // │ │ │ │ │ - // If we are over the layer div or a 'olScrollable' div: │ │ │ │ │ - // * zoom/in out │ │ │ │ │ - // then │ │ │ │ │ - // * kill event (so as not to also scroll the page after zooming) │ │ │ │ │ - // │ │ │ │ │ - // otherwise │ │ │ │ │ - // │ │ │ │ │ - // Kill the event (dont scroll the page if we wheel over the │ │ │ │ │ - // layerswitcher or the pan/zoom control) │ │ │ │ │ - // │ │ │ │ │ - if (!overScrollableDiv && overMapDiv) { │ │ │ │ │ - if (allowScroll) { │ │ │ │ │ - var delta = 0; │ │ │ │ │ - │ │ │ │ │ - if (e.wheelDelta) { │ │ │ │ │ - delta = e.wheelDelta; │ │ │ │ │ - if (delta % 160 === 0) { │ │ │ │ │ - // opera have steps of 160 instead of 120 │ │ │ │ │ - delta = delta * 0.75; │ │ │ │ │ - } │ │ │ │ │ - delta = delta / 120; │ │ │ │ │ - } else if (e.detail) { │ │ │ │ │ - // detail in Firefox on OS X is 1/3 of Windows │ │ │ │ │ - // so force delta 1 / -1 │ │ │ │ │ - delta = -(e.detail / Math.abs(e.detail)); │ │ │ │ │ - } │ │ │ │ │ - this.delta += delta; │ │ │ │ │ - │ │ │ │ │ - window.clearTimeout(this._timeoutId); │ │ │ │ │ - if (this.interval && Math.abs(this.delta) < this.maxDelta) { │ │ │ │ │ - // store e because window.event might change during delay │ │ │ │ │ - var evt = OpenLayers.Util.extend({}, e); │ │ │ │ │ - this._timeoutId = window.setTimeout( │ │ │ │ │ - OpenLayers.Function.bind(function() { │ │ │ │ │ - this.wheelZoom(evt); │ │ │ │ │ - }, this), │ │ │ │ │ - this.interval │ │ │ │ │ - ); │ │ │ │ │ - } else { │ │ │ │ │ - this.wheelZoom(e); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - OpenLayers.Event.stop(e); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: wheelZoom │ │ │ │ │ - * Given the wheel event, we carry out the appropriate zooming in or out, │ │ │ │ │ - * based on the 'wheelDelta' or 'detail' property of the event. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * e - {Event} │ │ │ │ │ - */ │ │ │ │ │ - wheelZoom: function(e) { │ │ │ │ │ - var delta = this.delta; │ │ │ │ │ - this.delta = 0; │ │ │ │ │ - │ │ │ │ │ - if (delta) { │ │ │ │ │ - e.xy = this.map.events.getMousePosition(e); │ │ │ │ │ - if (delta < 0) { │ │ │ │ │ - this.callback("down", │ │ │ │ │ - [e, this.cumulative ? Math.max(-this.maxDelta, delta) : -1]); │ │ │ │ │ - } else { │ │ │ │ │ - this.callback("up", │ │ │ │ │ - [e, this.cumulative ? Math.min(this.maxDelta, delta) : 1]); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: activate │ │ │ │ │ - */ │ │ │ │ │ - activate: function(evt) { │ │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ │ - //register mousewheel events specifically on the window and document │ │ │ │ │ - var wheelListener = this.wheelListener; │ │ │ │ │ - OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener); │ │ │ │ │ - OpenLayers.Event.observe(window, "mousewheel", wheelListener); │ │ │ │ │ - OpenLayers.Event.observe(document, "mousewheel", wheelListener); │ │ │ │ │ - return true; │ │ │ │ │ - } else { │ │ │ │ │ - return false; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: deactivate │ │ │ │ │ - */ │ │ │ │ │ - deactivate: function(evt) { │ │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ │ - // unregister mousewheel events specifically on the window and document │ │ │ │ │ - var wheelListener = this.wheelListener; │ │ │ │ │ - OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener); │ │ │ │ │ - OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener); │ │ │ │ │ - OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener); │ │ │ │ │ - return true; │ │ │ │ │ - } else { │ │ │ │ │ - return false; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.MouseWheel" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Handler/Feature.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Handler.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Handler.Feature │ │ │ │ │ - * Handler to respond to mouse events related to a drawn feature. Callbacks │ │ │ │ │ - * with the following keys will be notified of the following events │ │ │ │ │ - * associated with features: click, clickout, over, out, and dblclick. │ │ │ │ │ - * │ │ │ │ │ - * This handler stops event propagation for mousedown and mouseup if those │ │ │ │ │ - * browser events target features that can be selected. │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: EVENTMAP │ │ │ │ │ - * {Object} A object mapping the browser events to objects with callback │ │ │ │ │ - * keys for in and out. │ │ │ │ │ - */ │ │ │ │ │ - EVENTMAP: { │ │ │ │ │ - 'click': { │ │ │ │ │ - 'in': 'click', │ │ │ │ │ - 'out': 'clickout' │ │ │ │ │ - }, │ │ │ │ │ - 'mousemove': { │ │ │ │ │ - 'in': 'over', │ │ │ │ │ - 'out': 'out' │ │ │ │ │ - }, │ │ │ │ │ - 'dblclick': { │ │ │ │ │ - 'in': 'dblclick', │ │ │ │ │ - 'out': null │ │ │ │ │ - }, │ │ │ │ │ - 'mousedown': { │ │ │ │ │ - 'in': null, │ │ │ │ │ - 'out': null │ │ │ │ │ - }, │ │ │ │ │ - 'mouseup': { │ │ │ │ │ - 'in': null, │ │ │ │ │ - 'out': null │ │ │ │ │ - }, │ │ │ │ │ - 'touchstart': { │ │ │ │ │ - 'in': 'click', │ │ │ │ │ - 'out': 'clickout' │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: feature │ │ │ │ │ - * {} The last feature that was hovered. │ │ │ │ │ - */ │ │ │ │ │ - feature: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: lastFeature │ │ │ │ │ - * {} The last feature that was handled. │ │ │ │ │ - */ │ │ │ │ │ - lastFeature: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: down │ │ │ │ │ - * {} The location of the last mousedown. │ │ │ │ │ - */ │ │ │ │ │ - down: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: up │ │ │ │ │ - * {} The location of the last mouseup. │ │ │ │ │ - */ │ │ │ │ │ - up: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: clickTolerance │ │ │ │ │ - * {Number} The number of pixels the mouse can move between mousedown │ │ │ │ │ - * and mouseup for the event to still be considered a click. │ │ │ │ │ - * Dragging the map should not trigger the click and clickout callbacks │ │ │ │ │ - * unless the map is moved by less than this tolerance. Defaults to 4. │ │ │ │ │ - */ │ │ │ │ │ - clickTolerance: 4, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: geometryTypes │ │ │ │ │ - * To restrict dragging to a limited set of geometry types, send a list │ │ │ │ │ - * of strings corresponding to the geometry class names. │ │ │ │ │ - * │ │ │ │ │ - * @type Array(String) │ │ │ │ │ - */ │ │ │ │ │ - geometryTypes: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: stopClick │ │ │ │ │ - * {Boolean} If stopClick is set to true, handled clicks do not │ │ │ │ │ - * propagate to other click listeners. Otherwise, handled clicks │ │ │ │ │ - * do propagate. Unhandled clicks always propagate, whatever the │ │ │ │ │ - * value of stopClick. Defaults to true. │ │ │ │ │ - */ │ │ │ │ │ - stopClick: true, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: stopDown │ │ │ │ │ - * {Boolean} If stopDown is set to true, handled mousedowns do not │ │ │ │ │ - * propagate to other mousedown listeners. Otherwise, handled │ │ │ │ │ - * mousedowns do propagate. Unhandled mousedowns always propagate, │ │ │ │ │ - * whatever the value of stopDown. Defaults to true. │ │ │ │ │ - */ │ │ │ │ │ - stopDown: true, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: stopUp │ │ │ │ │ - * {Boolean} If stopUp is set to true, handled mouseups do not │ │ │ │ │ - * propagate to other mouseup listeners. Otherwise, handled mouseups │ │ │ │ │ - * do propagate. Unhandled mouseups always propagate, whatever the │ │ │ │ │ - * value of stopUp. Defaults to false. │ │ │ │ │ - */ │ │ │ │ │ - stopUp: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Handler.Feature │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * control - {} │ │ │ │ │ - * layer - {} │ │ │ │ │ - * callbacks - {Object} An object with a 'over' property whos value is │ │ │ │ │ - * a function to be called when the mouse is over a feature. The │ │ │ │ │ - * callback should expect to recieve a single argument, the feature. │ │ │ │ │ - * options - {Object} │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(control, layer, callbacks, options) { │ │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]); │ │ │ │ │ - this.layer = layer; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: touchstart │ │ │ │ │ - * Handle touchstart events │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} Let the event propagate. │ │ │ │ │ - */ │ │ │ │ │ - touchstart: function(evt) { │ │ │ │ │ - this.startTouch(); │ │ │ │ │ - return OpenLayers.Event.isMultiTouch(evt) ? │ │ │ │ │ - true : this.mousedown(evt); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: touchmove │ │ │ │ │ - * Handle touchmove events. We just prevent the browser default behavior, │ │ │ │ │ - * for Android Webkit not to select text when moving the finger after │ │ │ │ │ - * selecting a feature. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - */ │ │ │ │ │ - touchmove: function(evt) { │ │ │ │ │ - OpenLayers.Event.preventDefault(evt); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: mousedown │ │ │ │ │ - * Handle mouse down. Stop propagation if a feature is targeted by this │ │ │ │ │ - * event (stops map dragging during feature selection). │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - */ │ │ │ │ │ - mousedown: function(evt) { │ │ │ │ │ - // Feature selection is only done with a left click. Other handlers may stop the │ │ │ │ │ - // propagation of left-click mousedown events but not right-click mousedown events. │ │ │ │ │ - // This mismatch causes problems when comparing the location of the down and up │ │ │ │ │ - // events in the click function so it is important ignore right-clicks. │ │ │ │ │ - if (OpenLayers.Event.isLeftClick(evt) || OpenLayers.Event.isSingleTouch(evt)) { │ │ │ │ │ - this.down = evt.xy; │ │ │ │ │ - } │ │ │ │ │ - return this.handle(evt) ? !this.stopDown : true; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: mouseup │ │ │ │ │ - * Handle mouse up. Stop propagation if a feature is targeted by this │ │ │ │ │ - * event. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - */ │ │ │ │ │ - mouseup: function(evt) { │ │ │ │ │ - this.up = evt.xy; │ │ │ │ │ - return this.handle(evt) ? !this.stopUp : true; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: click │ │ │ │ │ - * Handle click. Call the "click" callback if click on a feature, │ │ │ │ │ - * or the "clickout" callback if click outside any feature. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} │ │ │ │ │ - */ │ │ │ │ │ - click: function(evt) { │ │ │ │ │ - return this.handle(evt) ? !this.stopClick : true; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: mousemove │ │ │ │ │ - * Handle mouse moves. Call the "over" callback if moving in to a feature, │ │ │ │ │ - * or the "out" callback if moving out of a feature. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} │ │ │ │ │ - */ │ │ │ │ │ - mousemove: function(evt) { │ │ │ │ │ - if (!this.callbacks['over'] && !this.callbacks['out']) { │ │ │ │ │ - return true; │ │ │ │ │ - } │ │ │ │ │ - this.handle(evt); │ │ │ │ │ - return true; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: dblclick │ │ │ │ │ - * Handle dblclick. Call the "dblclick" callback if dblclick on a feature. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} │ │ │ │ │ - */ │ │ │ │ │ - dblclick: function(evt) { │ │ │ │ │ - return !this.handle(evt); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: geometryTypeMatches │ │ │ │ │ - * Return true if the geometry type of the passed feature matches │ │ │ │ │ - * one of the geometry types in the geometryTypes array. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * feature - {} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} │ │ │ │ │ - */ │ │ │ │ │ - geometryTypeMatches: function(feature) { │ │ │ │ │ - return this.geometryTypes == null || │ │ │ │ │ - OpenLayers.Util.indexOf(this.geometryTypes, │ │ │ │ │ - feature.geometry.CLASS_NAME) > -1; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: handle │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The event occurred over a relevant feature. │ │ │ │ │ - */ │ │ │ │ │ - handle: function(evt) { │ │ │ │ │ - if (this.feature && !this.feature.layer) { │ │ │ │ │ - // feature has been destroyed │ │ │ │ │ - this.feature = null; │ │ │ │ │ - } │ │ │ │ │ - var type = evt.type; │ │ │ │ │ - var handled = false; │ │ │ │ │ - var previouslyIn = !!(this.feature); // previously in a feature │ │ │ │ │ - var click = (type == "click" || type == "dblclick" || type == "touchstart"); │ │ │ │ │ - this.feature = this.layer.getFeatureFromEvent(evt); │ │ │ │ │ - if (this.feature && !this.feature.layer) { │ │ │ │ │ - // feature has been destroyed │ │ │ │ │ - this.feature = null; │ │ │ │ │ - } │ │ │ │ │ - if (this.lastFeature && !this.lastFeature.layer) { │ │ │ │ │ - // last feature has been destroyed │ │ │ │ │ - this.lastFeature = null; │ │ │ │ │ - } │ │ │ │ │ - if (this.feature) { │ │ │ │ │ - if (type === "touchstart") { │ │ │ │ │ - // stop the event to prevent Android Webkit from │ │ │ │ │ - // "flashing" the map div │ │ │ │ │ - OpenLayers.Event.preventDefault(evt); │ │ │ │ │ - } │ │ │ │ │ - var inNew = (this.feature != this.lastFeature); │ │ │ │ │ - if (this.geometryTypeMatches(this.feature)) { │ │ │ │ │ - // in to a feature │ │ │ │ │ - if (previouslyIn && inNew) { │ │ │ │ │ - // out of last feature and in to another │ │ │ │ │ - if (this.lastFeature) { │ │ │ │ │ - this.triggerCallback(type, 'out', [this.lastFeature]); │ │ │ │ │ - } │ │ │ │ │ - this.triggerCallback(type, 'in', [this.feature]); │ │ │ │ │ - } else if (!previouslyIn || click) { │ │ │ │ │ - // in feature for the first time │ │ │ │ │ - this.triggerCallback(type, 'in', [this.feature]); │ │ │ │ │ - } │ │ │ │ │ - this.lastFeature = this.feature; │ │ │ │ │ - handled = true; │ │ │ │ │ - } else { │ │ │ │ │ - // not in to a feature │ │ │ │ │ - if (this.lastFeature && (previouslyIn && inNew || click)) { │ │ │ │ │ - // out of last feature for the first time │ │ │ │ │ - this.triggerCallback(type, 'out', [this.lastFeature]); │ │ │ │ │ - } │ │ │ │ │ - // next time the mouse goes in a feature whose geometry type │ │ │ │ │ - // doesn't match we don't want to call the 'out' callback │ │ │ │ │ - // again, so let's set this.feature to null so that │ │ │ │ │ - // previouslyIn will evaluate to false the next time │ │ │ │ │ - // we enter handle. Yes, a bit hackish... │ │ │ │ │ - this.feature = null; │ │ │ │ │ - } │ │ │ │ │ - } else if (this.lastFeature && (previouslyIn || click)) { │ │ │ │ │ - this.triggerCallback(type, 'out', [this.lastFeature]); │ │ │ │ │ - } │ │ │ │ │ - return handled; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: triggerCallback │ │ │ │ │ - * Call the callback keyed in the event map with the supplied arguments. │ │ │ │ │ - * For click and clickout, the is checked first. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * type - {String} │ │ │ │ │ - */ │ │ │ │ │ - triggerCallback: function(type, mode, args) { │ │ │ │ │ - var key = this.EVENTMAP[type][mode]; │ │ │ │ │ - if (key) { │ │ │ │ │ - if (type == 'click' && this.up && this.down) { │ │ │ │ │ - // for click/clickout, only trigger callback if tolerance is met │ │ │ │ │ - var dpx = Math.sqrt( │ │ │ │ │ - Math.pow(this.up.x - this.down.x, 2) + │ │ │ │ │ - Math.pow(this.up.y - this.down.y, 2) │ │ │ │ │ - ); │ │ │ │ │ - if (dpx <= this.clickTolerance) { │ │ │ │ │ - this.callback(key, args); │ │ │ │ │ - } │ │ │ │ │ - // we're done with this set of events now: clear the cached │ │ │ │ │ - // positions so we can't trip over them later (this can occur │ │ │ │ │ - // if one of the up/down events gets eaten before it gets to us │ │ │ │ │ - // but we still get the click) │ │ │ │ │ - this.up = this.down = null; │ │ │ │ │ - } else { │ │ │ │ │ - this.callback(key, args); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: activate │ │ │ │ │ - * Turn on the handler. Returns false if the handler was already active. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} │ │ │ │ │ - */ │ │ │ │ │ - activate: function() { │ │ │ │ │ - var activated = false; │ │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ │ - this.moveLayerToTop(); │ │ │ │ │ - this.map.events.on({ │ │ │ │ │ - "removelayer": this.handleMapEvents, │ │ │ │ │ - "changelayer": this.handleMapEvents, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ - activated = true; │ │ │ │ │ - } │ │ │ │ │ - return activated; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: deactivate │ │ │ │ │ - * Turn off the handler. Returns false if the handler was already active. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} │ │ │ │ │ - */ │ │ │ │ │ - deactivate: function() { │ │ │ │ │ - var deactivated = false; │ │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ │ - this.moveLayerBack(); │ │ │ │ │ - this.feature = null; │ │ │ │ │ - this.lastFeature = null; │ │ │ │ │ - this.down = null; │ │ │ │ │ - this.up = null; │ │ │ │ │ - this.map.events.un({ │ │ │ │ │ - "removelayer": this.handleMapEvents, │ │ │ │ │ - "changelayer": this.handleMapEvents, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ - deactivated = true; │ │ │ │ │ - } │ │ │ │ │ - return deactivated; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: handleMapEvents │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Object} │ │ │ │ │ - */ │ │ │ │ │ - handleMapEvents: function(evt) { │ │ │ │ │ - if (evt.type == "removelayer" || evt.property == "order") { │ │ │ │ │ - this.moveLayerToTop(); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: moveLayerToTop │ │ │ │ │ - * Moves the layer for this handler to the top, so mouse events can reach │ │ │ │ │ - * it. │ │ │ │ │ - */ │ │ │ │ │ - moveLayerToTop: function() { │ │ │ │ │ - var index = Math.max(this.map.Z_INDEX_BASE['Feature'] - 1, │ │ │ │ │ - this.layer.getZIndex()) + 1; │ │ │ │ │ - this.layer.setZIndex(index); │ │ │ │ │ - │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: moveLayerBack │ │ │ │ │ - * Moves the layer back to the position determined by the map's layers │ │ │ │ │ - * array. │ │ │ │ │ - */ │ │ │ │ │ - moveLayerBack: function() { │ │ │ │ │ - var index = this.layer.getZIndex() - 1; │ │ │ │ │ - if (index >= this.map.Z_INDEX_BASE['Feature']) { │ │ │ │ │ - this.layer.setZIndex(index); │ │ │ │ │ - } else { │ │ │ │ │ - this.map.setLayerZIndex(this.layer, │ │ │ │ │ - this.map.getLayerIndex(this.layer)); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Feature" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Handler/Polygon.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Handler/Path.js │ │ │ │ │ - * @requires OpenLayers/Geometry/Polygon.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Handler.Polygon │ │ │ │ │ - * Handler to draw a polygon on the map. Polygon is displayed on mouse down, │ │ │ │ │ - * moves on mouse move, and is finished on mouse up. │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ - * - │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Handler.Polygon = OpenLayers.Class(OpenLayers.Handler.Path, { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: holeModifier │ │ │ │ │ - * {String} Key modifier to trigger hole digitizing. Acceptable values are │ │ │ │ │ - * "altKey", "shiftKey", or "ctrlKey". If not set, no hole digitizing │ │ │ │ │ - * will take place. Default is null. │ │ │ │ │ - */ │ │ │ │ │ - holeModifier: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: drawingHole │ │ │ │ │ - * {Boolean} Currently drawing an interior ring. │ │ │ │ │ - */ │ │ │ │ │ - drawingHole: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: polygon │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - polygon: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Handler.Polygon │ │ │ │ │ - * Create a Polygon Handler. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * control - {} The control that owns this handler │ │ │ │ │ - * callbacks - {Object} An object with a properties whose values are │ │ │ │ │ - * functions. Various callbacks described below. │ │ │ │ │ - * options - {Object} An optional object with properties to be set on the │ │ │ │ │ - * handler │ │ │ │ │ - * │ │ │ │ │ - * Named callbacks: │ │ │ │ │ - * create - Called when a sketch is first created. Callback called with │ │ │ │ │ - * the creation point geometry and sketch feature. │ │ │ │ │ - * modify - Called with each move of a vertex with the vertex (point) │ │ │ │ │ - * geometry and the sketch feature. │ │ │ │ │ - * point - Called as each point is added. Receives the new point geometry. │ │ │ │ │ - * done - Called when the point drawing is finished. The callback will │ │ │ │ │ - * recieve a single argument, the polygon geometry. │ │ │ │ │ - * cancel - Called when the handler is deactivated while drawing. The │ │ │ │ │ - * cancel callback will receive a geometry. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: createFeature │ │ │ │ │ - * Add temporary geometries │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * pixel - {} The initial pixel location for the new │ │ │ │ │ - * feature. │ │ │ │ │ - */ │ │ │ │ │ - createFeature: function(pixel) { │ │ │ │ │ - var lonlat = this.layer.getLonLatFromViewPortPx(pixel); │ │ │ │ │ - var geometry = new OpenLayers.Geometry.Point( │ │ │ │ │ - lonlat.lon, lonlat.lat │ │ │ │ │ - ); │ │ │ │ │ - this.point = new OpenLayers.Feature.Vector(geometry); │ │ │ │ │ - this.line = new OpenLayers.Feature.Vector( │ │ │ │ │ - new OpenLayers.Geometry.LinearRing([this.point.geometry]) │ │ │ │ │ - ); │ │ │ │ │ - this.polygon = new OpenLayers.Feature.Vector( │ │ │ │ │ - new OpenLayers.Geometry.Polygon([this.line.geometry]) │ │ │ │ │ - ); │ │ │ │ │ - this.callback("create", [this.point.geometry, this.getSketch()]); │ │ │ │ │ - this.point.geometry.clearBounds(); │ │ │ │ │ - this.layer.addFeatures([this.polygon, this.point], { │ │ │ │ │ - silent: true │ │ │ │ │ - }); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: addPoint │ │ │ │ │ - * Add point to geometry. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * pixel - {} The pixel location for the new point. │ │ │ │ │ - */ │ │ │ │ │ - addPoint: function(pixel) { │ │ │ │ │ - if (!this.drawingHole && this.holeModifier && │ │ │ │ │ - this.evt && this.evt[this.holeModifier]) { │ │ │ │ │ - var geometry = this.point.geometry; │ │ │ │ │ - var features = this.control.layer.features; │ │ │ │ │ - var candidate, polygon; │ │ │ │ │ - // look for intersections, last drawn gets priority │ │ │ │ │ - for (var i = features.length - 1; i >= 0; --i) { │ │ │ │ │ - candidate = features[i].geometry; │ │ │ │ │ - if ((candidate instanceof OpenLayers.Geometry.Polygon || │ │ │ │ │ - candidate instanceof OpenLayers.Geometry.MultiPolygon) && │ │ │ │ │ - candidate.intersects(geometry)) { │ │ │ │ │ - polygon = features[i]; │ │ │ │ │ - this.control.layer.removeFeatures([polygon], { │ │ │ │ │ - silent: true │ │ │ │ │ - }); │ │ │ │ │ - this.control.layer.events.registerPriority( │ │ │ │ │ - "sketchcomplete", this, this.finalizeInteriorRing │ │ │ │ │ - ); │ │ │ │ │ - this.control.layer.events.registerPriority( │ │ │ │ │ - "sketchmodified", this, this.enforceTopology │ │ │ │ │ - ); │ │ │ │ │ - polygon.geometry.addComponent(this.line.geometry); │ │ │ │ │ - this.polygon = polygon; │ │ │ │ │ - this.drawingHole = true; │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - OpenLayers.Handler.Path.prototype.addPoint.apply(this, arguments); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: getCurrentPointIndex │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Number} The index of the most recently drawn point. │ │ │ │ │ - */ │ │ │ │ │ - getCurrentPointIndex: function() { │ │ │ │ │ - return this.line.geometry.components.length - 2; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: enforceTopology │ │ │ │ │ - * Simple topology enforcement for drawing interior rings. Ensures vertices │ │ │ │ │ - * of interior rings are contained by exterior ring. Other topology │ │ │ │ │ - * rules are enforced in to allow drawing of │ │ │ │ │ - * rings that intersect only during the sketch (e.g. a "C" shaped ring │ │ │ │ │ - * that nearly encloses another ring). │ │ │ │ │ - */ │ │ │ │ │ - enforceTopology: function(event) { │ │ │ │ │ - var point = event.vertex; │ │ │ │ │ - var components = this.line.geometry.components; │ │ │ │ │ - // ensure that vertices of interior ring are contained by exterior ring │ │ │ │ │ - if (!this.polygon.geometry.intersects(point)) { │ │ │ │ │ - var last = components[components.length - 3]; │ │ │ │ │ - point.x = last.x; │ │ │ │ │ - point.y = last.y; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: finishGeometry │ │ │ │ │ - * Finish the geometry and send it back to the control. │ │ │ │ │ - */ │ │ │ │ │ - finishGeometry: function() { │ │ │ │ │ - var index = this.line.geometry.components.length - 2; │ │ │ │ │ - this.line.geometry.removeComponent(this.line.geometry.components[index]); │ │ │ │ │ - this.removePoint(); │ │ │ │ │ - this.finalize(); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: finalizeInteriorRing │ │ │ │ │ - * Enforces that new ring has some area and doesn't contain vertices of any │ │ │ │ │ - * other rings. │ │ │ │ │ - */ │ │ │ │ │ - finalizeInteriorRing: function() { │ │ │ │ │ - var ring = this.line.geometry; │ │ │ │ │ - // ensure that ring has some area │ │ │ │ │ - var modified = (ring.getArea() !== 0); │ │ │ │ │ - if (modified) { │ │ │ │ │ - // ensure that new ring doesn't intersect any other rings │ │ │ │ │ - var rings = this.polygon.geometry.components; │ │ │ │ │ - for (var i = rings.length - 2; i >= 0; --i) { │ │ │ │ │ - if (ring.intersects(rings[i])) { │ │ │ │ │ - modified = false; │ │ │ │ │ - break; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - if (modified) { │ │ │ │ │ - // ensure that new ring doesn't contain any other rings │ │ │ │ │ - var target; │ │ │ │ │ - outer: for (var i = rings.length - 2; i > 0; --i) { │ │ │ │ │ - var points = rings[i].components; │ │ │ │ │ - for (var j = 0, jj = points.length; j < jj; ++j) { │ │ │ │ │ - if (ring.containsPoint(points[j])) { │ │ │ │ │ - modified = false; │ │ │ │ │ - break outer; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - if (modified) { │ │ │ │ │ - if (this.polygon.state !== OpenLayers.State.INSERT) { │ │ │ │ │ - this.polygon.state = OpenLayers.State.UPDATE; │ │ │ │ │ - } │ │ │ │ │ - } else { │ │ │ │ │ - this.polygon.geometry.removeComponent(ring); │ │ │ │ │ - } │ │ │ │ │ - this.restoreFeature(); │ │ │ │ │ - return false; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: cancel │ │ │ │ │ - * Finish the geometry and call the "cancel" callback. │ │ │ │ │ - */ │ │ │ │ │ - cancel: function() { │ │ │ │ │ - if (this.drawingHole) { │ │ │ │ │ - this.polygon.geometry.removeComponent(this.line.geometry); │ │ │ │ │ - this.restoreFeature(true); │ │ │ │ │ - } │ │ │ │ │ - return OpenLayers.Handler.Path.prototype.cancel.apply(this, arguments); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: restoreFeature │ │ │ │ │ - * Move the feature from the sketch layer to the target layer. │ │ │ │ │ - * │ │ │ │ │ - * Properties: │ │ │ │ │ - * cancel - {Boolean} Cancel drawing. If falsey, the "sketchcomplete" event │ │ │ │ │ - * will be fired. │ │ │ │ │ - */ │ │ │ │ │ - restoreFeature: function(cancel) { │ │ │ │ │ - this.control.layer.events.unregister( │ │ │ │ │ - "sketchcomplete", this, this.finalizeInteriorRing │ │ │ │ │ - ); │ │ │ │ │ - this.control.layer.events.unregister( │ │ │ │ │ - "sketchmodified", this, this.enforceTopology │ │ │ │ │ - ); │ │ │ │ │ - this.layer.removeFeatures([this.polygon], { │ │ │ │ │ - silent: true │ │ │ │ │ - }); │ │ │ │ │ - this.control.layer.addFeatures([this.polygon], { │ │ │ │ │ - silent: true │ │ │ │ │ - }); │ │ │ │ │ - this.drawingHole = false; │ │ │ │ │ - if (!cancel) { │ │ │ │ │ - // Re-trigger "sketchcomplete" so other listeners can do their │ │ │ │ │ - // business. While this is somewhat sloppy (if a listener is │ │ │ │ │ - // registered with registerPriority - not common - between the start │ │ │ │ │ - // and end of a single ring drawing - very uncommon - it will be │ │ │ │ │ - // called twice). │ │ │ │ │ - // TODO: In 3.0, collapse sketch handlers into geometry specific │ │ │ │ │ - // drawing controls. │ │ │ │ │ - this.control.layer.events.triggerEvent( │ │ │ │ │ - "sketchcomplete", { │ │ │ │ │ - feature: this.polygon │ │ │ │ │ - } │ │ │ │ │ - ); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: destroyFeature │ │ │ │ │ - * Destroy temporary geometries │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * force - {Boolean} Destroy even if persist is true. │ │ │ │ │ - */ │ │ │ │ │ - destroyFeature: function(force) { │ │ │ │ │ - OpenLayers.Handler.Path.prototype.destroyFeature.call( │ │ │ │ │ - this, force); │ │ │ │ │ - this.polygon = null; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: drawFeature │ │ │ │ │ - * Render geometries on the temporary layer. │ │ │ │ │ - */ │ │ │ │ │ - drawFeature: function() { │ │ │ │ │ - this.layer.drawFeature(this.polygon, this.style); │ │ │ │ │ - this.layer.drawFeature(this.point, this.style); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: getSketch │ │ │ │ │ - * Return the sketch feature. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - getSketch: function() { │ │ │ │ │ - return this.polygon; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: getGeometry │ │ │ │ │ - * Return the sketch geometry. If is true, this will return │ │ │ │ │ - * a multi-part geometry. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - getGeometry: function() { │ │ │ │ │ - var geometry = this.polygon && this.polygon.geometry; │ │ │ │ │ - if (geometry && this.multi) { │ │ │ │ │ - geometry = new OpenLayers.Geometry.MultiPolygon([geometry]); │ │ │ │ │ - } │ │ │ │ │ - return geometry; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Polygon" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Handler/RegularPolygon.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Handler/Drag.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Handler.RegularPolygon │ │ │ │ │ - * Handler to draw a regular polygon on the map. Polygon is displayed on mouse │ │ │ │ │ - * down, moves or is modified on mouse move, and is finished on mouse up. │ │ │ │ │ - * The handler triggers callbacks for 'done' and 'cancel'. Create a new │ │ │ │ │ - * instance with the constructor. │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Handler.RegularPolygon = OpenLayers.Class(OpenLayers.Handler.Drag, { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: sides │ │ │ │ │ - * {Integer} Number of sides for the regular polygon. Needs to be greater │ │ │ │ │ - * than 2. Defaults to 4. │ │ │ │ │ - */ │ │ │ │ │ - sides: 4, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: radius │ │ │ │ │ - * {Float} Optional radius in map units of the regular polygon. If this is │ │ │ │ │ - * set to some non-zero value, a polygon with a fixed radius will be │ │ │ │ │ - * drawn and dragged with mose movements. If this property is not │ │ │ │ │ - * set, dragging changes the radius of the polygon. Set to null by │ │ │ │ │ - * default. │ │ │ │ │ - */ │ │ │ │ │ - radius: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: snapAngle │ │ │ │ │ - * {Float} If set to a non-zero value, the handler will snap the polygon │ │ │ │ │ - * rotation to multiples of the snapAngle. Value is an angle measured │ │ │ │ │ - * in degrees counterclockwise from the positive x-axis. │ │ │ │ │ - */ │ │ │ │ │ - snapAngle: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: snapToggle │ │ │ │ │ - * {String} If set, snapToggle is checked on mouse events and will set │ │ │ │ │ - * the snap mode to the opposite of what it currently is. To disallow │ │ │ │ │ - * toggling between snap and non-snap mode, set freehandToggle to │ │ │ │ │ - * null. Acceptable toggle values are 'shiftKey', 'ctrlKey', and │ │ │ │ │ - * 'altKey'. Snap mode is only possible if this.snapAngle is set to a │ │ │ │ │ - * non-zero value. │ │ │ │ │ - */ │ │ │ │ │ - snapToggle: 'shiftKey', │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: layerOptions │ │ │ │ │ - * {Object} Any optional properties to be set on the sketch layer. │ │ │ │ │ - */ │ │ │ │ │ - layerOptions: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: persist │ │ │ │ │ - * {Boolean} Leave the feature rendered until clear is called. Default │ │ │ │ │ - * is false. If set to true, the feature remains rendered until │ │ │ │ │ - * clear is called, typically by deactivating the handler or starting │ │ │ │ │ - * another drawing. │ │ │ │ │ - */ │ │ │ │ │ - persist: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: irregular │ │ │ │ │ - * {Boolean} Draw an irregular polygon instead of a regular polygon. │ │ │ │ │ - * Default is false. If true, the initial mouse down will represent │ │ │ │ │ - * one corner of the polygon bounds and with each mouse movement, the │ │ │ │ │ - * polygon will be stretched so the opposite corner of its bounds │ │ │ │ │ - * follows the mouse position. This property takes precedence over │ │ │ │ │ - * the radius property. If set to true, the radius property will │ │ │ │ │ - * be ignored. │ │ │ │ │ - */ │ │ │ │ │ - irregular: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: citeCompliant │ │ │ │ │ - * {Boolean} If set to true, coordinates of features drawn in a map extent │ │ │ │ │ - * crossing the date line won't exceed the world bounds. Default is false. │ │ │ │ │ - */ │ │ │ │ │ - citeCompliant: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: angle │ │ │ │ │ - * {Float} The angle from the origin (mouse down) to the current mouse │ │ │ │ │ - * position, in radians. This is measured counterclockwise from the │ │ │ │ │ - * positive x-axis. │ │ │ │ │ - */ │ │ │ │ │ - angle: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: fixedRadius │ │ │ │ │ - * {Boolean} The polygon has a fixed radius. True if a radius is set before │ │ │ │ │ - * drawing begins. False otherwise. │ │ │ │ │ - */ │ │ │ │ │ - fixedRadius: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: feature │ │ │ │ │ - * {} The currently drawn polygon feature │ │ │ │ │ - */ │ │ │ │ │ - feature: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: layer │ │ │ │ │ - * {} The temporary drawing layer │ │ │ │ │ - */ │ │ │ │ │ - layer: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: origin │ │ │ │ │ - * {} Location of the first mouse down │ │ │ │ │ - */ │ │ │ │ │ - origin: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Handler.RegularPolygon │ │ │ │ │ - * Create a new regular polygon handler. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * control - {} The control that owns this handler │ │ │ │ │ - * callbacks - {Object} An object with a properties whose values are │ │ │ │ │ - * functions. Various callbacks described below. │ │ │ │ │ - * options - {Object} An object with properties to be set on the handler. │ │ │ │ │ - * If the options.sides property is not specified, the number of sides │ │ │ │ │ - * will default to 4. │ │ │ │ │ - * │ │ │ │ │ - * Named callbacks: │ │ │ │ │ - * create - Called when a sketch is first created. Callback called with │ │ │ │ │ - * the creation point geometry and sketch feature. │ │ │ │ │ - * done - Called when the sketch drawing is finished. The callback will │ │ │ │ │ - * recieve a single argument, the sketch geometry. │ │ │ │ │ - * cancel - Called when the handler is deactivated while drawing. The │ │ │ │ │ - * cancel callback will receive a geometry. │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ │ - if (!(options && options.layerOptions && options.layerOptions.styleMap)) { │ │ │ │ │ - this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {}); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - OpenLayers.Handler.Drag.prototype.initialize.apply(this, │ │ │ │ │ - [control, callbacks, options]); │ │ │ │ │ - this.options = (options) ? options : {}; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: setOptions │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * newOptions - {Object} │ │ │ │ │ - */ │ │ │ │ │ - setOptions: function(newOptions) { │ │ │ │ │ - OpenLayers.Util.extend(this.options, newOptions); │ │ │ │ │ - OpenLayers.Util.extend(this, newOptions); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: activate │ │ │ │ │ - * Turn on the handler. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The handler was successfully activated │ │ │ │ │ - */ │ │ │ │ │ - activate: function() { │ │ │ │ │ - var activated = false; │ │ │ │ │ - if (OpenLayers.Handler.Drag.prototype.activate.apply(this, arguments)) { │ │ │ │ │ - // create temporary vector layer for rendering geometry sketch │ │ │ │ │ - var options = OpenLayers.Util.extend({ │ │ │ │ │ - displayInLayerSwitcher: false, │ │ │ │ │ - // indicate that the temp vector layer will never be out of range │ │ │ │ │ - // without this, resolution properties must be specified at the │ │ │ │ │ - // map-level for this temporary layer to init its resolutions │ │ │ │ │ - // correctly │ │ │ │ │ - calculateInRange: OpenLayers.Function.True, │ │ │ │ │ - wrapDateLine: this.citeCompliant │ │ │ │ │ - }, this.layerOptions); │ │ │ │ │ - this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options); │ │ │ │ │ - this.map.addLayer(this.layer); │ │ │ │ │ - activated = true; │ │ │ │ │ - } │ │ │ │ │ - return activated; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: deactivate │ │ │ │ │ - * Turn off the handler. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The handler was successfully deactivated │ │ │ │ │ - */ │ │ │ │ │ - deactivate: function() { │ │ │ │ │ - var deactivated = false; │ │ │ │ │ - if (OpenLayers.Handler.Drag.prototype.deactivate.apply(this, arguments)) { │ │ │ │ │ - // call the cancel callback if mid-drawing │ │ │ │ │ - if (this.dragging) { │ │ │ │ │ - this.cancel(); │ │ │ │ │ - } │ │ │ │ │ - // If a layer's map property is set to null, it means that that │ │ │ │ │ - // layer isn't added to the map. Since we ourself added the layer │ │ │ │ │ - // to the map in activate(), we can assume that if this.layer.map │ │ │ │ │ - // is null it means that the layer has been destroyed (as a result │ │ │ │ │ - // of map.destroy() for example. │ │ │ │ │ - if (this.layer.map != null) { │ │ │ │ │ - this.layer.destroy(false); │ │ │ │ │ - if (this.feature) { │ │ │ │ │ - this.feature.destroy(); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - this.layer = null; │ │ │ │ │ - this.feature = null; │ │ │ │ │ - deactivated = true; │ │ │ │ │ - } │ │ │ │ │ - return deactivated; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: down │ │ │ │ │ - * Start drawing a new feature │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} The drag start event │ │ │ │ │ - */ │ │ │ │ │ - down: function(evt) { │ │ │ │ │ - this.fixedRadius = !!(this.radius); │ │ │ │ │ - var maploc = this.layer.getLonLatFromViewPortPx(evt.xy); │ │ │ │ │ - this.origin = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat); │ │ │ │ │ - // create the new polygon │ │ │ │ │ - if (!this.fixedRadius || this.irregular) { │ │ │ │ │ - // smallest radius should not be less one pixel in map units │ │ │ │ │ - // VML doesn't behave well with smaller │ │ │ │ │ - this.radius = this.map.getResolution(); │ │ │ │ │ - } │ │ │ │ │ - if (this.persist) { │ │ │ │ │ - this.clear(); │ │ │ │ │ - } │ │ │ │ │ - this.feature = new OpenLayers.Feature.Vector(); │ │ │ │ │ - this.createGeometry(); │ │ │ │ │ - this.callback("create", [this.origin, this.feature]); │ │ │ │ │ - this.layer.addFeatures([this.feature], { │ │ │ │ │ - silent: true │ │ │ │ │ - }); │ │ │ │ │ - this.layer.drawFeature(this.feature, this.style); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: move │ │ │ │ │ - * Respond to drag move events │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Evt} The move event │ │ │ │ │ - */ │ │ │ │ │ - move: function(evt) { │ │ │ │ │ - var maploc = this.layer.getLonLatFromViewPortPx(evt.xy); │ │ │ │ │ - var point = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat); │ │ │ │ │ - if (this.irregular) { │ │ │ │ │ - var ry = Math.sqrt(2) * Math.abs(point.y - this.origin.y) / 2; │ │ │ │ │ - this.radius = Math.max(this.map.getResolution() / 2, ry); │ │ │ │ │ - } else if (this.fixedRadius) { │ │ │ │ │ - this.origin = point; │ │ │ │ │ - } else { │ │ │ │ │ - this.calculateAngle(point, evt); │ │ │ │ │ - this.radius = Math.max(this.map.getResolution() / 2, │ │ │ │ │ - point.distanceTo(this.origin)); │ │ │ │ │ - } │ │ │ │ │ - this.modifyGeometry(); │ │ │ │ │ - if (this.irregular) { │ │ │ │ │ - var dx = point.x - this.origin.x; │ │ │ │ │ - var dy = point.y - this.origin.y; │ │ │ │ │ - var ratio; │ │ │ │ │ - if (dy == 0) { │ │ │ │ │ - ratio = dx / (this.radius * Math.sqrt(2)); │ │ │ │ │ - } else { │ │ │ │ │ - ratio = dx / dy; │ │ │ │ │ - } │ │ │ │ │ - this.feature.geometry.resize(1, this.origin, ratio); │ │ │ │ │ - this.feature.geometry.move(dx / 2, dy / 2); │ │ │ │ │ - } │ │ │ │ │ - this.layer.drawFeature(this.feature, this.style); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: up │ │ │ │ │ - * Finish drawing the feature │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} The mouse up event │ │ │ │ │ - */ │ │ │ │ │ - up: function(evt) { │ │ │ │ │ - this.finalize(); │ │ │ │ │ - // the mouseup method of superclass doesn't call the │ │ │ │ │ - // "done" callback if there's been no move between │ │ │ │ │ - // down and up │ │ │ │ │ - if (this.start == this.last) { │ │ │ │ │ - this.callback("done", [evt.xy]); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: out │ │ │ │ │ - * Finish drawing the feature. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} The mouse out event │ │ │ │ │ - */ │ │ │ │ │ - out: function(evt) { │ │ │ │ │ - this.finalize(); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: createGeometry │ │ │ │ │ - * Create the new polygon geometry. This is called at the start of the │ │ │ │ │ - * drag and at any point during the drag if the number of sides │ │ │ │ │ - * changes. │ │ │ │ │ - */ │ │ │ │ │ - createGeometry: function() { │ │ │ │ │ - this.angle = Math.PI * ((1 / this.sides) - (1 / 2)); │ │ │ │ │ - if (this.snapAngle) { │ │ │ │ │ - this.angle += this.snapAngle * (Math.PI / 180); │ │ │ │ │ - } │ │ │ │ │ - this.feature.geometry = OpenLayers.Geometry.Polygon.createRegularPolygon( │ │ │ │ │ - this.origin, this.radius, this.sides, this.snapAngle │ │ │ │ │ - ); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: modifyGeometry │ │ │ │ │ - * Modify the polygon geometry in place. │ │ │ │ │ - */ │ │ │ │ │ - modifyGeometry: function() { │ │ │ │ │ - var angle, point; │ │ │ │ │ - var ring = this.feature.geometry.components[0]; │ │ │ │ │ - // if the number of sides ever changes, create a new geometry │ │ │ │ │ - if (ring.components.length != (this.sides + 1)) { │ │ │ │ │ - this.createGeometry(); │ │ │ │ │ - ring = this.feature.geometry.components[0]; │ │ │ │ │ - } │ │ │ │ │ - for (var i = 0; i < this.sides; ++i) { │ │ │ │ │ - point = ring.components[i]; │ │ │ │ │ - angle = this.angle + (i * 2 * Math.PI / this.sides); │ │ │ │ │ - point.x = this.origin.x + (this.radius * Math.cos(angle)); │ │ │ │ │ - point.y = this.origin.y + (this.radius * Math.sin(angle)); │ │ │ │ │ - point.clearBounds(); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: calculateAngle │ │ │ │ │ - * Calculate the angle based on settings. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * point - {} │ │ │ │ │ - * evt - {Event} │ │ │ │ │ - */ │ │ │ │ │ - calculateAngle: function(point, evt) { │ │ │ │ │ - var alpha = Math.atan2(point.y - this.origin.y, │ │ │ │ │ - point.x - this.origin.x); │ │ │ │ │ - if (this.snapAngle && (this.snapToggle && !evt[this.snapToggle])) { │ │ │ │ │ - var snapAngleRad = (Math.PI / 180) * this.snapAngle; │ │ │ │ │ - this.angle = Math.round(alpha / snapAngleRad) * snapAngleRad; │ │ │ │ │ - } else { │ │ │ │ │ - this.angle = alpha; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: cancel │ │ │ │ │ - * Finish the geometry and call the "cancel" callback. │ │ │ │ │ - */ │ │ │ │ │ - cancel: function() { │ │ │ │ │ - // the polygon geometry gets cloned in the callback method │ │ │ │ │ - this.callback("cancel", null); │ │ │ │ │ - this.finalize(); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: finalize │ │ │ │ │ - * Finish the geometry and call the "done" callback. │ │ │ │ │ - */ │ │ │ │ │ - finalize: function() { │ │ │ │ │ - this.origin = null; │ │ │ │ │ - this.radius = this.options.radius; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: clear │ │ │ │ │ - * Clear any rendered features on the temporary layer. This is called │ │ │ │ │ - * when the handler is deactivated, canceled, or done (unless persist │ │ │ │ │ - * is true). │ │ │ │ │ - */ │ │ │ │ │ - clear: function() { │ │ │ │ │ - if (this.layer) { │ │ │ │ │ - this.layer.renderer.clear(); │ │ │ │ │ - this.layer.destroyFeatures(); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: callback │ │ │ │ │ - * Trigger the control's named callback with the given arguments │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * name - {String} The key for the callback that is one of the properties │ │ │ │ │ - * of the handler's callbacks object. │ │ │ │ │ - * args - {Array} An array of arguments with which to call the callback │ │ │ │ │ - * (defined by the control). │ │ │ │ │ - */ │ │ │ │ │ - callback: function(name, args) { │ │ │ │ │ - // override the callback method to always send the polygon geometry │ │ │ │ │ - if (this.callbacks[name]) { │ │ │ │ │ - this.callbacks[name].apply(this.control, │ │ │ │ │ - [this.feature.geometry.clone()]); │ │ │ │ │ - } │ │ │ │ │ - // since sketch features are added to the temporary layer │ │ │ │ │ - // they must be cleared here if done or cancel │ │ │ │ │ - if (!this.persist && (name == "done" || name == "cancel")) { │ │ │ │ │ - this.clear(); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.RegularPolygon" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Handler/Box.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Handler.js │ │ │ │ │ - * @requires OpenLayers/Handler/Drag.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Handler.Box │ │ │ │ │ - * Handler for dragging a rectangle across the map. Box is displayed │ │ │ │ │ - * on mouse down, moves on mouse move, and is finished on mouse up. │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: dragHandler │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - dragHandler: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: boxDivClassName │ │ │ │ │ - * {String} The CSS class to use for drawing the box. Default is │ │ │ │ │ - * olHandlerBoxZoomBox │ │ │ │ │ - */ │ │ │ │ │ - boxDivClassName: 'olHandlerBoxZoomBox', │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: boxOffsets │ │ │ │ │ - * {Object} Caches box offsets from css. This is used by the getBoxOffsets │ │ │ │ │ - * method. │ │ │ │ │ - */ │ │ │ │ │ - boxOffsets: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Handler.Box │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * control - {} │ │ │ │ │ - * callbacks - {Object} An object with a properties whose values are │ │ │ │ │ - * functions. Various callbacks described below. │ │ │ │ │ - * options - {Object} │ │ │ │ │ - * │ │ │ │ │ - * Named callbacks: │ │ │ │ │ - * start - Called when the box drag operation starts. │ │ │ │ │ - * done - Called when the box drag operation is finished. │ │ │ │ │ - * The callback should expect to receive a single argument, the box │ │ │ │ │ - * bounds or a pixel. If the box dragging didn't span more than a 5 │ │ │ │ │ - * pixel distance, a pixel will be returned instead of a bounds object. │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(control, callbacks, options) { │ │ │ │ │ - OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ │ - this.dragHandler = new OpenLayers.Handler.Drag( │ │ │ │ │ - this, { │ │ │ │ │ - down: this.startBox, │ │ │ │ │ - move: this.moveBox, │ │ │ │ │ - out: this.removeBox, │ │ │ │ │ - up: this.endBox │ │ │ │ │ - }, { │ │ │ │ │ - keyMask: this.keyMask │ │ │ │ │ - } │ │ │ │ │ - ); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: destroy │ │ │ │ │ - */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ │ - if (this.dragHandler) { │ │ │ │ │ - this.dragHandler.destroy(); │ │ │ │ │ - this.dragHandler = null; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: setMap │ │ │ │ │ - */ │ │ │ │ │ - setMap: function(map) { │ │ │ │ │ - OpenLayers.Handler.prototype.setMap.apply(this, arguments); │ │ │ │ │ - if (this.dragHandler) { │ │ │ │ │ - this.dragHandler.setMap(map); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: startBox │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * xy - {} │ │ │ │ │ - */ │ │ │ │ │ - startBox: function(xy) { │ │ │ │ │ - this.callback("start", []); │ │ │ │ │ - this.zoomBox = OpenLayers.Util.createDiv('zoomBox', { │ │ │ │ │ - x: -9999, │ │ │ │ │ - y: -9999 │ │ │ │ │ - }); │ │ │ │ │ - this.zoomBox.className = this.boxDivClassName; │ │ │ │ │ - this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1; │ │ │ │ │ - │ │ │ │ │ - this.map.viewPortDiv.appendChild(this.zoomBox); │ │ │ │ │ - │ │ │ │ │ - OpenLayers.Element.addClass( │ │ │ │ │ - this.map.viewPortDiv, "olDrawBox" │ │ │ │ │ - ); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: moveBox │ │ │ │ │ - */ │ │ │ │ │ - moveBox: function(xy) { │ │ │ │ │ - var startX = this.dragHandler.start.x; │ │ │ │ │ - var startY = this.dragHandler.start.y; │ │ │ │ │ - var deltaX = Math.abs(startX - xy.x); │ │ │ │ │ - var deltaY = Math.abs(startY - xy.y); │ │ │ │ │ - │ │ │ │ │ - var offset = this.getBoxOffsets(); │ │ │ │ │ - this.zoomBox.style.width = (deltaX + offset.width + 1) + "px"; │ │ │ │ │ - this.zoomBox.style.height = (deltaY + offset.height + 1) + "px"; │ │ │ │ │ - this.zoomBox.style.left = (xy.x < startX ? │ │ │ │ │ - startX - deltaX - offset.left : startX - offset.left) + "px"; │ │ │ │ │ - this.zoomBox.style.top = (xy.y < startY ? │ │ │ │ │ - startY - deltaY - offset.top : startY - offset.top) + "px"; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: endBox │ │ │ │ │ - */ │ │ │ │ │ - endBox: function(end) { │ │ │ │ │ - var result; │ │ │ │ │ - if (Math.abs(this.dragHandler.start.x - end.x) > 5 || │ │ │ │ │ - Math.abs(this.dragHandler.start.y - end.y) > 5) { │ │ │ │ │ - var start = this.dragHandler.start; │ │ │ │ │ - var top = Math.min(start.y, end.y); │ │ │ │ │ - var bottom = Math.max(start.y, end.y); │ │ │ │ │ - var left = Math.min(start.x, end.x); │ │ │ │ │ - var right = Math.max(start.x, end.x); │ │ │ │ │ - result = new OpenLayers.Bounds(left, bottom, right, top); │ │ │ │ │ - } else { │ │ │ │ │ - result = this.dragHandler.start.clone(); // i.e. OL.Pixel │ │ │ │ │ - } │ │ │ │ │ - this.removeBox(); │ │ │ │ │ - │ │ │ │ │ - this.callback("done", [result]); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: removeBox │ │ │ │ │ - * Remove the zoombox from the screen and nullify our reference to it. │ │ │ │ │ - */ │ │ │ │ │ - removeBox: function() { │ │ │ │ │ - this.map.viewPortDiv.removeChild(this.zoomBox); │ │ │ │ │ - this.zoomBox = null; │ │ │ │ │ - this.boxOffsets = null; │ │ │ │ │ - OpenLayers.Element.removeClass( │ │ │ │ │ - this.map.viewPortDiv, "olDrawBox" │ │ │ │ │ - ); │ │ │ │ │ - │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: activate │ │ │ │ │ - */ │ │ │ │ │ - activate: function() { │ │ │ │ │ - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ │ - this.dragHandler.activate(); │ │ │ │ │ - return true; │ │ │ │ │ - } else { │ │ │ │ │ - return false; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: deactivate │ │ │ │ │ - */ │ │ │ │ │ - deactivate: function() { │ │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ │ - if (this.dragHandler.deactivate()) { │ │ │ │ │ - if (this.zoomBox) { │ │ │ │ │ - this.removeBox(); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - return true; │ │ │ │ │ - } else { │ │ │ │ │ - return false; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: getBoxOffsets │ │ │ │ │ - * Determines border offsets for a box, according to the box model. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} an object with the following offsets: │ │ │ │ │ - * - left │ │ │ │ │ - * - right │ │ │ │ │ - * - top │ │ │ │ │ - * - bottom │ │ │ │ │ - * - width │ │ │ │ │ - * - height │ │ │ │ │ - */ │ │ │ │ │ - getBoxOffsets: function() { │ │ │ │ │ - if (!this.boxOffsets) { │ │ │ │ │ - // Determine the box model. If the testDiv's clientWidth is 3, then │ │ │ │ │ - // the borders are outside and we are dealing with the w3c box │ │ │ │ │ - // model. Otherwise, the browser uses the traditional box model and │ │ │ │ │ - // the borders are inside the box bounds, leaving us with a │ │ │ │ │ - // clientWidth of 1. │ │ │ │ │ - var testDiv = document.createElement("div"); │ │ │ │ │ - //testDiv.style.visibility = "hidden"; │ │ │ │ │ - testDiv.style.position = "absolute"; │ │ │ │ │ - testDiv.style.border = "1px solid black"; │ │ │ │ │ - testDiv.style.width = "3px"; │ │ │ │ │ - document.body.appendChild(testDiv); │ │ │ │ │ - var w3cBoxModel = testDiv.clientWidth == 3; │ │ │ │ │ - document.body.removeChild(testDiv); │ │ │ │ │ - │ │ │ │ │ - var left = parseInt(OpenLayers.Element.getStyle(this.zoomBox, │ │ │ │ │ - "border-left-width")); │ │ │ │ │ - var right = parseInt(OpenLayers.Element.getStyle( │ │ │ │ │ - this.zoomBox, "border-right-width")); │ │ │ │ │ - var top = parseInt(OpenLayers.Element.getStyle(this.zoomBox, │ │ │ │ │ - "border-top-width")); │ │ │ │ │ - var bottom = parseInt(OpenLayers.Element.getStyle( │ │ │ │ │ - this.zoomBox, "border-bottom-width")); │ │ │ │ │ - this.boxOffsets = { │ │ │ │ │ - left: left, │ │ │ │ │ - right: right, │ │ │ │ │ - top: top, │ │ │ │ │ - bottom: bottom, │ │ │ │ │ - width: w3cBoxModel === false ? left + right : 0, │ │ │ │ │ - height: w3cBoxModel === false ? top + bottom : 0 │ │ │ │ │ - }; │ │ │ │ │ - } │ │ │ │ │ - return this.boxOffsets; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Box" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Handler/Hover.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Handler.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Handler.Hover │ │ │ │ │ - * The hover handler is to be used to emulate mouseovers on objects │ │ │ │ │ - * on the map that aren't DOM elements. For example one can use │ │ │ │ │ - * this handler to send WMS/GetFeatureInfo requests as the user │ │ │ │ │ - * moves the mouve over the map. │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: delay │ │ │ │ │ - * {Integer} - Number of milliseconds between mousemoves before │ │ │ │ │ - * the event is considered a hover. Default is 500. │ │ │ │ │ - */ │ │ │ │ │ - delay: 500, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: pixelTolerance │ │ │ │ │ - * {Integer} - Maximum number of pixels between mousemoves for │ │ │ │ │ - * an event to be considered a hover. Default is null. │ │ │ │ │ - */ │ │ │ │ │ - pixelTolerance: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: stopMove │ │ │ │ │ - * {Boolean} - Stop other listeners from being notified on mousemoves. │ │ │ │ │ - * Default is false. │ │ │ │ │ - */ │ │ │ │ │ - stopMove: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: px │ │ │ │ │ - * {} - The location of the last mousemove, expressed │ │ │ │ │ - * in pixels. │ │ │ │ │ - */ │ │ │ │ │ - px: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: timerId │ │ │ │ │ - * {Number} - The id of the timer. │ │ │ │ │ - */ │ │ │ │ │ - timerId: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Constructor: OpenLayers.Handler.Hover │ │ │ │ │ - * Construct a hover handler. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * control - {} The control that initialized this │ │ │ │ │ - * handler. The control is assumed to have a valid map property; that │ │ │ │ │ - * map is used in the handler's own setMap method. │ │ │ │ │ - * callbacks - {Object} An object with keys corresponding to callbacks │ │ │ │ │ - * that will be called by the handler. The callbacks should │ │ │ │ │ - * expect to receive a single argument, the event. Callbacks for │ │ │ │ │ - * 'move', the mouse is moving, and 'pause', the mouse is pausing, │ │ │ │ │ - * are supported. │ │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ │ - * the handler. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: mousemove │ │ │ │ │ - * Called when the mouse moves on the map. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} Continue propagating this event. │ │ │ │ │ - */ │ │ │ │ │ - mousemove: function(evt) { │ │ │ │ │ - if (this.passesTolerance(evt.xy)) { │ │ │ │ │ - this.clearTimer(); │ │ │ │ │ - this.callback('move', [evt]); │ │ │ │ │ - this.px = evt.xy; │ │ │ │ │ - // clone the evt so original properties can be accessed even │ │ │ │ │ - // if the browser deletes them during the delay │ │ │ │ │ - evt = OpenLayers.Util.extend({}, evt); │ │ │ │ │ - this.timerId = window.setTimeout( │ │ │ │ │ - OpenLayers.Function.bind(this.delayedCall, this, evt), │ │ │ │ │ - this.delay │ │ │ │ │ - ); │ │ │ │ │ - } │ │ │ │ │ - return !this.stopMove; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: mouseout │ │ │ │ │ - * Called when the mouse goes out of the map. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} Continue propagating this event. │ │ │ │ │ - */ │ │ │ │ │ - mouseout: function(evt) { │ │ │ │ │ - if (OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { │ │ │ │ │ - this.clearTimer(); │ │ │ │ │ - this.callback('move', [evt]); │ │ │ │ │ - } │ │ │ │ │ - return true; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: passesTolerance │ │ │ │ │ - * Determine whether the mouse move is within the optional pixel tolerance. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * px - {} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The mouse move is within the pixel tolerance. │ │ │ │ │ - */ │ │ │ │ │ - passesTolerance: function(px) { │ │ │ │ │ - var passes = true; │ │ │ │ │ - if (this.pixelTolerance && this.px) { │ │ │ │ │ - var dpx = Math.sqrt( │ │ │ │ │ - Math.pow(this.px.x - px.x, 2) + │ │ │ │ │ - Math.pow(this.px.y - px.y, 2) │ │ │ │ │ - ); │ │ │ │ │ - if (dpx < this.pixelTolerance) { │ │ │ │ │ - passes = false; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - return passes; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: clearTimer │ │ │ │ │ - * Clear the timer and set to null. │ │ │ │ │ - */ │ │ │ │ │ - clearTimer: function() { │ │ │ │ │ - if (this.timerId != null) { │ │ │ │ │ - window.clearTimeout(this.timerId); │ │ │ │ │ - this.timerId = null; │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Method: delayedCall │ │ │ │ │ - * Triggers pause callback. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {} │ │ │ │ │ - */ │ │ │ │ │ - delayedCall: function(evt) { │ │ │ │ │ - this.callback('pause', [evt]); │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: deactivate │ │ │ │ │ - * Deactivate the handler. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} The handler was successfully deactivated. │ │ │ │ │ - */ │ │ │ │ │ - deactivate: function() { │ │ │ │ │ - var deactivated = false; │ │ │ │ │ - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ │ - this.clearTimer(); │ │ │ │ │ - deactivated = true; │ │ │ │ │ - } │ │ │ │ │ - return deactivated; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - CLASS_NAME: "OpenLayers.Handler.Hover" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Layer/Vector.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Layer.js │ │ │ │ │ - * @requires OpenLayers/Renderer.js │ │ │ │ │ - * @requires OpenLayers/StyleMap.js │ │ │ │ │ - * @requires OpenLayers/Feature/Vector.js │ │ │ │ │ - * @requires OpenLayers/Console.js │ │ │ │ │ - * @requires OpenLayers/Lang.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Layer.Vector │ │ │ │ │ - * Instances of OpenLayers.Layer.Vector are used to render vector data from │ │ │ │ │ - * a variety of sources. Create a new vector layer with the │ │ │ │ │ - * constructor. │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: events │ │ │ │ │ - * {} │ │ │ │ │ - * │ │ │ │ │ - * Register a listener for a particular event with the following syntax: │ │ │ │ │ - * (code) │ │ │ │ │ - * layer.events.register(type, obj, listener); │ │ │ │ │ - * (end) │ │ │ │ │ - * │ │ │ │ │ - * Listeners will be called with a reference to an event object. The │ │ │ │ │ - * properties of this event depends on exactly what happened. │ │ │ │ │ - * │ │ │ │ │ - * All event objects have at least the following properties: │ │ │ │ │ - * object - {Object} A reference to layer.events.object. │ │ │ │ │ - * element - {DOMElement} A reference to layer.events.element. │ │ │ │ │ - * │ │ │ │ │ - * Supported map event types (in addition to those from ): │ │ │ │ │ - * beforefeatureadded - Triggered before a feature is added. Listeners │ │ │ │ │ - * will receive an object with a *feature* property referencing the │ │ │ │ │ - * feature to be added. To stop the feature from being added, a │ │ │ │ │ - * listener should return false. │ │ │ │ │ - * beforefeaturesadded - Triggered before an array of features is added. │ │ │ │ │ - * Listeners will receive an object with a *features* property │ │ │ │ │ - * referencing the feature to be added. To stop the features from │ │ │ │ │ - * being added, a listener should return false. │ │ │ │ │ - * featureadded - Triggered after a feature is added. The event │ │ │ │ │ - * object passed to listeners will have a *feature* property with a │ │ │ │ │ - * reference to the added feature. │ │ │ │ │ - * featuresadded - Triggered after features are added. The event │ │ │ │ │ - * object passed to listeners will have a *features* property with a │ │ │ │ │ - * reference to an array of added features. │ │ │ │ │ - * beforefeatureremoved - Triggered before a feature is removed. Listeners │ │ │ │ │ - * will receive an object with a *feature* property referencing the │ │ │ │ │ - * feature to be removed. │ │ │ │ │ - * beforefeaturesremoved - Triggered before multiple features are removed. │ │ │ │ │ - * Listeners will receive an object with a *features* property │ │ │ │ │ - * referencing the features to be removed. │ │ │ │ │ - * featureremoved - Triggerd after a feature is removed. The event │ │ │ │ │ - * object passed to listeners will have a *feature* property with a │ │ │ │ │ - * reference to the removed feature. │ │ │ │ │ - * featuresremoved - Triggered after features are removed. The event │ │ │ │ │ - * object passed to listeners will have a *features* property with a │ │ │ │ │ - * reference to an array of removed features. │ │ │ │ │ - * beforefeatureselected - Triggered before a feature is selected. Listeners │ │ │ │ │ - * will receive an object with a *feature* property referencing the │ │ │ │ │ - * feature to be selected. To stop the feature from being selectd, a │ │ │ │ │ - * listener should return false. │ │ │ │ │ - * featureselected - Triggered after a feature is selected. Listeners │ │ │ │ │ - * will receive an object with a *feature* property referencing the │ │ │ │ │ - * selected feature. │ │ │ │ │ - * featureunselected - Triggered after a feature is unselected. │ │ │ │ │ - * Listeners will receive an object with a *feature* property │ │ │ │ │ - * referencing the unselected feature. │ │ │ │ │ - * beforefeaturemodified - Triggered when a feature is selected to │ │ │ │ │ - * be modified. Listeners will receive an object with a *feature* │ │ │ │ │ - * property referencing the selected feature. │ │ │ │ │ - * featuremodified - Triggered when a feature has been modified. │ │ │ │ │ - * Listeners will receive an object with a *feature* property referencing │ │ │ │ │ - * the modified feature. │ │ │ │ │ - * afterfeaturemodified - Triggered when a feature is finished being modified. │ │ │ │ │ - * Listeners will receive an object with a *feature* property referencing │ │ │ │ │ - * the modified feature. │ │ │ │ │ - * vertexmodified - Triggered when a vertex within any feature geometry │ │ │ │ │ - * has been modified. Listeners will receive an object with a │ │ │ │ │ - * *feature* property referencing the modified feature, a *vertex* │ │ │ │ │ - * property referencing the vertex modified (always a point geometry), │ │ │ │ │ - * and a *pixel* property referencing the pixel location of the │ │ │ │ │ - * modification. │ │ │ │ │ - * vertexremoved - Triggered when a vertex within any feature geometry │ │ │ │ │ - * has been deleted. Listeners will receive an object with a │ │ │ │ │ - * *feature* property referencing the modified feature, a *vertex* │ │ │ │ │ - * property referencing the vertex modified (always a point geometry), │ │ │ │ │ - * and a *pixel* property referencing the pixel location of the │ │ │ │ │ - * removal. │ │ │ │ │ - * sketchstarted - Triggered when a feature sketch bound for this layer │ │ │ │ │ - * is started. Listeners will receive an object with a *feature* │ │ │ │ │ - * property referencing the new sketch feature and a *vertex* property │ │ │ │ │ - * referencing the creation point. │ │ │ │ │ - * sketchmodified - Triggered when a feature sketch bound for this layer │ │ │ │ │ - * is modified. Listeners will receive an object with a *vertex* │ │ │ │ │ - * property referencing the modified vertex and a *feature* property │ │ │ │ │ - * referencing the sketch feature. │ │ │ │ │ - * sketchcomplete - Triggered when a feature sketch bound for this layer │ │ │ │ │ - * is complete. Listeners will receive an object with a *feature* │ │ │ │ │ - * property referencing the sketch feature. By returning false, a │ │ │ │ │ - * listener can stop the sketch feature from being added to the layer. │ │ │ │ │ - * refresh - Triggered when something wants a strategy to ask the protocol │ │ │ │ │ - * for a new set of features. │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ │ - * {Boolean} The layer is a base layer. Default is false. Set this property │ │ │ │ │ - * in the layer options. │ │ │ │ │ - */ │ │ │ │ │ - isBaseLayer: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: isFixed │ │ │ │ │ - * {Boolean} Whether the layer remains in one place while dragging the │ │ │ │ │ - * map. Note that setting this to true will move the layer to the bottom │ │ │ │ │ - * of the layer stack. │ │ │ │ │ - */ │ │ │ │ │ - isFixed: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: features │ │ │ │ │ - * {Array()} │ │ │ │ │ - */ │ │ │ │ │ - features: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: filter │ │ │ │ │ - * {} The filter set in this layer, │ │ │ │ │ - * a strategy launching read requests can combined │ │ │ │ │ - * this filter with its own filter. │ │ │ │ │ - */ │ │ │ │ │ - filter: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: selectedFeatures │ │ │ │ │ - * {Array()} │ │ │ │ │ - */ │ │ │ │ │ - selectedFeatures: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: unrenderedFeatures │ │ │ │ │ - * {Object} hash of features, keyed by feature.id, that the renderer │ │ │ │ │ - * failed to draw │ │ │ │ │ - */ │ │ │ │ │ - unrenderedFeatures: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: reportError │ │ │ │ │ - * {Boolean} report friendly error message when loading of renderer │ │ │ │ │ - * fails. │ │ │ │ │ - */ │ │ │ │ │ - reportError: true, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: style │ │ │ │ │ - * {Object} Default style for the layer │ │ │ │ │ - */ │ │ │ │ │ - style: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: styleMap │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - styleMap: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: strategies │ │ │ │ │ - * {Array(})} Optional list of strategies for the layer. │ │ │ │ │ - */ │ │ │ │ │ - strategies: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: protocol │ │ │ │ │ - * {} Optional protocol for the layer. │ │ │ │ │ - */ │ │ │ │ │ - protocol: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: renderers │ │ │ │ │ - * {Array(String)} List of supported Renderer classes. Add to this list to │ │ │ │ │ - * add support for additional renderers. This list is ordered: │ │ │ │ │ - * the first renderer which returns true for the 'supported()' │ │ │ │ │ - * method will be used, if not defined in the 'renderer' option. │ │ │ │ │ - */ │ │ │ │ │ - renderers: ['SVG', 'VML', 'Canvas'], │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: renderer │ │ │ │ │ - * {} │ │ │ │ │ - */ │ │ │ │ │ - renderer: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: rendererOptions │ │ │ │ │ - * {Object} Options for the renderer. See {} for │ │ │ │ │ - * supported options. │ │ │ │ │ - */ │ │ │ │ │ - rendererOptions: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: geometryType │ │ │ │ │ - * {String} geometryType allows you to limit the types of geometries this │ │ │ │ │ - * layer supports. This should be set to something like │ │ │ │ │ - * "OpenLayers.Geometry.Point" to limit types. │ │ │ │ │ - */ │ │ │ │ │ - geometryType: null, │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: geometryType │ │ │ │ │ + * {String} geometryType allows you to limit the types of geometries this │ │ │ │ │ + * layer supports. This should be set to something like │ │ │ │ │ + * "OpenLayers.Geometry.Point" to limit types. │ │ │ │ │ + */ │ │ │ │ │ + geometryType: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ * Property: drawn │ │ │ │ │ * {Boolean} Whether the Vector Layer features have been drawn yet. │ │ │ │ │ */ │ │ │ │ │ drawn: false, │ │ │ │ │ │ │ │ │ │ @@ -38432,8932 +40349,8680 @@ │ │ │ │ │ } │ │ │ │ │ return maxExtent; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ CLASS_NAME: "OpenLayers.Layer.Vector" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Layer/PointTrack.js │ │ │ │ │ + OpenLayers/Control/Split.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ │ + * @requires OpenLayers/Handler/Path.js │ │ │ │ │ * @requires OpenLayers/Layer/Vector.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Layer.PointTrack │ │ │ │ │ - * Vector layer to display ordered point features as a line, creating one │ │ │ │ │ - * LineString feature for each pair of two points. │ │ │ │ │ + * Class: OpenLayers.Control.Split │ │ │ │ │ + * Acts as a split feature agent while editing vector features. │ │ │ │ │ * │ │ │ │ │ * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Layer.PointTrack = OpenLayers.Class(OpenLayers.Layer.Vector, { │ │ │ │ │ +OpenLayers.Control.Split = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: events │ │ │ │ │ + * {} Events instance for listeners and triggering │ │ │ │ │ + * control specific events. │ │ │ │ │ + * │ │ │ │ │ + * Register a listener for a particular event with the following syntax: │ │ │ │ │ + * (code) │ │ │ │ │ + * control.events.register(type, obj, listener); │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Supported event types (in addition to those from ): │ │ │ │ │ + * beforesplit - Triggered before a split occurs. Listeners receive an │ │ │ │ │ + * event object with *source* and *target* properties. │ │ │ │ │ + * split - Triggered when a split occurs. Listeners receive an event with │ │ │ │ │ + * an *original* property and a *features* property. The original │ │ │ │ │ + * is a reference to the target feature that the sketch or modified │ │ │ │ │ + * feature intersects. The features property is a list of all features │ │ │ │ │ + * that result from this single split. This event is triggered before │ │ │ │ │ + * the resulting features are added to the layer (while the layer still │ │ │ │ │ + * has a reference to the original). │ │ │ │ │ + * aftersplit - Triggered after all splits resulting from a single sketch │ │ │ │ │ + * or feature modification have occurred. The original features │ │ │ │ │ + * have been destroyed and features that result from the split │ │ │ │ │ + * have already been added to the layer. Listeners receive an event │ │ │ │ │ + * with a *source* and *features* property. The source references the │ │ │ │ │ + * sketch or modified feature used as a splitter. The features │ │ │ │ │ + * property is a list of all resulting features. │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: dataFrom │ │ │ │ │ - * {} or │ │ │ │ │ - * {} optional. If the lines │ │ │ │ │ - * should get the data/attributes from one of the two points it is │ │ │ │ │ - * composed of, which one should it be? │ │ │ │ │ + * APIProperty: layer │ │ │ │ │ + * {} The target layer with features to be split. │ │ │ │ │ + * Set at construction or after construction with . │ │ │ │ │ */ │ │ │ │ │ - dataFrom: null, │ │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: styleFrom │ │ │ │ │ - * {} or │ │ │ │ │ - * {} optional. If the lines │ │ │ │ │ - * should get the style from one of the two points it is composed of, │ │ │ │ │ - * which one should it be? │ │ │ │ │ + * Property: source │ │ │ │ │ + * {} Optional source layer. Any newly created │ │ │ │ │ + * or modified features from this layer will be used to split features │ │ │ │ │ + * on the target layer. If not provided, a temporary sketch layer will │ │ │ │ │ + * be created. │ │ │ │ │ */ │ │ │ │ │ - styleFrom: null, │ │ │ │ │ + source: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.PointTrack │ │ │ │ │ - * Constructor for a new OpenLayers.PointTrack instance. │ │ │ │ │ + * Property: sourceOptions │ │ │ │ │ + * {Options} If a temporary sketch layer is created, these layer options │ │ │ │ │ + * will be applied. │ │ │ │ │ + */ │ │ │ │ │ + sourceOptions: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: tolerance │ │ │ │ │ + * {Number} Distance between the calculated intersection and a vertex on │ │ │ │ │ + * the source geometry below which the existing vertex will be used │ │ │ │ │ + * for the split. Default is null. │ │ │ │ │ + */ │ │ │ │ │ + tolerance: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: edge │ │ │ │ │ + * {Boolean} Allow splits given intersection of edges only. Default is │ │ │ │ │ + * true. If false, a vertex on the source must be within the │ │ │ │ │ + * distance of the calculated intersection for a split │ │ │ │ │ + * to occur. │ │ │ │ │ + */ │ │ │ │ │ + edge: true, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: deferDelete │ │ │ │ │ + * {Boolean} Instead of removing features from the layer, set feature │ │ │ │ │ + * states of split features to DELETE. This assumes a save strategy │ │ │ │ │ + * or other component is in charge of removing features from the │ │ │ │ │ + * layer. Default is false. If false, split features will be │ │ │ │ │ + * immediately deleted from the layer. │ │ │ │ │ + */ │ │ │ │ │ + deferDelete: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: mutual │ │ │ │ │ + * {Boolean} If source and target layers are the same, split source │ │ │ │ │ + * features and target features where they intersect. Default is │ │ │ │ │ + * true. If false, only target features will be split. │ │ │ │ │ + */ │ │ │ │ │ + mutual: true, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: targetFilter │ │ │ │ │ + * {} Optional filter that will be evaluated │ │ │ │ │ + * to determine if a feature from the target layer is eligible for │ │ │ │ │ + * splitting. │ │ │ │ │ + */ │ │ │ │ │ + targetFilter: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: sourceFilter │ │ │ │ │ + * {} Optional filter that will be evaluated │ │ │ │ │ + * to determine if a feature from the source layer is eligible for │ │ │ │ │ + * splitting. │ │ │ │ │ + */ │ │ │ │ │ + sourceFilter: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: handler │ │ │ │ │ + * {} The temporary sketch handler created if │ │ │ │ │ + * no source layer is provided. │ │ │ │ │ + */ │ │ │ │ │ + handler: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Control.Split │ │ │ │ │ + * Creates a new split control. A control is constructed with a target │ │ │ │ │ + * layer and an optional source layer. While the control is active, │ │ │ │ │ + * creating new features or modifying existing features on the source │ │ │ │ │ + * layer will result in splitting any eligible features on the target │ │ │ │ │ + * layer. If no source layer is provided, a temporary sketch layer will │ │ │ │ │ + * be created to create lines for splitting features on the target. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * name - {String} name of the layer │ │ │ │ │ - * options - {Object} Optional object with properties to tag onto the │ │ │ │ │ - * instance. │ │ │ │ │ + * options - {Object} An object containing all configuration properties for │ │ │ │ │ + * the control. │ │ │ │ │ + * │ │ │ │ │ + * Valid options: │ │ │ │ │ + * layer - {} The target layer. Features from this │ │ │ │ │ + * layer will be split by new or modified features on the source layer │ │ │ │ │ + * or temporary sketch layer. │ │ │ │ │ + * source - {} Optional source layer. If provided │ │ │ │ │ + * newly created features or modified features will be used to split │ │ │ │ │ + * features on the target layer. If not provided, a temporary sketch │ │ │ │ │ + * layer will be created for drawing lines. │ │ │ │ │ + * tolerance - {Number} Optional value for the distance between a source │ │ │ │ │ + * vertex and the calculated intersection below which the split will │ │ │ │ │ + * occur at the vertex. │ │ │ │ │ + * edge - {Boolean} Allow splits given intersection of edges only. Default │ │ │ │ │ + * is true. If false, a vertex on the source must be within the │ │ │ │ │ + * distance of the calculated intersection for a split │ │ │ │ │ + * to occur. │ │ │ │ │ + * mutual - {Boolean} If source and target are the same, split source │ │ │ │ │ + * features and target features where they intersect. Default is │ │ │ │ │ + * true. If false, only target features will be split. │ │ │ │ │ + * targetFilter - {} Optional filter that will be evaluated │ │ │ │ │ + * to determine if a feature from the target layer is eligible for │ │ │ │ │ + * splitting. │ │ │ │ │ + * sourceFilter - {} Optional filter that will be evaluated │ │ │ │ │ + * to determine if a feature from the target layer is eligible for │ │ │ │ │ + * splitting. │ │ │ │ │ */ │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ │ + this.options = options || {}; // TODO: this could be done by the super │ │ │ │ │ + │ │ │ │ │ + // set the source layer if provided │ │ │ │ │ + if (this.options.source) { │ │ │ │ │ + this.setSource(this.options.source); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: addNodes │ │ │ │ │ - * Adds point features that will be used to create lines from, using point │ │ │ │ │ - * pairs. The first point of a pair will be the source node, the second │ │ │ │ │ - * will be the target node. │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: setSource │ │ │ │ │ + * Set the source layer for edits layer. │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * pointFeatures - {Array()} │ │ │ │ │ - * options - {Object} │ │ │ │ │ - * │ │ │ │ │ - * Supported options: │ │ │ │ │ - * silent - {Boolean} true to suppress (before)feature(s)added events │ │ │ │ │ + * layer - {} The new source layer layer. If │ │ │ │ │ + * null, a temporary sketch layer will be created. │ │ │ │ │ */ │ │ │ │ │ - addNodes: function(pointFeatures, options) { │ │ │ │ │ - if (pointFeatures.length < 2) { │ │ │ │ │ - throw new Error("At least two point features have to be added to " + │ │ │ │ │ - "create a line from"); │ │ │ │ │ + setSource: function(layer) { │ │ │ │ │ + if (this.active) { │ │ │ │ │ + this.deactivate(); │ │ │ │ │ + if (this.handler) { │ │ │ │ │ + this.handler.destroy(); │ │ │ │ │ + delete this.handler; │ │ │ │ │ + } │ │ │ │ │ + this.source = layer; │ │ │ │ │ + this.activate(); │ │ │ │ │ + } else { │ │ │ │ │ + this.source = layer; │ │ │ │ │ } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var lines = new Array(pointFeatures.length - 1); │ │ │ │ │ - │ │ │ │ │ - var pointFeature, startPoint, endPoint; │ │ │ │ │ - for (var i = 0, len = pointFeatures.length; i < len; i++) { │ │ │ │ │ - pointFeature = pointFeatures[i]; │ │ │ │ │ - endPoint = pointFeature.geometry; │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: activate │ │ │ │ │ + * Activate the control. Activating the control registers listeners for │ │ │ │ │ + * editing related events so that during feature creation and │ │ │ │ │ + * modification, features in the target will be considered for │ │ │ │ │ + * splitting. │ │ │ │ │ + */ │ │ │ │ │ + activate: function() { │ │ │ │ │ + var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ │ + if (activated) { │ │ │ │ │ + if (!this.source) { │ │ │ │ │ + if (!this.handler) { │ │ │ │ │ + this.handler = new OpenLayers.Handler.Path(this, { │ │ │ │ │ + done: function(geometry) { │ │ │ │ │ + this.onSketchComplete({ │ │ │ │ │ + feature: new OpenLayers.Feature.Vector(geometry) │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + }, { │ │ │ │ │ + layerOptions: this.sourceOptions │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + this.handler.activate(); │ │ │ │ │ + } else if (this.source.events) { │ │ │ │ │ + this.source.events.on({ │ │ │ │ │ + sketchcomplete: this.onSketchComplete, │ │ │ │ │ + afterfeaturemodified: this.afterFeatureModified, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return activated; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (!endPoint) { │ │ │ │ │ - var lonlat = pointFeature.lonlat; │ │ │ │ │ - endPoint = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat); │ │ │ │ │ - } else if (endPoint.CLASS_NAME != "OpenLayers.Geometry.Point") { │ │ │ │ │ - throw new TypeError("Only features with point geometries are supported."); │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: deactivate │ │ │ │ │ + * Deactivate the control. Deactivating the control unregisters listeners │ │ │ │ │ + * so feature editing may proceed without engaging the split agent. │ │ │ │ │ + */ │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ │ + if (deactivated) { │ │ │ │ │ + if (this.source && this.source.events) { │ │ │ │ │ + this.source.events.un({ │ │ │ │ │ + sketchcomplete: this.onSketchComplete, │ │ │ │ │ + afterfeaturemodified: this.afterFeatureModified, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ } │ │ │ │ │ + } │ │ │ │ │ + return deactivated; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (i > 0) { │ │ │ │ │ - var attributes = (this.dataFrom != null) ? │ │ │ │ │ - (pointFeatures[i + this.dataFrom].data || │ │ │ │ │ - pointFeatures[i + this.dataFrom].attributes) : │ │ │ │ │ - null; │ │ │ │ │ - var style = (this.styleFrom != null) ? │ │ │ │ │ - (pointFeatures[i + this.styleFrom].style) : │ │ │ │ │ - null; │ │ │ │ │ - var line = new OpenLayers.Geometry.LineString([startPoint, │ │ │ │ │ - endPoint │ │ │ │ │ - ]); │ │ │ │ │ + /** │ │ │ │ │ + * Method: onSketchComplete │ │ │ │ │ + * Registered as a listener for the sketchcomplete event on the editable │ │ │ │ │ + * layer. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * event - {Object} The sketch complete event. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Stop the sketch from being added to the layer (it has been │ │ │ │ │ + * split). │ │ │ │ │ + */ │ │ │ │ │ + onSketchComplete: function(event) { │ │ │ │ │ + this.feature = null; │ │ │ │ │ + return !this.considerSplit(event.feature); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - lines[i - 1] = new OpenLayers.Feature.Vector(line, attributes, │ │ │ │ │ - style); │ │ │ │ │ + /** │ │ │ │ │ + * Method: afterFeatureModified │ │ │ │ │ + * Registered as a listener for the afterfeaturemodified event on the │ │ │ │ │ + * editable layer. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * event - {Object} The after feature modified event. │ │ │ │ │ + */ │ │ │ │ │ + afterFeatureModified: function(event) { │ │ │ │ │ + if (event.modified) { │ │ │ │ │ + var feature = event.feature; │ │ │ │ │ + if (typeof feature.geometry.split === "function") { │ │ │ │ │ + this.feature = event.feature; │ │ │ │ │ + this.considerSplit(event.feature); │ │ │ │ │ } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - startPoint = endPoint; │ │ │ │ │ + /** │ │ │ │ │ + * Method: removeByGeometry │ │ │ │ │ + * Remove a feature from a list based on the given geometry. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * features - {Array()} A list of features. │ │ │ │ │ + * geometry - {} A geometry. │ │ │ │ │ + */ │ │ │ │ │ + removeByGeometry: function(features, geometry) { │ │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ │ + if (features[i].geometry === geometry) { │ │ │ │ │ + features.splice(i, 1); │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - this.addFeatures(lines, options); │ │ │ │ │ + /** │ │ │ │ │ + * Method: isEligible │ │ │ │ │ + * Test if a target feature is eligible for splitting. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * target - {} The target feature. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The target is eligible for splitting. │ │ │ │ │ + */ │ │ │ │ │ + isEligible: function(target) { │ │ │ │ │ + if (!target.geometry) { │ │ │ │ │ + return false; │ │ │ │ │ + } else { │ │ │ │ │ + return ( │ │ │ │ │ + target.state !== OpenLayers.State.DELETE │ │ │ │ │ + ) && ( │ │ │ │ │ + typeof target.geometry.split === "function" │ │ │ │ │ + ) && ( │ │ │ │ │ + this.feature !== target │ │ │ │ │ + ) && ( │ │ │ │ │ + !this.targetFilter || │ │ │ │ │ + this.targetFilter.evaluate(target.attributes) │ │ │ │ │ + ); │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.PointTrack" │ │ │ │ │ -}); │ │ │ │ │ + /** │ │ │ │ │ + * Method: considerSplit │ │ │ │ │ + * Decide whether or not to split target features with the supplied │ │ │ │ │ + * feature. If is true, both the source and target features │ │ │ │ │ + * will be split if eligible. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * feature - {} The newly created or modified │ │ │ │ │ + * feature. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The supplied feature was split (and destroyed). │ │ │ │ │ + */ │ │ │ │ │ + considerSplit: function(feature) { │ │ │ │ │ + var sourceSplit = false; │ │ │ │ │ + var targetSplit = false; │ │ │ │ │ + if (!this.sourceFilter || │ │ │ │ │ + this.sourceFilter.evaluate(feature.attributes)) { │ │ │ │ │ + var features = this.layer && this.layer.features || []; │ │ │ │ │ + var target, results, proceed; │ │ │ │ │ + var additions = [], │ │ │ │ │ + removals = []; │ │ │ │ │ + var mutual = (this.layer === this.source) && this.mutual; │ │ │ │ │ + var options = { │ │ │ │ │ + edge: this.edge, │ │ │ │ │ + tolerance: this.tolerance, │ │ │ │ │ + mutual: mutual │ │ │ │ │ + }; │ │ │ │ │ + var sourceParts = [feature.geometry]; │ │ │ │ │ + var targetFeature, targetParts; │ │ │ │ │ + var source, parts; │ │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ │ + targetFeature = features[i]; │ │ │ │ │ + if (this.isEligible(targetFeature)) { │ │ │ │ │ + targetParts = [targetFeature.geometry]; │ │ │ │ │ + // work through source geoms - this array may change │ │ │ │ │ + for (var j = 0; j < sourceParts.length; ++j) { │ │ │ │ │ + source = sourceParts[j]; │ │ │ │ │ + // work through target parts - this array may change │ │ │ │ │ + for (var k = 0; k < targetParts.length; ++k) { │ │ │ │ │ + target = targetParts[k]; │ │ │ │ │ + if (source.getBounds().intersectsBounds(target.getBounds())) { │ │ │ │ │ + results = source.split(target, options); │ │ │ │ │ + if (results) { │ │ │ │ │ + proceed = this.events.triggerEvent( │ │ │ │ │ + "beforesplit", { │ │ │ │ │ + source: feature, │ │ │ │ │ + target: targetFeature │ │ │ │ │ + } │ │ │ │ │ + ); │ │ │ │ │ + if (proceed !== false) { │ │ │ │ │ + if (mutual) { │ │ │ │ │ + parts = results[0]; │ │ │ │ │ + // handle parts that result from source splitting │ │ │ │ │ + if (parts.length > 1) { │ │ │ │ │ + // splice in new source parts │ │ │ │ │ + parts.unshift(j, 1); // add args for splice below │ │ │ │ │ + Array.prototype.splice.apply(sourceParts, parts); │ │ │ │ │ + j += parts.length - 3; │ │ │ │ │ + } │ │ │ │ │ + results = results[1]; │ │ │ │ │ + } │ │ │ │ │ + // handle parts that result from target splitting │ │ │ │ │ + if (results.length > 1) { │ │ │ │ │ + // splice in new target parts │ │ │ │ │ + results.unshift(k, 1); // add args for splice below │ │ │ │ │ + Array.prototype.splice.apply(targetParts, results); │ │ │ │ │ + k += results.length - 3; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + if (targetParts && targetParts.length > 1) { │ │ │ │ │ + this.geomsToFeatures(targetFeature, targetParts); │ │ │ │ │ + this.events.triggerEvent("split", { │ │ │ │ │ + original: targetFeature, │ │ │ │ │ + features: targetParts │ │ │ │ │ + }); │ │ │ │ │ + Array.prototype.push.apply(additions, targetParts); │ │ │ │ │ + removals.push(targetFeature); │ │ │ │ │ + targetSplit = true; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + if (sourceParts && sourceParts.length > 1) { │ │ │ │ │ + this.geomsToFeatures(feature, sourceParts); │ │ │ │ │ + this.events.triggerEvent("split", { │ │ │ │ │ + original: feature, │ │ │ │ │ + features: sourceParts │ │ │ │ │ + }); │ │ │ │ │ + Array.prototype.push.apply(additions, sourceParts); │ │ │ │ │ + removals.push(feature); │ │ │ │ │ + sourceSplit = true; │ │ │ │ │ + } │ │ │ │ │ + if (sourceSplit || targetSplit) { │ │ │ │ │ + // remove and add feature events are suppressed │ │ │ │ │ + // listen for split event on this control instead │ │ │ │ │ + if (this.deferDelete) { │ │ │ │ │ + // Set state instead of removing. Take care to avoid │ │ │ │ │ + // setting delete for features that have not yet been │ │ │ │ │ + // inserted - those should be destroyed immediately. │ │ │ │ │ + var feat, destroys = []; │ │ │ │ │ + for (var i = 0, len = removals.length; i < len; ++i) { │ │ │ │ │ + feat = removals[i]; │ │ │ │ │ + if (feat.state === OpenLayers.State.INSERT) { │ │ │ │ │ + destroys.push(feat); │ │ │ │ │ + } else { │ │ │ │ │ + feat.state = OpenLayers.State.DELETE; │ │ │ │ │ + this.layer.drawFeature(feat); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + this.layer.destroyFeatures(destroys, { │ │ │ │ │ + silent: true │ │ │ │ │ + }); │ │ │ │ │ + for (var i = 0, len = additions.length; i < len; ++i) { │ │ │ │ │ + additions[i].state = OpenLayers.State.INSERT; │ │ │ │ │ + } │ │ │ │ │ + } else { │ │ │ │ │ + this.layer.destroyFeatures(removals, { │ │ │ │ │ + silent: true │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + this.layer.addFeatures(additions, { │ │ │ │ │ + silent: true │ │ │ │ │ + }); │ │ │ │ │ + this.events.triggerEvent("aftersplit", { │ │ │ │ │ + source: feature, │ │ │ │ │ + features: additions │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return sourceSplit; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Layer.PointTrack.SOURCE_NODE │ │ │ │ │ - * {Number} value for and │ │ │ │ │ - * │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Layer.PointTrack.SOURCE_NODE = -1; │ │ │ │ │ + /** │ │ │ │ │ + * Method: geomsToFeatures │ │ │ │ │ + * Create new features given a template feature and a list of geometries. │ │ │ │ │ + * The list of geometries is modified in place. The result will be │ │ │ │ │ + * a list of new features. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * feature - {} The feature to be cloned. │ │ │ │ │ + * geoms - {Array()} List of goemetries. This will │ │ │ │ │ + * become a list of new features. │ │ │ │ │ + */ │ │ │ │ │ + geomsToFeatures: function(feature, geoms) { │ │ │ │ │ + var clone = feature.clone(); │ │ │ │ │ + delete clone.geometry; │ │ │ │ │ + var newFeature; │ │ │ │ │ + for (var i = 0, len = geoms.length; i < len; ++i) { │ │ │ │ │ + // turn results list from geoms to features │ │ │ │ │ + newFeature = clone.clone(); │ │ │ │ │ + newFeature.geometry = geoms[i]; │ │ │ │ │ + newFeature.state = OpenLayers.State.INSERT; │ │ │ │ │ + geoms[i] = newFeature; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Layer.PointTrack.TARGET_NODE │ │ │ │ │ - * {Number} value for and │ │ │ │ │ - * │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Layer.PointTrack.TARGET_NODE = 0; │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroy │ │ │ │ │ + * Clean up the control. │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + if (this.active) { │ │ │ │ │ + this.deactivate(); // TODO: this should be handled by the super │ │ │ │ │ + } │ │ │ │ │ + OpenLayers.Control.prototype.destroy.call(this); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Constant: OpenLayers.Layer.PointTrack.dataFrom │ │ │ │ │ - * {Object} with the following keys - *deprecated* │ │ │ │ │ - * - SOURCE_NODE: take data/attributes from the source node of the line │ │ │ │ │ - * - TARGET_NODE: take data/attributes from the target node of the line │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Layer.PointTrack.dataFrom = { │ │ │ │ │ - 'SOURCE_NODE': -1, │ │ │ │ │ - 'TARGET_NODE': 0 │ │ │ │ │ -}; │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Split" │ │ │ │ │ +}); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Layer/EventPane.js │ │ │ │ │ + OpenLayers/Handler/Pinch.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Layer.js │ │ │ │ │ - * @requires OpenLayers/Util.js │ │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Layer.EventPane │ │ │ │ │ - * Base class for 3rd party layers, providing a DOM element which isolates │ │ │ │ │ - * the 3rd-party layer from mouse events. │ │ │ │ │ - * Only used by Google layers. │ │ │ │ │ + * Class: OpenLayers.Handler.Pinch │ │ │ │ │ + * The pinch handler is used to deal with sequences of browser events related │ │ │ │ │ + * to pinch gestures. The handler is used by controls that want to know │ │ │ │ │ + * when a pinch sequence begins, when a pinch is happening, and when it has │ │ │ │ │ + * finished. │ │ │ │ │ * │ │ │ │ │ - * Automatically instantiated by the Google constructor, and not usually instantiated directly. │ │ │ │ │ + * Controls that use the pinch handler typically construct it with callbacks │ │ │ │ │ + * for 'start', 'move', and 'done'. Callbacks for these keys are │ │ │ │ │ + * called when the pinch begins, with each change, and when the pinch is │ │ │ │ │ + * done. │ │ │ │ │ + * │ │ │ │ │ + * Create a new pinch handler with the constructor. │ │ │ │ │ * │ │ │ │ │ - * Create a new event pane layer with the │ │ │ │ │ - * constructor. │ │ │ │ │ - * │ │ │ │ │ * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Layer.EventPane = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ │ +OpenLayers.Handler.Pinch = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: smoothDragPan │ │ │ │ │ - * {Boolean} smoothDragPan determines whether non-public/internal API │ │ │ │ │ - * methods are used for better performance while dragging EventPane │ │ │ │ │ - * layers. When not in sphericalMercator mode, the smoother dragging │ │ │ │ │ - * doesn't actually move north/south directly with the number of │ │ │ │ │ - * pixels moved, resulting in a slight offset when you drag your mouse │ │ │ │ │ - * north south with this option on. If this visual disparity bothers │ │ │ │ │ - * you, you should turn this option off, or use spherical mercator. │ │ │ │ │ - * Default is on. │ │ │ │ │ + * Property: started │ │ │ │ │ + * {Boolean} When a touchstart event is received, we want to record it, │ │ │ │ │ + * but not set 'pinching' until the touchmove get started after │ │ │ │ │ + * starting. │ │ │ │ │ */ │ │ │ │ │ - smoothDragPan: true, │ │ │ │ │ + started: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: isBaseLayer │ │ │ │ │ - * {Boolean} EventPaned layers are always base layers, by necessity. │ │ │ │ │ + * Property: stopDown │ │ │ │ │ + * {Boolean} Stop propagation of touchstart events from getting to │ │ │ │ │ + * listeners on the same element. Default is false. │ │ │ │ │ */ │ │ │ │ │ - isBaseLayer: true, │ │ │ │ │ + stopDown: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: isFixed │ │ │ │ │ - * {Boolean} EventPaned layers are fixed by default. │ │ │ │ │ + * Property: pinching │ │ │ │ │ + * {Boolean} │ │ │ │ │ */ │ │ │ │ │ - isFixed: true, │ │ │ │ │ + pinching: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: pane │ │ │ │ │ - * {DOMElement} A reference to the element that controls the events. │ │ │ │ │ + * Property: last │ │ │ │ │ + * {Object} Object that store informations related to pinch last touch. │ │ │ │ │ */ │ │ │ │ │ - pane: null, │ │ │ │ │ - │ │ │ │ │ + last: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: mapObject │ │ │ │ │ - * {Object} This is the object which will be used to load the 3rd party library │ │ │ │ │ - * in the case of the google layer, this will be of type GMap, │ │ │ │ │ - * in the case of the ve layer, this will be of type VEMap │ │ │ │ │ + * Property: start │ │ │ │ │ + * {Object} Object that store informations related to pinch touchstart. │ │ │ │ │ */ │ │ │ │ │ - mapObject: null, │ │ │ │ │ + start: null, │ │ │ │ │ │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Handler.Pinch │ │ │ │ │ + * Returns OpenLayers.Handler.Pinch │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * control - {} The control that is making use of │ │ │ │ │ + * this handler. If a handler is being used without a control, the │ │ │ │ │ + * handlers setMap method must be overridden to deal properly with │ │ │ │ │ + * the map. │ │ │ │ │ + * callbacks - {Object} An object containing functions to be called when │ │ │ │ │ + * the pinch operation start, change, or is finished. The callbacks │ │ │ │ │ + * should expect to receive an object argument, which contains │ │ │ │ │ + * information about scale, distance, and position of touch points. │ │ │ │ │ + * options - {Object} │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Layer.EventPane │ │ │ │ │ - * Create a new event pane layer │ │ │ │ │ + * Method: touchstart │ │ │ │ │ + * Handle touchstart events │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * name - {String} │ │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ │ + * evt - {Event} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ │ */ │ │ │ │ │ - initialize: function(name, options) { │ │ │ │ │ - OpenLayers.Layer.prototype.initialize.apply(this, arguments); │ │ │ │ │ - if (this.pane == null) { │ │ │ │ │ - this.pane = OpenLayers.Util.createDiv(this.div.id + "_EventPane"); │ │ │ │ │ + touchstart: function(evt) { │ │ │ │ │ + var propagate = true; │ │ │ │ │ + this.pinching = false; │ │ │ │ │ + if (OpenLayers.Event.isMultiTouch(evt)) { │ │ │ │ │ + this.started = true; │ │ │ │ │ + this.last = this.start = { │ │ │ │ │ + distance: this.getDistance(evt.touches), │ │ │ │ │ + delta: 0, │ │ │ │ │ + scale: 1 │ │ │ │ │ + }; │ │ │ │ │ + this.callback("start", [evt, this.start]); │ │ │ │ │ + propagate = !this.stopDown; │ │ │ │ │ + } else if (this.started) { │ │ │ │ │ + // Some webkit versions send fake single-touch events during │ │ │ │ │ + // multitouch, which cause the drag handler to trigger │ │ │ │ │ + return false; │ │ │ │ │ + } else { │ │ │ │ │ + this.started = false; │ │ │ │ │ + this.start = null; │ │ │ │ │ + this.last = null; │ │ │ │ │ } │ │ │ │ │ + // prevent document dragging │ │ │ │ │ + OpenLayers.Event.preventDefault(evt); │ │ │ │ │ + return propagate; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ - * Deconstruct this layer. │ │ │ │ │ + * Method: touchmove │ │ │ │ │ + * Handle touchmove events │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {Event} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ │ */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - this.mapObject = null; │ │ │ │ │ - this.pane = null; │ │ │ │ │ - OpenLayers.Layer.prototype.destroy.apply(this, arguments); │ │ │ │ │ + touchmove: function(evt) { │ │ │ │ │ + if (this.started && OpenLayers.Event.isMultiTouch(evt)) { │ │ │ │ │ + this.pinching = true; │ │ │ │ │ + var current = this.getPinchData(evt); │ │ │ │ │ + this.callback("move", [evt, current]); │ │ │ │ │ + this.last = current; │ │ │ │ │ + // prevent document dragging │ │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ │ + } else if (this.started) { │ │ │ │ │ + // Some webkit versions send fake single-touch events during │ │ │ │ │ + // multitouch, which cause the drag handler to trigger │ │ │ │ │ + return false; │ │ │ │ │ + } │ │ │ │ │ + return true; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ /** │ │ │ │ │ - * Method: setMap │ │ │ │ │ - * Set the map property for the layer. This is done through an accessor │ │ │ │ │ - * so that subclasses can override this and take special action once │ │ │ │ │ - * they have their map variable set. │ │ │ │ │ + * Method: touchend │ │ │ │ │ + * Handle touchend events │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * map - {} │ │ │ │ │ + * evt - {Event} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} Let the event propagate. │ │ │ │ │ */ │ │ │ │ │ - setMap: function(map) { │ │ │ │ │ - OpenLayers.Layer.prototype.setMap.apply(this, arguments); │ │ │ │ │ - │ │ │ │ │ - this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1; │ │ │ │ │ - this.pane.style.display = this.div.style.display; │ │ │ │ │ - this.pane.style.width = "100%"; │ │ │ │ │ - this.pane.style.height = "100%"; │ │ │ │ │ - if (OpenLayers.BROWSER_NAME == "msie") { │ │ │ │ │ - this.pane.style.background = │ │ │ │ │ - "url(" + OpenLayers.Util.getImageLocation("blank.gif") + ")"; │ │ │ │ │ + touchend: function(evt) { │ │ │ │ │ + if (this.started && !OpenLayers.Event.isMultiTouch(evt)) { │ │ │ │ │ + this.started = false; │ │ │ │ │ + this.pinching = false; │ │ │ │ │ + this.callback("done", [evt, this.start, this.last]); │ │ │ │ │ + this.start = null; │ │ │ │ │ + this.last = null; │ │ │ │ │ + return false; │ │ │ │ │ } │ │ │ │ │ + return true; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (this.isFixed) { │ │ │ │ │ - this.map.viewPortDiv.appendChild(this.pane); │ │ │ │ │ - } else { │ │ │ │ │ - this.map.layerContainerDiv.appendChild(this.pane); │ │ │ │ │ + /** │ │ │ │ │ + * Method: activate │ │ │ │ │ + * Activate the handler. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The handler was successfully activated. │ │ │ │ │ + */ │ │ │ │ │ + activate: function() { │ │ │ │ │ + var activated = false; │ │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ │ + this.pinching = false; │ │ │ │ │ + activated = true; │ │ │ │ │ } │ │ │ │ │ + return activated; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // once our layer has been added to the map, we can load it │ │ │ │ │ - this.loadMapObject(); │ │ │ │ │ - │ │ │ │ │ - // if map didn't load, display warning │ │ │ │ │ - if (this.mapObject == null) { │ │ │ │ │ - this.loadWarningMessage(); │ │ │ │ │ + /** │ │ │ │ │ + * Method: deactivate │ │ │ │ │ + * Deactivate the handler. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The handler was successfully deactivated. │ │ │ │ │ + */ │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + var deactivated = false; │ │ │ │ │ + if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ │ + this.started = false; │ │ │ │ │ + this.pinching = false; │ │ │ │ │ + this.start = null; │ │ │ │ │ + this.last = null; │ │ │ │ │ + deactivated = true; │ │ │ │ │ } │ │ │ │ │ + return deactivated; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: removeMap │ │ │ │ │ - * On being removed from the map, we'll like to remove the invisible 'pane' │ │ │ │ │ - * div that we added to it on creation. │ │ │ │ │ - * │ │ │ │ │ + * Method: getDistance │ │ │ │ │ + * Get the distance in pixels between two touches. │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * map - {} │ │ │ │ │ + * touches - {Array(Object)} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Number} The distance in pixels. │ │ │ │ │ */ │ │ │ │ │ - removeMap: function(map) { │ │ │ │ │ - if (this.pane && this.pane.parentNode) { │ │ │ │ │ - this.pane.parentNode.removeChild(this.pane); │ │ │ │ │ - } │ │ │ │ │ - OpenLayers.Layer.prototype.removeMap.apply(this, arguments); │ │ │ │ │ + getDistance: function(touches) { │ │ │ │ │ + var t0 = touches[0]; │ │ │ │ │ + var t1 = touches[1]; │ │ │ │ │ + return Math.sqrt( │ │ │ │ │ + Math.pow(t0.olClientX - t1.olClientX, 2) + │ │ │ │ │ + Math.pow(t0.olClientY - t1.olClientY, 2) │ │ │ │ │ + ); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ /** │ │ │ │ │ - * Method: loadWarningMessage │ │ │ │ │ - * If we can't load the map lib, then display an error message to the │ │ │ │ │ - * user and tell them where to go for help. │ │ │ │ │ - * │ │ │ │ │ - * This function sets up the layout for the warning message. Each 3rd │ │ │ │ │ - * party layer must implement its own getWarningHTML() function to │ │ │ │ │ - * provide the actual warning message. │ │ │ │ │ + * Method: getPinchData │ │ │ │ │ + * Get informations about the pinch event. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {Event} │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Object} Object that contains data about the current pinch. │ │ │ │ │ */ │ │ │ │ │ - loadWarningMessage: function() { │ │ │ │ │ + getPinchData: function(evt) { │ │ │ │ │ + var distance = this.getDistance(evt.touches); │ │ │ │ │ + var scale = distance / this.start.distance; │ │ │ │ │ + return { │ │ │ │ │ + distance: distance, │ │ │ │ │ + delta: this.last.distance - distance, │ │ │ │ │ + scale: scale │ │ │ │ │ + }; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - this.div.style.backgroundColor = "darkblue"; │ │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Pinch" │ │ │ │ │ +}); │ │ │ │ │ │ │ │ │ │ - var viewSize = this.map.getSize(); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Control/PinchZoom.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - var msgW = Math.min(viewSize.w, 300); │ │ │ │ │ - var msgH = Math.min(viewSize.h, 200); │ │ │ │ │ - var size = new OpenLayers.Size(msgW, msgH); │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - var centerPx = new OpenLayers.Pixel(viewSize.w / 2, viewSize.h / 2); │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Handler/Pinch.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - var topLeft = centerPx.add(-size.w / 2, -size.h / 2); │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.PinchZoom │ │ │ │ │ + * │ │ │ │ │ + * Inherits: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ │ │ - var div = OpenLayers.Util.createDiv(this.name + "_warning", │ │ │ │ │ - topLeft, │ │ │ │ │ - size, │ │ │ │ │ - null, │ │ │ │ │ - null, │ │ │ │ │ - null, │ │ │ │ │ - "auto"); │ │ │ │ │ + /** │ │ │ │ │ + * Property: type │ │ │ │ │ + * {OpenLayers.Control.TYPES} │ │ │ │ │ + */ │ │ │ │ │ + type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ │ │ │ │ │ │ - div.style.padding = "7px"; │ │ │ │ │ - div.style.backgroundColor = "yellow"; │ │ │ │ │ + /** │ │ │ │ │ + * Property: pinchOrigin │ │ │ │ │ + * {Object} Cached object representing the pinch start (in pixels). │ │ │ │ │ + */ │ │ │ │ │ + pinchOrigin: null, │ │ │ │ │ │ │ │ │ │ - div.innerHTML = this.getWarningHTML(); │ │ │ │ │ - this.div.appendChild(div); │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * Property: currentCenter │ │ │ │ │ + * {Object} Cached object representing the latest pinch center (in pixels). │ │ │ │ │ + */ │ │ │ │ │ + currentCenter: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: getWarningHTML │ │ │ │ │ - * To be implemented by subclasses. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} String with information on why layer is broken, how to get │ │ │ │ │ - * it working. │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: autoActivate │ │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ │ + * true. │ │ │ │ │ */ │ │ │ │ │ - getWarningHTML: function() { │ │ │ │ │ - //should be implemented by subclasses │ │ │ │ │ - return ""; │ │ │ │ │ - }, │ │ │ │ │ + autoActivate: true, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: display │ │ │ │ │ - * Set the display on the pane │ │ │ │ │ + * APIProperty: preserveCenter │ │ │ │ │ + * {Boolean} Set this to true if you don't want the map center to change │ │ │ │ │ + * while pinching. For example you may want to set preserveCenter to │ │ │ │ │ + * true when the user location is being watched and you want to preserve │ │ │ │ │ + * the user location at the center of the map even if he zooms in or │ │ │ │ │ + * out using pinch. This property's value can be changed any time on an │ │ │ │ │ + * existing instance. Default is false. │ │ │ │ │ + */ │ │ │ │ │ + preserveCenter: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: handlerOptions │ │ │ │ │ + * {Object} Used to set non-default properties on the pinch handler │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Control.PinchZoom │ │ │ │ │ + * Create a control for zooming with pinch gestures. This works on devices │ │ │ │ │ + * with multi-touch support. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * display - {Boolean} │ │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ │ + * the control │ │ │ │ │ */ │ │ │ │ │ - display: function(display) { │ │ │ │ │ - OpenLayers.Layer.prototype.display.apply(this, arguments); │ │ │ │ │ - this.pane.style.display = this.div.style.display; │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ │ + this.handler = new OpenLayers.Handler.Pinch(this, { │ │ │ │ │ + start: this.pinchStart, │ │ │ │ │ + move: this.pinchMove, │ │ │ │ │ + done: this.pinchDone │ │ │ │ │ + }, this.handlerOptions); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: setZIndex │ │ │ │ │ - * Set the z-index order for the pane. │ │ │ │ │ - * │ │ │ │ │ + * Method: pinchStart │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * zIndex - {int} │ │ │ │ │ + * evt - {Event} │ │ │ │ │ + * pinchData - {Object} pinch data object related to the current touchmove │ │ │ │ │ + * of the pinch gesture. This give us the current scale of the pinch. │ │ │ │ │ */ │ │ │ │ │ - setZIndex: function(zIndex) { │ │ │ │ │ - OpenLayers.Layer.prototype.setZIndex.apply(this, arguments); │ │ │ │ │ - this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1; │ │ │ │ │ + pinchStart: function(evt, pinchData) { │ │ │ │ │ + var xy = (this.preserveCenter) ? │ │ │ │ │ + this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy; │ │ │ │ │ + this.pinchOrigin = xy; │ │ │ │ │ + this.currentCenter = xy; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: moveByPx │ │ │ │ │ - * Move the layer based on pixel vector. To be implemented by subclasses. │ │ │ │ │ + * Method: pinchMove │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * dx - {Number} The x coord of the displacement vector. │ │ │ │ │ - * dy - {Number} The y coord of the displacement vector. │ │ │ │ │ + * evt - {Event} │ │ │ │ │ + * pinchData - {Object} pinch data object related to the current touchmove │ │ │ │ │ + * of the pinch gesture. This give us the current scale of the pinch. │ │ │ │ │ */ │ │ │ │ │ - moveByPx: function(dx, dy) { │ │ │ │ │ - OpenLayers.Layer.prototype.moveByPx.apply(this, arguments); │ │ │ │ │ + pinchMove: function(evt, pinchData) { │ │ │ │ │ + var scale = pinchData.scale; │ │ │ │ │ + var containerOrigin = this.map.layerContainerOriginPx; │ │ │ │ │ + var pinchOrigin = this.pinchOrigin; │ │ │ │ │ + var current = (this.preserveCenter) ? │ │ │ │ │ + this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy; │ │ │ │ │ │ │ │ │ │ - if (this.dragPanMapObject) { │ │ │ │ │ - this.dragPanMapObject(dx, -dy); │ │ │ │ │ - } else { │ │ │ │ │ - this.moveTo(this.map.getCachedCenter()); │ │ │ │ │ - } │ │ │ │ │ + var dx = Math.round((containerOrigin.x + current.x - pinchOrigin.x) + (scale - 1) * (containerOrigin.x - pinchOrigin.x)); │ │ │ │ │ + var dy = Math.round((containerOrigin.y + current.y - pinchOrigin.y) + (scale - 1) * (containerOrigin.y - pinchOrigin.y)); │ │ │ │ │ + │ │ │ │ │ + this.map.applyTransform(dx, dy, scale); │ │ │ │ │ + this.currentCenter = current; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: moveTo │ │ │ │ │ - * Handle calls to move the layer. │ │ │ │ │ - * │ │ │ │ │ + * Method: pinchDone │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * bounds - {} │ │ │ │ │ - * zoomChanged - {Boolean} │ │ │ │ │ - * dragging - {Boolean} │ │ │ │ │ + * evt - {Event} │ │ │ │ │ + * start - {Object} pinch data object related to the touchstart event that │ │ │ │ │ + * started the pinch gesture. │ │ │ │ │ + * last - {Object} pinch data object related to the last touchmove event │ │ │ │ │ + * of the pinch gesture. This give us the final scale of the pinch. │ │ │ │ │ */ │ │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ │ - OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ │ + pinchDone: function(evt, start, last) { │ │ │ │ │ + this.map.applyTransform(); │ │ │ │ │ + var zoom = this.map.getZoomForResolution(this.map.getResolution() / last.scale, true); │ │ │ │ │ + if (zoom !== this.map.getZoom() || !this.currentCenter.equals(this.pinchOrigin)) { │ │ │ │ │ + var resolution = this.map.getResolutionForZoom(zoom); │ │ │ │ │ │ │ │ │ │ - if (this.mapObject != null) { │ │ │ │ │ + var location = this.map.getLonLatFromPixel(this.pinchOrigin); │ │ │ │ │ + var zoomPixel = this.currentCenter; │ │ │ │ │ + var size = this.map.getSize(); │ │ │ │ │ │ │ │ │ │ - var newCenter = this.map.getCenter(); │ │ │ │ │ - var newZoom = this.map.getZoom(); │ │ │ │ │ + location.lon += resolution * ((size.w / 2) - zoomPixel.x); │ │ │ │ │ + location.lat -= resolution * ((size.h / 2) - zoomPixel.y); │ │ │ │ │ │ │ │ │ │ - if (newCenter != null) { │ │ │ │ │ + // Force a reflow before calling setCenter. This is to work │ │ │ │ │ + // around an issue occuring in iOS. │ │ │ │ │ + // │ │ │ │ │ + // See https://github.com/openlayers/openlayers/pull/351. │ │ │ │ │ + // │ │ │ │ │ + // Without a reflow setting the layer container div's top left │ │ │ │ │ + // style properties to "0px" - as done in Map.moveTo when zoom │ │ │ │ │ + // is changed - won't actually correctly reposition the layer │ │ │ │ │ + // container div. │ │ │ │ │ + // │ │ │ │ │ + // Also, we need to use a statement that the Google Closure │ │ │ │ │ + // compiler won't optimize away. │ │ │ │ │ + this.map.div.clientWidth = this.map.div.clientWidth; │ │ │ │ │ │ │ │ │ │ - var moOldCenter = this.getMapObjectCenter(); │ │ │ │ │ - var oldCenter = this.getOLLonLatFromMapObjectLonLat(moOldCenter); │ │ │ │ │ + this.map.setCenter(location, zoom); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var moOldZoom = this.getMapObjectZoom(); │ │ │ │ │ - var oldZoom = this.getOLZoomFromMapObjectZoom(moOldZoom); │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.PinchZoom" │ │ │ │ │ │ │ │ │ │ - if (!(newCenter.equals(oldCenter)) || newZoom != oldZoom) { │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Control/ZoomIn.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - if (!zoomChanged && oldCenter && this.dragPanMapObject && │ │ │ │ │ - this.smoothDragPan) { │ │ │ │ │ - var oldPx = this.map.getViewPortPxFromLonLat(oldCenter); │ │ │ │ │ - var newPx = this.map.getViewPortPxFromLonLat(newCenter); │ │ │ │ │ - this.dragPanMapObject(newPx.x - oldPx.x, oldPx.y - newPx.y); │ │ │ │ │ - } else { │ │ │ │ │ - var center = this.getMapObjectLonLatFromOLLonLat(newCenter); │ │ │ │ │ - var zoom = this.getMapObjectZoomFromOLZoom(newZoom); │ │ │ │ │ - this.setMapObjectCenter(center, zoom, dragging); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Control/Button.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - /********************************************************/ │ │ │ │ │ - /* */ │ │ │ │ │ - /* Baselayer Functions */ │ │ │ │ │ - /* */ │ │ │ │ │ - /********************************************************/ │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.ZoomIn │ │ │ │ │ + * The ZoomIn control is a button to increase the zoom level of a map. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.ZoomIn = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getLonLatFromViewPortPx │ │ │ │ │ - * Get a map location from a pixel location │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * viewPortPx - {} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} An OpenLayers.LonLat which is the passed-in view │ │ │ │ │ - * port OpenLayers.Pixel, translated into lon/lat by map lib │ │ │ │ │ - * If the map lib is not loaded or not centered, returns null │ │ │ │ │ + * Method: trigger │ │ │ │ │ */ │ │ │ │ │ - getLonLatFromViewPortPx: function(viewPortPx) { │ │ │ │ │ - var lonlat = null; │ │ │ │ │ - if ((this.mapObject != null) && │ │ │ │ │ - (this.getMapObjectCenter() != null)) { │ │ │ │ │ - var moPixel = this.getMapObjectPixelFromOLPixel(viewPortPx); │ │ │ │ │ - var moLonLat = this.getMapObjectLonLatFromMapObjectPixel(moPixel); │ │ │ │ │ - lonlat = this.getOLLonLatFromMapObjectLonLat(moLonLat); │ │ │ │ │ + trigger: function() { │ │ │ │ │ + if (this.map) { │ │ │ │ │ + this.map.zoomIn(); │ │ │ │ │ } │ │ │ │ │ - return lonlat; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomIn" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Control/DragPan.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ │ + * @requires OpenLayers/Handler/Drag.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.DragPan │ │ │ │ │ + * The DragPan control pans the map with a drag of the mouse. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: type │ │ │ │ │ + * {OpenLayers.Control.TYPES} │ │ │ │ │ + */ │ │ │ │ │ + type: OpenLayers.Control.TYPE_TOOL, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getViewPortPxFromLonLat │ │ │ │ │ - * Get a pixel location from a map location │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * lonlat - {} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} An OpenLayers.Pixel which is the passed-in │ │ │ │ │ - * OpenLayers.LonLat, translated into view port pixels by map lib │ │ │ │ │ - * If map lib is not loaded or not centered, returns null │ │ │ │ │ + * Property: panned │ │ │ │ │ + * {Boolean} The map moved. │ │ │ │ │ */ │ │ │ │ │ - getViewPortPxFromLonLat: function(lonlat) { │ │ │ │ │ - var viewPortPx = null; │ │ │ │ │ - if ((this.mapObject != null) && │ │ │ │ │ - (this.getMapObjectCenter() != null)) { │ │ │ │ │ + panned: false, │ │ │ │ │ │ │ │ │ │ - var moLonLat = this.getMapObjectLonLatFromOLLonLat(lonlat); │ │ │ │ │ - var moPixel = this.getMapObjectPixelFromMapObjectLonLat(moLonLat); │ │ │ │ │ + /** │ │ │ │ │ + * Property: interval │ │ │ │ │ + * {Integer} The number of milliseconds that should ellapse before │ │ │ │ │ + * panning the map again. Defaults to 0 milliseconds, which means that │ │ │ │ │ + * no separate cycle is used for panning. In most cases you won't want │ │ │ │ │ + * to change this value. For slow machines/devices larger values can be │ │ │ │ │ + * tried out. │ │ │ │ │ + */ │ │ │ │ │ + interval: 0, │ │ │ │ │ │ │ │ │ │ - viewPortPx = this.getOLPixelFromMapObjectPixel(moPixel); │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: documentDrag │ │ │ │ │ + * {Boolean} If set to true, mouse dragging will continue even if the │ │ │ │ │ + * mouse cursor leaves the map viewport. Default is false. │ │ │ │ │ + */ │ │ │ │ │ + documentDrag: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: kinetic │ │ │ │ │ + * {} The OpenLayers.Kinetic object. │ │ │ │ │ + */ │ │ │ │ │ + kinetic: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: enableKinetic │ │ │ │ │ + * {Boolean} Set this option to enable "kinetic dragging". Can be │ │ │ │ │ + * set to true or to an object. If set to an object this │ │ │ │ │ + * object will be passed to the {} │ │ │ │ │ + * constructor. Defaults to true. │ │ │ │ │ + * To get kinetic dragging, ensure that OpenLayers/Kinetic.js is │ │ │ │ │ + * included in your build config. │ │ │ │ │ + */ │ │ │ │ │ + enableKinetic: true, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: kineticInterval │ │ │ │ │ + * {Integer} Interval in milliseconds between 2 steps in the "kinetic │ │ │ │ │ + * scrolling". Applies only if enableKinetic is set. Defaults │ │ │ │ │ + * to 10 milliseconds. │ │ │ │ │ + */ │ │ │ │ │ + kineticInterval: 10, │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: draw │ │ │ │ │ + * Creates a Drag handler, using and │ │ │ │ │ + * as callbacks. │ │ │ │ │ + */ │ │ │ │ │ + draw: function() { │ │ │ │ │ + if (this.enableKinetic && OpenLayers.Kinetic) { │ │ │ │ │ + var config = { │ │ │ │ │ + interval: this.kineticInterval │ │ │ │ │ + }; │ │ │ │ │ + if (typeof this.enableKinetic === "object") { │ │ │ │ │ + config = OpenLayers.Util.extend(config, this.enableKinetic); │ │ │ │ │ + } │ │ │ │ │ + this.kinetic = new OpenLayers.Kinetic(config); │ │ │ │ │ } │ │ │ │ │ - return viewPortPx; │ │ │ │ │ + this.handler = new OpenLayers.Handler.Drag(this, { │ │ │ │ │ + "move": this.panMap, │ │ │ │ │ + "done": this.panMapDone, │ │ │ │ │ + "down": this.panMapStart │ │ │ │ │ + }, { │ │ │ │ │ + interval: this.interval, │ │ │ │ │ + documentDrag: this.documentDrag │ │ │ │ │ + }); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /********************************************************/ │ │ │ │ │ - /* */ │ │ │ │ │ - /* Translation Functions */ │ │ │ │ │ - /* */ │ │ │ │ │ - /* The following functions translate Map Object and */ │ │ │ │ │ - /* OL formats for Pixel, LonLat */ │ │ │ │ │ - /* */ │ │ │ │ │ - /********************************************************/ │ │ │ │ │ - │ │ │ │ │ - // │ │ │ │ │ - // TRANSLATION: MapObject LatLng <-> OpenLayers.LonLat │ │ │ │ │ - // │ │ │ │ │ + /** │ │ │ │ │ + * Method: panMapStart │ │ │ │ │ + */ │ │ │ │ │ + panMapStart: function() { │ │ │ │ │ + if (this.kinetic) { │ │ │ │ │ + this.kinetic.begin(); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getOLLonLatFromMapObjectLonLat │ │ │ │ │ - * Get an OL style map location from a 3rd party style map location │ │ │ │ │ + * Method: panMap │ │ │ │ │ * │ │ │ │ │ - * Parameters │ │ │ │ │ - * moLonLat - {Object} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} An OpenLayers.LonLat, translated from the passed in │ │ │ │ │ - * MapObject LonLat │ │ │ │ │ - * Returns null if null value is passed in │ │ │ │ │ + * Parameters: │ │ │ │ │ + * xy - {} Pixel of the mouse position │ │ │ │ │ */ │ │ │ │ │ - getOLLonLatFromMapObjectLonLat: function(moLonLat) { │ │ │ │ │ - var olLonLat = null; │ │ │ │ │ - if (moLonLat != null) { │ │ │ │ │ - var lon = this.getLongitudeFromMapObjectLonLat(moLonLat); │ │ │ │ │ - var lat = this.getLatitudeFromMapObjectLonLat(moLonLat); │ │ │ │ │ - olLonLat = new OpenLayers.LonLat(lon, lat); │ │ │ │ │ + panMap: function(xy) { │ │ │ │ │ + if (this.kinetic) { │ │ │ │ │ + this.kinetic.update(xy); │ │ │ │ │ } │ │ │ │ │ - return olLonLat; │ │ │ │ │ + this.panned = true; │ │ │ │ │ + this.map.pan( │ │ │ │ │ + this.handler.last.x - xy.x, │ │ │ │ │ + this.handler.last.y - xy.y, { │ │ │ │ │ + dragging: true, │ │ │ │ │ + animate: false │ │ │ │ │ + } │ │ │ │ │ + ); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getMapObjectLonLatFromOLLonLat │ │ │ │ │ - * Get a 3rd party map location from an OL map location. │ │ │ │ │ + * Method: panMapDone │ │ │ │ │ + * Finish the panning operation. Only call setCenter (through ) │ │ │ │ │ + * if the map has actually been moved. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * olLonLat - {} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} A MapObject LonLat, translated from the passed in │ │ │ │ │ - * OpenLayers.LonLat │ │ │ │ │ - * Returns null if null value is passed in │ │ │ │ │ + * xy - {} Pixel of the mouse position │ │ │ │ │ */ │ │ │ │ │ - getMapObjectLonLatFromOLLonLat: function(olLonLat) { │ │ │ │ │ - var moLatLng = null; │ │ │ │ │ - if (olLonLat != null) { │ │ │ │ │ - moLatLng = this.getMapObjectLonLatFromLonLat(olLonLat.lon, │ │ │ │ │ - olLonLat.lat); │ │ │ │ │ + panMapDone: function(xy) { │ │ │ │ │ + if (this.panned) { │ │ │ │ │ + var res = null; │ │ │ │ │ + if (this.kinetic) { │ │ │ │ │ + res = this.kinetic.end(xy); │ │ │ │ │ + } │ │ │ │ │ + this.map.pan( │ │ │ │ │ + this.handler.last.x - xy.x, │ │ │ │ │ + this.handler.last.y - xy.y, { │ │ │ │ │ + dragging: !!res, │ │ │ │ │ + animate: false │ │ │ │ │ + } │ │ │ │ │ + ); │ │ │ │ │ + if (res) { │ │ │ │ │ + var self = this; │ │ │ │ │ + this.kinetic.move(res, function(x, y, end) { │ │ │ │ │ + self.map.pan(x, y, { │ │ │ │ │ + dragging: !end, │ │ │ │ │ + animate: false │ │ │ │ │ + }); │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + this.panned = false; │ │ │ │ │ } │ │ │ │ │ - return moLatLng; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.DragPan" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Events/buttonclick.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - // │ │ │ │ │ - // TRANSLATION: MapObject Pixel <-> OpenLayers.Pixel │ │ │ │ │ - // │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Events.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Events.buttonclick │ │ │ │ │ + * Extension event type for handling buttons on top of a dom element. This │ │ │ │ │ + * event type fires "buttonclick" on its when a button was │ │ │ │ │ + * clicked. Buttons are detected by the "olButton" class. │ │ │ │ │ + * │ │ │ │ │ + * This event type makes sure that button clicks do not interfere with other │ │ │ │ │ + * events that are registered on the same . │ │ │ │ │ + * │ │ │ │ │ + * Event types provided by this extension: │ │ │ │ │ + * - *buttonclick* Triggered when a button is clicked. Listeners receive an │ │ │ │ │ + * object with a *buttonElement* property referencing the dom element of │ │ │ │ │ + * the clicked button, and an *buttonXY* property with the click position │ │ │ │ │ + * relative to the button. │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Events.buttonclick = OpenLayers.Class({ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getOLPixelFromMapObjectPixel │ │ │ │ │ - * Get an OL pixel location from a 3rd party pixel location. │ │ │ │ │ + * Property: target │ │ │ │ │ + * {} The events instance that the buttonclick event will │ │ │ │ │ + * be triggered on. │ │ │ │ │ + */ │ │ │ │ │ + target: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: events │ │ │ │ │ + * {Array} Events to observe and conditionally stop from propagating when │ │ │ │ │ + * an element with the olButton class (or its olAlphaImg child) is │ │ │ │ │ + * clicked. │ │ │ │ │ + */ │ │ │ │ │ + events: [ │ │ │ │ │ + 'mousedown', 'mouseup', 'click', 'dblclick', │ │ │ │ │ + 'touchstart', 'touchmove', 'touchend', 'keydown' │ │ │ │ │ + ], │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: startRegEx │ │ │ │ │ + * {RegExp} Regular expression to test Event.type for events that start │ │ │ │ │ + * a buttonclick sequence. │ │ │ │ │ + */ │ │ │ │ │ + startRegEx: /^mousedown|touchstart$/, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: cancelRegEx │ │ │ │ │ + * {RegExp} Regular expression to test Event.type for events that cancel │ │ │ │ │ + * a buttonclick sequence. │ │ │ │ │ + */ │ │ │ │ │ + cancelRegEx: /^touchmove$/, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: completeRegEx │ │ │ │ │ + * {RegExp} Regular expression to test Event.type for events that complete │ │ │ │ │ + * a buttonclick sequence. │ │ │ │ │ + */ │ │ │ │ │ + completeRegEx: /^mouseup|touchend$/, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: startEvt │ │ │ │ │ + * {Event} The event that started the click sequence │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Events.buttonclick │ │ │ │ │ + * Construct a buttonclick event type. Applications are not supposed to │ │ │ │ │ + * create instances of this class - they are created on demand by │ │ │ │ │ + * instances. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * moPixel - {Object} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} An OpenLayers.Pixel, translated from the passed in │ │ │ │ │ - * MapObject Pixel │ │ │ │ │ - * Returns null if null value is passed in │ │ │ │ │ + * target - {} The events instance that the buttonclick │ │ │ │ │ + * event will be triggered on. │ │ │ │ │ */ │ │ │ │ │ - getOLPixelFromMapObjectPixel: function(moPixel) { │ │ │ │ │ - var olPixel = null; │ │ │ │ │ - if (moPixel != null) { │ │ │ │ │ - var x = this.getXFromMapObjectPixel(moPixel); │ │ │ │ │ - var y = this.getYFromMapObjectPixel(moPixel); │ │ │ │ │ - olPixel = new OpenLayers.Pixel(x, y); │ │ │ │ │ + initialize: function(target) { │ │ │ │ │ + this.target = target; │ │ │ │ │ + for (var i = this.events.length - 1; i >= 0; --i) { │ │ │ │ │ + this.target.register(this.events[i], this, this.buttonClick, { │ │ │ │ │ + extension: true │ │ │ │ │ + }); │ │ │ │ │ } │ │ │ │ │ - return olPixel; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getMapObjectPixelFromOLPixel │ │ │ │ │ - * Get a 3rd party pixel location from an OL pixel location │ │ │ │ │ + * Method: destroy │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + for (var i = this.events.length - 1; i >= 0; --i) { │ │ │ │ │ + this.target.unregister(this.events[i], this, this.buttonClick); │ │ │ │ │ + } │ │ │ │ │ + delete this.target; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: getPressedButton │ │ │ │ │ + * Get the pressed button, if any. Returns undefined if no button │ │ │ │ │ + * was pressed. │ │ │ │ │ + * │ │ │ │ │ + * Arguments: │ │ │ │ │ + * element - {DOMElement} The event target. │ │ │ │ │ * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * olPixel - {} │ │ │ │ │ - * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Object} A MapObject Pixel, translated from the passed in │ │ │ │ │ - * OpenLayers.Pixel │ │ │ │ │ - * Returns null if null value is passed in │ │ │ │ │ + * {DOMElement} The button element, or undefined. │ │ │ │ │ */ │ │ │ │ │ - getMapObjectPixelFromOLPixel: function(olPixel) { │ │ │ │ │ - var moPixel = null; │ │ │ │ │ - if (olPixel != null) { │ │ │ │ │ - moPixel = this.getMapObjectPixelFromXY(olPixel.x, olPixel.y); │ │ │ │ │ - } │ │ │ │ │ - return moPixel; │ │ │ │ │ + getPressedButton: function(element) { │ │ │ │ │ + var depth = 3, // limit the search depth │ │ │ │ │ + button; │ │ │ │ │ + do { │ │ │ │ │ + if (OpenLayers.Element.hasClass(element, "olButton")) { │ │ │ │ │ + // hit! │ │ │ │ │ + button = element; │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + element = element.parentNode; │ │ │ │ │ + } while (--depth > 0 && element); │ │ │ │ │ + return button; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.EventPane" │ │ │ │ │ + /** │ │ │ │ │ + * Method: ignore │ │ │ │ │ + * Check for event target elements that should be ignored by OpenLayers. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * element - {DOMElement} The event target. │ │ │ │ │ + */ │ │ │ │ │ + ignore: function(element) { │ │ │ │ │ + var depth = 3, │ │ │ │ │ + ignore = false; │ │ │ │ │ + do { │ │ │ │ │ + if (element.nodeName.toLowerCase() === 'a') { │ │ │ │ │ + ignore = true; │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + element = element.parentNode; │ │ │ │ │ + } while (--depth > 0 && element); │ │ │ │ │ + return ignore; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: buttonClick │ │ │ │ │ + * Check if a button was clicked, and fire the buttonclick event │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {Event} │ │ │ │ │ + */ │ │ │ │ │ + buttonClick: function(evt) { │ │ │ │ │ + var propagate = true, │ │ │ │ │ + element = OpenLayers.Event.element(evt); │ │ │ │ │ + if (element && (OpenLayers.Event.isLeftClick(evt) || !~evt.type.indexOf("mouse"))) { │ │ │ │ │ + // was a button pressed? │ │ │ │ │ + var button = this.getPressedButton(element); │ │ │ │ │ + if (button) { │ │ │ │ │ + if (evt.type === "keydown") { │ │ │ │ │ + switch (evt.keyCode) { │ │ │ │ │ + case OpenLayers.Event.KEY_RETURN: │ │ │ │ │ + case OpenLayers.Event.KEY_SPACE: │ │ │ │ │ + this.target.triggerEvent("buttonclick", { │ │ │ │ │ + buttonElement: button │ │ │ │ │ + }); │ │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ │ + propagate = false; │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } else if (this.startEvt) { │ │ │ │ │ + if (this.completeRegEx.test(evt.type)) { │ │ │ │ │ + var pos = OpenLayers.Util.pagePosition(button); │ │ │ │ │ + var viewportElement = OpenLayers.Util.getViewportElement(); │ │ │ │ │ + var scrollTop = window.pageYOffset || viewportElement.scrollTop; │ │ │ │ │ + var scrollLeft = window.pageXOffset || viewportElement.scrollLeft; │ │ │ │ │ + pos[0] = pos[0] - scrollLeft; │ │ │ │ │ + pos[1] = pos[1] - scrollTop; │ │ │ │ │ + │ │ │ │ │ + this.target.triggerEvent("buttonclick", { │ │ │ │ │ + buttonElement: button, │ │ │ │ │ + buttonXY: { │ │ │ │ │ + x: this.startEvt.clientX - pos[0], │ │ │ │ │ + y: this.startEvt.clientY - pos[1] │ │ │ │ │ + } │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + if (this.cancelRegEx.test(evt.type)) { │ │ │ │ │ + delete this.startEvt; │ │ │ │ │ + } │ │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ │ + propagate = false; │ │ │ │ │ + } │ │ │ │ │ + if (this.startRegEx.test(evt.type)) { │ │ │ │ │ + this.startEvt = evt; │ │ │ │ │ + OpenLayers.Event.stop(evt); │ │ │ │ │ + propagate = false; │ │ │ │ │ + } │ │ │ │ │ + } else { │ │ │ │ │ + propagate = !this.ignore(OpenLayers.Event.element(evt)); │ │ │ │ │ + delete this.startEvt; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return propagate; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Format/ArcXML.js │ │ │ │ │ + OpenLayers/Control/Panel.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Format/XML.js │ │ │ │ │ - * @requires OpenLayers/Geometry/Polygon.js │ │ │ │ │ - * @requires OpenLayers/Geometry/Point.js │ │ │ │ │ - * @requires OpenLayers/Geometry/MultiPolygon.js │ │ │ │ │ - * @requires OpenLayers/Geometry/LinearRing.js │ │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ │ + * @requires OpenLayers/Events/buttonclick.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Format.ArcXML │ │ │ │ │ - * Read/Write ArcXML. Create a new instance with the │ │ │ │ │ - * constructor. │ │ │ │ │ - * │ │ │ │ │ + * Class: OpenLayers.Control.Panel │ │ │ │ │ + * The Panel control is a container for other controls. With it toolbars │ │ │ │ │ + * may be composed. │ │ │ │ │ + * │ │ │ │ │ * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Format.ArcXML = OpenLayers.Class(OpenLayers.Format.XML, { │ │ │ │ │ +OpenLayers.Control.Panel = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ + /** │ │ │ │ │ + * Property: controls │ │ │ │ │ + * {Array()} │ │ │ │ │ + */ │ │ │ │ │ + controls: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: fontStyleKeys │ │ │ │ │ - * {Array} List of keys used in font styling. │ │ │ │ │ + * APIProperty: autoActivate │ │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ │ + * true. │ │ │ │ │ */ │ │ │ │ │ - fontStyleKeys: [ │ │ │ │ │ - 'antialiasing', 'blockout', 'font', 'fontcolor', 'fontsize', 'fontstyle', │ │ │ │ │ - 'glowing', 'interval', 'outline', 'printmode', 'shadow', 'transparency' │ │ │ │ │ - ], │ │ │ │ │ + autoActivate: true, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: defaultControl │ │ │ │ │ + * {} The control which is activated when the control is │ │ │ │ │ + * activated (turned on), which also happens at instantiation. │ │ │ │ │ + * If is true, will be nullified after the │ │ │ │ │ + * first activation of the panel. │ │ │ │ │ + */ │ │ │ │ │ + defaultControl: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: request │ │ │ │ │ - * A get_image request destined for an ArcIMS server. │ │ │ │ │ + * APIProperty: saveState │ │ │ │ │ + * {Boolean} If set to true, the active state of this panel's controls will │ │ │ │ │ + * be stored on panel deactivation, and restored on reactivation. Default │ │ │ │ │ + * is false. │ │ │ │ │ */ │ │ │ │ │ - request: null, │ │ │ │ │ + saveState: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: response │ │ │ │ │ - * A parsed response from an ArcIMS server. │ │ │ │ │ + * APIProperty: allowDepress │ │ │ │ │ + * {Boolean} If is true the controls can │ │ │ │ │ + * be deactivated by clicking the icon that represents them. Default │ │ │ │ │ + * is false. │ │ │ │ │ */ │ │ │ │ │ - response: null, │ │ │ │ │ + allowDepress: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Format.ArcXML │ │ │ │ │ - * Create a new parser/writer for ArcXML. Create an instance of this class │ │ │ │ │ - * to begin authoring a request to an ArcIMS service. This is used │ │ │ │ │ - * primarily by the ArcIMS layer, but could be used to do other wild │ │ │ │ │ - * stuff, like geocoding. │ │ │ │ │ + * Property: activeState │ │ │ │ │ + * {Object} stores the active state of this panel's controls. │ │ │ │ │ + */ │ │ │ │ │ + activeState: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Control.Panel │ │ │ │ │ + * Create a new control panel. │ │ │ │ │ + * │ │ │ │ │ + * Each control in the panel is represented by an icon. When clicking │ │ │ │ │ + * on an icon, the method is called. │ │ │ │ │ + * │ │ │ │ │ + * Specific properties for controls on a panel: │ │ │ │ │ + * type - {Number} One of , │ │ │ │ │ + * , . │ │ │ │ │ + * If not provided, is assumed. │ │ │ │ │ + * title - {string} Text displayed when mouse is over the icon that │ │ │ │ │ + * represents the control. │ │ │ │ │ + * │ │ │ │ │ + * The of a control determines the behavior when │ │ │ │ │ + * clicking its icon: │ │ │ │ │ + * - The control is activated and other │ │ │ │ │ + * controls of this type in the same panel are deactivated. This is │ │ │ │ │ + * the default type. │ │ │ │ │ + * - The active state of the control is │ │ │ │ │ + * toggled. │ │ │ │ │ + * - The │ │ │ │ │ + * method of the control is called, │ │ │ │ │ + * but its active state is not changed. │ │ │ │ │ + * │ │ │ │ │ + * If a control is , it will be drawn with the │ │ │ │ │ + * olControl[Name]ItemActive class, otherwise with the │ │ │ │ │ + * olControl[Name]ItemInactive class. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ │ - * this instance. │ │ │ │ │ + * options - {Object} An optional object whose properties will be used │ │ │ │ │ + * to extend the control. │ │ │ │ │ */ │ │ │ │ │ initialize: function(options) { │ │ │ │ │ - this.request = new OpenLayers.Format.ArcXML.Request(); │ │ │ │ │ - this.response = new OpenLayers.Format.ArcXML.Response(); │ │ │ │ │ - │ │ │ │ │ - if (options) { │ │ │ │ │ - if (options.requesttype == "feature") { │ │ │ │ │ - this.request.get_image = null; │ │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ │ + this.controls = []; │ │ │ │ │ + this.activeState = {}; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var qry = this.request.get_feature.query; │ │ │ │ │ - this.addCoordSys(qry.featurecoordsys, options.featureCoordSys); │ │ │ │ │ - this.addCoordSys(qry.filtercoordsys, options.filterCoordSys); │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + if (this.map) { │ │ │ │ │ + this.map.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ │ + } │ │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ │ + for (var ctl, i = this.controls.length - 1; i >= 0; i--) { │ │ │ │ │ + ctl = this.controls[i]; │ │ │ │ │ + if (ctl.events) { │ │ │ │ │ + ctl.events.un({ │ │ │ │ │ + activate: this.iconOn, │ │ │ │ │ + deactivate: this.iconOff │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + ctl.panel_div = null; │ │ │ │ │ + } │ │ │ │ │ + this.activeState = null; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (options.polygon) { │ │ │ │ │ - qry.isspatial = true; │ │ │ │ │ - qry.spatialfilter.polygon = options.polygon; │ │ │ │ │ - } else if (options.envelope) { │ │ │ │ │ - qry.isspatial = true; │ │ │ │ │ - qry.spatialfilter.envelope = { │ │ │ │ │ - minx: 0, │ │ │ │ │ - miny: 0, │ │ │ │ │ - maxx: 0, │ │ │ │ │ - maxy: 0 │ │ │ │ │ - }; │ │ │ │ │ - this.parseEnvelope(qry.spatialfilter.envelope, options.envelope); │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: activate │ │ │ │ │ + */ │ │ │ │ │ + activate: function() { │ │ │ │ │ + if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ │ + var control; │ │ │ │ │ + for (var i = 0, len = this.controls.length; i < len; i++) { │ │ │ │ │ + control = this.controls[i]; │ │ │ │ │ + if (control === this.defaultControl || │ │ │ │ │ + (this.saveState && this.activeState[control.id])) { │ │ │ │ │ + control.activate(); │ │ │ │ │ } │ │ │ │ │ - } else if (options.requesttype == "image") { │ │ │ │ │ - this.request.get_feature = null; │ │ │ │ │ - │ │ │ │ │ - var props = this.request.get_image.properties; │ │ │ │ │ - this.parseEnvelope(props.envelope, options.envelope); │ │ │ │ │ - │ │ │ │ │ - this.addLayers(props.layerlist, options.layers); │ │ │ │ │ - this.addImageSize(props.imagesize, options.tileSize); │ │ │ │ │ - this.addCoordSys(props.featurecoordsys, options.featureCoordSys); │ │ │ │ │ - this.addCoordSys(props.filtercoordsys, options.filterCoordSys); │ │ │ │ │ - } else { │ │ │ │ │ - // if an arcxml object is being created with no request type, it is │ │ │ │ │ - // probably going to consume a response, so do not throw an error if │ │ │ │ │ - // the requesttype is not defined │ │ │ │ │ - this.request = null; │ │ │ │ │ } │ │ │ │ │ + if (this.saveState === true) { │ │ │ │ │ + this.defaultControl = null; │ │ │ │ │ + } │ │ │ │ │ + this.redraw(); │ │ │ │ │ + return true; │ │ │ │ │ + } else { │ │ │ │ │ + return false; │ │ │ │ │ } │ │ │ │ │ - │ │ │ │ │ - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: parseEnvelope │ │ │ │ │ - * Parse an array of coordinates into an ArcXML envelope structure. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * env - {Object} An envelope object that will contain the parsed coordinates. │ │ │ │ │ - * arr - {Array(double)} An array of coordinates in the order: [ minx, miny, maxx, maxy ] │ │ │ │ │ + * APIMethod: deactivate │ │ │ │ │ */ │ │ │ │ │ - parseEnvelope: function(env, arr) { │ │ │ │ │ - if (arr && arr.length == 4) { │ │ │ │ │ - env.minx = arr[0]; │ │ │ │ │ - env.miny = arr[1]; │ │ │ │ │ - env.maxx = arr[2]; │ │ │ │ │ - env.maxy = arr[3]; │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ │ + var control; │ │ │ │ │ + for (var i = 0, len = this.controls.length; i < len; i++) { │ │ │ │ │ + control = this.controls[i]; │ │ │ │ │ + this.activeState[control.id] = control.deactivate(); │ │ │ │ │ + } │ │ │ │ │ + this.redraw(); │ │ │ │ │ + return true; │ │ │ │ │ + } else { │ │ │ │ │ + return false; │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: addLayers │ │ │ │ │ - * Add a collection of layers to another collection of layers. Each layer in the list is tuple of │ │ │ │ │ - * { id, visible }. These layer collections represent the │ │ │ │ │ - * /ARCXML/REQUEST/get_image/PROPERTIES/LAYERLIST/LAYERDEF items in ArcXML │ │ │ │ │ - * │ │ │ │ │ - * TODO: Add support for dynamic layer rendering. │ │ │ │ │ + /** │ │ │ │ │ + * Method: draw │ │ │ │ │ * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * ll - {Array({id,visible})} A list of layer definitions. │ │ │ │ │ - * lyrs - {Array({id,visible})} A list of layer definitions. │ │ │ │ │ + * Returns: │ │ │ │ │ + * {DOMElement} │ │ │ │ │ */ │ │ │ │ │ - addLayers: function(ll, lyrs) { │ │ │ │ │ - for (var lind = 0, len = lyrs.length; lind < len; lind++) { │ │ │ │ │ - ll.push(lyrs[lind]); │ │ │ │ │ + draw: function() { │ │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ │ + if (this.outsideViewport) { │ │ │ │ │ + this.events.attachToElement(this.div); │ │ │ │ │ + this.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ │ + } else { │ │ │ │ │ + this.map.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ │ } │ │ │ │ │ + this.addControlsToMap(this.controls); │ │ │ │ │ + return this.div; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: addImageSize │ │ │ │ │ - * Set the size of the requested image. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * imsize - {Object} An ArcXML imagesize object. │ │ │ │ │ - * olsize - {} The image size to set. │ │ │ │ │ + * Method: redraw │ │ │ │ │ */ │ │ │ │ │ - addImageSize: function(imsize, olsize) { │ │ │ │ │ - if (olsize !== null) { │ │ │ │ │ - imsize.width = olsize.w; │ │ │ │ │ - imsize.height = olsize.h; │ │ │ │ │ - imsize.printwidth = olsize.w; │ │ │ │ │ - imsize.printheight = olsize.h; │ │ │ │ │ + redraw: function() { │ │ │ │ │ + for (var l = this.div.childNodes.length, i = l - 1; i >= 0; i--) { │ │ │ │ │ + this.div.removeChild(this.div.childNodes[i]); │ │ │ │ │ + } │ │ │ │ │ + this.div.innerHTML = ""; │ │ │ │ │ + if (this.active) { │ │ │ │ │ + for (var i = 0, len = this.controls.length; i < len; i++) { │ │ │ │ │ + this.div.appendChild(this.controls[i].panel_div); │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: addCoordSys │ │ │ │ │ - * Add the coordinate system information to an object. The object may be │ │ │ │ │ + * APIMethod: activateControl │ │ │ │ │ + * This method is called when the user click on the icon representing a │ │ │ │ │ + * control in the panel. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * featOrFilt - {Object} A featurecoordsys or filtercoordsys ArcXML structure. │ │ │ │ │ - * fsys - {String} or {} or {filtercoordsys} or │ │ │ │ │ - * {featurecoordsys} A projection representation. If it's a {String}, │ │ │ │ │ - * the value is assumed to be the SRID. If it's a {OpenLayers.Projection} │ │ │ │ │ - * AND Proj4js is available, the projection number and name are extracted │ │ │ │ │ - * from there. If it's a filter or feature ArcXML structure, it is copied. │ │ │ │ │ + * control - {} │ │ │ │ │ */ │ │ │ │ │ - addCoordSys: function(featOrFilt, fsys) { │ │ │ │ │ - if (typeof fsys == "string") { │ │ │ │ │ - featOrFilt.id = parseInt(fsys); │ │ │ │ │ - featOrFilt.string = fsys; │ │ │ │ │ + activateControl: function(control) { │ │ │ │ │ + if (!this.active) { │ │ │ │ │ + return false; │ │ │ │ │ } │ │ │ │ │ - // is this a proj4js instance? │ │ │ │ │ - else if (typeof fsys == "object" && fsys.proj !== null) { │ │ │ │ │ - featOrFilt.id = fsys.proj.srsProjNumber; │ │ │ │ │ - featOrFilt.string = fsys.proj.srsCode; │ │ │ │ │ + if (control.type == OpenLayers.Control.TYPE_BUTTON) { │ │ │ │ │ + control.trigger(); │ │ │ │ │ + return; │ │ │ │ │ + } │ │ │ │ │ + if (control.type == OpenLayers.Control.TYPE_TOGGLE) { │ │ │ │ │ + if (control.active) { │ │ │ │ │ + control.deactivate(); │ │ │ │ │ + } else { │ │ │ │ │ + control.activate(); │ │ │ │ │ + } │ │ │ │ │ + return; │ │ │ │ │ + } │ │ │ │ │ + if (this.allowDepress && control.active) { │ │ │ │ │ + control.deactivate(); │ │ │ │ │ } else { │ │ │ │ │ - featOrFilt = fsys; │ │ │ │ │ + var c; │ │ │ │ │ + for (var i = 0, len = this.controls.length; i < len; i++) { │ │ │ │ │ + c = this.controls[i]; │ │ │ │ │ + if (c != control && │ │ │ │ │ + (c.type === OpenLayers.Control.TYPE_TOOL || c.type == null)) { │ │ │ │ │ + c.deactivate(); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + control.activate(); │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: iserror │ │ │ │ │ - * Check to see if the response from the server was an error. │ │ │ │ │ + * APIMethod: addControls │ │ │ │ │ + * To build a toolbar, you add a set of controls to it. addControls │ │ │ │ │ + * lets you add a single control or a list of controls to the │ │ │ │ │ + * Control Panel. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. If nothing is supplied, │ │ │ │ │ - * the current response is examined. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} true if the response was an error. │ │ │ │ │ + * controls - {} Controls to add in the panel. │ │ │ │ │ */ │ │ │ │ │ - iserror: function(data) { │ │ │ │ │ - var ret = null; │ │ │ │ │ + addControls: function(controls) { │ │ │ │ │ + if (!(OpenLayers.Util.isArray(controls))) { │ │ │ │ │ + controls = [controls]; │ │ │ │ │ + } │ │ │ │ │ + this.controls = this.controls.concat(controls); │ │ │ │ │ │ │ │ │ │ - if (!data) { │ │ │ │ │ - ret = (this.response.error !== ''); │ │ │ │ │ - } else { │ │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ │ - var errorNodes = data.documentElement.getElementsByTagName("ERROR"); │ │ │ │ │ - ret = (errorNodes !== null && errorNodes.length > 0); │ │ │ │ │ + for (var i = 0, len = controls.length; i < len; i++) { │ │ │ │ │ + var control = controls[i], │ │ │ │ │ + element = this.createControlMarkup(control); │ │ │ │ │ + OpenLayers.Element.addClass(element, │ │ │ │ │ + control.displayClass + "ItemInactive"); │ │ │ │ │ + OpenLayers.Element.addClass(element, "olButton"); │ │ │ │ │ + if (control.title != "" && !element.title) { │ │ │ │ │ + element.title = control.title; │ │ │ │ │ + } │ │ │ │ │ + control.panel_div = element; │ │ │ │ │ } │ │ │ │ │ │ │ │ │ │ - return ret; │ │ │ │ │ + if (this.map) { // map.addControl() has already been called on the panel │ │ │ │ │ + this.addControlsToMap(controls); │ │ │ │ │ + this.redraw(); │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: read │ │ │ │ │ - * Read data from a string, and return an response. │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: createControlMarkup │ │ │ │ │ + * This function just creates a div for the control. If specific HTML │ │ │ │ │ + * markup is needed this function can be overridden in specific classes, │ │ │ │ │ + * or at panel instantiation time: │ │ │ │ │ + * │ │ │ │ │ + * Example: │ │ │ │ │ + * (code) │ │ │ │ │ + * var panel = new OpenLayers.Control.Panel({ │ │ │ │ │ + * defaultControl: control, │ │ │ │ │ + * // ovverride createControlMarkup to create actual buttons │ │ │ │ │ + * // including texts wrapped into span elements. │ │ │ │ │ + * createControlMarkup: function(control) { │ │ │ │ │ + * var button = document.createElement('button'), │ │ │ │ │ + * span = document.createElement('span'); │ │ │ │ │ + * if (control.text) { │ │ │ │ │ + * span.innerHTML = control.text; │ │ │ │ │ + * } │ │ │ │ │ + * return button; │ │ │ │ │ + * } │ │ │ │ │ + * }); │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * data - {String} or {DOMElement} data to read/parse. │ │ │ │ │ + * control - {} The control to create the HTML │ │ │ │ │ + * markup for. │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {} An ArcXML response. Note that this response │ │ │ │ │ - * data may change in the future. │ │ │ │ │ + * {DOMElement} The markup. │ │ │ │ │ */ │ │ │ │ │ - read: function(data) { │ │ │ │ │ - if (typeof data == "string") { │ │ │ │ │ - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); │ │ │ │ │ - } │ │ │ │ │ + createControlMarkup: function(control) { │ │ │ │ │ + return document.createElement("div"); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var arcNode = null; │ │ │ │ │ - if (data && data.documentElement) { │ │ │ │ │ - if (data.documentElement.nodeName == "ARCXML") { │ │ │ │ │ - arcNode = data.documentElement; │ │ │ │ │ + /** │ │ │ │ │ + * Method: addControlsToMap │ │ │ │ │ + * Only for internal use in draw() and addControls() methods. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * controls - {Array()} Controls to add into map. │ │ │ │ │ + */ │ │ │ │ │ + addControlsToMap: function(controls) { │ │ │ │ │ + var control; │ │ │ │ │ + for (var i = 0, len = controls.length; i < len; i++) { │ │ │ │ │ + control = controls[i]; │ │ │ │ │ + if (control.autoActivate === true) { │ │ │ │ │ + control.autoActivate = false; │ │ │ │ │ + this.map.addControl(control); │ │ │ │ │ + control.autoActivate = true; │ │ │ │ │ } else { │ │ │ │ │ - arcNode = data.documentElement.getElementsByTagName("ARCXML")[0]; │ │ │ │ │ + this.map.addControl(control); │ │ │ │ │ + control.deactivate(); │ │ │ │ │ } │ │ │ │ │ + control.events.on({ │ │ │ │ │ + activate: this.iconOn, │ │ │ │ │ + deactivate: this.iconOff │ │ │ │ │ + }); │ │ │ │ │ } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // in Safari, arcNode will be there but will have a child named │ │ │ │ │ - // parsererror │ │ │ │ │ - if (!arcNode || arcNode.firstChild.nodeName === 'parsererror') { │ │ │ │ │ - var error, source; │ │ │ │ │ - try { │ │ │ │ │ - error = data.firstChild.nodeValue; │ │ │ │ │ - source = data.firstChild.childNodes[1].firstChild.nodeValue; │ │ │ │ │ - } catch (err) { │ │ │ │ │ - // pass │ │ │ │ │ + /** │ │ │ │ │ + * Method: iconOn │ │ │ │ │ + * Internal use, for use only with "controls[i].events.on/un". │ │ │ │ │ + */ │ │ │ │ │ + iconOn: function() { │ │ │ │ │ + var d = this.panel_div; // "this" refers to a control on panel! │ │ │ │ │ + var re = new RegExp("\\b(" + this.displayClass + "Item)Inactive\\b"); │ │ │ │ │ + d.className = d.className.replace(re, "$1Active"); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: iconOff │ │ │ │ │ + * Internal use, for use only with "controls[i].events.on/un". │ │ │ │ │ + */ │ │ │ │ │ + iconOff: function() { │ │ │ │ │ + var d = this.panel_div; // "this" refers to a control on panel! │ │ │ │ │ + var re = new RegExp("\\b(" + this.displayClass + "Item)Active\\b"); │ │ │ │ │ + d.className = d.className.replace(re, "$1Inactive"); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: onButtonClick │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {Event} │ │ │ │ │ + */ │ │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ │ + var controls = this.controls, │ │ │ │ │ + button = evt.buttonElement; │ │ │ │ │ + for (var i = controls.length - 1; i >= 0; --i) { │ │ │ │ │ + if (controls[i].panel_div === button) { │ │ │ │ │ + this.activateControl(controls[i]); │ │ │ │ │ + break; │ │ │ │ │ } │ │ │ │ │ - throw { │ │ │ │ │ - message: "Error parsing the ArcXML request", │ │ │ │ │ - error: error, │ │ │ │ │ - source: source │ │ │ │ │ - }; │ │ │ │ │ } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var response = this.parseResponse(arcNode); │ │ │ │ │ - return response; │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: getControlsBy │ │ │ │ │ + * Get a list of controls with properties matching the given criteria. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * property - {String} A control property to be matched. │ │ │ │ │ + * match - {String | Object} A string to match. Can also be a regular │ │ │ │ │ + * expression literal or object. In addition, it can be any object │ │ │ │ │ + * with a method named test. For reqular expressions or other, if │ │ │ │ │ + * match.test(control[property]) evaluates to true, the control will be │ │ │ │ │ + * included in the array returned. If no controls are found, an empty │ │ │ │ │ + * array is returned. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Array()} A list of controls matching the given criteria. │ │ │ │ │ + * An empty array is returned if no matches are found. │ │ │ │ │ + */ │ │ │ │ │ + getControlsBy: function(property, match) { │ │ │ │ │ + var test = (typeof match.test == "function"); │ │ │ │ │ + var found = OpenLayers.Array.filter(this.controls, function(item) { │ │ │ │ │ + return item[property] == match || (test && match.test(item[property])); │ │ │ │ │ + }); │ │ │ │ │ + return found; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: write │ │ │ │ │ - * Generate an ArcXml document string for sending to an ArcIMS server. │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: getControlsByName │ │ │ │ │ + * Get a list of contorls with names matching the given name. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * match - {String | Object} A control name. The name can also be a regular │ │ │ │ │ + * expression literal or object. In addition, it can be any object │ │ │ │ │ + * with a method named test. For reqular expressions or other, if │ │ │ │ │ + * name.test(control.name) evaluates to true, the control will be included │ │ │ │ │ + * in the list of controls returned. If no controls are found, an empty │ │ │ │ │ + * array is returned. │ │ │ │ │ + * │ │ │ │ │ * Returns: │ │ │ │ │ - * {String} A string representing the ArcXML document request. │ │ │ │ │ + * {Array()} A list of controls matching the given name. │ │ │ │ │ + * An empty array is returned if no matches are found. │ │ │ │ │ */ │ │ │ │ │ - write: function(request) { │ │ │ │ │ - if (!request) { │ │ │ │ │ - request = this.request; │ │ │ │ │ - } │ │ │ │ │ - var root = this.createElementNS("", "ARCXML"); │ │ │ │ │ - root.setAttribute("version", "1.1"); │ │ │ │ │ + getControlsByName: function(match) { │ │ │ │ │ + return this.getControlsBy("name", match); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var reqElem = this.createElementNS("", "REQUEST"); │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: getControlsByClass │ │ │ │ │ + * Get a list of controls of a given type (CLASS_NAME). │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * match - {String | Object} A control class name. The type can also be a │ │ │ │ │ + * regular expression literal or object. In addition, it can be any │ │ │ │ │ + * object with a method named test. For reqular expressions or other, │ │ │ │ │ + * if type.test(control.CLASS_NAME) evaluates to true, the control will │ │ │ │ │ + * be included in the list of controls returned. If no controls are │ │ │ │ │ + * found, an empty array is returned. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Array()} A list of controls matching the given type. │ │ │ │ │ + * An empty array is returned if no matches are found. │ │ │ │ │ + */ │ │ │ │ │ + getControlsByClass: function(match) { │ │ │ │ │ + return this.getControlsBy("CLASS_NAME", match); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (request.get_image != null) { │ │ │ │ │ - var getElem = this.createElementNS("", "GET_IMAGE"); │ │ │ │ │ - reqElem.appendChild(getElem); │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Panel" │ │ │ │ │ +}); │ │ │ │ │ │ │ │ │ │ - var propElem = this.createElementNS("", "PROPERTIES"); │ │ │ │ │ - getElem.appendChild(propElem); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Control/Pan.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - var props = request.get_image.properties; │ │ │ │ │ - if (props.featurecoordsys != null) { │ │ │ │ │ - var feat = this.createElementNS("", "FEATURECOORDSYS"); │ │ │ │ │ - propElem.appendChild(feat); │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - if (props.featurecoordsys.id === 0) { │ │ │ │ │ - feat.setAttribute("string", props.featurecoordsys['string']); │ │ │ │ │ - } else { │ │ │ │ │ - feat.setAttribute("id", props.featurecoordsys.id); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Control/Button.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - if (props.filtercoordsys != null) { │ │ │ │ │ - var filt = this.createElementNS("", "FILTERCOORDSYS"); │ │ │ │ │ - propElem.appendChild(filt); │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.Pan │ │ │ │ │ + * The Pan control is a single button to pan the map in one direction. For │ │ │ │ │ + * a more complete control see . │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.Pan = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ │ │ │ │ │ │ - if (props.filtercoordsys.id === 0) { │ │ │ │ │ - filt.setAttribute("string", props.filtercoordsys.string); │ │ │ │ │ - } else { │ │ │ │ │ - filt.setAttribute("id", props.filtercoordsys.id); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: slideFactor │ │ │ │ │ + * {Integer} Number of pixels by which we'll pan the map in any direction │ │ │ │ │ + * on clicking the arrow buttons, defaults to 50. If you want to pan │ │ │ │ │ + * by some ratio of the map dimensions, use instead. │ │ │ │ │ + */ │ │ │ │ │ + slideFactor: 50, │ │ │ │ │ │ │ │ │ │ - if (props.envelope != null) { │ │ │ │ │ - var env = this.createElementNS("", "ENVELOPE"); │ │ │ │ │ - propElem.appendChild(env); │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: slideRatio │ │ │ │ │ + * {Number} The fraction of map width/height by which we'll pan the map │ │ │ │ │ + * on clicking the arrow buttons. Default is null. If set, will │ │ │ │ │ + * override . E.g. if slideRatio is .5, then Pan Up will │ │ │ │ │ + * pan up half the map height. │ │ │ │ │ + */ │ │ │ │ │ + slideRatio: null, │ │ │ │ │ │ │ │ │ │ - env.setAttribute("minx", props.envelope.minx); │ │ │ │ │ - env.setAttribute("miny", props.envelope.miny); │ │ │ │ │ - env.setAttribute("maxx", props.envelope.maxx); │ │ │ │ │ - env.setAttribute("maxy", props.envelope.maxy); │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Property: direction │ │ │ │ │ + * {String} in {'North', 'South', 'East', 'West'} │ │ │ │ │ + */ │ │ │ │ │ + direction: null, │ │ │ │ │ │ │ │ │ │ - var imagesz = this.createElementNS("", "IMAGESIZE"); │ │ │ │ │ - propElem.appendChild(imagesz); │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Control.Pan │ │ │ │ │ + * Control which handles the panning (in any of the cardinal directions) │ │ │ │ │ + * of the map by a set px distance. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * direction - {String} The direction this button should pan. │ │ │ │ │ + * options - {Object} An optional object whose properties will be used │ │ │ │ │ + * to extend the control. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(direction, options) { │ │ │ │ │ │ │ │ │ │ - imagesz.setAttribute("height", props.imagesize.height); │ │ │ │ │ - imagesz.setAttribute("width", props.imagesize.width); │ │ │ │ │ + this.direction = direction; │ │ │ │ │ + this.CLASS_NAME += this.direction; │ │ │ │ │ │ │ │ │ │ - if (props.imagesize.height != props.imagesize.printheight || │ │ │ │ │ - props.imagesize.width != props.imagesize.printwidth) { │ │ │ │ │ - imagesz.setAttribute("printheight", props.imagesize.printheight); │ │ │ │ │ - imagesz.setArrtibute("printwidth", props.imagesize.printwidth); │ │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: trigger │ │ │ │ │ + */ │ │ │ │ │ + trigger: function() { │ │ │ │ │ + if (this.map) { │ │ │ │ │ + var getSlideFactor = OpenLayers.Function.bind(function(dim) { │ │ │ │ │ + return this.slideRatio ? │ │ │ │ │ + this.map.getSize()[dim] * this.slideRatio : │ │ │ │ │ + this.slideFactor; │ │ │ │ │ + }, this); │ │ │ │ │ + │ │ │ │ │ + switch (this.direction) { │ │ │ │ │ + case OpenLayers.Control.Pan.NORTH: │ │ │ │ │ + this.map.pan(0, -getSlideFactor("h")); │ │ │ │ │ + break; │ │ │ │ │ + case OpenLayers.Control.Pan.SOUTH: │ │ │ │ │ + this.map.pan(0, getSlideFactor("h")); │ │ │ │ │ + break; │ │ │ │ │ + case OpenLayers.Control.Pan.WEST: │ │ │ │ │ + this.map.pan(-getSlideFactor("w"), 0); │ │ │ │ │ + break; │ │ │ │ │ + case OpenLayers.Control.Pan.EAST: │ │ │ │ │ + this.map.pan(getSlideFactor("w"), 0); │ │ │ │ │ + break; │ │ │ │ │ } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (props.background != null) { │ │ │ │ │ - var backgrnd = this.createElementNS("", "BACKGROUND"); │ │ │ │ │ - propElem.appendChild(backgrnd); │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Pan" │ │ │ │ │ +}); │ │ │ │ │ │ │ │ │ │ - backgrnd.setAttribute("color", │ │ │ │ │ - props.background.color.r + "," + │ │ │ │ │ - props.background.color.g + "," + │ │ │ │ │ - props.background.color.b); │ │ │ │ │ +OpenLayers.Control.Pan.NORTH = "North"; │ │ │ │ │ +OpenLayers.Control.Pan.SOUTH = "South"; │ │ │ │ │ +OpenLayers.Control.Pan.EAST = "East"; │ │ │ │ │ +OpenLayers.Control.Pan.WEST = "West"; │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Control/PanPanel.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - if (props.background.transcolor !== null) { │ │ │ │ │ - backgrnd.setAttribute("transcolor", │ │ │ │ │ - props.background.transcolor.r + "," + │ │ │ │ │ - props.background.transcolor.g + "," + │ │ │ │ │ - props.background.transcolor.b); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - if (props.layerlist != null && props.layerlist.length > 0) { │ │ │ │ │ - var layerlst = this.createElementNS("", "LAYERLIST"); │ │ │ │ │ - propElem.appendChild(layerlst); │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Control/Panel.js │ │ │ │ │ + * @requires OpenLayers/Control/Pan.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - for (var ld = 0; ld < props.layerlist.length; ld++) { │ │ │ │ │ - var ldef = this.createElementNS("", "LAYERDEF"); │ │ │ │ │ - layerlst.appendChild(ldef); │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.PanPanel │ │ │ │ │ + * The PanPanel is visible control for panning the map North, South, East or │ │ │ │ │ + * West in small steps. By default it is drawn in the top left corner of the │ │ │ │ │ + * map. │ │ │ │ │ + * │ │ │ │ │ + * Note: │ │ │ │ │ + * If you wish to use this class with the default images and you want │ │ │ │ │ + * it to look nice in ie6, you should add the following, conditionally │ │ │ │ │ + * added css stylesheet to your HTML file: │ │ │ │ │ + * │ │ │ │ │ + * (code) │ │ │ │ │ + * │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.PanPanel = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ │ │ │ │ │ │ - ldef.setAttribute("id", props.layerlist[ld].id); │ │ │ │ │ - ldef.setAttribute("visible", props.layerlist[ld].visible); │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: slideFactor │ │ │ │ │ + * {Integer} Number of pixels by which we'll pan the map in any direction │ │ │ │ │ + * on clicking the arrow buttons, defaults to 50. If you want to pan │ │ │ │ │ + * by some ratio of the map dimensions, use instead. │ │ │ │ │ + */ │ │ │ │ │ + slideFactor: 50, │ │ │ │ │ │ │ │ │ │ - if (typeof props.layerlist[ld].query == "object") { │ │ │ │ │ - var query = props.layerlist[ld].query; │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: slideRatio │ │ │ │ │ + * {Number} The fraction of map width/height by which we'll pan the map │ │ │ │ │ + * on clicking the arrow buttons. Default is null. If set, will │ │ │ │ │ + * override . E.g. if slideRatio is .5, then Pan Up will │ │ │ │ │ + * pan up half the map height. │ │ │ │ │ + */ │ │ │ │ │ + slideRatio: null, │ │ │ │ │ │ │ │ │ │ - if (query.where.length < 0) { │ │ │ │ │ - continue; │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Control.PanPanel │ │ │ │ │ + * Add the four directional pan buttons. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} An optional object whose properties will be used │ │ │ │ │ + * to extend the control. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ │ + var options = { │ │ │ │ │ + slideFactor: this.slideFactor, │ │ │ │ │ + slideRatio: this.slideRatio │ │ │ │ │ + }; │ │ │ │ │ + this.addControls([ │ │ │ │ │ + new OpenLayers.Control.Pan(OpenLayers.Control.Pan.NORTH, options), │ │ │ │ │ + new OpenLayers.Control.Pan(OpenLayers.Control.Pan.SOUTH, options), │ │ │ │ │ + new OpenLayers.Control.Pan(OpenLayers.Control.Pan.EAST, options), │ │ │ │ │ + new OpenLayers.Control.Pan(OpenLayers.Control.Pan.WEST, options) │ │ │ │ │ + ]); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var queryElem = null; │ │ │ │ │ - if (typeof query.spatialfilter == "boolean" && query.spatialfilter) { │ │ │ │ │ - // handle spatial filter madness │ │ │ │ │ - queryElem = this.createElementNS("", "SPATIALQUERY"); │ │ │ │ │ - } else { │ │ │ │ │ - queryElem = this.createElementNS("", "QUERY"); │ │ │ │ │ - } │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.PanPanel" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Control/ZoomOut.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - queryElem.setAttribute("where", query.where); │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - if (typeof query.accuracy == "number" && query.accuracy > 0) { │ │ │ │ │ - queryElem.setAttribute("accuracy", query.accuracy); │ │ │ │ │ - } │ │ │ │ │ - if (typeof query.featurelimit == "number" && query.featurelimit < 2000) { │ │ │ │ │ - queryElem.setAttribute("featurelimit", query.featurelimit); │ │ │ │ │ - } │ │ │ │ │ - if (typeof query.subfields == "string" && query.subfields != "#ALL#") { │ │ │ │ │ - queryElem.setAttribute("subfields", query.subfields); │ │ │ │ │ - } │ │ │ │ │ - if (typeof query.joinexpression == "string" && query.joinexpression.length > 0) { │ │ │ │ │ - queryElem.setAttribute("joinexpression", query.joinexpression); │ │ │ │ │ - } │ │ │ │ │ - if (typeof query.jointables == "string" && query.jointables.length > 0) { │ │ │ │ │ - queryElem.setAttribute("jointables", query.jointables); │ │ │ │ │ - } │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Control/Button.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - ldef.appendChild(queryElem); │ │ │ │ │ - } │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.ZoomOut │ │ │ │ │ + * The ZoomOut control is a button to decrease the zoom level of a map. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.ZoomOut = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ │ │ │ │ │ │ - if (typeof props.layerlist[ld].renderer == "object") { │ │ │ │ │ - this.addRenderer(ldef, props.layerlist[ld].renderer); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } else if (request.get_feature != null) { │ │ │ │ │ - var getElem = this.createElementNS("", "GET_FEATURES"); │ │ │ │ │ - getElem.setAttribute("outputmode", "newxml"); │ │ │ │ │ - getElem.setAttribute("checkesc", "true"); │ │ │ │ │ + /** │ │ │ │ │ + * Method: trigger │ │ │ │ │ + */ │ │ │ │ │ + trigger: function() { │ │ │ │ │ + if (this.map) { │ │ │ │ │ + this.map.zoomOut(); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (request.get_feature.geometry) { │ │ │ │ │ - getElem.setAttribute("geometry", request.get_feature.geometry); │ │ │ │ │ - } else { │ │ │ │ │ - getElem.setAttribute("geometry", "false"); │ │ │ │ │ - } │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomOut" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Control/ZoomToMaxExtent.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - if (request.get_feature.compact) { │ │ │ │ │ - getElem.setAttribute("compact", request.get_feature.compact); │ │ │ │ │ - } │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - if (request.get_feature.featurelimit == "number") { │ │ │ │ │ - getElem.setAttribute("featurelimit", request.get_feature.featurelimit); │ │ │ │ │ - } │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Control/Button.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - getElem.setAttribute("globalenvelope", "true"); │ │ │ │ │ - reqElem.appendChild(getElem); │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.ZoomToMaxExtent │ │ │ │ │ + * The ZoomToMaxExtent control is a button that zooms out to the maximum │ │ │ │ │ + * extent of the map. It is designed to be used with a │ │ │ │ │ + * . │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.ZoomToMaxExtent = OpenLayers.Class(OpenLayers.Control.Button, { │ │ │ │ │ │ │ │ │ │ - if (request.get_feature.layer != null && request.get_feature.layer.length > 0) { │ │ │ │ │ - var lyrElem = this.createElementNS("", "LAYER"); │ │ │ │ │ - lyrElem.setAttribute("id", request.get_feature.layer); │ │ │ │ │ - getElem.appendChild(lyrElem); │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Method: trigger │ │ │ │ │ + * │ │ │ │ │ + * Called whenever this control is being rendered inside of a panel and a │ │ │ │ │ + * click occurs on this controls element. Actually zooms to the maximum │ │ │ │ │ + * extent of this controls map. │ │ │ │ │ + */ │ │ │ │ │ + trigger: function() { │ │ │ │ │ + if (this.map) { │ │ │ │ │ + this.map.zoomToMaxExtent(); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var fquery = request.get_feature.query; │ │ │ │ │ - if (fquery != null) { │ │ │ │ │ - var qElem = null; │ │ │ │ │ - if (fquery.isspatial) { │ │ │ │ │ - qElem = this.createElementNS("", "SPATIALQUERY"); │ │ │ │ │ - } else { │ │ │ │ │ - qElem = this.createElementNS("", "QUERY"); │ │ │ │ │ - } │ │ │ │ │ - getElem.appendChild(qElem); │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomToMaxExtent" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Control/ZoomPanel.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - if (typeof fquery.accuracy == "number") { │ │ │ │ │ - qElem.setAttribute("accuracy", fquery.accuracy); │ │ │ │ │ - } │ │ │ │ │ - //qElem.setAttribute("featurelimit", "5"); │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - if (fquery.featurecoordsys != null) { │ │ │ │ │ - var fcsElem1 = this.createElementNS("", "FEATURECOORDSYS"); │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Control/Panel.js │ │ │ │ │ + * @requires OpenLayers/Control/ZoomIn.js │ │ │ │ │ + * @requires OpenLayers/Control/ZoomOut.js │ │ │ │ │ + * @requires OpenLayers/Control/ZoomToMaxExtent.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - if (fquery.featurecoordsys.id == 0) { │ │ │ │ │ - fcsElem1.setAttribute("string", fquery.featurecoordsys.string); │ │ │ │ │ - } else { │ │ │ │ │ - fcsElem1.setAttribute("id", fquery.featurecoordsys.id); │ │ │ │ │ - } │ │ │ │ │ - qElem.appendChild(fcsElem1); │ │ │ │ │ - } │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.ZoomPanel │ │ │ │ │ + * The ZoomPanel control is a compact collecton of 3 zoom controls: a │ │ │ │ │ + * , a , and a │ │ │ │ │ + * . By default it is drawn in the upper left │ │ │ │ │ + * corner of the map. │ │ │ │ │ + * │ │ │ │ │ + * Note: │ │ │ │ │ + * If you wish to use this class with the default images and you want │ │ │ │ │ + * it to look nice in ie6, you should add the following, conditionally │ │ │ │ │ + * added css stylesheet to your HTML file: │ │ │ │ │ + * │ │ │ │ │ + * (code) │ │ │ │ │ + * │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.ZoomPanel = OpenLayers.Class(OpenLayers.Control.Panel, { │ │ │ │ │ │ │ │ │ │ - if (fquery.filtercoordsys != null) { │ │ │ │ │ - var fcsElem2 = this.createElementNS("", "FILTERCOORDSYS"); │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Control.ZoomPanel │ │ │ │ │ + * Add the three zooming controls. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} An optional object whose properties will be used │ │ │ │ │ + * to extend the control. │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ │ + this.addControls([ │ │ │ │ │ + new OpenLayers.Control.ZoomIn(), │ │ │ │ │ + new OpenLayers.Control.ZoomToMaxExtent(), │ │ │ │ │ + new OpenLayers.Control.ZoomOut() │ │ │ │ │ + ]); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (fquery.filtercoordsys.id === 0) { │ │ │ │ │ - fcsElem2.setAttribute("string", fquery.filtercoordsys.string); │ │ │ │ │ - } else { │ │ │ │ │ - fcsElem2.setAttribute("id", fquery.filtercoordsys.id); │ │ │ │ │ - } │ │ │ │ │ - qElem.appendChild(fcsElem2); │ │ │ │ │ - } │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ZoomPanel" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Control/Zoom.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - if (fquery.buffer > 0) { │ │ │ │ │ - var bufElem = this.createElementNS("", "BUFFER"); │ │ │ │ │ - bufElem.setAttribute("distance", fquery.buffer); │ │ │ │ │ - qElem.appendChild(bufElem); │ │ │ │ │ - } │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - if (fquery.isspatial) { │ │ │ │ │ - var spfElem = this.createElementNS("", "SPATIALFILTER"); │ │ │ │ │ - spfElem.setAttribute("relation", fquery.spatialfilter.relation); │ │ │ │ │ - qElem.appendChild(spfElem); │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ │ + * @requires OpenLayers/Events/buttonclick.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - if (fquery.spatialfilter.envelope) { │ │ │ │ │ - var envElem = this.createElementNS("", "ENVELOPE"); │ │ │ │ │ - envElem.setAttribute("minx", fquery.spatialfilter.envelope.minx); │ │ │ │ │ - envElem.setAttribute("miny", fquery.spatialfilter.envelope.miny); │ │ │ │ │ - envElem.setAttribute("maxx", fquery.spatialfilter.envelope.maxx); │ │ │ │ │ - envElem.setAttribute("maxy", fquery.spatialfilter.envelope.maxy); │ │ │ │ │ - spfElem.appendChild(envElem); │ │ │ │ │ - } else if (typeof fquery.spatialfilter.polygon == "object") { │ │ │ │ │ - spfElem.appendChild(this.writePolygonGeometry(fquery.spatialfilter.polygon)); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.Zoom │ │ │ │ │ + * The Zoom control is a pair of +/- links for zooming in and out. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.Zoom = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ │ │ - if (fquery.where != null && fquery.where.length > 0) { │ │ │ │ │ - qElem.setAttribute("where", fquery.where); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: zoomInText │ │ │ │ │ + * {String} │ │ │ │ │ + * Text for zoom-in link. Default is "+". │ │ │ │ │ + */ │ │ │ │ │ + zoomInText: "+", │ │ │ │ │ │ │ │ │ │ - root.appendChild(reqElem); │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: zoomInId │ │ │ │ │ + * {String} │ │ │ │ │ + * Instead of having the control create a zoom in link, you can provide │ │ │ │ │ + * the identifier for an anchor element already added to the document. │ │ │ │ │ + * By default, an element with id "olZoomInLink" will be searched for │ │ │ │ │ + * and used if it exists. │ │ │ │ │ + */ │ │ │ │ │ + zoomInId: "olZoomInLink", │ │ │ │ │ │ │ │ │ │ - return OpenLayers.Format.XML.prototype.write.apply(this, [root]); │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: zoomOutText │ │ │ │ │ + * {String} │ │ │ │ │ + * Text for zoom-out link. Default is "\u2212". │ │ │ │ │ + */ │ │ │ │ │ + zoomOutText: "\u2212", │ │ │ │ │ │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: zoomOutId │ │ │ │ │ + * {String} │ │ │ │ │ + * Instead of having the control create a zoom out link, you can provide │ │ │ │ │ + * the identifier for an anchor element already added to the document. │ │ │ │ │ + * By default, an element with id "olZoomOutLink" will be searched for │ │ │ │ │ + * and used if it exists. │ │ │ │ │ + */ │ │ │ │ │ + zoomOutId: "olZoomOutLink", │ │ │ │ │ │ │ │ │ │ - addGroupRenderer: function(ldef, toprenderer) { │ │ │ │ │ - var topRelem = this.createElementNS("", "GROUPRENDERER"); │ │ │ │ │ - ldef.appendChild(topRelem); │ │ │ │ │ + /** │ │ │ │ │ + * Method: draw │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {DOMElement} A reference to the DOMElement containing the zoom links. │ │ │ │ │ + */ │ │ │ │ │ + draw: function() { │ │ │ │ │ + var div = OpenLayers.Control.prototype.draw.apply(this), │ │ │ │ │ + links = this.getOrCreateLinks(div), │ │ │ │ │ + zoomIn = links.zoomIn, │ │ │ │ │ + zoomOut = links.zoomOut, │ │ │ │ │ + eventsInstance = this.map.events; │ │ │ │ │ │ │ │ │ │ - for (var rind = 0; rind < toprenderer.length; rind++) { │ │ │ │ │ - var renderer = toprenderer[rind]; │ │ │ │ │ - this.addRenderer(topRelem, renderer); │ │ │ │ │ + if (zoomOut.parentNode !== div) { │ │ │ │ │ + eventsInstance = this.events; │ │ │ │ │ + eventsInstance.attachToElement(zoomOut.parentNode); │ │ │ │ │ } │ │ │ │ │ + eventsInstance.register("buttonclick", this, this.onZoomClick); │ │ │ │ │ + │ │ │ │ │ + this.zoomInLink = zoomIn; │ │ │ │ │ + this.zoomOutLink = zoomOut; │ │ │ │ │ + return div; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ + /** │ │ │ │ │ + * Method: getOrCreateLinks │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * el - {DOMElement} │ │ │ │ │ + * │ │ │ │ │ + * Return: │ │ │ │ │ + * {Object} Object with zoomIn and zoomOut properties referencing links. │ │ │ │ │ + */ │ │ │ │ │ + getOrCreateLinks: function(el) { │ │ │ │ │ + var zoomIn = document.getElementById(this.zoomInId), │ │ │ │ │ + zoomOut = document.getElementById(this.zoomOutId); │ │ │ │ │ + if (!zoomIn) { │ │ │ │ │ + zoomIn = document.createElement("a"); │ │ │ │ │ + zoomIn.href = "#zoomIn"; │ │ │ │ │ + zoomIn.appendChild(document.createTextNode(this.zoomInText)); │ │ │ │ │ + zoomIn.className = "olControlZoomIn"; │ │ │ │ │ + el.appendChild(zoomIn); │ │ │ │ │ + } │ │ │ │ │ + OpenLayers.Element.addClass(zoomIn, "olButton"); │ │ │ │ │ + if (!zoomOut) { │ │ │ │ │ + zoomOut = document.createElement("a"); │ │ │ │ │ + zoomOut.href = "#zoomOut"; │ │ │ │ │ + zoomOut.appendChild(document.createTextNode(this.zoomOutText)); │ │ │ │ │ + zoomOut.className = "olControlZoomOut"; │ │ │ │ │ + el.appendChild(zoomOut); │ │ │ │ │ + } │ │ │ │ │ + OpenLayers.Element.addClass(zoomOut, "olButton"); │ │ │ │ │ + return { │ │ │ │ │ + zoomIn: zoomIn, │ │ │ │ │ + zoomOut: zoomOut │ │ │ │ │ + }; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - addRenderer: function(topRelem, renderer) { │ │ │ │ │ - if (OpenLayers.Util.isArray(renderer)) { │ │ │ │ │ - this.addGroupRenderer(topRelem, renderer); │ │ │ │ │ - } else { │ │ │ │ │ - var renderElem = this.createElementNS("", renderer.type.toUpperCase() + "RENDERER"); │ │ │ │ │ - topRelem.appendChild(renderElem); │ │ │ │ │ + /** │ │ │ │ │ + * Method: onZoomClick │ │ │ │ │ + * Called when zoomin/out link is clicked. │ │ │ │ │ + */ │ │ │ │ │ + onZoomClick: function(evt) { │ │ │ │ │ + var button = evt.buttonElement; │ │ │ │ │ + if (button === this.zoomInLink) { │ │ │ │ │ + this.map.zoomIn(); │ │ │ │ │ + } else if (button === this.zoomOutLink) { │ │ │ │ │ + this.map.zoomOut(); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (renderElem.tagName == "VALUEMAPRENDERER") { │ │ │ │ │ - this.addValueMapRenderer(renderElem, renderer); │ │ │ │ │ - } else if (renderElem.tagName == "VALUEMAPLABELRENDERER") { │ │ │ │ │ - this.addValueMapLabelRenderer(renderElem, renderer); │ │ │ │ │ - } else if (renderElem.tagName == "SIMPLELABELRENDERER") { │ │ │ │ │ - this.addSimpleLabelRenderer(renderElem, renderer); │ │ │ │ │ - } else if (renderElem.tagName == "SCALEDEPENDENTRENDERER") { │ │ │ │ │ - this.addScaleDependentRenderer(renderElem, renderer); │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroy │ │ │ │ │ + * Clean up. │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + if (this.map) { │ │ │ │ │ + this.map.events.unregister("buttonclick", this, this.onZoomClick); │ │ │ │ │ } │ │ │ │ │ + delete this.zoomInLink; │ │ │ │ │ + delete this.zoomOutLink; │ │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Zoom" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Control/Attribution.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - addScaleDependentRenderer: function(renderElem, renderer) { │ │ │ │ │ - if (typeof renderer.lower == "string" || typeof renderer.lower == "number") { │ │ │ │ │ - renderElem.setAttribute("lower", renderer.lower); │ │ │ │ │ - } │ │ │ │ │ - if (typeof renderer.upper == "string" || typeof renderer.upper == "number") { │ │ │ │ │ - renderElem.setAttribute("upper", renderer.upper); │ │ │ │ │ - } │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - this.addRenderer(renderElem, renderer.renderer); │ │ │ │ │ - }, │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.Attribution │ │ │ │ │ + * The attribution control adds attribution from layers to the map display. │ │ │ │ │ + * It uses 'attribution' property of each layer. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.Attribution = │ │ │ │ │ + OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ │ │ - addValueMapLabelRenderer: function(renderElem, renderer) { │ │ │ │ │ - renderElem.setAttribute("lookupfield", renderer.lookupfield); │ │ │ │ │ - renderElem.setAttribute("labelfield", renderer.labelfield); │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: separator │ │ │ │ │ + * {String} String used to separate layers. │ │ │ │ │ + */ │ │ │ │ │ + separator: ", ", │ │ │ │ │ │ │ │ │ │ - if (typeof renderer.exacts == "object") { │ │ │ │ │ - for (var ext = 0, extlen = renderer.exacts.length; ext < extlen; ext++) { │ │ │ │ │ - var exact = renderer.exacts[ext]; │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: template │ │ │ │ │ + * {String} Template for the attribution. This has to include the substring │ │ │ │ │ + * "${layers}", which will be replaced by the layer specific │ │ │ │ │ + * attributions, separated by . The default is "${layers}". │ │ │ │ │ + */ │ │ │ │ │ + template: "${layers}", │ │ │ │ │ │ │ │ │ │ - var eelem = this.createElementNS("", "EXACT"); │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Control.Attribution │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} Options for control. │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - if (typeof exact.value == "string") { │ │ │ │ │ - eelem.setAttribute("value", exact.value); │ │ │ │ │ - } │ │ │ │ │ - if (typeof exact.label == "string") { │ │ │ │ │ - eelem.setAttribute("label", exact.label); │ │ │ │ │ - } │ │ │ │ │ - if (typeof exact.method == "string") { │ │ │ │ │ - eelem.setAttribute("method", exact.method); │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroy │ │ │ │ │ + * Destroy control. │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + this.map.events.un({ │ │ │ │ │ + "removelayer": this.updateAttribution, │ │ │ │ │ + "addlayer": this.updateAttribution, │ │ │ │ │ + "changelayer": this.updateAttribution, │ │ │ │ │ + "changebaselayer": this.updateAttribution, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ │ │ │ │ │ - renderElem.appendChild(eelem); │ │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (typeof exact.symbol == "object") { │ │ │ │ │ - var selem = null; │ │ │ │ │ + /** │ │ │ │ │ + * Method: draw │ │ │ │ │ + * Initialize control. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {DOMElement} A reference to the DIV DOMElement containing the control │ │ │ │ │ + */ │ │ │ │ │ + draw: function() { │ │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ │ │ │ │ │ │ - if (exact.symbol.type == "text") { │ │ │ │ │ - selem = this.createElementNS("", "TEXTSYMBOL"); │ │ │ │ │ - } │ │ │ │ │ + this.map.events.on({ │ │ │ │ │ + 'changebaselayer': this.updateAttribution, │ │ │ │ │ + 'changelayer': this.updateAttribution, │ │ │ │ │ + 'addlayer': this.updateAttribution, │ │ │ │ │ + 'removelayer': this.updateAttribution, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + this.updateAttribution(); │ │ │ │ │ │ │ │ │ │ - if (selem != null) { │ │ │ │ │ - var keys = this.fontStyleKeys; │ │ │ │ │ - for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ │ - var key = keys[i]; │ │ │ │ │ - if (exact.symbol[key]) { │ │ │ │ │ - selem.setAttribute(key, exact.symbol[key]); │ │ │ │ │ - } │ │ │ │ │ + return this.div; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: updateAttribution │ │ │ │ │ + * Update attribution string. │ │ │ │ │ + */ │ │ │ │ │ + updateAttribution: function() { │ │ │ │ │ + var attributions = []; │ │ │ │ │ + if (this.map && this.map.layers) { │ │ │ │ │ + for (var i = 0, len = this.map.layers.length; i < len; i++) { │ │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ │ + if (layer.attribution && layer.getVisibility()) { │ │ │ │ │ + // add attribution only if attribution text is unique │ │ │ │ │ + if (OpenLayers.Util.indexOf( │ │ │ │ │ + attributions, layer.attribution) === -1) { │ │ │ │ │ + attributions.push(layer.attribution); │ │ │ │ │ } │ │ │ │ │ - eelem.appendChild(selem); │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ - } // for each exact │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - addValueMapRenderer: function(renderElem, renderer) { │ │ │ │ │ - renderElem.setAttribute("lookupfield", renderer.lookupfield); │ │ │ │ │ + this.div.innerHTML = OpenLayers.String.format(this.template, { │ │ │ │ │ + layers: attributions.join(this.separator) │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (typeof renderer.ranges == "object") { │ │ │ │ │ - for (var rng = 0, rnglen = renderer.ranges.length; rng < rnglen; rng++) { │ │ │ │ │ - var range = renderer.ranges[rng]; │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Attribution" │ │ │ │ │ + }); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Control/TouchNavigation.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - var relem = this.createElementNS("", "RANGE"); │ │ │ │ │ - relem.setAttribute("lower", range.lower); │ │ │ │ │ - relem.setAttribute("upper", range.upper); │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - renderElem.appendChild(relem); │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Control/DragPan.js │ │ │ │ │ + * @requires OpenLayers/Control/PinchZoom.js │ │ │ │ │ + * @requires OpenLayers/Handler/Click.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - if (typeof range.symbol == "object") { │ │ │ │ │ - var selem = null; │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.TouchNavigation │ │ │ │ │ + * The navigation control handles map browsing with touch events (dragging, │ │ │ │ │ + * double-tapping, tap with two fingers, and pinch zoom). Create a new │ │ │ │ │ + * control with the constructor. │ │ │ │ │ + * │ │ │ │ │ + * If you’re only targeting touch enabled devices with your mapping application, │ │ │ │ │ + * you can create a map with only a TouchNavigation control. The │ │ │ │ │ + * control is mobile ready by default, but │ │ │ │ │ + * you can generate a smaller build of the library by only including this │ │ │ │ │ + * touch navigation control if you aren't concerned about mouse interaction. │ │ │ │ │ + * │ │ │ │ │ + * Inherits: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.TouchNavigation = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ │ │ - if (range.symbol.type == "simplepolygon") { │ │ │ │ │ - selem = this.createElementNS("", "SIMPLEPOLYGONSYMBOL"); │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Property: dragPan │ │ │ │ │ + * {} │ │ │ │ │ + */ │ │ │ │ │ + dragPan: null, │ │ │ │ │ │ │ │ │ │ - if (selem != null) { │ │ │ │ │ - if (typeof range.symbol.boundarycolor == "string") { │ │ │ │ │ - selem.setAttribute("boundarycolor", range.symbol.boundarycolor); │ │ │ │ │ - } │ │ │ │ │ - if (typeof range.symbol.fillcolor == "string") { │ │ │ │ │ - selem.setAttribute("fillcolor", range.symbol.fillcolor); │ │ │ │ │ - } │ │ │ │ │ - if (typeof range.symbol.filltransparency == "number") { │ │ │ │ │ - selem.setAttribute("filltransparency", range.symbol.filltransparency); │ │ │ │ │ - } │ │ │ │ │ - relem.appendChild(selem); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } // for each range │ │ │ │ │ - } else if (typeof renderer.exacts == "object") { │ │ │ │ │ - for (var ext = 0, extlen = renderer.exacts.length; ext < extlen; ext++) { │ │ │ │ │ - var exact = renderer.exacts[ext]; │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: dragPanOptions │ │ │ │ │ + * {Object} Options passed to the DragPan control. │ │ │ │ │ + */ │ │ │ │ │ + dragPanOptions: null, │ │ │ │ │ │ │ │ │ │ - var eelem = this.createElementNS("", "EXACT"); │ │ │ │ │ - if (typeof exact.value == "string") { │ │ │ │ │ - eelem.setAttribute("value", exact.value); │ │ │ │ │ - } │ │ │ │ │ - if (typeof exact.label == "string") { │ │ │ │ │ - eelem.setAttribute("label", exact.label); │ │ │ │ │ - } │ │ │ │ │ - if (typeof exact.method == "string") { │ │ │ │ │ - eelem.setAttribute("method", exact.method); │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Property: pinchZoom │ │ │ │ │ + * {} │ │ │ │ │ + */ │ │ │ │ │ + pinchZoom: null, │ │ │ │ │ │ │ │ │ │ - renderElem.appendChild(eelem); │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: pinchZoomOptions │ │ │ │ │ + * {Object} Options passed to the PinchZoom control. │ │ │ │ │ + */ │ │ │ │ │ + pinchZoomOptions: null, │ │ │ │ │ │ │ │ │ │ - if (typeof exact.symbol == "object") { │ │ │ │ │ - var selem = null; │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: clickHandlerOptions │ │ │ │ │ + * {Object} Options passed to the Click handler. │ │ │ │ │ + */ │ │ │ │ │ + clickHandlerOptions: null, │ │ │ │ │ │ │ │ │ │ - if (exact.symbol.type == "simplemarker") { │ │ │ │ │ - selem = this.createElementNS("", "SIMPLEMARKERSYMBOL"); │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: documentDrag │ │ │ │ │ + * {Boolean} Allow panning of the map by dragging outside map viewport. │ │ │ │ │ + * Default is false. │ │ │ │ │ + */ │ │ │ │ │ + documentDrag: false, │ │ │ │ │ │ │ │ │ │ - if (selem != null) { │ │ │ │ │ - if (typeof exact.symbol.antialiasing == "string") { │ │ │ │ │ - selem.setAttribute("antialiasing", exact.symbol.antialiasing); │ │ │ │ │ - } │ │ │ │ │ - if (typeof exact.symbol.color == "string") { │ │ │ │ │ - selem.setAttribute("color", exact.symbol.color); │ │ │ │ │ - } │ │ │ │ │ - if (typeof exact.symbol.outline == "string") { │ │ │ │ │ - selem.setAttribute("outline", exact.symbol.outline); │ │ │ │ │ - } │ │ │ │ │ - if (typeof exact.symbol.overlap == "string") { │ │ │ │ │ - selem.setAttribute("overlap", exact.symbol.overlap); │ │ │ │ │ - } │ │ │ │ │ - if (typeof exact.symbol.shadow == "string") { │ │ │ │ │ - selem.setAttribute("shadow", exact.symbol.shadow); │ │ │ │ │ - } │ │ │ │ │ - if (typeof exact.symbol.transparency == "number") { │ │ │ │ │ - selem.setAttribute("transparency", exact.symbol.transparency); │ │ │ │ │ - } │ │ │ │ │ - //if (typeof exact.symbol.type == "string") │ │ │ │ │ - // selem.setAttribute("type", exact.symbol.type); │ │ │ │ │ - if (typeof exact.symbol.usecentroid == "string") { │ │ │ │ │ - selem.setAttribute("usecentroid", exact.symbol.usecentroid); │ │ │ │ │ - } │ │ │ │ │ - if (typeof exact.symbol.width == "number") { │ │ │ │ │ - selem.setAttribute("width", exact.symbol.width); │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: autoActivate │ │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ │ + * true. │ │ │ │ │ + */ │ │ │ │ │ + autoActivate: true, │ │ │ │ │ │ │ │ │ │ - eelem.appendChild(selem); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } // for each exact │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Control.TouchNavigation │ │ │ │ │ + * Create a new navigation control │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ │ + * the control │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + this.handlers = {}; │ │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ - addSimpleLabelRenderer: function(renderElem, renderer) { │ │ │ │ │ - renderElem.setAttribute("field", renderer.field); │ │ │ │ │ - var keys = ['featureweight', 'howmanylabels', 'labelbufferratio', │ │ │ │ │ - 'labelpriorities', 'labelweight', 'linelabelposition', │ │ │ │ │ - 'rotationalangles' │ │ │ │ │ - ]; │ │ │ │ │ - for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ │ - var key = keys[i]; │ │ │ │ │ - if (renderer[key]) { │ │ │ │ │ - renderElem.setAttribute(key, renderer[key]); │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroy │ │ │ │ │ + * The destroy method is used to perform any clean up before the control │ │ │ │ │ + * is dereferenced. Typically this is where event listeners are removed │ │ │ │ │ + * to prevent memory leaks. │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + this.deactivate(); │ │ │ │ │ + if (this.dragPan) { │ │ │ │ │ + this.dragPan.destroy(); │ │ │ │ │ } │ │ │ │ │ - │ │ │ │ │ - if (renderer.symbol.type == "text") { │ │ │ │ │ - var symbol = renderer.symbol; │ │ │ │ │ - var selem = this.createElementNS("", "TEXTSYMBOL"); │ │ │ │ │ - renderElem.appendChild(selem); │ │ │ │ │ - │ │ │ │ │ - var keys = this.fontStyleKeys; │ │ │ │ │ - for (var i = 0, len = keys.length; i < len; i++) { │ │ │ │ │ - var key = keys[i]; │ │ │ │ │ - if (symbol[key]) { │ │ │ │ │ - selem.setAttribute(key, renderer[key]); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ + this.dragPan = null; │ │ │ │ │ + if (this.pinchZoom) { │ │ │ │ │ + this.pinchZoom.destroy(); │ │ │ │ │ + delete this.pinchZoom; │ │ │ │ │ } │ │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - writePolygonGeometry: function(polygon) { │ │ │ │ │ - if (!(polygon instanceof OpenLayers.Geometry.Polygon)) { │ │ │ │ │ - throw { │ │ │ │ │ - message: 'Cannot write polygon geometry to ArcXML with an ' + │ │ │ │ │ - polygon.CLASS_NAME + ' object.', │ │ │ │ │ - geometry: polygon │ │ │ │ │ - }; │ │ │ │ │ + /** │ │ │ │ │ + * Method: activate │ │ │ │ │ + */ │ │ │ │ │ + activate: function() { │ │ │ │ │ + if (OpenLayers.Control.prototype.activate.apply(this, arguments)) { │ │ │ │ │ + this.dragPan.activate(); │ │ │ │ │ + this.handlers.click.activate(); │ │ │ │ │ + this.pinchZoom.activate(); │ │ │ │ │ + return true; │ │ │ │ │ } │ │ │ │ │ + return false; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var polyElem = this.createElementNS("", "POLYGON"); │ │ │ │ │ - │ │ │ │ │ - for (var ln = 0, lnlen = polygon.components.length; ln < lnlen; ln++) { │ │ │ │ │ - var ring = polygon.components[ln]; │ │ │ │ │ - var ringElem = this.createElementNS("", "RING"); │ │ │ │ │ - │ │ │ │ │ - for (var rn = 0, rnlen = ring.components.length; rn < rnlen; rn++) { │ │ │ │ │ - var point = ring.components[rn]; │ │ │ │ │ - var pointElem = this.createElementNS("", "POINT"); │ │ │ │ │ - │ │ │ │ │ - pointElem.setAttribute("x", point.x); │ │ │ │ │ - pointElem.setAttribute("y", point.y); │ │ │ │ │ - │ │ │ │ │ - ringElem.appendChild(pointElem); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - polyElem.appendChild(ringElem); │ │ │ │ │ + /** │ │ │ │ │ + * Method: deactivate │ │ │ │ │ + */ │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { │ │ │ │ │ + this.dragPan.deactivate(); │ │ │ │ │ + this.handlers.click.deactivate(); │ │ │ │ │ + this.pinchZoom.deactivate(); │ │ │ │ │ + return true; │ │ │ │ │ } │ │ │ │ │ + return false; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - return polyElem; │ │ │ │ │ + /** │ │ │ │ │ + * Method: draw │ │ │ │ │ + */ │ │ │ │ │ + draw: function() { │ │ │ │ │ + var clickCallbacks = { │ │ │ │ │ + click: this.defaultClick, │ │ │ │ │ + dblclick: this.defaultDblClick │ │ │ │ │ + }; │ │ │ │ │ + var clickOptions = OpenLayers.Util.extend({ │ │ │ │ │ + "double": true, │ │ │ │ │ + stopDouble: true, │ │ │ │ │ + pixelTolerance: 2 │ │ │ │ │ + }, this.clickHandlerOptions); │ │ │ │ │ + this.handlers.click = new OpenLayers.Handler.Click( │ │ │ │ │ + this, clickCallbacks, clickOptions │ │ │ │ │ + ); │ │ │ │ │ + this.dragPan = new OpenLayers.Control.DragPan( │ │ │ │ │ + OpenLayers.Util.extend({ │ │ │ │ │ + map: this.map, │ │ │ │ │ + documentDrag: this.documentDrag │ │ │ │ │ + }, this.dragPanOptions) │ │ │ │ │ + ); │ │ │ │ │ + this.dragPan.draw(); │ │ │ │ │ + this.pinchZoom = new OpenLayers.Control.PinchZoom( │ │ │ │ │ + OpenLayers.Util.extend({ │ │ │ │ │ + map: this.map │ │ │ │ │ + }, this.pinchZoomOptions) │ │ │ │ │ + ); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: parseResponse │ │ │ │ │ - * Take an ArcXML response, and parse in into this object's internal properties. │ │ │ │ │ + * Method: defaultClick │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * data - {String} or {DOMElement} The ArcXML response, as either a string or the │ │ │ │ │ - * top level DOMElement of the response. │ │ │ │ │ + * evt - {Event} │ │ │ │ │ */ │ │ │ │ │ - parseResponse: function(data) { │ │ │ │ │ - if (typeof data == "string") { │ │ │ │ │ - var newData = new OpenLayers.Format.XML(); │ │ │ │ │ - data = newData.read(data); │ │ │ │ │ + defaultClick: function(evt) { │ │ │ │ │ + if (evt.lastTouches && evt.lastTouches.length == 2) { │ │ │ │ │ + this.map.zoomOut(); │ │ │ │ │ } │ │ │ │ │ - var response = new OpenLayers.Format.ArcXML.Response(); │ │ │ │ │ - │ │ │ │ │ - var errorNode = data.getElementsByTagName("ERROR"); │ │ │ │ │ - │ │ │ │ │ - if (errorNode != null && errorNode.length > 0) { │ │ │ │ │ - response.error = this.getChildValue(errorNode, "Unknown error."); │ │ │ │ │ - } else { │ │ │ │ │ - var responseNode = data.getElementsByTagName("RESPONSE"); │ │ │ │ │ - │ │ │ │ │ - if (responseNode == null || responseNode.length == 0) { │ │ │ │ │ - response.error = "No RESPONSE tag found in ArcXML response."; │ │ │ │ │ - return response; │ │ │ │ │ - } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var rtype = responseNode[0].firstChild.nodeName; │ │ │ │ │ - if (rtype == "#text") { │ │ │ │ │ - rtype = responseNode[0].firstChild.nextSibling.nodeName; │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Method: defaultDblClick │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {Event} │ │ │ │ │ + */ │ │ │ │ │ + defaultDblClick: function(evt) { │ │ │ │ │ + this.map.zoomTo(this.map.zoom + 1, evt.xy); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (rtype == "IMAGE") { │ │ │ │ │ - var envelopeNode = data.getElementsByTagName("ENVELOPE"); │ │ │ │ │ - var outputNode = data.getElementsByTagName("OUTPUT"); │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.TouchNavigation" │ │ │ │ │ +}); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Control/DrawFeature.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ │ │ │ │ │ - if (envelopeNode == null || envelopeNode.length == 0) { │ │ │ │ │ - response.error = "No ENVELOPE tag found in ArcXML response."; │ │ │ │ │ - } else if (outputNode == null || outputNode.length == 0) { │ │ │ │ │ - response.error = "No OUTPUT tag found in ArcXML response."; │ │ │ │ │ - } else { │ │ │ │ │ - var envAttr = this.parseAttributes(envelopeNode[0]); │ │ │ │ │ - var outputAttr = this.parseAttributes(outputNode[0]); │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - if (typeof outputAttr.type == "string") { │ │ │ │ │ - response.image = { │ │ │ │ │ - envelope: envAttr, │ │ │ │ │ - output: { │ │ │ │ │ - type: outputAttr.type, │ │ │ │ │ - data: this.getChildValue(outputNode[0]) │ │ │ │ │ - } │ │ │ │ │ - }; │ │ │ │ │ - } else { │ │ │ │ │ - response.image = { │ │ │ │ │ - envelope: envAttr, │ │ │ │ │ - output: outputAttr │ │ │ │ │ - }; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } else if (rtype == "FEATURES") { │ │ │ │ │ - var features = responseNode[0].getElementsByTagName("FEATURES"); │ │ │ │ │ │ │ │ │ │ - // get the feature count │ │ │ │ │ - var featureCount = features[0].getElementsByTagName("FEATURECOUNT"); │ │ │ │ │ - response.features.featurecount = featureCount[0].getAttribute("count"); │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ │ + * @requires OpenLayers/Feature/Vector.js │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - if (response.features.featurecount > 0) { │ │ │ │ │ - // get the feature envelope │ │ │ │ │ - var envelope = features[0].getElementsByTagName("ENVELOPE"); │ │ │ │ │ - response.features.envelope = this.parseAttributes(envelope[0], typeof(0)); │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.DrawFeature │ │ │ │ │ + * The DrawFeature control draws point, line or polygon features on a vector │ │ │ │ │ + * layer when active. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.DrawFeature = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ │ │ - // get the field values per feature │ │ │ │ │ - var featureList = features[0].getElementsByTagName("FEATURE"); │ │ │ │ │ - for (var fn = 0; fn < featureList.length; fn++) { │ │ │ │ │ - var feature = new OpenLayers.Feature.Vector(); │ │ │ │ │ - var fields = featureList[fn].getElementsByTagName("FIELD"); │ │ │ │ │ + /** │ │ │ │ │ + * Property: layer │ │ │ │ │ + * {} │ │ │ │ │ + */ │ │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ │ │ - for (var fdn = 0; fdn < fields.length; fdn++) { │ │ │ │ │ - var fieldName = fields[fdn].getAttribute("name"); │ │ │ │ │ - var fieldValue = fields[fdn].getAttribute("value"); │ │ │ │ │ - feature.attributes[fieldName] = fieldValue; │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Property: callbacks │ │ │ │ │ + * {Object} The functions that are sent to the handler for callback │ │ │ │ │ + */ │ │ │ │ │ + callbacks: null, │ │ │ │ │ │ │ │ │ │ - var geom = featureList[fn].getElementsByTagName("POLYGON"); │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: events │ │ │ │ │ + * {} Events instance for listeners and triggering │ │ │ │ │ + * control specific events. │ │ │ │ │ + * │ │ │ │ │ + * Register a listener for a particular event with the following syntax: │ │ │ │ │ + * (code) │ │ │ │ │ + * control.events.register(type, obj, listener); │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Supported event types (in addition to those from ): │ │ │ │ │ + * featureadded - Triggered when a feature is added │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - if (geom.length > 0) { │ │ │ │ │ - // if there is a polygon, create an openlayers polygon, and assign │ │ │ │ │ - // it to the .geometry property of the feature │ │ │ │ │ - var ring = geom[0].getElementsByTagName("RING"); │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: multi │ │ │ │ │ + * {Boolean} Cast features to multi-part geometries before passing to the │ │ │ │ │ + * layer. Default is false. │ │ │ │ │ + */ │ │ │ │ │ + multi: false, │ │ │ │ │ │ │ │ │ │ - var polys = []; │ │ │ │ │ - for (var rn = 0; rn < ring.length; rn++) { │ │ │ │ │ - var linearRings = []; │ │ │ │ │ - linearRings.push(this.parsePointGeometry(ring[rn])); │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: featureAdded │ │ │ │ │ + * {Function} Called after each feature is added │ │ │ │ │ + */ │ │ │ │ │ + featureAdded: function() {}, │ │ │ │ │ │ │ │ │ │ - var holes = ring[rn].getElementsByTagName("HOLE"); │ │ │ │ │ - for (var hn = 0; hn < holes.length; hn++) { │ │ │ │ │ - linearRings.push(this.parsePointGeometry(holes[hn])); │ │ │ │ │ - } │ │ │ │ │ - holes = null; │ │ │ │ │ - polys.push(new OpenLayers.Geometry.Polygon(linearRings)); │ │ │ │ │ - linearRings = null; │ │ │ │ │ - } │ │ │ │ │ - ring = null; │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: handlerOptions │ │ │ │ │ + * {Object} Used to set non-default properties on the control's handler │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ - if (polys.length == 1) { │ │ │ │ │ - feature.geometry = polys[0]; │ │ │ │ │ - } else { │ │ │ │ │ - feature.geometry = new OpenLayers.Geometry.MultiPolygon(polys); │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Control.DrawFeature │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * layer - {} │ │ │ │ │ + * handler - {} │ │ │ │ │ + * options - {Object} │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(layer, handler, options) { │ │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ │ + this.callbacks = OpenLayers.Util.extend({ │ │ │ │ │ + done: this.drawFeature, │ │ │ │ │ + modify: function(vertex, feature) { │ │ │ │ │ + this.layer.events.triggerEvent( │ │ │ │ │ + "sketchmodified", { │ │ │ │ │ + vertex: vertex, │ │ │ │ │ + feature: feature │ │ │ │ │ } │ │ │ │ │ - │ │ │ │ │ - response.features.feature.push(feature); │ │ │ │ │ - } │ │ │ │ │ + ); │ │ │ │ │ + }, │ │ │ │ │ + create: function(vertex, feature) { │ │ │ │ │ + this.layer.events.triggerEvent( │ │ │ │ │ + "sketchstarted", { │ │ │ │ │ + vertex: vertex, │ │ │ │ │ + feature: feature │ │ │ │ │ + } │ │ │ │ │ + ); │ │ │ │ │ } │ │ │ │ │ - } else { │ │ │ │ │ - response.error = "Unidentified response type."; │ │ │ │ │ + }, │ │ │ │ │ + this.callbacks │ │ │ │ │ + ); │ │ │ │ │ + this.layer = layer; │ │ │ │ │ + this.handlerOptions = this.handlerOptions || {}; │ │ │ │ │ + this.handlerOptions.layerOptions = OpenLayers.Util.applyDefaults( │ │ │ │ │ + this.handlerOptions.layerOptions, { │ │ │ │ │ + renderers: layer.renderers, │ │ │ │ │ + rendererOptions: layer.rendererOptions │ │ │ │ │ } │ │ │ │ │ + ); │ │ │ │ │ + if (!("multi" in this.handlerOptions)) { │ │ │ │ │ + this.handlerOptions.multi = this.multi; │ │ │ │ │ } │ │ │ │ │ - return response; │ │ │ │ │ + var sketchStyle = this.layer.styleMap && this.layer.styleMap.styles.temporary; │ │ │ │ │ + if (sketchStyle) { │ │ │ │ │ + this.handlerOptions.layerOptions = OpenLayers.Util.applyDefaults( │ │ │ │ │ + this.handlerOptions.layerOptions, { │ │ │ │ │ + styleMap: new OpenLayers.StyleMap({ │ │ │ │ │ + "default": sketchStyle │ │ │ │ │ + }) │ │ │ │ │ + } │ │ │ │ │ + ); │ │ │ │ │ + } │ │ │ │ │ + this.handler = new handler(this, this.callbacks, this.handlerOptions); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ + /** │ │ │ │ │ + * Method: drawFeature │ │ │ │ │ + */ │ │ │ │ │ + drawFeature: function(geometry) { │ │ │ │ │ + var feature = new OpenLayers.Feature.Vector(geometry); │ │ │ │ │ + var proceed = this.layer.events.triggerEvent( │ │ │ │ │ + "sketchcomplete", { │ │ │ │ │ + feature: feature │ │ │ │ │ + } │ │ │ │ │ + ); │ │ │ │ │ + if (proceed !== false) { │ │ │ │ │ + feature.state = OpenLayers.State.INSERT; │ │ │ │ │ + this.layer.addFeatures([feature]); │ │ │ │ │ + this.featureAdded(feature); │ │ │ │ │ + this.events.triggerEvent("featureadded", { │ │ │ │ │ + feature: feature │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: parseAttributes │ │ │ │ │ + * APIMethod: insertXY │ │ │ │ │ + * Insert a point in the current sketch given x & y coordinates. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * node - {} An element to parse attributes from. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} An attributes object, with properties set to attribute values. │ │ │ │ │ + * x - {Number} The x-coordinate of the point. │ │ │ │ │ + * y - {Number} The y-coordinate of the point. │ │ │ │ │ */ │ │ │ │ │ - parseAttributes: function(node, type) { │ │ │ │ │ - var attributes = {}; │ │ │ │ │ - for (var attr = 0; attr < node.attributes.length; attr++) { │ │ │ │ │ - if (type == "number") { │ │ │ │ │ - attributes[node.attributes[attr].nodeName] = parseFloat(node.attributes[attr].nodeValue); │ │ │ │ │ - } else { │ │ │ │ │ - attributes[node.attributes[attr].nodeName] = node.attributes[attr].nodeValue; │ │ │ │ │ - } │ │ │ │ │ + insertXY: function(x, y) { │ │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ │ + this.handler.insertXY(x, y); │ │ │ │ │ } │ │ │ │ │ - return attributes; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ /** │ │ │ │ │ - * Method: parsePointGeometry │ │ │ │ │ + * APIMethod: insertDeltaXY │ │ │ │ │ + * Insert a point given offsets from the previously inserted point. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * node - {} An element to parse or arcxml data from. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} A linear ring represented by the node's points. │ │ │ │ │ + * dx - {Number} The x-coordinate offset of the point. │ │ │ │ │ + * dy - {Number} The y-coordinate offset of the point. │ │ │ │ │ */ │ │ │ │ │ - parsePointGeometry: function(node) { │ │ │ │ │ - var ringPoints = []; │ │ │ │ │ - var coords = node.getElementsByTagName("COORDS"); │ │ │ │ │ - │ │ │ │ │ - if (coords.length > 0) { │ │ │ │ │ - // if coords is present, it's the only coords item │ │ │ │ │ - var coordArr = this.getChildValue(coords[0]); │ │ │ │ │ - coordArr = coordArr.split(/;/); │ │ │ │ │ - for (var cn = 0; cn < coordArr.length; cn++) { │ │ │ │ │ - var coordItems = coordArr[cn].split(/ /); │ │ │ │ │ - ringPoints.push(new OpenLayers.Geometry.Point(coordItems[0], coordItems[1])); │ │ │ │ │ - } │ │ │ │ │ - coords = null; │ │ │ │ │ - } else { │ │ │ │ │ - var point = node.getElementsByTagName("POINT"); │ │ │ │ │ - if (point.length > 0) { │ │ │ │ │ - for (var pn = 0; pn < point.length; pn++) { │ │ │ │ │ - ringPoints.push( │ │ │ │ │ - new OpenLayers.Geometry.Point( │ │ │ │ │ - parseFloat(point[pn].getAttribute("x")), │ │ │ │ │ - parseFloat(point[pn].getAttribute("y")) │ │ │ │ │ - ) │ │ │ │ │ - ); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - point = null; │ │ │ │ │ + insertDeltaXY: function(dx, dy) { │ │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ │ + this.handler.insertDeltaXY(dx, dy); │ │ │ │ │ } │ │ │ │ │ - │ │ │ │ │ - return new OpenLayers.Geometry.LinearRing(ringPoints); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.ArcXML" │ │ │ │ │ -}); │ │ │ │ │ - │ │ │ │ │ -OpenLayers.Format.ArcXML.Request = OpenLayers.Class({ │ │ │ │ │ - initialize: function(params) { │ │ │ │ │ - var defaults = { │ │ │ │ │ - get_image: { │ │ │ │ │ - properties: { │ │ │ │ │ - background: null, │ │ │ │ │ - /*{ │ │ │ │ │ - color: { r:255, g:255, b:255 }, │ │ │ │ │ - transcolor: null │ │ │ │ │ - },*/ │ │ │ │ │ - draw: true, │ │ │ │ │ - envelope: { │ │ │ │ │ - minx: 0, │ │ │ │ │ - miny: 0, │ │ │ │ │ - maxx: 0, │ │ │ │ │ - maxy: 0 │ │ │ │ │ - }, │ │ │ │ │ - featurecoordsys: { │ │ │ │ │ - id: 0, │ │ │ │ │ - string: "", │ │ │ │ │ - datumtransformid: 0, │ │ │ │ │ - datumtransformstring: "" │ │ │ │ │ - }, │ │ │ │ │ - filtercoordsys: { │ │ │ │ │ - id: 0, │ │ │ │ │ - string: "", │ │ │ │ │ - datumtransformid: 0, │ │ │ │ │ - datumtransformstring: "" │ │ │ │ │ - }, │ │ │ │ │ - imagesize: { │ │ │ │ │ - height: 0, │ │ │ │ │ - width: 0, │ │ │ │ │ - dpi: 96, │ │ │ │ │ - printheight: 0, │ │ │ │ │ - printwidth: 0, │ │ │ │ │ - scalesymbols: false │ │ │ │ │ - }, │ │ │ │ │ - layerlist: [], │ │ │ │ │ - /* no support for legends */ │ │ │ │ │ - output: { │ │ │ │ │ - baseurl: "", │ │ │ │ │ - legendbaseurl: "", │ │ │ │ │ - legendname: "", │ │ │ │ │ - legendpath: "", │ │ │ │ │ - legendurl: "", │ │ │ │ │ - name: "", │ │ │ │ │ - path: "", │ │ │ │ │ - type: "jpg", │ │ │ │ │ - url: "" │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - get_feature: { │ │ │ │ │ - layer: "", │ │ │ │ │ - query: { │ │ │ │ │ - isspatial: false, │ │ │ │ │ - featurecoordsys: { │ │ │ │ │ - id: 0, │ │ │ │ │ - string: "", │ │ │ │ │ - datumtransformid: 0, │ │ │ │ │ - datumtransformstring: "" │ │ │ │ │ - }, │ │ │ │ │ - filtercoordsys: { │ │ │ │ │ - id: 0, │ │ │ │ │ - string: "", │ │ │ │ │ - datumtransformid: 0, │ │ │ │ │ - datumtransformstring: "" │ │ │ │ │ - }, │ │ │ │ │ - buffer: 0, │ │ │ │ │ - where: "", │ │ │ │ │ - spatialfilter: { │ │ │ │ │ - relation: "envelope_intersection", │ │ │ │ │ - envelope: null │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - environment: { │ │ │ │ │ - separators: { │ │ │ │ │ - cs: " ", │ │ │ │ │ - ts: ";" │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - layer: [], │ │ │ │ │ - workspaces: [] │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - return OpenLayers.Util.extend(this, defaults); │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: insertDirectionLength │ │ │ │ │ + * Insert a point in the current sketch given a direction and a length. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * direction - {Number} Degrees clockwise from the positive x-axis. │ │ │ │ │ + * length - {Number} Distance from the previously drawn point. │ │ │ │ │ + */ │ │ │ │ │ + insertDirectionLength: function(direction, length) { │ │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ │ + this.handler.insertDirectionLength(direction, length); │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.ArcXML.Request" │ │ │ │ │ -}); │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: insertDeflectionLength │ │ │ │ │ + * Insert a point in the current sketch given a deflection and a length. │ │ │ │ │ + * The deflection should be degrees clockwise from the previously │ │ │ │ │ + * digitized segment. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * deflection - {Number} Degrees clockwise from the previous segment. │ │ │ │ │ + * length - {Number} Distance from the previously drawn point. │ │ │ │ │ + */ │ │ │ │ │ + insertDeflectionLength: function(deflection, length) { │ │ │ │ │ + if (this.handler && this.handler.line) { │ │ │ │ │ + this.handler.insertDeflectionLength(deflection, length); │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ -OpenLayers.Format.ArcXML.Response = OpenLayers.Class({ │ │ │ │ │ - initialize: function(params) { │ │ │ │ │ - var defaults = { │ │ │ │ │ - image: { │ │ │ │ │ - envelope: null, │ │ │ │ │ - output: '' │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: undo │ │ │ │ │ + * Remove the most recently added point in the current sketch geometry. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} An edit was undone. │ │ │ │ │ + */ │ │ │ │ │ + undo: function() { │ │ │ │ │ + return this.handler.undo && this.handler.undo(); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - features: { │ │ │ │ │ - featurecount: 0, │ │ │ │ │ - envelope: null, │ │ │ │ │ - feature: [] │ │ │ │ │ - }, │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: redo │ │ │ │ │ + * Reinsert the most recently removed point resulting from an call. │ │ │ │ │ + * The undo stack is deleted whenever a point is added by other means. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} An edit was redone. │ │ │ │ │ + */ │ │ │ │ │ + redo: function() { │ │ │ │ │ + return this.handler.redo && this.handler.redo(); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - error: '' │ │ │ │ │ - }; │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: finishSketch │ │ │ │ │ + * Finishes the sketch without including the currently drawn point. │ │ │ │ │ + * This method can be called to terminate drawing programmatically │ │ │ │ │ + * instead of waiting for the user to end the sketch. │ │ │ │ │ + */ │ │ │ │ │ + finishSketch: function() { │ │ │ │ │ + this.handler.finishGeometry(); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - return OpenLayers.Util.extend(this, defaults); │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: cancel │ │ │ │ │ + * Cancel the current sketch. This removes the current sketch and keeps │ │ │ │ │ + * the drawing control active. │ │ │ │ │ + */ │ │ │ │ │ + cancel: function() { │ │ │ │ │ + this.handler.cancel(); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.ArcXML.Response" │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.DrawFeature" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Layer/ArcIMS.js │ │ │ │ │ + OpenLayers/Control/Snapping.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Layer/Grid.js │ │ │ │ │ - * @requires OpenLayers/Format/ArcXML.js │ │ │ │ │ - * @requires OpenLayers/Request.js │ │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ │ + * @requires OpenLayers/Layer/Vector.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Layer.ArcIMS │ │ │ │ │ - * Instances of OpenLayers.Layer.ArcIMS are used to display data from ESRI ArcIMS │ │ │ │ │ - * Mapping Services. Create a new ArcIMS layer with the │ │ │ │ │ - * constructor. │ │ │ │ │ - * │ │ │ │ │ + * Class: OpenLayers.Control.Snapping │ │ │ │ │ + * Acts as a snapping agent while editing vector features. │ │ │ │ │ + * │ │ │ │ │ * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Layer.ArcIMS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ │ +OpenLayers.Control.Snapping = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: events │ │ │ │ │ + * {} Events instance for listeners and triggering │ │ │ │ │ + * control specific events. │ │ │ │ │ + * │ │ │ │ │ + * Register a listener for a particular event with the following syntax: │ │ │ │ │ + * (code) │ │ │ │ │ + * control.events.register(type, obj, listener); │ │ │ │ │ + * (end) │ │ │ │ │ + * │ │ │ │ │ + * Supported event types (in addition to those from ): │ │ │ │ │ + * beforesnap - Triggered before a snap occurs. Listeners receive an │ │ │ │ │ + * event object with *point*, *x*, *y*, *distance*, *layer*, and │ │ │ │ │ + * *snapType* properties. The point property will be original point │ │ │ │ │ + * geometry considered for snapping. The x and y properties represent │ │ │ │ │ + * coordinates the point will receive. The distance is the distance │ │ │ │ │ + * of the snap. The layer is the target layer. The snapType property │ │ │ │ │ + * will be one of "node", "vertex", or "edge". Return false to stop │ │ │ │ │ + * snapping from occurring. │ │ │ │ │ + * snap - Triggered when a snap occurs. Listeners receive an event with │ │ │ │ │ + * *point*, *snapType*, *layer*, and *distance* properties. The point │ │ │ │ │ + * will be the location snapped to. The snapType will be one of "node", │ │ │ │ │ + * "vertex", or "edge". The layer will be the target layer. The │ │ │ │ │ + * distance will be the distance of the snap in map units. │ │ │ │ │ + * unsnap - Triggered when a vertex is unsnapped. Listeners receive an │ │ │ │ │ + * event with a *point* property. │ │ │ │ │ + */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constant: DEFAULT_PARAMS │ │ │ │ │ - * {Object} Default query string parameters. │ │ │ │ │ + * CONSTANT: DEFAULTS │ │ │ │ │ + * Default target properties. │ │ │ │ │ */ │ │ │ │ │ - DEFAULT_PARAMS: { │ │ │ │ │ - ClientVersion: "9.2", │ │ │ │ │ - ServiceName: '' │ │ │ │ │ + DEFAULTS: { │ │ │ │ │ + tolerance: 10, │ │ │ │ │ + node: true, │ │ │ │ │ + edge: true, │ │ │ │ │ + vertex: true │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: featureCoordSys │ │ │ │ │ - * {String} Code for feature coordinate system. Default is "4326". │ │ │ │ │ + * Property: greedy │ │ │ │ │ + * {Boolean} Snap to closest feature in first layer with an eligible │ │ │ │ │ + * feature. Default is true. │ │ │ │ │ */ │ │ │ │ │ - featureCoordSys: "4326", │ │ │ │ │ + greedy: true, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: filterCoordSys │ │ │ │ │ - * {String} Code for filter coordinate system. Default is "4326". │ │ │ │ │ + * Property: precedence │ │ │ │ │ + * {Array} List representing precedence of different snapping types. │ │ │ │ │ + * Default is "node", "vertex", "edge". │ │ │ │ │ */ │ │ │ │ │ - filterCoordSys: "4326", │ │ │ │ │ + precedence: ["node", "vertex", "edge"], │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: layers │ │ │ │ │ - * {Array} An array of objects with layer properties. │ │ │ │ │ + * Property: resolution │ │ │ │ │ + * {Float} The map resolution for the previously considered snap. │ │ │ │ │ */ │ │ │ │ │ - layers: null, │ │ │ │ │ + resolution: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: async │ │ │ │ │ - * {Boolean} Request images asynchronously. Default is true. │ │ │ │ │ + * Property: geoToleranceCache │ │ │ │ │ + * {Object} A cache of geo-tolerances. Tolerance values (in map units) are │ │ │ │ │ + * calculated when the map resolution changes. │ │ │ │ │ */ │ │ │ │ │ - async: true, │ │ │ │ │ + geoToleranceCache: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: name │ │ │ │ │ - * {String} Layer name. Default is "ArcIMS". │ │ │ │ │ + * Property: layer │ │ │ │ │ + * {} The current editable layer. Set at │ │ │ │ │ + * construction or after construction with . │ │ │ │ │ */ │ │ │ │ │ - name: "ArcIMS", │ │ │ │ │ + layer: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ │ - * {Boolean} The layer is a base layer. Default is true. │ │ │ │ │ + * Property: feature │ │ │ │ │ + * {} The current editable feature. │ │ │ │ │ */ │ │ │ │ │ - isBaseLayer: true, │ │ │ │ │ + feature: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constant: DEFAULT_OPTIONS │ │ │ │ │ - * {Object} Default layers properties. │ │ │ │ │ + * Property: point │ │ │ │ │ + * {} The currently snapped vertex. │ │ │ │ │ */ │ │ │ │ │ - DEFAULT_OPTIONS: { │ │ │ │ │ - tileSize: new OpenLayers.Size(512, 512), │ │ │ │ │ - featureCoordSys: "4326", │ │ │ │ │ - filterCoordSys: "4326", │ │ │ │ │ - layers: null, │ │ │ │ │ - isBaseLayer: true, │ │ │ │ │ - async: true, │ │ │ │ │ - name: "ArcIMS" │ │ │ │ │ - }, │ │ │ │ │ + point: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Layer.ArcIMS │ │ │ │ │ - * Create a new ArcIMS layer object. │ │ │ │ │ - * │ │ │ │ │ - * Example: │ │ │ │ │ - * (code) │ │ │ │ │ - * var arcims = new OpenLayers.Layer.ArcIMS( │ │ │ │ │ - * "Global Sample", │ │ │ │ │ - * "http://sample.avencia.com/servlet/com.esri.esrimap.Esrimap", │ │ │ │ │ - * { │ │ │ │ │ - * service: "OpenLayers_Sample", │ │ │ │ │ - * layers: [ │ │ │ │ │ - * // layers to manipulate │ │ │ │ │ - * {id: "1", visible: true} │ │ │ │ │ - * ] │ │ │ │ │ - * } │ │ │ │ │ - * ); │ │ │ │ │ - * (end) │ │ │ │ │ + * Constructor: OpenLayers.Control.Snapping │ │ │ │ │ + * Creates a new snapping control. A control is constructed with an editable │ │ │ │ │ + * layer and a set of configuration objects for target layers. While the │ │ │ │ │ + * control is active, dragging vertices while drawing new features or │ │ │ │ │ + * modifying existing features on the editable layer will engage │ │ │ │ │ + * snapping to features on the target layers. Whether a vertex snaps to │ │ │ │ │ + * a feature on a target layer depends on the target layer configuration. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * name - {String} A name for the layer │ │ │ │ │ - * url - {String} Base url for the ArcIMS server │ │ │ │ │ - * options - {Object} Optional object with properties to be set on the │ │ │ │ │ + * options - {Object} An object containing all configuration properties for │ │ │ │ │ + * the control. │ │ │ │ │ + * │ │ │ │ │ + * Valid options: │ │ │ │ │ + * layer - {} The editable layer. Features from this │ │ │ │ │ + * layer that are digitized or modified may have vertices snapped to │ │ │ │ │ + * features from any of the target layers. │ │ │ │ │ + * targets - {Array(Object | OpenLayers.Layer.Vector)} A list of objects for │ │ │ │ │ + * configuring target layers. See valid properties of the target │ │ │ │ │ + * objects below. If the items in the targets list are vector layers │ │ │ │ │ + * (instead of configuration objects), the defaults from the │ │ │ │ │ + * property will apply. The editable layer itself may be a target │ │ │ │ │ + * layer, allowing newly created or edited features to be snapped to │ │ │ │ │ + * existing features from the same layer. If no targets are provided │ │ │ │ │ + * the layer given in the constructor (as ) will become the │ │ │ │ │ + * initial target. │ │ │ │ │ + * defaults - {Object} An object with default properties to be applied │ │ │ │ │ + * to all target objects. │ │ │ │ │ + * greedy - {Boolean} Snap to closest feature in first target layer that │ │ │ │ │ + * applies. Default is true. If false, all features in all target │ │ │ │ │ + * layers will be checked and the closest feature in all target layers │ │ │ │ │ + * will be chosen. The greedy property determines if the order of the │ │ │ │ │ + * target layers is significant. By default, the order of the target │ │ │ │ │ + * layers is significant where layers earlier in the target layer list │ │ │ │ │ + * have precedence over layers later in the list. Within a single │ │ │ │ │ + * layer, the closest feature is always chosen for snapping. This │ │ │ │ │ + * property only determines whether the search for a closer feature │ │ │ │ │ + * continues after an eligible feature is found in a target layer. │ │ │ │ │ + * │ │ │ │ │ + * Valid target properties: │ │ │ │ │ + * layer - {} A target layer. Features from this │ │ │ │ │ + * layer will be eligible to act as snapping target for the editable │ │ │ │ │ * layer. │ │ │ │ │ + * tolerance - {Float} The distance (in pixels) at which snapping may occur. │ │ │ │ │ + * Default is 10. │ │ │ │ │ + * node - {Boolean} Snap to nodes (first or last point in a geometry) in │ │ │ │ │ + * target layer. Default is true. │ │ │ │ │ + * nodeTolerance - {Float} Optional distance at which snapping may occur │ │ │ │ │ + * for nodes specifically. If none is provided, will be │ │ │ │ │ + * used. │ │ │ │ │ + * vertex - {Boolean} Snap to vertices in target layer. Default is true. │ │ │ │ │ + * vertexTolerance - {Float} Optional distance at which snapping may occur │ │ │ │ │ + * for vertices specifically. If none is provided, will be │ │ │ │ │ + * used. │ │ │ │ │ + * edge - {Boolean} Snap to edges in target layer. Default is true. │ │ │ │ │ + * edgeTolerance - {Float} Optional distance at which snapping may occur │ │ │ │ │ + * for edges specifically. If none is provided, will be │ │ │ │ │ + * used. │ │ │ │ │ + * filter - {} Optional filter to evaluate to determine if │ │ │ │ │ + * feature is eligible for snapping. If filter evaluates to true for a │ │ │ │ │ + * target feature a vertex may be snapped to the feature. │ │ │ │ │ + * minResolution - {Number} If a minResolution is provided, snapping to this │ │ │ │ │ + * target will only be considered if the map resolution is greater than │ │ │ │ │ + * or equal to this value (the minResolution is inclusive). Default is │ │ │ │ │ + * no minimum resolution limit. │ │ │ │ │ + * maxResolution - {Number} If a maxResolution is provided, snapping to this │ │ │ │ │ + * target will only be considered if the map resolution is strictly │ │ │ │ │ + * less than this value (the maxResolution is exclusive). Default is │ │ │ │ │ + * no maximum resolution limit. │ │ │ │ │ */ │ │ │ │ │ - initialize: function(name, url, options) { │ │ │ │ │ - │ │ │ │ │ - this.tileSize = new OpenLayers.Size(512, 512); │ │ │ │ │ - │ │ │ │ │ - // parameters │ │ │ │ │ - this.params = OpenLayers.Util.applyDefaults({ │ │ │ │ │ - ServiceName: options.serviceName │ │ │ │ │ - }, │ │ │ │ │ - this.DEFAULT_PARAMS │ │ │ │ │ - ); │ │ │ │ │ - this.options = OpenLayers.Util.applyDefaults( │ │ │ │ │ - options, this.DEFAULT_OPTIONS │ │ │ │ │ - ); │ │ │ │ │ - │ │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply( │ │ │ │ │ - this, [name, url, this.params, options] │ │ │ │ │ - ); │ │ │ │ │ - │ │ │ │ │ - //layer is transparent │ │ │ │ │ - if (this.transparent) { │ │ │ │ │ - │ │ │ │ │ - // unless explicitly set in options, make layer an overlay │ │ │ │ │ - if (!this.isBaseLayer) { │ │ │ │ │ - this.isBaseLayer = false; │ │ │ │ │ - } │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ │ + this.options = options || {}; // TODO: this could be done by the super │ │ │ │ │ │ │ │ │ │ - // jpegs can never be transparent, so intelligently switch the │ │ │ │ │ - // format, depending on the browser's capabilities │ │ │ │ │ - if (this.format == "image/jpeg") { │ │ │ │ │ - this.format = OpenLayers.Util.alphaHack() ? "image/gif" : "image/png"; │ │ │ │ │ - } │ │ │ │ │ + // set the editable layer if provided │ │ │ │ │ + if (this.options.layer) { │ │ │ │ │ + this.setLayer(this.options.layer); │ │ │ │ │ } │ │ │ │ │ - │ │ │ │ │ - // create an empty layer list if no layers specified in the options │ │ │ │ │ - if (this.options.layers === null) { │ │ │ │ │ - this.options.layers = []; │ │ │ │ │ + // configure target layers │ │ │ │ │ + var defaults = OpenLayers.Util.extend({}, this.options.defaults); │ │ │ │ │ + this.defaults = OpenLayers.Util.applyDefaults(defaults, this.DEFAULTS); │ │ │ │ │ + this.setTargets(this.options.targets); │ │ │ │ │ + if (this.targets.length === 0 && this.layer) { │ │ │ │ │ + this.addTargetLayer(this.layer); │ │ │ │ │ } │ │ │ │ │ + │ │ │ │ │ + this.geoToleranceCache = {}; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getURL │ │ │ │ │ - * Return an image url this layer. │ │ │ │ │ + * APIMethod: setLayer │ │ │ │ │ + * Set the editable layer. Call the setLayer method if the editable layer │ │ │ │ │ + * changes and the same control should be used on a new editable layer. │ │ │ │ │ + * If the control is already active, it will be active after the new │ │ │ │ │ + * layer is set. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * bounds - {} A bounds representing the bbox for the │ │ │ │ │ - * request. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} A string with the map image's url. │ │ │ │ │ + * layer - {} The new editable layer. │ │ │ │ │ */ │ │ │ │ │ - getURL: function(bounds) { │ │ │ │ │ - var url = ""; │ │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ │ - │ │ │ │ │ - // create an arcxml request to generate the image │ │ │ │ │ - var axlReq = new OpenLayers.Format.ArcXML( │ │ │ │ │ - OpenLayers.Util.extend(this.options, { │ │ │ │ │ - requesttype: "image", │ │ │ │ │ - envelope: bounds.toArray(), │ │ │ │ │ - tileSize: this.tileSize │ │ │ │ │ - }) │ │ │ │ │ - ); │ │ │ │ │ - │ │ │ │ │ - // create a synchronous ajax request to get an arcims image │ │ │ │ │ - var req = new OpenLayers.Request.POST({ │ │ │ │ │ - url: this.getFullRequestString(), │ │ │ │ │ - data: axlReq.write(), │ │ │ │ │ - async: false │ │ │ │ │ - }); │ │ │ │ │ - │ │ │ │ │ - // if the response exists │ │ │ │ │ - if (req != null) { │ │ │ │ │ - var doc = req.responseXML; │ │ │ │ │ - │ │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ │ - doc = req.responseText; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // create a new arcxml format to read the response │ │ │ │ │ - var axlResp = new OpenLayers.Format.ArcXML(); │ │ │ │ │ - var arcxml = axlResp.read(doc); │ │ │ │ │ - url = this.getUrlOrImage(arcxml.image.output); │ │ │ │ │ + setLayer: function(layer) { │ │ │ │ │ + if (this.active) { │ │ │ │ │ + this.deactivate(); │ │ │ │ │ + this.layer = layer; │ │ │ │ │ + this.activate(); │ │ │ │ │ + } else { │ │ │ │ │ + this.layer = layer; │ │ │ │ │ } │ │ │ │ │ - │ │ │ │ │ - return url; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ /** │ │ │ │ │ - * Method: getURLasync │ │ │ │ │ - * Get an image url this layer asynchronously, and execute a callback │ │ │ │ │ - * when the image url is generated. │ │ │ │ │ + * Method: setTargets │ │ │ │ │ + * Set the targets for the snapping agent. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * bounds - {} A bounds representing the bbox for the │ │ │ │ │ - * request. │ │ │ │ │ - * callback - {Function} Function to call when image url is retrieved. │ │ │ │ │ - * scope - {Object} The scope of the callback method. │ │ │ │ │ + * targets - {Array} An array of target configs or target layers. │ │ │ │ │ */ │ │ │ │ │ - getURLasync: function(bounds, callback, scope) { │ │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ │ - │ │ │ │ │ - // create an arcxml request to generate the image │ │ │ │ │ - var axlReq = new OpenLayers.Format.ArcXML( │ │ │ │ │ - OpenLayers.Util.extend(this.options, { │ │ │ │ │ - requesttype: "image", │ │ │ │ │ - envelope: bounds.toArray(), │ │ │ │ │ - tileSize: this.tileSize │ │ │ │ │ - }) │ │ │ │ │ - ); │ │ │ │ │ - │ │ │ │ │ - // create an asynchronous ajax request to get an arcims image │ │ │ │ │ - OpenLayers.Request.POST({ │ │ │ │ │ - url: this.getFullRequestString(), │ │ │ │ │ - async: true, │ │ │ │ │ - data: axlReq.write(), │ │ │ │ │ - callback: function(req) { │ │ │ │ │ - // process the response from ArcIMS, and call the callback function │ │ │ │ │ - // to set the image URL │ │ │ │ │ - var doc = req.responseXML; │ │ │ │ │ - if (!doc || !doc.documentElement) { │ │ │ │ │ - doc = req.responseText; │ │ │ │ │ + setTargets: function(targets) { │ │ │ │ │ + this.targets = []; │ │ │ │ │ + if (targets && targets.length) { │ │ │ │ │ + var target; │ │ │ │ │ + for (var i = 0, len = targets.length; i < len; ++i) { │ │ │ │ │ + target = targets[i]; │ │ │ │ │ + if (target instanceof OpenLayers.Layer.Vector) { │ │ │ │ │ + this.addTargetLayer(target); │ │ │ │ │ + } else { │ │ │ │ │ + this.addTarget(target); │ │ │ │ │ } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // create a new arcxml format to read the response │ │ │ │ │ - var axlResp = new OpenLayers.Format.ArcXML(); │ │ │ │ │ - var arcxml = axlResp.read(doc); │ │ │ │ │ - │ │ │ │ │ - callback.call(scope, this.getUrlOrImage(arcxml.image.output)); │ │ │ │ │ - }, │ │ │ │ │ - scope: this │ │ │ │ │ + /** │ │ │ │ │ + * Method: addTargetLayer │ │ │ │ │ + * Add a target layer with the default target config. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * layer - {} A target layer. │ │ │ │ │ + */ │ │ │ │ │ + addTargetLayer: function(layer) { │ │ │ │ │ + this.addTarget({ │ │ │ │ │ + layer: layer │ │ │ │ │ }); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getUrlOrImage │ │ │ │ │ - * Extract a url or image from the ArcXML image output. │ │ │ │ │ + * Method: addTarget │ │ │ │ │ + * Add a configured target layer. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * output - {Object} The image.output property of the object returned from │ │ │ │ │ - * the ArcXML format read method. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} A URL for an image (potentially with the data protocol). │ │ │ │ │ + * target - {Object} A target config. │ │ │ │ │ */ │ │ │ │ │ - getUrlOrImage: function(output) { │ │ │ │ │ - var ret = ""; │ │ │ │ │ - if (output.url) { │ │ │ │ │ - // If the image response output url is a string, then the image │ │ │ │ │ - // data is not inline. │ │ │ │ │ - ret = output.url; │ │ │ │ │ - } else if (output.data) { │ │ │ │ │ - // The image data is inline and base64 encoded, create a data │ │ │ │ │ - // url for the image. This will only work for small images, │ │ │ │ │ - // due to browser url length limits. │ │ │ │ │ - ret = "data:image/" + output.type + │ │ │ │ │ - ";base64," + output.data; │ │ │ │ │ - } │ │ │ │ │ - return ret; │ │ │ │ │ + addTarget: function(target) { │ │ │ │ │ + target = OpenLayers.Util.applyDefaults(target, this.defaults); │ │ │ │ │ + target.nodeTolerance = target.nodeTolerance || target.tolerance; │ │ │ │ │ + target.vertexTolerance = target.vertexTolerance || target.tolerance; │ │ │ │ │ + target.edgeTolerance = target.edgeTolerance || target.tolerance; │ │ │ │ │ + this.targets.push(target); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: setLayerQuery │ │ │ │ │ - * Set the query definition on this layer. Query definitions are used to │ │ │ │ │ - * render parts of the spatial data in an image, and can be used to │ │ │ │ │ - * filter features or layers in the ArcIMS service. │ │ │ │ │ + * Method: removeTargetLayer │ │ │ │ │ + * Remove a target layer. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * id - {String} The ArcIMS layer ID. │ │ │ │ │ - * querydef - {Object} The query definition to apply to this layer. │ │ │ │ │ + * layer - {} The target layer to remove. │ │ │ │ │ */ │ │ │ │ │ - setLayerQuery: function(id, querydef) { │ │ │ │ │ - // find the matching layer, if it exists │ │ │ │ │ - for (var lyr = 0; lyr < this.options.layers.length; lyr++) { │ │ │ │ │ - if (id == this.options.layers[lyr].id) { │ │ │ │ │ - // replace this layer definition │ │ │ │ │ - this.options.layers[lyr].query = querydef; │ │ │ │ │ - return; │ │ │ │ │ + removeTargetLayer: function(layer) { │ │ │ │ │ + var target; │ │ │ │ │ + for (var i = this.targets.length - 1; i >= 0; --i) { │ │ │ │ │ + target = this.targets[i]; │ │ │ │ │ + if (target.layer === layer) { │ │ │ │ │ + this.removeTarget(target); │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ - │ │ │ │ │ - // no layer found, create a new definition │ │ │ │ │ - this.options.layers.push({ │ │ │ │ │ - id: id, │ │ │ │ │ - visible: true, │ │ │ │ │ - query: querydef │ │ │ │ │ - }); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getFeatureInfo │ │ │ │ │ - * Get feature information from ArcIMS. Using the applied geometry, apply │ │ │ │ │ - * the options to the query (buffer, area/envelope intersection), and │ │ │ │ │ - * query the ArcIMS service. │ │ │ │ │ - * │ │ │ │ │ - * A note about accuracy: │ │ │ │ │ - * ArcIMS interprets the accuracy attribute in feature requests to be │ │ │ │ │ - * something like the 'modulus' operator on feature coordinates, │ │ │ │ │ - * applied to the database geometry of the feature. It doesn't round, │ │ │ │ │ - * so your feature coordinates may be up to (1 x accuracy) offset from │ │ │ │ │ - * the actual feature coordinates. If the accuracy of the layer is not │ │ │ │ │ - * specified, the accuracy will be computed to be approximately 1 │ │ │ │ │ - * feature coordinate per screen pixel. │ │ │ │ │ + * Method: removeTarget │ │ │ │ │ + * Remove a target. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * geometry - {} or {} The │ │ │ │ │ - * geometry to use when making the query. This should be a closed │ │ │ │ │ - * polygon for behavior approximating a free selection. │ │ │ │ │ - * layer - {Object} The ArcIMS layer definition. This is an anonymous object │ │ │ │ │ - * that looks like: │ │ │ │ │ - * (code) │ │ │ │ │ - * { │ │ │ │ │ - * id: "ArcXML layer ID", // the ArcXML layer ID │ │ │ │ │ - * query: { │ │ │ │ │ - * where: "STATE = 'PA'", // the where clause of the query │ │ │ │ │ - * accuracy: 100 // the accuracy of the returned feature │ │ │ │ │ - * } │ │ │ │ │ - * } │ │ │ │ │ - * (end) │ │ │ │ │ - * options - {Object} Object with non-default properties to set on the layer. │ │ │ │ │ - * Supported properties are buffer, callback, scope, and any other │ │ │ │ │ - * properties applicable to the ArcXML format. Set the 'callback' and │ │ │ │ │ - * 'scope' for an object and function to recieve the parsed features │ │ │ │ │ - * from ArcIMS. │ │ │ │ │ + * target - {Object} A target config. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Array} The targets array. │ │ │ │ │ */ │ │ │ │ │ - getFeatureInfo: function(geometry, layer, options) { │ │ │ │ │ - // set the buffer to 1 unit (dd/m/ft?) by default │ │ │ │ │ - var buffer = options.buffer || 1; │ │ │ │ │ - // empty callback by default │ │ │ │ │ - var callback = options.callback || function() {}; │ │ │ │ │ - // default scope is window (global) │ │ │ │ │ - var scope = options.scope || window; │ │ │ │ │ - │ │ │ │ │ - // apply these option to the request options │ │ │ │ │ - var requestOptions = {}; │ │ │ │ │ - OpenLayers.Util.extend(requestOptions, this.options); │ │ │ │ │ - │ │ │ │ │ - // this is a feature request │ │ │ │ │ - requestOptions.requesttype = "feature"; │ │ │ │ │ + removeTarget: function(target) { │ │ │ │ │ + return OpenLayers.Util.removeItem(this.targets, target); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (geometry instanceof OpenLayers.LonLat) { │ │ │ │ │ - // create an envelope if the geometry is really a lon/lat │ │ │ │ │ - requestOptions.polygon = null; │ │ │ │ │ - requestOptions.envelope = [ │ │ │ │ │ - geometry.lon - buffer, │ │ │ │ │ - geometry.lat - buffer, │ │ │ │ │ - geometry.lon + buffer, │ │ │ │ │ - geometry.lat + buffer │ │ │ │ │ - ]; │ │ │ │ │ - } else if (geometry instanceof OpenLayers.Geometry.Polygon) { │ │ │ │ │ - // use the polygon assigned, and empty the envelope │ │ │ │ │ - requestOptions.envelope = null; │ │ │ │ │ - requestOptions.polygon = geometry; │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: activate │ │ │ │ │ + * Activate the control. Activating the control registers listeners for │ │ │ │ │ + * editing related events so that during feature creation and │ │ │ │ │ + * modification, moving vertices will trigger snapping. │ │ │ │ │ + */ │ │ │ │ │ + activate: function() { │ │ │ │ │ + var activated = OpenLayers.Control.prototype.activate.call(this); │ │ │ │ │ + if (activated) { │ │ │ │ │ + if (this.layer && this.layer.events) { │ │ │ │ │ + this.layer.events.on({ │ │ │ │ │ + sketchstarted: this.onSketchModified, │ │ │ │ │ + sketchmodified: this.onSketchModified, │ │ │ │ │ + vertexmodified: this.onVertexModified, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ + return activated; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // create an arcxml request to get feature requests │ │ │ │ │ - var arcxml = new OpenLayers.Format.ArcXML(requestOptions); │ │ │ │ │ - │ │ │ │ │ - // apply any get feature options to the arcxml request │ │ │ │ │ - OpenLayers.Util.extend(arcxml.request.get_feature, options); │ │ │ │ │ - │ │ │ │ │ - arcxml.request.get_feature.layer = layer.id; │ │ │ │ │ - if (typeof layer.query.accuracy == "number") { │ │ │ │ │ - // set the accuracy if it was specified │ │ │ │ │ - arcxml.request.get_feature.query.accuracy = layer.query.accuracy; │ │ │ │ │ - } else { │ │ │ │ │ - // guess that the accuracy is 1 per screen pixel │ │ │ │ │ - var mapCenter = this.map.getCenter(); │ │ │ │ │ - var viewPx = this.map.getViewPortPxFromLonLat(mapCenter); │ │ │ │ │ - viewPx.x++; │ │ │ │ │ - var mapOffCenter = this.map.getLonLatFromPixel(viewPx); │ │ │ │ │ - arcxml.request.get_feature.query.accuracy = mapOffCenter.lon - mapCenter.lon; │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: deactivate │ │ │ │ │ + * Deactivate the control. Deactivating the control unregisters listeners │ │ │ │ │ + * so feature editing may proceed without engaging the snapping agent. │ │ │ │ │ + */ │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + var deactivated = OpenLayers.Control.prototype.deactivate.call(this); │ │ │ │ │ + if (deactivated) { │ │ │ │ │ + if (this.layer && this.layer.events) { │ │ │ │ │ + this.layer.events.un({ │ │ │ │ │ + sketchstarted: this.onSketchModified, │ │ │ │ │ + sketchmodified: this.onSketchModified, │ │ │ │ │ + vertexmodified: this.onVertexModified, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ + this.feature = null; │ │ │ │ │ + this.point = null; │ │ │ │ │ + return deactivated; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // set the get_feature query to be the same as the layer passed in │ │ │ │ │ - arcxml.request.get_feature.query.where = layer.query.where; │ │ │ │ │ - │ │ │ │ │ - // use area_intersection │ │ │ │ │ - arcxml.request.get_feature.query.spatialfilter.relation = "area_intersection"; │ │ │ │ │ + /** │ │ │ │ │ + * Method: onSketchModified │ │ │ │ │ + * Registered as a listener for the sketchmodified event on the editable │ │ │ │ │ + * layer. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * event - {Object} The sketch modified event. │ │ │ │ │ + */ │ │ │ │ │ + onSketchModified: function(event) { │ │ │ │ │ + this.feature = event.feature; │ │ │ │ │ + this.considerSnapping(event.vertex, event.vertex); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - // create a new asynchronous request to get the feature info │ │ │ │ │ - OpenLayers.Request.POST({ │ │ │ │ │ - url: this.getFullRequestString({ │ │ │ │ │ - 'CustomService': 'Query' │ │ │ │ │ - }), │ │ │ │ │ - data: arcxml.write(), │ │ │ │ │ - callback: function(request) { │ │ │ │ │ - // parse the arcxml response │ │ │ │ │ - var response = arcxml.parseResponse(request.responseText); │ │ │ │ │ + /** │ │ │ │ │ + * Method: onVertexModified │ │ │ │ │ + * Registered as a listener for the vertexmodified event on the editable │ │ │ │ │ + * layer. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * event - {Object} The vertex modified event. │ │ │ │ │ + */ │ │ │ │ │ + onVertexModified: function(event) { │ │ │ │ │ + this.feature = event.feature; │ │ │ │ │ + var loc = this.layer.map.getLonLatFromViewPortPx(event.pixel); │ │ │ │ │ + this.considerSnapping( │ │ │ │ │ + event.vertex, new OpenLayers.Geometry.Point(loc.lon, loc.lat) │ │ │ │ │ + ); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - if (!arcxml.iserror()) { │ │ │ │ │ - // if the arcxml is not an error, call the callback with the features parsed │ │ │ │ │ - callback.call(scope, response.features); │ │ │ │ │ + /** │ │ │ │ │ + * Method: considerSnapping │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * point - {} The vertex to be snapped (or │ │ │ │ │ + * unsnapped). │ │ │ │ │ + * loc - {} The location of the mouse in map │ │ │ │ │ + * coords. │ │ │ │ │ + */ │ │ │ │ │ + considerSnapping: function(point, loc) { │ │ │ │ │ + var best = { │ │ │ │ │ + rank: Number.POSITIVE_INFINITY, │ │ │ │ │ + dist: Number.POSITIVE_INFINITY, │ │ │ │ │ + x: null, │ │ │ │ │ + y: null │ │ │ │ │ + }; │ │ │ │ │ + var snapped = false; │ │ │ │ │ + var result, target; │ │ │ │ │ + for (var i = 0, len = this.targets.length; i < len; ++i) { │ │ │ │ │ + target = this.targets[i]; │ │ │ │ │ + result = this.testTarget(target, loc); │ │ │ │ │ + if (result) { │ │ │ │ │ + if (this.greedy) { │ │ │ │ │ + best = result; │ │ │ │ │ + best.target = target; │ │ │ │ │ + snapped = true; │ │ │ │ │ + break; │ │ │ │ │ } else { │ │ │ │ │ - // if the arcxml is an error, return null features selected │ │ │ │ │ - callback.call(scope, null); │ │ │ │ │ + if ((result.rank < best.rank) || │ │ │ │ │ + (result.rank === best.rank && result.dist < best.dist)) { │ │ │ │ │ + best = result; │ │ │ │ │ + best.target = target; │ │ │ │ │ + snapped = true; │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ - }); │ │ │ │ │ + } │ │ │ │ │ + if (snapped) { │ │ │ │ │ + var proceed = this.events.triggerEvent("beforesnap", { │ │ │ │ │ + point: point, │ │ │ │ │ + x: best.x, │ │ │ │ │ + y: best.y, │ │ │ │ │ + distance: best.dist, │ │ │ │ │ + layer: best.target.layer, │ │ │ │ │ + snapType: this.precedence[best.rank] │ │ │ │ │ + }); │ │ │ │ │ + if (proceed !== false) { │ │ │ │ │ + point.x = best.x; │ │ │ │ │ + point.y = best.y; │ │ │ │ │ + this.point = point; │ │ │ │ │ + this.events.triggerEvent("snap", { │ │ │ │ │ + point: point, │ │ │ │ │ + snapType: this.precedence[best.rank], │ │ │ │ │ + layer: best.target.layer, │ │ │ │ │ + distance: best.dist │ │ │ │ │ + }); │ │ │ │ │ + } else { │ │ │ │ │ + snapped = false; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + if (this.point && !snapped) { │ │ │ │ │ + point.x = loc.x; │ │ │ │ │ + point.y = loc.y; │ │ │ │ │ + this.point = null; │ │ │ │ │ + this.events.triggerEvent("unsnap", { │ │ │ │ │ + point: point │ │ │ │ │ + }); │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: clone │ │ │ │ │ - * Create a clone of this layer │ │ │ │ │ + * Method: testTarget │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * target - {Object} Object with target layer configuration. │ │ │ │ │ + * loc - {} The location of the mouse in map │ │ │ │ │ + * coords. │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {} An exact clone of this layer │ │ │ │ │ + * {Object} A result object with rank, dist, x, and y properties. │ │ │ │ │ + * Returns null if candidate is not eligible for snapping. │ │ │ │ │ */ │ │ │ │ │ - clone: function(obj) { │ │ │ │ │ - │ │ │ │ │ - if (obj == null) { │ │ │ │ │ - obj = new OpenLayers.Layer.ArcIMS(this.name, │ │ │ │ │ - this.url, │ │ │ │ │ - this.getOptions()); │ │ │ │ │ + testTarget: function(target, loc) { │ │ │ │ │ + var resolution = this.layer.map.getResolution(); │ │ │ │ │ + if ("minResolution" in target) { │ │ │ │ │ + if (resolution < target.minResolution) { │ │ │ │ │ + return null; │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ + if ("maxResolution" in target) { │ │ │ │ │ + if (resolution >= target.maxResolution) { │ │ │ │ │ + return null; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + var tolerance = { │ │ │ │ │ + node: this.getGeoTolerance(target.nodeTolerance, resolution), │ │ │ │ │ + vertex: this.getGeoTolerance(target.vertexTolerance, resolution), │ │ │ │ │ + edge: this.getGeoTolerance(target.edgeTolerance, resolution) │ │ │ │ │ + }; │ │ │ │ │ + // this could be cached if we don't support setting tolerance values directly │ │ │ │ │ + var maxTolerance = Math.max( │ │ │ │ │ + tolerance.node, tolerance.vertex, tolerance.edge │ │ │ │ │ + ); │ │ │ │ │ + var result = { │ │ │ │ │ + rank: Number.POSITIVE_INFINITY, │ │ │ │ │ + dist: Number.POSITIVE_INFINITY │ │ │ │ │ + }; │ │ │ │ │ + var eligible = false; │ │ │ │ │ + var features = target.layer.features; │ │ │ │ │ + var feature, type, vertices, vertex, closest, dist, found; │ │ │ │ │ + var numTypes = this.precedence.length; │ │ │ │ │ + var ll = new OpenLayers.LonLat(loc.x, loc.y); │ │ │ │ │ + for (var i = 0, len = features.length; i < len; ++i) { │ │ │ │ │ + feature = features[i]; │ │ │ │ │ + if (feature !== this.feature && !feature._sketch && │ │ │ │ │ + feature.state !== OpenLayers.State.DELETE && │ │ │ │ │ + (!target.filter || target.filter.evaluate(feature))) { │ │ │ │ │ + if (feature.atPoint(ll, maxTolerance, maxTolerance)) { │ │ │ │ │ + for (var j = 0, stop = Math.min(result.rank + 1, numTypes); j < stop; ++j) { │ │ │ │ │ + type = this.precedence[j]; │ │ │ │ │ + if (target[type]) { │ │ │ │ │ + if (type === "edge") { │ │ │ │ │ + closest = feature.geometry.distanceTo(loc, { │ │ │ │ │ + details: true │ │ │ │ │ + }); │ │ │ │ │ + dist = closest.distance; │ │ │ │ │ + if (dist <= tolerance[type] && dist < result.dist) { │ │ │ │ │ + result = { │ │ │ │ │ + rank: j, │ │ │ │ │ + dist: dist, │ │ │ │ │ + x: closest.x0, │ │ │ │ │ + y: closest.y0 // closest coords on feature │ │ │ │ │ + }; │ │ │ │ │ + eligible = true; │ │ │ │ │ + // don't look for lower precedence types for this feature │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } else { │ │ │ │ │ + // look for nodes or vertices │ │ │ │ │ + vertices = feature.geometry.getVertices(type === "node"); │ │ │ │ │ + found = false; │ │ │ │ │ + for (var k = 0, klen = vertices.length; k < klen; ++k) { │ │ │ │ │ + vertex = vertices[k]; │ │ │ │ │ + dist = vertex.distanceTo(loc); │ │ │ │ │ + if (dist <= tolerance[type] && │ │ │ │ │ + (j < result.rank || (j === result.rank && dist < result.dist))) { │ │ │ │ │ + result = { │ │ │ │ │ + rank: j, │ │ │ │ │ + dist: dist, │ │ │ │ │ + x: vertex.x, │ │ │ │ │ + y: vertex.y │ │ │ │ │ + }; │ │ │ │ │ + eligible = true; │ │ │ │ │ + found = true; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + if (found) { │ │ │ │ │ + // don't look for lower precedence types for this feature │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + return eligible ? result : null; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - //get all additions from superclasses │ │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ │ - │ │ │ │ │ - // copy/set any non-init, non-simple values here │ │ │ │ │ + /** │ │ │ │ │ + * Method: getGeoTolerance │ │ │ │ │ + * Calculate a tolerance in map units given a tolerance in pixels. This │ │ │ │ │ + * takes advantage of the when the map resolution │ │ │ │ │ + * has not changed. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * tolerance - {Number} A tolerance value in pixels. │ │ │ │ │ + * resolution - {Number} Map resolution. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Number} A tolerance value in map units. │ │ │ │ │ + */ │ │ │ │ │ + getGeoTolerance: function(tolerance, resolution) { │ │ │ │ │ + if (resolution !== this.resolution) { │ │ │ │ │ + this.resolution = resolution; │ │ │ │ │ + this.geoToleranceCache = {}; │ │ │ │ │ + } │ │ │ │ │ + var geoTolerance = this.geoToleranceCache[tolerance]; │ │ │ │ │ + if (geoTolerance === undefined) { │ │ │ │ │ + geoTolerance = tolerance * resolution; │ │ │ │ │ + this.geoToleranceCache[tolerance] = geoTolerance; │ │ │ │ │ + } │ │ │ │ │ + return geoTolerance; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - return obj; │ │ │ │ │ + /** │ │ │ │ │ + * Method: destroy │ │ │ │ │ + * Clean up the control. │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ + if (this.active) { │ │ │ │ │ + this.deactivate(); // TODO: this should be handled by the super │ │ │ │ │ + } │ │ │ │ │ + delete this.layer; │ │ │ │ │ + delete this.targets; │ │ │ │ │ + OpenLayers.Control.prototype.destroy.call(this); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.ArcIMS" │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Snapping" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Layer/WorldWind.js │ │ │ │ │ + OpenLayers/Control/LayerSwitcher.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Layer/Grid.js │ │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ │ + * @requires OpenLayers/Util.js │ │ │ │ │ + * @requires OpenLayers/Events/buttonclick.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Layer.WorldWind │ │ │ │ │ - * │ │ │ │ │ + * Class: OpenLayers.Control.LayerSwitcher │ │ │ │ │ + * The LayerSwitcher control displays a table of contents for the map. This │ │ │ │ │ + * allows the user interface to switch between BaseLasyers and to show or hide │ │ │ │ │ + * Overlays. By default the switcher is shown minimized on the right edge of │ │ │ │ │ + * the map, the user may expand it by clicking on the handle. │ │ │ │ │ + * │ │ │ │ │ + * To create the LayerSwitcher outside of the map, pass the Id of a html div │ │ │ │ │ + * as the first argument to the constructor. │ │ │ │ │ + * │ │ │ │ │ * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Layer.WorldWind = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ │ +OpenLayers.Control.LayerSwitcher = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ │ │ - DEFAULT_PARAMS: {}, │ │ │ │ │ + /** │ │ │ │ │ + * Property: layerStates │ │ │ │ │ + * {Array(Object)} Basically a copy of the "state" of the map's layers │ │ │ │ │ + * the last time the control was drawn. We have this in order to avoid │ │ │ │ │ + * unnecessarily redrawing the control. │ │ │ │ │ + */ │ │ │ │ │ + layerStates: null, │ │ │ │ │ + │ │ │ │ │ + // DOM Elements │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ │ - * {Boolean} WorldWind layer is a base layer by default. │ │ │ │ │ + * Property: layersDiv │ │ │ │ │ + * {DOMElement} │ │ │ │ │ */ │ │ │ │ │ - isBaseLayer: true, │ │ │ │ │ + layersDiv: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: lzd │ │ │ │ │ - * {Float} LevelZeroTileSizeDegrees │ │ │ │ │ + /** │ │ │ │ │ + * Property: baseLayersDiv │ │ │ │ │ + * {DOMElement} │ │ │ │ │ */ │ │ │ │ │ - lzd: null, │ │ │ │ │ + baseLayersDiv: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: zoomLevels │ │ │ │ │ - * {Integer} Number of zoom levels. │ │ │ │ │ + * Property: baseLayers │ │ │ │ │ + * {Array(Object)} │ │ │ │ │ */ │ │ │ │ │ - zoomLevels: null, │ │ │ │ │ + baseLayers: null, │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Layer.WorldWind │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * name - {String} Name of Layer │ │ │ │ │ - * url - {String} Base URL │ │ │ │ │ - * lzd - {Float} Level zero tile size degrees │ │ │ │ │ - * zoomLevels - {Integer} number of zoom levels │ │ │ │ │ - * params - {Object} additional parameters │ │ │ │ │ - * options - {Object} additional options │ │ │ │ │ + * Property: dataLbl │ │ │ │ │ + * {DOMElement} │ │ │ │ │ */ │ │ │ │ │ - initialize: function(name, url, lzd, zoomLevels, params, options) { │ │ │ │ │ - this.lzd = lzd; │ │ │ │ │ - this.zoomLevels = zoomLevels; │ │ │ │ │ - var newArguments = []; │ │ │ │ │ - newArguments.push(name, url, params, options); │ │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments); │ │ │ │ │ - this.params = OpenLayers.Util.applyDefaults( │ │ │ │ │ - this.params, this.DEFAULT_PARAMS │ │ │ │ │ - ); │ │ │ │ │ - }, │ │ │ │ │ + dataLbl: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getZoom │ │ │ │ │ - * Convert map zoom to WW zoom. │ │ │ │ │ + * Property: dataLayersDiv │ │ │ │ │ + * {DOMElement} │ │ │ │ │ */ │ │ │ │ │ - getZoom: function() { │ │ │ │ │ - var zoom = this.map.getZoom(); │ │ │ │ │ - var extent = this.map.getMaxExtent(); │ │ │ │ │ - zoom = zoom - Math.log(this.maxResolution / (this.lzd / 512)) / Math.log(2); │ │ │ │ │ - return zoom; │ │ │ │ │ - }, │ │ │ │ │ + dataLayersDiv: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getURL │ │ │ │ │ + * Property: dataLayers │ │ │ │ │ + * {Array(Object)} │ │ │ │ │ + */ │ │ │ │ │ + dataLayers: null, │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: minimizeDiv │ │ │ │ │ + * {DOMElement} │ │ │ │ │ + */ │ │ │ │ │ + minimizeDiv: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: maximizeDiv │ │ │ │ │ + * {DOMElement} │ │ │ │ │ + */ │ │ │ │ │ + maximizeDiv: null, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: ascending │ │ │ │ │ + * {Boolean} │ │ │ │ │ + */ │ │ │ │ │ + ascending: true, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Control.LayerSwitcher │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * bounds - {} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} A string with the layer's url and parameters and also the │ │ │ │ │ - * passed-in bounds and appropriate tile size specified as │ │ │ │ │ - * parameters │ │ │ │ │ + * options - {Object} │ │ │ │ │ */ │ │ │ │ │ - getURL: function(bounds) { │ │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ │ - var zoom = this.getZoom(); │ │ │ │ │ - var extent = this.map.getMaxExtent(); │ │ │ │ │ - var deg = this.lzd / Math.pow(2, this.getZoom()); │ │ │ │ │ - var x = Math.floor((bounds.left - extent.left) / deg); │ │ │ │ │ - var y = Math.floor((bounds.bottom - extent.bottom) / deg); │ │ │ │ │ - if (this.map.getResolution() <= (this.lzd / 512) && │ │ │ │ │ - this.getZoom() <= this.zoomLevels) { │ │ │ │ │ - return this.getFullRequestString({ │ │ │ │ │ - L: zoom, │ │ │ │ │ - X: x, │ │ │ │ │ - Y: y │ │ │ │ │ - }); │ │ │ │ │ - } else { │ │ │ │ │ - return OpenLayers.Util.getImageLocation("blank.gif"); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ │ + this.layerStates = []; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.WorldWind" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Layer/ArcGIS93Rest.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ + /** │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ + */ │ │ │ │ │ + destroy: function() { │ │ │ │ │ │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ + //clear out layers info and unregister their events │ │ │ │ │ + this.clearLayersArray("base"); │ │ │ │ │ + this.clearLayersArray("data"); │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Layer/Grid.js │ │ │ │ │ - */ │ │ │ │ │ + this.map.events.un({ │ │ │ │ │ + buttonclick: this.onButtonClick, │ │ │ │ │ + addlayer: this.redraw, │ │ │ │ │ + changelayer: this.redraw, │ │ │ │ │ + removelayer: this.redraw, │ │ │ │ │ + changebaselayer: this.redraw, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + this.events.unregister("buttonclick", this, this.onButtonClick); │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Layer.ArcGIS93Rest │ │ │ │ │ - * Instances of OpenLayers.Layer.ArcGIS93Rest are used to display data from │ │ │ │ │ - * ESRI ArcGIS Server 9.3 (and up?) Mapping Services using the REST API. │ │ │ │ │ - * Create a new ArcGIS93Rest layer with the │ │ │ │ │ - * constructor. More detail on the REST API is available at │ │ │ │ │ - * http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/index.html ; │ │ │ │ │ - * specifically, the URL provided to this layer should be an export service │ │ │ │ │ - * URL: http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/export.html │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Layer.ArcGIS93Rest = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constant: DEFAULT_PARAMS │ │ │ │ │ - * {Object} Hashtable of default parameter key/value pairs │ │ │ │ │ + * Method: setMap │ │ │ │ │ + * │ │ │ │ │ + * Properties: │ │ │ │ │ + * map - {} │ │ │ │ │ */ │ │ │ │ │ - DEFAULT_PARAMS: { │ │ │ │ │ - format: "png" │ │ │ │ │ + setMap: function(map) { │ │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ │ + │ │ │ │ │ + this.map.events.on({ │ │ │ │ │ + addlayer: this.redraw, │ │ │ │ │ + changelayer: this.redraw, │ │ │ │ │ + removelayer: this.redraw, │ │ │ │ │ + changebaselayer: this.redraw, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + if (this.outsideViewport) { │ │ │ │ │ + this.events.attachToElement(this.div); │ │ │ │ │ + this.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ │ + } else { │ │ │ │ │ + this.map.events.register("buttonclick", this, this.onButtonClick); │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ │ - * {Boolean} Default is true for ArcGIS93Rest layer │ │ │ │ │ + * Method: draw │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {DOMElement} A reference to the DIV DOMElement containing the │ │ │ │ │ + * switcher tabs. │ │ │ │ │ */ │ │ │ │ │ - isBaseLayer: true, │ │ │ │ │ + draw: function() { │ │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this); │ │ │ │ │ + │ │ │ │ │ + // create layout divs │ │ │ │ │ + this.loadContents(); │ │ │ │ │ + │ │ │ │ │ + // set mode to minimize │ │ │ │ │ + if (!this.outsideViewport) { │ │ │ │ │ + this.minimizeControl(); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // populate div with current info │ │ │ │ │ + this.redraw(); │ │ │ │ │ │ │ │ │ │ + return this.div; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Layer.ArcGIS93Rest │ │ │ │ │ - * Create a new ArcGIS93Rest layer object. │ │ │ │ │ - * │ │ │ │ │ - * Example: │ │ │ │ │ - * (code) │ │ │ │ │ - * var arcims = new OpenLayers.Layer.ArcGIS93Rest("MyName", │ │ │ │ │ - * "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer/export", │ │ │ │ │ - * { │ │ │ │ │ - * layers: "0,1,2" │ │ │ │ │ - * }); │ │ │ │ │ - * (end) │ │ │ │ │ + * Method: onButtonClick │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * name - {String} A name for the layer │ │ │ │ │ - * url - {String} Base url for the ArcGIS server REST service │ │ │ │ │ - * options - {Object} An object with key/value pairs representing the │ │ │ │ │ - * options and option values. │ │ │ │ │ + * evt - {Event} │ │ │ │ │ + */ │ │ │ │ │ + onButtonClick: function(evt) { │ │ │ │ │ + var button = evt.buttonElement; │ │ │ │ │ + if (button === this.minimizeDiv) { │ │ │ │ │ + this.minimizeControl(); │ │ │ │ │ + } else if (button === this.maximizeDiv) { │ │ │ │ │ + this.maximizeControl(); │ │ │ │ │ + } else if (button._layerSwitcher === this.id) { │ │ │ │ │ + if (button["for"]) { │ │ │ │ │ + button = document.getElementById(button["for"]); │ │ │ │ │ + } │ │ │ │ │ + if (!button.disabled) { │ │ │ │ │ + if (button.type == "radio") { │ │ │ │ │ + button.checked = true; │ │ │ │ │ + this.map.setBaseLayer(this.map.getLayer(button._layer)); │ │ │ │ │ + } else { │ │ │ │ │ + button.checked = !button.checked; │ │ │ │ │ + this.updateMap(); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: clearLayersArray │ │ │ │ │ + * User specifies either "base" or "data". we then clear all the │ │ │ │ │ + * corresponding listeners, the div, and reinitialize a new array. │ │ │ │ │ * │ │ │ │ │ - * Valid Options: │ │ │ │ │ - * format - {String} MIME type of desired image type. │ │ │ │ │ - * layers - {String} Comma-separated list of layers to display. │ │ │ │ │ - * srs - {String} Projection ID. │ │ │ │ │ + * Parameters: │ │ │ │ │ + * layersType - {String} │ │ │ │ │ */ │ │ │ │ │ - initialize: function(name, url, params, options) { │ │ │ │ │ - var newArguments = []; │ │ │ │ │ - //uppercase params │ │ │ │ │ - params = OpenLayers.Util.upperCaseObject(params); │ │ │ │ │ - newArguments.push(name, url, params, options); │ │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments); │ │ │ │ │ - OpenLayers.Util.applyDefaults( │ │ │ │ │ - this.params, │ │ │ │ │ - OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS) │ │ │ │ │ - ); │ │ │ │ │ + clearLayersArray: function(layersType) { │ │ │ │ │ + this[layersType + "LayersDiv"].innerHTML = ""; │ │ │ │ │ + this[layersType + "Layers"] = []; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - //layer is transparent │ │ │ │ │ - if (this.params.TRANSPARENT && │ │ │ │ │ - this.params.TRANSPARENT.toString().toLowerCase() == "true") { │ │ │ │ │ │ │ │ │ │ - // unless explicitly set in options, make layer an overlay │ │ │ │ │ - if ((options == null) || (!options.isBaseLayer)) { │ │ │ │ │ - this.isBaseLayer = false; │ │ │ │ │ - } │ │ │ │ │ + /** │ │ │ │ │ + * Method: checkRedraw │ │ │ │ │ + * Checks if the layer state has changed since the last redraw() call. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Boolean} The layer state changed since the last redraw() call. │ │ │ │ │ + */ │ │ │ │ │ + checkRedraw: function() { │ │ │ │ │ + if (!this.layerStates.length || │ │ │ │ │ + (this.map.layers.length != this.layerStates.length)) { │ │ │ │ │ + return true; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - // jpegs can never be transparent, so intelligently switch the │ │ │ │ │ - // format, depending on the browser's capabilities │ │ │ │ │ - if (this.params.FORMAT == "jpg") { │ │ │ │ │ - this.params.FORMAT = OpenLayers.Util.alphaHack() ? "gif" : │ │ │ │ │ - "png"; │ │ │ │ │ + for (var i = 0, len = this.layerStates.length; i < len; i++) { │ │ │ │ │ + var layerState = this.layerStates[i]; │ │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ │ + if ((layerState.name != layer.name) || │ │ │ │ │ + (layerState.inRange != layer.inRange) || │ │ │ │ │ + (layerState.id != layer.id) || │ │ │ │ │ + (layerState.visibility != layer.visibility)) { │ │ │ │ │ + return true; │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ + │ │ │ │ │ + return false; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: clone │ │ │ │ │ - * Create a clone of this layer │ │ │ │ │ + * Method: redraw │ │ │ │ │ + * Goes through and takes the current state of the Map and rebuilds the │ │ │ │ │ + * control to display that state. Groups base layers into a │ │ │ │ │ + * radio-button group and lists each data layer with a checkbox. │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {} An exact clone of this layer │ │ │ │ │ + * {DOMElement} A reference to the DIV DOMElement containing the control │ │ │ │ │ */ │ │ │ │ │ - clone: function(obj) { │ │ │ │ │ + redraw: function() { │ │ │ │ │ + //if the state hasn't changed since last redraw, no need │ │ │ │ │ + // to do anything. Just return the existing div. │ │ │ │ │ + if (!this.checkRedraw()) { │ │ │ │ │ + return this.div; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - if (obj == null) { │ │ │ │ │ - obj = new OpenLayers.Layer.ArcGIS93Rest(this.name, │ │ │ │ │ - this.url, │ │ │ │ │ - this.params, │ │ │ │ │ - this.getOptions()); │ │ │ │ │ + //clear out previous layers │ │ │ │ │ + this.clearLayersArray("base"); │ │ │ │ │ + this.clearLayersArray("data"); │ │ │ │ │ + │ │ │ │ │ + var containsOverlays = false; │ │ │ │ │ + var containsBaseLayers = false; │ │ │ │ │ + │ │ │ │ │ + // Save state -- for checking layer if the map state changed. │ │ │ │ │ + // We save this before redrawing, because in the process of redrawing │ │ │ │ │ + // we will trigger more visibility changes, and we want to not redraw │ │ │ │ │ + // and enter an infinite loop. │ │ │ │ │ + var len = this.map.layers.length; │ │ │ │ │ + this.layerStates = new Array(len); │ │ │ │ │ + for (var i = 0; i < len; i++) { │ │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ │ + this.layerStates[i] = { │ │ │ │ │ + 'name': layer.name, │ │ │ │ │ + 'visibility': layer.visibility, │ │ │ │ │ + 'inRange': layer.inRange, │ │ │ │ │ + 'id': layer.id │ │ │ │ │ + }; │ │ │ │ │ } │ │ │ │ │ │ │ │ │ │ - //get all additions from superclasses │ │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ │ + var layers = this.map.layers.slice(); │ │ │ │ │ + if (!this.ascending) { │ │ │ │ │ + layers.reverse(); │ │ │ │ │ + } │ │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ │ + var layer = layers[i]; │ │ │ │ │ + var baseLayer = layer.isBaseLayer; │ │ │ │ │ │ │ │ │ │ - // copy/set any non-init, non-simple values here │ │ │ │ │ + if (layer.displayInLayerSwitcher) { │ │ │ │ │ │ │ │ │ │ - return obj; │ │ │ │ │ - }, │ │ │ │ │ + if (baseLayer) { │ │ │ │ │ + containsBaseLayers = true; │ │ │ │ │ + } else { │ │ │ │ │ + containsOverlays = true; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ + // only check a baselayer if it is *the* baselayer, check data │ │ │ │ │ + // layers if they are visible │ │ │ │ │ + var checked = (baseLayer) ? (layer == this.map.baseLayer) : │ │ │ │ │ + layer.getVisibility(); │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: getURL │ │ │ │ │ - * Return an image url this layer. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * bounds - {} A bounds representing the bbox for the │ │ │ │ │ - * request. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} A string with the map image's url. │ │ │ │ │ - */ │ │ │ │ │ - getURL: function(bounds) { │ │ │ │ │ - bounds = this.adjustBounds(bounds); │ │ │ │ │ + // create input element │ │ │ │ │ + var inputElem = document.createElement("input"), │ │ │ │ │ + // The input shall have an id attribute so we can use │ │ │ │ │ + // labels to interact with them. │ │ │ │ │ + inputId = OpenLayers.Util.createUniqueID( │ │ │ │ │ + this.id + "_input_" │ │ │ │ │ + ); │ │ │ │ │ │ │ │ │ │ - // ArcGIS Server only wants the numeric portion of the projection ID. │ │ │ │ │ - var projWords = this.projection.getCode().split(":"); │ │ │ │ │ - var srid = projWords[projWords.length - 1]; │ │ │ │ │ + inputElem.id = inputId; │ │ │ │ │ + inputElem.name = (baseLayer) ? this.id + "_baseLayers" : layer.name; │ │ │ │ │ + inputElem.type = (baseLayer) ? "radio" : "checkbox"; │ │ │ │ │ + inputElem.value = layer.name; │ │ │ │ │ + inputElem.checked = checked; │ │ │ │ │ + inputElem.defaultChecked = checked; │ │ │ │ │ + inputElem.className = "olButton"; │ │ │ │ │ + inputElem._layer = layer.id; │ │ │ │ │ + inputElem._layerSwitcher = this.id; │ │ │ │ │ │ │ │ │ │ - var imageSize = this.getImageSize(); │ │ │ │ │ - var newParams = { │ │ │ │ │ - 'BBOX': bounds.toBBOX(), │ │ │ │ │ - 'SIZE': imageSize.w + "," + imageSize.h, │ │ │ │ │ - // We always want image, the other options were json, image with a whole lotta html around it, etc. │ │ │ │ │ - 'F': "image", │ │ │ │ │ - 'BBOXSR': srid, │ │ │ │ │ - 'IMAGESR': srid │ │ │ │ │ - }; │ │ │ │ │ + if (!baseLayer && !layer.inRange) { │ │ │ │ │ + inputElem.disabled = true; │ │ │ │ │ + } │ │ │ │ │ │ │ │ │ │ - // Now add the filter parameters. │ │ │ │ │ - if (this.layerDefs) { │ │ │ │ │ - var layerDefStrList = []; │ │ │ │ │ - var layerID; │ │ │ │ │ - for (layerID in this.layerDefs) { │ │ │ │ │ - if (this.layerDefs.hasOwnProperty(layerID)) { │ │ │ │ │ - if (this.layerDefs[layerID]) { │ │ │ │ │ - layerDefStrList.push(layerID); │ │ │ │ │ - layerDefStrList.push(":"); │ │ │ │ │ - layerDefStrList.push(this.layerDefs[layerID]); │ │ │ │ │ - layerDefStrList.push(";"); │ │ │ │ │ - } │ │ │ │ │ + // create span │ │ │ │ │ + var labelSpan = document.createElement("label"); │ │ │ │ │ + // this isn't the DOM attribute 'for', but an arbitrary name we │ │ │ │ │ + // use to find the appropriate input element in │ │ │ │ │ + labelSpan["for"] = inputElem.id; │ │ │ │ │ + OpenLayers.Element.addClass(labelSpan, "labelSpan olButton"); │ │ │ │ │ + labelSpan._layer = layer.id; │ │ │ │ │ + labelSpan._layerSwitcher = this.id; │ │ │ │ │ + if (!baseLayer && !layer.inRange) { │ │ │ │ │ + labelSpan.style.color = "gray"; │ │ │ │ │ } │ │ │ │ │ + labelSpan.innerHTML = layer.name; │ │ │ │ │ + labelSpan.style.verticalAlign = (baseLayer) ? "bottom" : │ │ │ │ │ + "baseline"; │ │ │ │ │ + // create line break │ │ │ │ │ + var br = document.createElement("br"); │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ + var groupArray = (baseLayer) ? this.baseLayers : │ │ │ │ │ + this.dataLayers; │ │ │ │ │ + groupArray.push({ │ │ │ │ │ + 'layer': layer, │ │ │ │ │ + 'inputElem': inputElem, │ │ │ │ │ + 'labelSpan': labelSpan │ │ │ │ │ + }); │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ │ + var groupDiv = (baseLayer) ? this.baseLayersDiv : │ │ │ │ │ + this.dataLayersDiv; │ │ │ │ │ + groupDiv.appendChild(inputElem); │ │ │ │ │ + groupDiv.appendChild(labelSpan); │ │ │ │ │ + groupDiv.appendChild(br); │ │ │ │ │ } │ │ │ │ │ - if (layerDefStrList.length > 0) { │ │ │ │ │ - newParams['LAYERDEFS'] = layerDefStrList.join(""); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // if no overlays, dont display the overlay label │ │ │ │ │ + this.dataLbl.style.display = (containsOverlays) ? "" : "none"; │ │ │ │ │ + │ │ │ │ │ + // if no baselayers, dont display the baselayer label │ │ │ │ │ + this.baseLbl.style.display = (containsBaseLayers) ? "" : "none"; │ │ │ │ │ + │ │ │ │ │ + return this.div; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: updateMap │ │ │ │ │ + * Cycles through the loaded data and base layer input arrays and makes │ │ │ │ │ + * the necessary calls to the Map object such that that the map's │ │ │ │ │ + * visual state corresponds to what the user has selected in │ │ │ │ │ + * the control. │ │ │ │ │ + */ │ │ │ │ │ + updateMap: function() { │ │ │ │ │ + │ │ │ │ │ + // set the newly selected base layer │ │ │ │ │ + for (var i = 0, len = this.baseLayers.length; i < len; i++) { │ │ │ │ │ + var layerEntry = this.baseLayers[i]; │ │ │ │ │ + if (layerEntry.inputElem.checked) { │ │ │ │ │ + this.map.setBaseLayer(layerEntry.layer, false); │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ - var requestString = this.getFullRequestString(newParams); │ │ │ │ │ - return requestString; │ │ │ │ │ + │ │ │ │ │ + // set the correct visibilities for the overlays │ │ │ │ │ + for (var i = 0, len = this.dataLayers.length; i < len; i++) { │ │ │ │ │ + var layerEntry = this.dataLayers[i]; │ │ │ │ │ + layerEntry.layer.setVisibility(layerEntry.inputElem.checked); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: setLayerFilter │ │ │ │ │ - * addTile creates a tile, initializes it, and adds it to the layer div. │ │ │ │ │ + * Method: maximizeControl │ │ │ │ │ + * Set up the labels and divs for the control │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * id - {String} The id of the layer to which the filter applies. │ │ │ │ │ - * queryDef - {String} A sql-ish query filter, for more detail see the ESRI │ │ │ │ │ - * documentation at http://sampleserver1.arcgisonline.com/ArcGIS/SDK/REST/export.html │ │ │ │ │ + * e - {Event} │ │ │ │ │ */ │ │ │ │ │ - setLayerFilter: function(id, queryDef) { │ │ │ │ │ - if (!this.layerDefs) { │ │ │ │ │ - this.layerDefs = {}; │ │ │ │ │ - } │ │ │ │ │ - if (queryDef) { │ │ │ │ │ - this.layerDefs[id] = queryDef; │ │ │ │ │ - } else { │ │ │ │ │ - delete this.layerDefs[id]; │ │ │ │ │ + maximizeControl: function(e) { │ │ │ │ │ + │ │ │ │ │ + // set the div's width and height to empty values, so │ │ │ │ │ + // the div dimensions can be controlled by CSS │ │ │ │ │ + this.div.style.width = ""; │ │ │ │ │ + this.div.style.height = ""; │ │ │ │ │ + │ │ │ │ │ + this.showControls(false); │ │ │ │ │ + │ │ │ │ │ + if (e != null) { │ │ │ │ │ + OpenLayers.Event.stop(e); │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: clearLayerFilter │ │ │ │ │ - * Clears layer filters, either from a specific layer, │ │ │ │ │ - * or all of them. │ │ │ │ │ + * Method: minimizeControl │ │ │ │ │ + * Hide all the contents of the control, shrink the size, │ │ │ │ │ + * add the maximize icon │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * id - {String} The id of the layer from which to remove any │ │ │ │ │ - * filter. If unspecified/blank, all filters │ │ │ │ │ - * will be removed. │ │ │ │ │ + * e - {Event} │ │ │ │ │ */ │ │ │ │ │ - clearLayerFilter: function(id) { │ │ │ │ │ - if (id) { │ │ │ │ │ - delete this.layerDefs[id]; │ │ │ │ │ - } else { │ │ │ │ │ - delete this.layerDefs; │ │ │ │ │ + minimizeControl: function(e) { │ │ │ │ │ + │ │ │ │ │ + // to minimize the control we set its div's width │ │ │ │ │ + // and height to 0px, we cannot just set "display" │ │ │ │ │ + // to "none" because it would hide the maximize │ │ │ │ │ + // div │ │ │ │ │ + this.div.style.width = "0px"; │ │ │ │ │ + this.div.style.height = "0px"; │ │ │ │ │ + │ │ │ │ │ + this.showControls(true); │ │ │ │ │ + │ │ │ │ │ + if (e != null) { │ │ │ │ │ + OpenLayers.Event.stop(e); │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: mergeNewParams │ │ │ │ │ - * Catch changeParams and uppercase the new params to be merged in │ │ │ │ │ - * before calling changeParams on the super class. │ │ │ │ │ - * │ │ │ │ │ - * Once params have been changed, the tiles will be reloaded with │ │ │ │ │ - * the new parameters. │ │ │ │ │ - * │ │ │ │ │ + * Method: showControls │ │ │ │ │ + * Hide/Show all LayerSwitcher controls depending on whether we are │ │ │ │ │ + * minimized or not │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * newParams - {Object} Hashtable of new params to use │ │ │ │ │ + * minimize - {Boolean} │ │ │ │ │ */ │ │ │ │ │ - mergeNewParams: function(newParams) { │ │ │ │ │ - var upperParams = OpenLayers.Util.upperCaseObject(newParams); │ │ │ │ │ - var newArguments = [upperParams]; │ │ │ │ │ - return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, │ │ │ │ │ - newArguments); │ │ │ │ │ + showControls: function(minimize) { │ │ │ │ │ + │ │ │ │ │ + this.maximizeDiv.style.display = minimize ? "" : "none"; │ │ │ │ │ + this.minimizeDiv.style.display = minimize ? "none" : ""; │ │ │ │ │ + │ │ │ │ │ + this.layersDiv.style.display = minimize ? "none" : ""; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.ArcGIS93Rest" │ │ │ │ │ + /** │ │ │ │ │ + * Method: loadContents │ │ │ │ │ + * Set up the labels and divs for the control │ │ │ │ │ + */ │ │ │ │ │ + loadContents: function() { │ │ │ │ │ + │ │ │ │ │ + // layers list div │ │ │ │ │ + this.layersDiv = document.createElement("div"); │ │ │ │ │ + this.layersDiv.id = this.id + "_layersDiv"; │ │ │ │ │ + OpenLayers.Element.addClass(this.layersDiv, "layersDiv"); │ │ │ │ │ + │ │ │ │ │ + this.baseLbl = document.createElement("div"); │ │ │ │ │ + this.baseLbl.innerHTML = OpenLayers.i18n("Base Layer"); │ │ │ │ │ + OpenLayers.Element.addClass(this.baseLbl, "baseLbl"); │ │ │ │ │ + │ │ │ │ │ + this.baseLayersDiv = document.createElement("div"); │ │ │ │ │ + OpenLayers.Element.addClass(this.baseLayersDiv, "baseLayersDiv"); │ │ │ │ │ + │ │ │ │ │ + this.dataLbl = document.createElement("div"); │ │ │ │ │ + this.dataLbl.innerHTML = OpenLayers.i18n("Overlays"); │ │ │ │ │ + OpenLayers.Element.addClass(this.dataLbl, "dataLbl"); │ │ │ │ │ + │ │ │ │ │ + this.dataLayersDiv = document.createElement("div"); │ │ │ │ │ + OpenLayers.Element.addClass(this.dataLayersDiv, "dataLayersDiv"); │ │ │ │ │ + │ │ │ │ │ + if (this.ascending) { │ │ │ │ │ + this.layersDiv.appendChild(this.baseLbl); │ │ │ │ │ + this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ │ + this.layersDiv.appendChild(this.dataLbl); │ │ │ │ │ + this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ │ + } else { │ │ │ │ │ + this.layersDiv.appendChild(this.dataLbl); │ │ │ │ │ + this.layersDiv.appendChild(this.dataLayersDiv); │ │ │ │ │ + this.layersDiv.appendChild(this.baseLbl); │ │ │ │ │ + this.layersDiv.appendChild(this.baseLayersDiv); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.div.appendChild(this.layersDiv); │ │ │ │ │ + │ │ │ │ │ + // maximize button div │ │ │ │ │ + var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png'); │ │ │ │ │ + this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ │ + "OpenLayers_Control_MaximizeDiv", │ │ │ │ │ + null, │ │ │ │ │ + null, │ │ │ │ │ + img, │ │ │ │ │ + "absolute"); │ │ │ │ │ + OpenLayers.Element.addClass(this.maximizeDiv, "maximizeDiv olButton"); │ │ │ │ │ + this.maximizeDiv.style.display = "none"; │ │ │ │ │ + │ │ │ │ │ + this.div.appendChild(this.maximizeDiv); │ │ │ │ │ + │ │ │ │ │ + // minimize button div │ │ │ │ │ + var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png'); │ │ │ │ │ + this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv( │ │ │ │ │ + "OpenLayers_Control_MinimizeDiv", │ │ │ │ │ + null, │ │ │ │ │ + null, │ │ │ │ │ + img, │ │ │ │ │ + "absolute"); │ │ │ │ │ + OpenLayers.Element.addClass(this.minimizeDiv, "minimizeDiv olButton"); │ │ │ │ │ + this.minimizeDiv.style.display = "none"; │ │ │ │ │ + │ │ │ │ │ + this.div.appendChild(this.minimizeDiv); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.LayerSwitcher" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Layer/XYZ.js │ │ │ │ │ + OpenLayers/Control/ArgParser.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Layer/Grid.js │ │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Layer.XYZ │ │ │ │ │ - * The XYZ class is designed to make it easier for people who have tiles │ │ │ │ │ - * arranged by a standard XYZ grid. │ │ │ │ │ - * │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.ArgParser │ │ │ │ │ + * The ArgParser control adds location bar query string parsing functionality │ │ │ │ │ + * to an OpenLayers Map. │ │ │ │ │ + * When added to a Map control, on a page load/refresh, the Map will │ │ │ │ │ + * automatically take the href string and parse it for lon, lat, zoom, and │ │ │ │ │ + * layers information. │ │ │ │ │ + * │ │ │ │ │ * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Layer.XYZ = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ │ +OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ │ - * Default is true, as this is designed to be a base tile source. │ │ │ │ │ + * Property: center │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - isBaseLayer: true, │ │ │ │ │ + center: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: sphericalMercator │ │ │ │ │ - * Whether the tile extents should be set to the defaults for │ │ │ │ │ - * spherical mercator. Useful for things like OpenStreetMap. │ │ │ │ │ - * Default is false, except for the OSM subclass. │ │ │ │ │ + * Property: zoom │ │ │ │ │ + * {int} │ │ │ │ │ */ │ │ │ │ │ - sphericalMercator: false, │ │ │ │ │ + zoom: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: zoomOffset │ │ │ │ │ - * {Number} If your cache has more zoom levels than you want to provide │ │ │ │ │ - * access to with this layer, supply a zoomOffset. This zoom offset │ │ │ │ │ - * is added to the current map zoom level to determine the level │ │ │ │ │ - * for a requested tile. For example, if you supply a zoomOffset │ │ │ │ │ - * of 3, when the map is at the zoom 0, tiles will be requested from │ │ │ │ │ - * level 3 of your cache. Default is 0 (assumes cache level and map │ │ │ │ │ - * zoom are equivalent). Using is an alternative to │ │ │ │ │ - * setting if you only want to expose a subset │ │ │ │ │ - * of the server resolutions. │ │ │ │ │ + * Property: layers │ │ │ │ │ + * {String} Each character represents the state of the corresponding layer │ │ │ │ │ + * on the map. │ │ │ │ │ */ │ │ │ │ │ - zoomOffset: 0, │ │ │ │ │ + layers: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: serverResolutions │ │ │ │ │ - * {Array} A list of all resolutions available on the server. Only set this │ │ │ │ │ - * property if the map resolutions differ from the server. This │ │ │ │ │ - * property serves two purposes. (a) can include │ │ │ │ │ - * resolutions that the server supports and that you don't want to │ │ │ │ │ - * provide with this layer; you can also look at , which is │ │ │ │ │ - * an alternative to for that specific purpose. │ │ │ │ │ - * (b) The map can work with resolutions that aren't supported by │ │ │ │ │ - * the server, i.e. that aren't in . When the │ │ │ │ │ - * map is displayed in such a resolution data for the closest │ │ │ │ │ - * server-supported resolution is loaded and the layer div is │ │ │ │ │ - * stretched as necessary. │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: displayProjection │ │ │ │ │ + * {} Requires proj4js support. │ │ │ │ │ + * Projection used when reading the coordinates from the URL. This will │ │ │ │ │ + * reproject the map coordinates from the URL into the map's │ │ │ │ │ + * projection. │ │ │ │ │ + * │ │ │ │ │ + * If you are using this functionality, be aware that any permalink │ │ │ │ │ + * which is added to the map will determine the coordinate type which │ │ │ │ │ + * is read from the URL, which means you should not add permalinks with │ │ │ │ │ + * different displayProjections to the same map. │ │ │ │ │ */ │ │ │ │ │ - serverResolutions: null, │ │ │ │ │ + displayProjection: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Layer.XYZ │ │ │ │ │ + * Constructor: OpenLayers.Control.ArgParser │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * name - {String} │ │ │ │ │ - * url - {String} │ │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ │ + * options - {Object} │ │ │ │ │ */ │ │ │ │ │ - initialize: function(name, url, options) { │ │ │ │ │ - if (options && options.sphericalMercator || this.sphericalMercator) { │ │ │ │ │ - options = OpenLayers.Util.extend({ │ │ │ │ │ - projection: "EPSG:900913", │ │ │ │ │ - numZoomLevels: 19 │ │ │ │ │ - }, options); │ │ │ │ │ - } │ │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply(this, [ │ │ │ │ │ - name || this.name, url || this.url, {}, │ │ │ │ │ - options │ │ │ │ │ - ]); │ │ │ │ │ - }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: clone │ │ │ │ │ - * Create a clone of this layer │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * obj - {Object} Is this ever used? │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} An exact clone of this OpenLayers.Layer.XYZ │ │ │ │ │ + * Method: getParameters │ │ │ │ │ */ │ │ │ │ │ - clone: function(obj) { │ │ │ │ │ - │ │ │ │ │ - if (obj == null) { │ │ │ │ │ - obj = new OpenLayers.Layer.XYZ(this.name, │ │ │ │ │ - this.url, │ │ │ │ │ - this.getOptions()); │ │ │ │ │ - } │ │ │ │ │ + getParameters: function(url) { │ │ │ │ │ + url = url || window.location.href; │ │ │ │ │ + var parameters = OpenLayers.Util.getParameters(url); │ │ │ │ │ │ │ │ │ │ - //get all additions from superclasses │ │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ │ + // If we have an anchor in the url use it to split the url │ │ │ │ │ + var index = url.indexOf('#'); │ │ │ │ │ + if (index > 0) { │ │ │ │ │ + // create an url to parse on the getParameters │ │ │ │ │ + url = '?' + url.substring(index + 1, url.length); │ │ │ │ │ │ │ │ │ │ - return obj; │ │ │ │ │ + OpenLayers.Util.extend(parameters, │ │ │ │ │ + OpenLayers.Util.getParameters(url)); │ │ │ │ │ + } │ │ │ │ │ + return parameters; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getURL │ │ │ │ │ - * │ │ │ │ │ + * Method: setMap │ │ │ │ │ + * Set the map property for the control. │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * bounds - {} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} A string with the layer's url and parameters and also the │ │ │ │ │ - * passed-in bounds and appropriate tile size specified as │ │ │ │ │ - * parameters │ │ │ │ │ + * map - {} │ │ │ │ │ */ │ │ │ │ │ - getURL: function(bounds) { │ │ │ │ │ - var xyz = this.getXYZ(bounds); │ │ │ │ │ - var url = this.url; │ │ │ │ │ - if (OpenLayers.Util.isArray(url)) { │ │ │ │ │ - var s = '' + xyz.x + xyz.y + xyz.z; │ │ │ │ │ - url = this.selectUrl(s, url); │ │ │ │ │ + setMap: function(map) { │ │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ │ + │ │ │ │ │ + //make sure we dont already have an arg parser attached │ │ │ │ │ + for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ │ + var control = this.map.controls[i]; │ │ │ │ │ + if ((control != this) && │ │ │ │ │ + (control.CLASS_NAME == "OpenLayers.Control.ArgParser")) { │ │ │ │ │ + │ │ │ │ │ + // If a second argparser is added to the map, then we │ │ │ │ │ + // override the displayProjection to be the one added to the │ │ │ │ │ + // map. │ │ │ │ │ + if (control.displayProjection != this.displayProjection) { │ │ │ │ │ + this.displayProjection = control.displayProjection; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ + if (i == this.map.controls.length) { │ │ │ │ │ │ │ │ │ │ - return OpenLayers.String.format(url, xyz); │ │ │ │ │ + var args = this.getParameters(); │ │ │ │ │ + // Be careful to set layer first, to not trigger unnecessary layer loads │ │ │ │ │ + if (args.layers) { │ │ │ │ │ + this.layers = args.layers; │ │ │ │ │ + │ │ │ │ │ + // when we add a new layer, set its visibility │ │ │ │ │ + this.map.events.register('addlayer', this, │ │ │ │ │ + this.configureLayers); │ │ │ │ │ + this.configureLayers(); │ │ │ │ │ + } │ │ │ │ │ + if (args.lat && args.lon) { │ │ │ │ │ + this.center = new OpenLayers.LonLat(parseFloat(args.lon), │ │ │ │ │ + parseFloat(args.lat)); │ │ │ │ │ + if (args.zoom) { │ │ │ │ │ + this.zoom = parseFloat(args.zoom); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // when we add a new baselayer to see when we can set the center │ │ │ │ │ + this.map.events.register('changebaselayer', this, │ │ │ │ │ + this.setCenter); │ │ │ │ │ + this.setCenter(); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: getXYZ │ │ │ │ │ - * Calculates x, y and z for the given bounds. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * bounds - {} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} - an object with x, y and z properties. │ │ │ │ │ + /** │ │ │ │ │ + * Method: setCenter │ │ │ │ │ + * As soon as a baseLayer has been loaded, we center and zoom │ │ │ │ │ + * ...and remove the handler. │ │ │ │ │ */ │ │ │ │ │ - getXYZ: function(bounds) { │ │ │ │ │ - var res = this.getServerResolution(); │ │ │ │ │ - var x = Math.round((bounds.left - this.maxExtent.left) / │ │ │ │ │ - (res * this.tileSize.w)); │ │ │ │ │ - var y = Math.round((this.maxExtent.top - bounds.top) / │ │ │ │ │ - (res * this.tileSize.h)); │ │ │ │ │ - var z = this.getServerZoom(); │ │ │ │ │ + setCenter: function() { │ │ │ │ │ │ │ │ │ │ - if (this.wrapDateLine) { │ │ │ │ │ - var limit = Math.pow(2, z); │ │ │ │ │ - x = ((x % limit) + limit) % limit; │ │ │ │ │ - } │ │ │ │ │ + if (this.map.baseLayer) { │ │ │ │ │ + //dont need to listen for this one anymore │ │ │ │ │ + this.map.events.unregister('changebaselayer', this, │ │ │ │ │ + this.setCenter); │ │ │ │ │ │ │ │ │ │ - return { │ │ │ │ │ - 'x': x, │ │ │ │ │ - 'y': y, │ │ │ │ │ - 'z': z │ │ │ │ │ - }; │ │ │ │ │ + if (this.displayProjection) { │ │ │ │ │ + this.center.transform(this.displayProjection, │ │ │ │ │ + this.map.getProjectionObject()); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.map.setCenter(this.center, this.zoom); │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /* APIMethod: setMap │ │ │ │ │ - * When the layer is added to a map, then we can fetch our origin │ │ │ │ │ - * (if we don't have one.) │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * map - {} │ │ │ │ │ + /** │ │ │ │ │ + * Method: configureLayers │ │ │ │ │ + * As soon as all the layers are loaded, cycle through them and │ │ │ │ │ + * hide or show them. │ │ │ │ │ */ │ │ │ │ │ - setMap: function(map) { │ │ │ │ │ - OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments); │ │ │ │ │ - if (!this.tileOrigin) { │ │ │ │ │ - this.tileOrigin = new OpenLayers.LonLat(this.maxExtent.left, │ │ │ │ │ - this.maxExtent.bottom); │ │ │ │ │ + configureLayers: function() { │ │ │ │ │ + │ │ │ │ │ + if (this.layers.length == this.map.layers.length) { │ │ │ │ │ + this.map.events.unregister('addlayer', this, this.configureLayers); │ │ │ │ │ + │ │ │ │ │ + for (var i = 0, len = this.layers.length; i < len; i++) { │ │ │ │ │ + │ │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ │ + var c = this.layers.charAt(i); │ │ │ │ │ + │ │ │ │ │ + if (c == "B") { │ │ │ │ │ + this.map.setBaseLayer(layer); │ │ │ │ │ + } else if ((c == "T") || (c == "F")) { │ │ │ │ │ + layer.setVisibility(c == "T"); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.XYZ" │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.ArgParser" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Tile/UTFGrid.js │ │ │ │ │ + OpenLayers/Control/Permalink.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Tile.js │ │ │ │ │ - * @requires OpenLayers/Format/JSON.js │ │ │ │ │ - * @requires OpenLayers/Request.js │ │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ │ + * @requires OpenLayers/Control/ArgParser.js │ │ │ │ │ + * @requires OpenLayers/Lang.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Tile.UTFGrid │ │ │ │ │ - * Instances of OpenLayers.Tile.UTFGrid are used to manage │ │ │ │ │ - * UTFGrids. This is an unusual tile type in that it doesn't have a │ │ │ │ │ - * rendered image; only a 'hit grid' that can be used to │ │ │ │ │ - * look up feature attributes. │ │ │ │ │ - * │ │ │ │ │ - * See the constructor for details on constructing a │ │ │ │ │ - * new instance. │ │ │ │ │ - * │ │ │ │ │ + * Class: OpenLayers.Control.Permalink │ │ │ │ │ + * The Permalink control is hyperlink that will return the user to the │ │ │ │ │ + * current map view. By default it is drawn in the lower right corner of the │ │ │ │ │ + * map. The href is updated as the map is zoomed, panned and whilst layers │ │ │ │ │ + * are switched. │ │ │ │ │ + * │ │ │ │ │ * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Tile.UTFGrid = OpenLayers.Class(OpenLayers.Tile, { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: url │ │ │ │ │ - * {String} │ │ │ │ │ - * The URL of the UTFGrid file being requested. Provided by the │ │ │ │ │ - * method. │ │ │ │ │ - */ │ │ │ │ │ - url: null, │ │ │ │ │ +OpenLayers.Control.Permalink = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: utfgridResolution │ │ │ │ │ - * {Number} │ │ │ │ │ - * Ratio of the pixel width to the width of a UTFGrid data point. If an │ │ │ │ │ - * entry in the grid represents a 4x4 block of pixels, the │ │ │ │ │ - * utfgridResolution would be 4. Default is 2. │ │ │ │ │ + * APIProperty: argParserClass │ │ │ │ │ + * {Class} The ArgParser control class (not instance) to use with this │ │ │ │ │ + * control. │ │ │ │ │ */ │ │ │ │ │ - utfgridResolution: 2, │ │ │ │ │ + argParserClass: OpenLayers.Control.ArgParser, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: json │ │ │ │ │ - * {Object} │ │ │ │ │ - * Stores the parsed JSON tile data structure. │ │ │ │ │ + * Property: element │ │ │ │ │ + * {DOMElement} │ │ │ │ │ */ │ │ │ │ │ - json: null, │ │ │ │ │ + element: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: format │ │ │ │ │ - * {OpenLayers.Format.JSON} │ │ │ │ │ - * Parser instance used to parse JSON for cross browser support. The native │ │ │ │ │ - * JSON.parse method will be used where available (all except IE<8). │ │ │ │ │ + * APIProperty: anchor │ │ │ │ │ + * {Boolean} This option changes 3 things: │ │ │ │ │ + * the character '#' is used in place of the character '?', │ │ │ │ │ + * the window.href is updated if no element is provided. │ │ │ │ │ + * When this option is set to true it's not recommend to provide │ │ │ │ │ + * a base without provide an element. │ │ │ │ │ */ │ │ │ │ │ - format: null, │ │ │ │ │ + anchor: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Tile.UTFGrid │ │ │ │ │ - * Constructor for a new instance. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * layer - {} layer that the tile will go in. │ │ │ │ │ - * position - {} │ │ │ │ │ - * bounds - {} │ │ │ │ │ - * url - {} Deprecated. Remove me in 3.0. │ │ │ │ │ - * size - {} │ │ │ │ │ - * options - {Object} │ │ │ │ │ + * APIProperty: base │ │ │ │ │ + * {String} │ │ │ │ │ */ │ │ │ │ │ + base: '', │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ - * Clean up. │ │ │ │ │ + * APIProperty: displayProjection │ │ │ │ │ + * {} Requires proj4js support. Projection used │ │ │ │ │ + * when creating the coordinates in the link. This will reproject the │ │ │ │ │ + * map coordinates into display coordinates. If you are using this │ │ │ │ │ + * functionality, the permalink which is last added to the map will │ │ │ │ │ + * determine the coordinate type which is read from the URL, which │ │ │ │ │ + * means you should not add permalinks with different │ │ │ │ │ + * displayProjections to the same map. │ │ │ │ │ */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - this.clear(); │ │ │ │ │ - OpenLayers.Tile.prototype.destroy.apply(this, arguments); │ │ │ │ │ - }, │ │ │ │ │ + displayProjection: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: draw │ │ │ │ │ - * Check that a tile should be drawn, and draw it. │ │ │ │ │ - * In the case of UTFGrids, "drawing" it means fetching and │ │ │ │ │ - * parsing the json. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Boolean} Was a tile drawn? │ │ │ │ │ + * Constructor: OpenLayers.Control.Permalink │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * element - {DOMElement} │ │ │ │ │ + * base - {String} │ │ │ │ │ + * options - {Object} options to the control. │ │ │ │ │ + * │ │ │ │ │ + * Or for anchor: │ │ │ │ │ + * options - {Object} options to the control. │ │ │ │ │ */ │ │ │ │ │ - draw: function() { │ │ │ │ │ - var drawn = OpenLayers.Tile.prototype.draw.apply(this, arguments); │ │ │ │ │ - if (drawn) { │ │ │ │ │ - if (this.isLoading) { │ │ │ │ │ - this.abortLoading(); │ │ │ │ │ - //if we're already loading, send 'reload' instead of 'loadstart'. │ │ │ │ │ - this.events.triggerEvent("reload"); │ │ │ │ │ - } else { │ │ │ │ │ - this.isLoading = true; │ │ │ │ │ - this.events.triggerEvent("loadstart"); │ │ │ │ │ - } │ │ │ │ │ - this.url = this.layer.getURL(this.bounds); │ │ │ │ │ - │ │ │ │ │ - if (this.layer.useJSONP) { │ │ │ │ │ - // Use JSONP method to avoid xbrowser policy │ │ │ │ │ - var ols = new OpenLayers.Protocol.Script({ │ │ │ │ │ - url: this.url, │ │ │ │ │ - callback: function(response) { │ │ │ │ │ - this.isLoading = false; │ │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ │ - this.json = response.data; │ │ │ │ │ - }, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ - ols.read(); │ │ │ │ │ - this.request = ols; │ │ │ │ │ - } else { │ │ │ │ │ - // Use standard XHR │ │ │ │ │ - this.request = OpenLayers.Request.GET({ │ │ │ │ │ - url: this.url, │ │ │ │ │ - callback: function(response) { │ │ │ │ │ - this.isLoading = false; │ │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ │ - if (response.status === 200) { │ │ │ │ │ - this.parseData(response.responseText); │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ + initialize: function(element, base, options) { │ │ │ │ │ + if (element !== null && typeof element == 'object' && !OpenLayers.Util.isElement(element)) { │ │ │ │ │ + options = element; │ │ │ │ │ + this.base = document.location.href; │ │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ │ + if (this.element != null) { │ │ │ │ │ + this.element = OpenLayers.Util.getElement(this.element); │ │ │ │ │ } │ │ │ │ │ } else { │ │ │ │ │ - this.unload(); │ │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ │ + this.element = OpenLayers.Util.getElement(element); │ │ │ │ │ + this.base = base || document.location.href; │ │ │ │ │ } │ │ │ │ │ - return drawn; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: abortLoading │ │ │ │ │ - * Cancel a pending request. │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ */ │ │ │ │ │ - abortLoading: function() { │ │ │ │ │ - if (this.request) { │ │ │ │ │ - this.request.abort(); │ │ │ │ │ - delete this.request; │ │ │ │ │ + destroy: function() { │ │ │ │ │ + if (this.element && this.element.parentNode == this.div) { │ │ │ │ │ + this.div.removeChild(this.element); │ │ │ │ │ + this.element = null; │ │ │ │ │ } │ │ │ │ │ - this.isLoading = false; │ │ │ │ │ + if (this.map) { │ │ │ │ │ + this.map.events.unregister('moveend', this, this.updateLink); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getFeatureInfo │ │ │ │ │ - * Get feature information associated with a pixel offset. If the pixel │ │ │ │ │ - * offset corresponds to a feature, the returned object will have id │ │ │ │ │ - * and data properties. Otherwise, null will be returned. │ │ │ │ │ - * │ │ │ │ │ - * │ │ │ │ │ + * Method: setMap │ │ │ │ │ + * Set the map property for the control. │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * i - {Number} X-axis pixel offset (from top left of tile) │ │ │ │ │ - * j - {Number} Y-axis pixel offset (from top left of tile) │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} Object with feature id and data properties corresponding to the │ │ │ │ │ - * given pixel offset. │ │ │ │ │ + * map - {} │ │ │ │ │ */ │ │ │ │ │ - getFeatureInfo: function(i, j) { │ │ │ │ │ - var info = null; │ │ │ │ │ - if (this.json) { │ │ │ │ │ - var id = this.getFeatureId(i, j); │ │ │ │ │ - if (id !== null) { │ │ │ │ │ - info = { │ │ │ │ │ - id: id, │ │ │ │ │ - data: this.json.data[id] │ │ │ │ │ - }; │ │ │ │ │ + setMap: function(map) { │ │ │ │ │ + OpenLayers.Control.prototype.setMap.apply(this, arguments); │ │ │ │ │ + │ │ │ │ │ + //make sure we have an arg parser attached │ │ │ │ │ + for (var i = 0, len = this.map.controls.length; i < len; i++) { │ │ │ │ │ + var control = this.map.controls[i]; │ │ │ │ │ + if (control.CLASS_NAME == this.argParserClass.CLASS_NAME) { │ │ │ │ │ + │ │ │ │ │ + // If a permalink is added to the map, and an ArgParser already │ │ │ │ │ + // exists, we override the displayProjection to be the one │ │ │ │ │ + // on the permalink. │ │ │ │ │ + if (control.displayProjection != this.displayProjection) { │ │ │ │ │ + this.displayProjection = control.displayProjection; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + break; │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ - return info; │ │ │ │ │ + if (i == this.map.controls.length) { │ │ │ │ │ + this.map.addControl(new this.argParserClass({ │ │ │ │ │ + 'displayProjection': this.displayProjection │ │ │ │ │ + })); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getFeatureId │ │ │ │ │ - * Get the identifier for the feature associated with a pixel offset. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * i - {Number} X-axis pixel offset (from top left of tile) │ │ │ │ │ - * j - {Number} Y-axis pixel offset (from top left of tile) │ │ │ │ │ + * Method: draw │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Object} The feature identifier corresponding to the given pixel offset. │ │ │ │ │ - * Returns null if pixel doesn't correspond to a feature. │ │ │ │ │ + * {DOMElement} │ │ │ │ │ */ │ │ │ │ │ - getFeatureId: function(i, j) { │ │ │ │ │ - var id = null; │ │ │ │ │ - if (this.json) { │ │ │ │ │ - var resolution = this.utfgridResolution; │ │ │ │ │ - var row = Math.floor(j / resolution); │ │ │ │ │ - var col = Math.floor(i / resolution); │ │ │ │ │ - var charCode = this.json.grid[row].charCodeAt(col); │ │ │ │ │ - var index = this.indexFromCharCode(charCode); │ │ │ │ │ - var keys = this.json.keys; │ │ │ │ │ - if (!isNaN(index) && (index in keys)) { │ │ │ │ │ - id = keys[index]; │ │ │ │ │ - } │ │ │ │ │ + draw: function() { │ │ │ │ │ + OpenLayers.Control.prototype.draw.apply(this, arguments); │ │ │ │ │ + │ │ │ │ │ + if (!this.element && !this.anchor) { │ │ │ │ │ + this.element = document.createElement("a"); │ │ │ │ │ + this.element.innerHTML = OpenLayers.i18n("Permalink"); │ │ │ │ │ + this.element.href = ""; │ │ │ │ │ + this.div.appendChild(this.element); │ │ │ │ │ } │ │ │ │ │ - return id; │ │ │ │ │ + this.map.events.on({ │ │ │ │ │ + 'moveend': this.updateLink, │ │ │ │ │ + 'changelayer': this.updateLink, │ │ │ │ │ + 'changebaselayer': this.updateLink, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + │ │ │ │ │ + // Make it so there is at least a link even though the map may not have │ │ │ │ │ + // moved yet. │ │ │ │ │ + this.updateLink(); │ │ │ │ │ + │ │ │ │ │ + return this.div; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: indexFromCharCode │ │ │ │ │ - * Given a character code for one of the UTFGrid "grid" characters, │ │ │ │ │ - * resolve the integer index for the feature id in the UTFGrid "keys" │ │ │ │ │ - * array. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * charCode - {Integer} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Integer} Index for the feature id from the keys array. │ │ │ │ │ + * Method: updateLink │ │ │ │ │ */ │ │ │ │ │ - indexFromCharCode: function(charCode) { │ │ │ │ │ - if (charCode >= 93) { │ │ │ │ │ - charCode--; │ │ │ │ │ + updateLink: function() { │ │ │ │ │ + var separator = this.anchor ? '#' : '?'; │ │ │ │ │ + var href = this.base; │ │ │ │ │ + var anchor = null; │ │ │ │ │ + if (href.indexOf("#") != -1 && this.anchor == false) { │ │ │ │ │ + anchor = href.substring(href.indexOf("#"), href.length); │ │ │ │ │ } │ │ │ │ │ - if (charCode >= 35) { │ │ │ │ │ - charCode--; │ │ │ │ │ + if (href.indexOf(separator) != -1) { │ │ │ │ │ + href = href.substring(0, href.indexOf(separator)); │ │ │ │ │ + } │ │ │ │ │ + var splits = href.split("#"); │ │ │ │ │ + href = splits[0] + separator + OpenLayers.Util.getParameterString(this.createParams()); │ │ │ │ │ + if (anchor) { │ │ │ │ │ + href += anchor; │ │ │ │ │ + } │ │ │ │ │ + if (this.anchor && !this.element) { │ │ │ │ │ + window.location.href = href; │ │ │ │ │ + } else { │ │ │ │ │ + this.element.href = href; │ │ │ │ │ } │ │ │ │ │ - return charCode - 32; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: parseData │ │ │ │ │ - * Parse the JSON from a request │ │ │ │ │ - * │ │ │ │ │ + * APIMethod: createParams │ │ │ │ │ + * Creates the parameters that need to be encoded into the permalink url. │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * str - {String} UTFGrid as a JSON string. │ │ │ │ │ + * center - {} center to encode in the permalink. │ │ │ │ │ + * Defaults to the current map center. │ │ │ │ │ + * zoom - {Integer} zoom level to encode in the permalink. Defaults to the │ │ │ │ │ + * current map zoom level. │ │ │ │ │ + * layers - {Array()} layers to encode in the permalink. │ │ │ │ │ + * Defaults to the current map layers. │ │ │ │ │ * │ │ │ │ │ * Returns: │ │ │ │ │ - * {Object} parsed javascript data │ │ │ │ │ + * {Object} Hash of parameters that will be url-encoded into the │ │ │ │ │ + * permalink. │ │ │ │ │ */ │ │ │ │ │ - parseData: function(str) { │ │ │ │ │ - if (!this.format) { │ │ │ │ │ - this.format = new OpenLayers.Format.JSON(); │ │ │ │ │ + createParams: function(center, zoom, layers) { │ │ │ │ │ + center = center || this.map.getCenter(); │ │ │ │ │ + │ │ │ │ │ + var params = OpenLayers.Util.getParameters(this.base); │ │ │ │ │ + │ │ │ │ │ + // If there's still no center, map is not initialized yet. │ │ │ │ │ + // Break out of this function, and simply return the params from the │ │ │ │ │ + // base link. │ │ │ │ │ + if (center) { │ │ │ │ │ + │ │ │ │ │ + //zoom │ │ │ │ │ + params.zoom = zoom || this.map.getZoom(); │ │ │ │ │ + │ │ │ │ │ + //lon,lat │ │ │ │ │ + var lat = center.lat; │ │ │ │ │ + var lon = center.lon; │ │ │ │ │ + │ │ │ │ │ + if (this.displayProjection) { │ │ │ │ │ + var mapPosition = OpenLayers.Projection.transform({ │ │ │ │ │ + x: lon, │ │ │ │ │ + y: lat │ │ │ │ │ + }, │ │ │ │ │ + this.map.getProjectionObject(), │ │ │ │ │ + this.displayProjection); │ │ │ │ │ + lon = mapPosition.x; │ │ │ │ │ + lat = mapPosition.y; │ │ │ │ │ + } │ │ │ │ │ + params.lat = Math.round(lat * 100000) / 100000; │ │ │ │ │ + params.lon = Math.round(lon * 100000) / 100000; │ │ │ │ │ + │ │ │ │ │ + //layers │ │ │ │ │ + layers = layers || this.map.layers; │ │ │ │ │ + params.layers = ''; │ │ │ │ │ + for (var i = 0, len = layers.length; i < len; i++) { │ │ │ │ │ + var layer = layers[i]; │ │ │ │ │ + │ │ │ │ │ + if (layer.isBaseLayer) { │ │ │ │ │ + params.layers += (layer == this.map.baseLayer) ? "B" : "0"; │ │ │ │ │ + } else { │ │ │ │ │ + params.layers += (layer.getVisibility()) ? "T" : "F"; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ - this.json = this.format.read(str); │ │ │ │ │ - }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: clear │ │ │ │ │ - * Delete data stored with this tile. │ │ │ │ │ - */ │ │ │ │ │ - clear: function() { │ │ │ │ │ - this.json = null; │ │ │ │ │ + return params; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Tile.UTFGrid" │ │ │ │ │ - │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Permalink" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Layer/UTFGrid.js │ │ │ │ │ + OpenLayers/Handler/MouseWheel.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Layer/XYZ.js │ │ │ │ │ - * @requires OpenLayers/Tile/UTFGrid.js │ │ │ │ │ + * @requires OpenLayers/Handler.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Layer.UTFGrid │ │ │ │ │ - * This Layer reads from UTFGrid tiled data sources. Since UTFGrids are │ │ │ │ │ - * essentially JSON-based ASCII art with attached attributes, they are not │ │ │ │ │ - * visibly rendered. In order to use them in the map, you must add a │ │ │ │ │ - * control as well. │ │ │ │ │ - * │ │ │ │ │ - * Example: │ │ │ │ │ - * │ │ │ │ │ - * (start code) │ │ │ │ │ - * var world_utfgrid = new OpenLayers.Layer.UTFGrid({ │ │ │ │ │ - * url: "/tiles/world_utfgrid/${z}/${x}/${y}.json", │ │ │ │ │ - * utfgridResolution: 4, │ │ │ │ │ - * displayInLayerSwitcher: false │ │ │ │ │ - * ); │ │ │ │ │ - * map.addLayer(world_utfgrid); │ │ │ │ │ - * │ │ │ │ │ - * var control = new OpenLayers.Control.UTFGrid({ │ │ │ │ │ - * layers: [world_utfgrid], │ │ │ │ │ - * handlerMode: 'move', │ │ │ │ │ - * callback: function(dataLookup) { │ │ │ │ │ - * // do something with returned data │ │ │ │ │ - * } │ │ │ │ │ - * }) │ │ │ │ │ - * (end code) │ │ │ │ │ - * │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Handler.MouseWheel │ │ │ │ │ + * Handler for wheel up/down events. │ │ │ │ │ * │ │ │ │ │ * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Layer.UTFGrid = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ │ - * Default is false, as UTFGrids are designed to be a transparent overlay layer. │ │ │ │ │ - */ │ │ │ │ │ - isBaseLayer: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: projection │ │ │ │ │ - * {} │ │ │ │ │ - * Source projection for the UTFGrids. Default is "EPSG:900913". │ │ │ │ │ +OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, { │ │ │ │ │ + /** │ │ │ │ │ + * Property: wheelListener │ │ │ │ │ + * {function} │ │ │ │ │ */ │ │ │ │ │ - projection: new OpenLayers.Projection("EPSG:900913"), │ │ │ │ │ + wheelListener: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: useJSONP │ │ │ │ │ - * {Boolean} │ │ │ │ │ - * Should we use a JSONP script approach instead of a standard AJAX call? │ │ │ │ │ - * │ │ │ │ │ - * Set to true for using utfgrids from another server. │ │ │ │ │ - * Avoids same-domain policy restrictions. │ │ │ │ │ - * Note that this only works if the server accepts │ │ │ │ │ - * the callback GET parameter and dynamically │ │ │ │ │ - * wraps the returned json in a function call. │ │ │ │ │ - * │ │ │ │ │ - * Default is false │ │ │ │ │ + * Property: interval │ │ │ │ │ + * {Integer} In order to increase server performance, an interval (in │ │ │ │ │ + * milliseconds) can be set to reduce the number of up/down events │ │ │ │ │ + * called. If set, a new up/down event will not be set until the │ │ │ │ │ + * interval has passed. │ │ │ │ │ + * Defaults to 0, meaning no interval. │ │ │ │ │ */ │ │ │ │ │ - useJSONP: false, │ │ │ │ │ + interval: 0, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: url │ │ │ │ │ - * {String} │ │ │ │ │ - * URL tempate for UTFGrid tiles. Include x, y, and z parameters. │ │ │ │ │ - * E.g. "/tiles/${z}/${x}/${y}.json" │ │ │ │ │ + * Property: maxDelta │ │ │ │ │ + * {Integer} Maximum delta to collect before breaking from the current │ │ │ │ │ + * interval. In cumulative mode, this also limits the maximum delta │ │ │ │ │ + * returned from the handler. Default is Number.POSITIVE_INFINITY. │ │ │ │ │ */ │ │ │ │ │ + maxDelta: Number.POSITIVE_INFINITY, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: utfgridResolution │ │ │ │ │ - * {Number} │ │ │ │ │ - * Ratio of the pixel width to the width of a UTFGrid data point. If an │ │ │ │ │ - * entry in the grid represents a 4x4 block of pixels, the │ │ │ │ │ - * utfgridResolution would be 4. Default is 2 (specified in │ │ │ │ │ - * ). │ │ │ │ │ + * Property: delta │ │ │ │ │ + * {Integer} When interval is set, delta collects the mousewheel z-deltas │ │ │ │ │ + * of the events that occur within the interval. │ │ │ │ │ + * See also the cumulative option │ │ │ │ │ */ │ │ │ │ │ + delta: 0, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: tileClass │ │ │ │ │ - * {} The tile class to use for this layer. │ │ │ │ │ - * Defaults is . │ │ │ │ │ + * Property: cumulative │ │ │ │ │ + * {Boolean} When interval is set: true to collect all the mousewheel │ │ │ │ │ + * z-deltas, false to only record the delta direction (positive or │ │ │ │ │ + * negative) │ │ │ │ │ */ │ │ │ │ │ - tileClass: OpenLayers.Tile.UTFGrid, │ │ │ │ │ + cumulative: true, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Layer.UTFGrid │ │ │ │ │ - * Create a new UTFGrid layer. │ │ │ │ │ + * Constructor: OpenLayers.Handler.MouseWheel │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * config - {Object} Configuration properties for the layer. │ │ │ │ │ - * │ │ │ │ │ - * Required configuration properties: │ │ │ │ │ - * url - {String} The url template for UTFGrid tiles. See the property. │ │ │ │ │ + * control - {} │ │ │ │ │ + * callbacks - {Object} An object containing a single function to be │ │ │ │ │ + * called when the drag operation is finished. │ │ │ │ │ + * The callback should expect to recieve a single │ │ │ │ │ + * argument, the point geometry. │ │ │ │ │ + * options - {Object} │ │ │ │ │ */ │ │ │ │ │ - initialize: function(options) { │ │ │ │ │ - OpenLayers.Layer.Grid.prototype.initialize.apply( │ │ │ │ │ - this, [options.name, options.url, {}, options] │ │ │ │ │ + initialize: function(control, callbacks, options) { │ │ │ │ │ + OpenLayers.Handler.prototype.initialize.apply(this, arguments); │ │ │ │ │ + this.wheelListener = OpenLayers.Function.bindAsEventListener( │ │ │ │ │ + this.onWheelEvent, this │ │ │ │ │ ); │ │ │ │ │ - this.tileOptions = OpenLayers.Util.extend({ │ │ │ │ │ - utfgridResolution: this.utfgridResolution │ │ │ │ │ - }, this.tileOptions); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: createBackBuffer │ │ │ │ │ - * The UTFGrid cannot create a back buffer, so this method is overriden. │ │ │ │ │ + * Method: destroy │ │ │ │ │ */ │ │ │ │ │ - createBackBuffer: function() {}, │ │ │ │ │ + destroy: function() { │ │ │ │ │ + OpenLayers.Handler.prototype.destroy.apply(this, arguments); │ │ │ │ │ + this.wheelListener = null; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: clone │ │ │ │ │ - * Create a clone of this layer │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * obj - {Object} Only used by a subclass of this layer. │ │ │ │ │ + * Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/ │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: onWheelEvent │ │ │ │ │ + * Catch the wheel event and handle it xbrowserly │ │ │ │ │ * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} An exact clone of this OpenLayers.Layer.UTFGrid │ │ │ │ │ + * Parameters: │ │ │ │ │ + * e - {Event} │ │ │ │ │ */ │ │ │ │ │ - clone: function(obj) { │ │ │ │ │ - if (obj == null) { │ │ │ │ │ - obj = new OpenLayers.Layer.UTFGrid(this.getOptions()); │ │ │ │ │ + onWheelEvent: function(e) { │ │ │ │ │ + │ │ │ │ │ + // make sure we have a map and check keyboard modifiers │ │ │ │ │ + if (!this.map || !this.checkModifiers(e)) { │ │ │ │ │ + return; │ │ │ │ │ } │ │ │ │ │ │ │ │ │ │ - // get all additions from superclasses │ │ │ │ │ - obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]); │ │ │ │ │ + // Ride up the element's DOM hierarchy to determine if it or any of │ │ │ │ │ + // its ancestors was: │ │ │ │ │ + // * specifically marked as scrollable (CSS overflow property) │ │ │ │ │ + // * one of our layer divs or a div marked as scrollable │ │ │ │ │ + // ('olScrollable' CSS class) │ │ │ │ │ + // * the map div │ │ │ │ │ + // │ │ │ │ │ + var overScrollableDiv = false; │ │ │ │ │ + var allowScroll = false; │ │ │ │ │ + var overMapDiv = false; │ │ │ │ │ │ │ │ │ │ - return obj; │ │ │ │ │ + var elem = OpenLayers.Event.element(e); │ │ │ │ │ + while ((elem != null) && !overMapDiv && !overScrollableDiv) { │ │ │ │ │ + │ │ │ │ │ + if (!overScrollableDiv) { │ │ │ │ │ + try { │ │ │ │ │ + var overflow; │ │ │ │ │ + if (elem.currentStyle) { │ │ │ │ │ + overflow = elem.currentStyle["overflow"]; │ │ │ │ │ + } else { │ │ │ │ │ + var style = │ │ │ │ │ + document.defaultView.getComputedStyle(elem, null); │ │ │ │ │ + overflow = style.getPropertyValue("overflow"); │ │ │ │ │ + } │ │ │ │ │ + overScrollableDiv = (overflow && │ │ │ │ │ + (overflow == "auto") || (overflow == "scroll")); │ │ │ │ │ + } catch (err) { │ │ │ │ │ + //sometimes when scrolling in a popup, this causes │ │ │ │ │ + // obscure browser error │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (!allowScroll) { │ │ │ │ │ + allowScroll = OpenLayers.Element.hasClass(elem, 'olScrollable'); │ │ │ │ │ + if (!allowScroll) { │ │ │ │ │ + for (var i = 0, len = this.map.layers.length; i < len; i++) { │ │ │ │ │ + // Are we in the layer div? Note that we have two cases │ │ │ │ │ + // here: one is to catch EventPane layers, which have a │ │ │ │ │ + // pane above the layer (layer.pane) │ │ │ │ │ + var layer = this.map.layers[i]; │ │ │ │ │ + if (elem == layer.div || elem == layer.pane) { │ │ │ │ │ + allowScroll = true; │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + overMapDiv = (elem == this.map.div); │ │ │ │ │ + │ │ │ │ │ + elem = elem.parentNode; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + // Logic below is the following: │ │ │ │ │ + // │ │ │ │ │ + // If we are over a scrollable div or not over the map div: │ │ │ │ │ + // * do nothing (let the browser handle scrolling) │ │ │ │ │ + // │ │ │ │ │ + // otherwise │ │ │ │ │ + // │ │ │ │ │ + // If we are over the layer div or a 'olScrollable' div: │ │ │ │ │ + // * zoom/in out │ │ │ │ │ + // then │ │ │ │ │ + // * kill event (so as not to also scroll the page after zooming) │ │ │ │ │ + // │ │ │ │ │ + // otherwise │ │ │ │ │ + // │ │ │ │ │ + // Kill the event (dont scroll the page if we wheel over the │ │ │ │ │ + // layerswitcher or the pan/zoom control) │ │ │ │ │ + // │ │ │ │ │ + if (!overScrollableDiv && overMapDiv) { │ │ │ │ │ + if (allowScroll) { │ │ │ │ │ + var delta = 0; │ │ │ │ │ + │ │ │ │ │ + if (e.wheelDelta) { │ │ │ │ │ + delta = e.wheelDelta; │ │ │ │ │ + if (delta % 160 === 0) { │ │ │ │ │ + // opera have steps of 160 instead of 120 │ │ │ │ │ + delta = delta * 0.75; │ │ │ │ │ + } │ │ │ │ │ + delta = delta / 120; │ │ │ │ │ + } else if (e.detail) { │ │ │ │ │ + // detail in Firefox on OS X is 1/3 of Windows │ │ │ │ │ + // so force delta 1 / -1 │ │ │ │ │ + delta = -(e.detail / Math.abs(e.detail)); │ │ │ │ │ + } │ │ │ │ │ + this.delta += delta; │ │ │ │ │ + │ │ │ │ │ + window.clearTimeout(this._timeoutId); │ │ │ │ │ + if (this.interval && Math.abs(this.delta) < this.maxDelta) { │ │ │ │ │ + // store e because window.event might change during delay │ │ │ │ │ + var evt = OpenLayers.Util.extend({}, e); │ │ │ │ │ + this._timeoutId = window.setTimeout( │ │ │ │ │ + OpenLayers.Function.bind(function() { │ │ │ │ │ + this.wheelZoom(evt); │ │ │ │ │ + }, this), │ │ │ │ │ + this.interval │ │ │ │ │ + ); │ │ │ │ │ + } else { │ │ │ │ │ + this.wheelZoom(e); │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + OpenLayers.Event.stop(e); │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: getFeatureInfo │ │ │ │ │ - * Get details about a feature associated with a map location. The object │ │ │ │ │ - * returned will have id and data properties. If the given location │ │ │ │ │ - * doesn't correspond to a feature, null will be returned. │ │ │ │ │ - * │ │ │ │ │ + * Method: wheelZoom │ │ │ │ │ + * Given the wheel event, we carry out the appropriate zooming in or out, │ │ │ │ │ + * based on the 'wheelDelta' or 'detail' property of the event. │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * location - {} map location │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {Object} Object representing the feature id and UTFGrid data │ │ │ │ │ - * corresponding to the given map location. Returns null if the given │ │ │ │ │ - * location doesn't hit a feature. │ │ │ │ │ + * e - {Event} │ │ │ │ │ */ │ │ │ │ │ - getFeatureInfo: function(location) { │ │ │ │ │ - var info = null; │ │ │ │ │ - var tileInfo = this.getTileData(location); │ │ │ │ │ - if (tileInfo && tileInfo.tile) { │ │ │ │ │ - info = tileInfo.tile.getFeatureInfo(tileInfo.i, tileInfo.j); │ │ │ │ │ + wheelZoom: function(e) { │ │ │ │ │ + var delta = this.delta; │ │ │ │ │ + this.delta = 0; │ │ │ │ │ + │ │ │ │ │ + if (delta) { │ │ │ │ │ + e.xy = this.map.events.getMousePosition(e); │ │ │ │ │ + if (delta < 0) { │ │ │ │ │ + this.callback("down", │ │ │ │ │ + [e, this.cumulative ? Math.max(-this.maxDelta, delta) : -1]); │ │ │ │ │ + } else { │ │ │ │ │ + this.callback("up", │ │ │ │ │ + [e, this.cumulative ? Math.min(this.maxDelta, delta) : 1]); │ │ │ │ │ + } │ │ │ │ │ } │ │ │ │ │ - return info; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: getFeatureId │ │ │ │ │ - * Get the identifier for the feature associated with a map location. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * location - {} map location │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {String} The feature identifier corresponding to the given map location. │ │ │ │ │ - * Returns null if the location doesn't hit a feature. │ │ │ │ │ + * Method: activate │ │ │ │ │ */ │ │ │ │ │ - getFeatureId: function(location) { │ │ │ │ │ - var id = null; │ │ │ │ │ - var info = this.getTileData(location); │ │ │ │ │ - if (info.tile) { │ │ │ │ │ - id = info.tile.getFeatureId(info.i, info.j); │ │ │ │ │ + activate: function(evt) { │ │ │ │ │ + if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { │ │ │ │ │ + //register mousewheel events specifically on the window and document │ │ │ │ │ + var wheelListener = this.wheelListener; │ │ │ │ │ + OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener); │ │ │ │ │ + OpenLayers.Event.observe(window, "mousewheel", wheelListener); │ │ │ │ │ + OpenLayers.Event.observe(document, "mousewheel", wheelListener); │ │ │ │ │ + return true; │ │ │ │ │ + } else { │ │ │ │ │ + return false; │ │ │ │ │ } │ │ │ │ │ - return id; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.UTFGrid" │ │ │ │ │ + /** │ │ │ │ │ + * Method: deactivate │ │ │ │ │ + */ │ │ │ │ │ + deactivate: function(evt) { │ │ │ │ │ + if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { │ │ │ │ │ + // unregister mousewheel events specifically on the window and document │ │ │ │ │ + var wheelListener = this.wheelListener; │ │ │ │ │ + OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener); │ │ │ │ │ + OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener); │ │ │ │ │ + OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener); │ │ │ │ │ + return true; │ │ │ │ │ + } else { │ │ │ │ │ + return false; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.MouseWheel" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Layer/Bing.js │ │ │ │ │ + OpenLayers/Control/Navigation.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Layer/XYZ.js │ │ │ │ │ + * @requires OpenLayers/Control/ZoomBox.js │ │ │ │ │ + * @requires OpenLayers/Control/DragPan.js │ │ │ │ │ + * @requires OpenLayers/Handler/MouseWheel.js │ │ │ │ │ + * @requires OpenLayers/Handler/Click.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Layer.Bing │ │ │ │ │ - * Bing layer using direct tile access as provided by Bing Maps REST Services. │ │ │ │ │ - * See http://msdn.microsoft.com/en-us/library/ff701713.aspx for more │ │ │ │ │ - * information. Note: Terms of Service compliant use requires the map to be │ │ │ │ │ - * configured with an control and the │ │ │ │ │ - * attribution placed on or near the map. │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.Navigation │ │ │ │ │ + * The navigation control handles map browsing with mouse events (dragging, │ │ │ │ │ + * double-clicking, and scrolling the wheel). Create a new navigation │ │ │ │ │ + * control with the control. │ │ │ │ │ * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * Note that this control is added to the map by default (if no controls │ │ │ │ │ + * array is sent in the options object to the │ │ │ │ │ + * constructor). │ │ │ │ │ + * │ │ │ │ │ + * Inherits: │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, { │ │ │ │ │ +OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: dragPan │ │ │ │ │ + * {} │ │ │ │ │ + */ │ │ │ │ │ + dragPan: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: key │ │ │ │ │ - * {String} API key for Bing maps, get your own key │ │ │ │ │ - * at http://bingmapsportal.com/ . │ │ │ │ │ + * APIProperty: dragPanOptions │ │ │ │ │ + * {Object} Options passed to the DragPan control. │ │ │ │ │ */ │ │ │ │ │ - key: null, │ │ │ │ │ + dragPanOptions: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: serverResolutions │ │ │ │ │ - * {Array} the resolutions provided by the Bing servers. │ │ │ │ │ + * Property: pinchZoom │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - serverResolutions: [ │ │ │ │ │ - 156543.03390625, 78271.516953125, 39135.7584765625, │ │ │ │ │ - 19567.87923828125, 9783.939619140625, 4891.9698095703125, │ │ │ │ │ - 2445.9849047851562, 1222.9924523925781, 611.4962261962891, │ │ │ │ │ - 305.74811309814453, 152.87405654907226, 76.43702827453613, │ │ │ │ │ - 38.218514137268066, 19.109257068634033, 9.554628534317017, │ │ │ │ │ - 4.777314267158508, 2.388657133579254, 1.194328566789627, │ │ │ │ │ - 0.5971642833948135, 0.29858214169740677, 0.14929107084870338, │ │ │ │ │ - 0.07464553542435169 │ │ │ │ │ - ], │ │ │ │ │ + pinchZoom: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: attributionTemplate │ │ │ │ │ - * {String} │ │ │ │ │ + * APIProperty: pinchZoomOptions │ │ │ │ │ + * {Object} Options passed to the PinchZoom control. │ │ │ │ │ */ │ │ │ │ │ - attributionTemplate: '' + │ │ │ │ │ - '${copyrights}' + │ │ │ │ │ - '' + │ │ │ │ │ - 'Terms of Use', │ │ │ │ │ + pinchZoomOptions: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: metadata │ │ │ │ │ - * {Object} Metadata for this layer, as returned by the callback script │ │ │ │ │ + * APIProperty: documentDrag │ │ │ │ │ + * {Boolean} Allow panning of the map by dragging outside map viewport. │ │ │ │ │ + * Default is false. │ │ │ │ │ */ │ │ │ │ │ - metadata: null, │ │ │ │ │ + documentDrag: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Property: zoomBox │ │ │ │ │ + * {} │ │ │ │ │ + */ │ │ │ │ │ + zoomBox: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: protocolRegex │ │ │ │ │ - * {RegExp} Regular expression to match and replace http: in bing urls │ │ │ │ │ + * APIProperty: zoomBoxEnabled │ │ │ │ │ + * {Boolean} Whether the user can draw a box to zoom │ │ │ │ │ */ │ │ │ │ │ - protocolRegex: /^http:/i, │ │ │ │ │ + zoomBoxEnabled: true, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: type │ │ │ │ │ - * {String} The layer identifier. Any non-birdseye imageryType │ │ │ │ │ - * from http://msdn.microsoft.com/en-us/library/ff701716.aspx can be │ │ │ │ │ - * used. Default is "Road". │ │ │ │ │ + * APIProperty: zoomWheelEnabled │ │ │ │ │ + * {Boolean} Whether the mousewheel should zoom the map │ │ │ │ │ */ │ │ │ │ │ - type: "Road", │ │ │ │ │ + zoomWheelEnabled: true, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: culture │ │ │ │ │ - * {String} The culture identifier. See http://msdn.microsoft.com/en-us/library/ff701709.aspx │ │ │ │ │ - * for the definition and the possible values. Default is "en-US". │ │ │ │ │ + * Property: mouseWheelOptions │ │ │ │ │ + * {Object} Options passed to the MouseWheel control (only useful if │ │ │ │ │ + * is set to true). Default is no options for maps │ │ │ │ │ + * with fractionalZoom set to true, otherwise │ │ │ │ │ + * {cumulative: false, interval: 50, maxDelta: 6} │ │ │ │ │ */ │ │ │ │ │ - culture: "en-US", │ │ │ │ │ + mouseWheelOptions: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: metadataParams │ │ │ │ │ - * {Object} Optional url parameters for the Get Imagery Metadata request │ │ │ │ │ - * as described here: http://msdn.microsoft.com/en-us/library/ff701716.aspx │ │ │ │ │ + * APIProperty: handleRightClicks │ │ │ │ │ + * {Boolean} Whether or not to handle right clicks. Default is false. │ │ │ │ │ */ │ │ │ │ │ - metadataParams: null, │ │ │ │ │ + handleRightClicks: false, │ │ │ │ │ │ │ │ │ │ - /** APIProperty: tileOptions │ │ │ │ │ - * {Object} optional configuration options for instances │ │ │ │ │ - * created by this Layer. Default is │ │ │ │ │ - * │ │ │ │ │ - * (code) │ │ │ │ │ - * {crossOriginKeyword: 'anonymous'} │ │ │ │ │ - * (end) │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: zoomBoxKeyMask │ │ │ │ │ + * {Integer} key code of the key, which has to be │ │ │ │ │ + * pressed, while drawing the zoom box with the mouse on the screen. │ │ │ │ │ + * You should probably set handleRightClicks to true if you use this │ │ │ │ │ + * with MOD_CTRL, to disable the context menu for machines which use │ │ │ │ │ + * CTRL-Click as a right click. │ │ │ │ │ + * Default: │ │ │ │ │ */ │ │ │ │ │ - tileOptions: null, │ │ │ │ │ + zoomBoxKeyMask: OpenLayers.Handler.MOD_SHIFT, │ │ │ │ │ │ │ │ │ │ - /** APIProperty: protocol │ │ │ │ │ - * {String} Protocol to use to fetch Imagery Metadata, tiles and bing logo │ │ │ │ │ - * Can be 'http:' 'https:' or '' │ │ │ │ │ - * │ │ │ │ │ - * Warning: tiles may not be available under both HTTP and HTTPS protocols. │ │ │ │ │ - * Microsoft approved use of both HTTP and HTTPS urls for tiles. However │ │ │ │ │ - * this is undocumented and the Imagery Metadata API always returns HTTP │ │ │ │ │ - * urls. │ │ │ │ │ - * │ │ │ │ │ - * Default is '', unless when executed from a file:/// uri, in which case │ │ │ │ │ - * it is 'http:'. │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: autoActivate │ │ │ │ │ + * {Boolean} Activate the control when it is added to a map. Default is │ │ │ │ │ + * true. │ │ │ │ │ */ │ │ │ │ │ - protocol: ~window.location.href.indexOf('http') ? '' : 'http:', │ │ │ │ │ + autoActivate: true, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Layer.Bing │ │ │ │ │ - * Create a new Bing layer. │ │ │ │ │ - * │ │ │ │ │ - * Example: │ │ │ │ │ - * (code) │ │ │ │ │ - * var road = new OpenLayers.Layer.Bing({ │ │ │ │ │ - * name: "My Bing Aerial Layer", │ │ │ │ │ - * type: "Aerial", │ │ │ │ │ - * key: "my-api-key-here", │ │ │ │ │ - * }); │ │ │ │ │ - * (end) │ │ │ │ │ - * │ │ │ │ │ + * Constructor: OpenLayers.Control.Navigation │ │ │ │ │ + * Create a new navigation control │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * options - {Object} Configuration properties for the layer. │ │ │ │ │ - * │ │ │ │ │ - * Required configuration properties: │ │ │ │ │ - * key - {String} Bing Maps API key for your application. Get one at │ │ │ │ │ - * http://bingmapsportal.com/. │ │ │ │ │ - * type - {String} The layer identifier. Any non-birdseye imageryType │ │ │ │ │ - * from http://msdn.microsoft.com/en-us/library/ff701716.aspx can be │ │ │ │ │ - * used. │ │ │ │ │ - * │ │ │ │ │ - * Any other documented layer properties can be provided in the config object. │ │ │ │ │ + * options - {Object} An optional object whose properties will be set on │ │ │ │ │ + * the control │ │ │ │ │ */ │ │ │ │ │ initialize: function(options) { │ │ │ │ │ - options = OpenLayers.Util.applyDefaults({ │ │ │ │ │ - sphericalMercator: true │ │ │ │ │ - }, options); │ │ │ │ │ - var name = options.name || "Bing " + (options.type || this.type); │ │ │ │ │ - │ │ │ │ │ - var newArgs = [name, null, options]; │ │ │ │ │ - OpenLayers.Layer.XYZ.prototype.initialize.apply(this, newArgs); │ │ │ │ │ - this.tileOptions = OpenLayers.Util.extend({ │ │ │ │ │ - crossOriginKeyword: 'anonymous' │ │ │ │ │ - }, this.options.tileOptions); │ │ │ │ │ - this.loadMetadata(); │ │ │ │ │ + this.handlers = {}; │ │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, arguments); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: loadMetadata │ │ │ │ │ + * Method: destroy │ │ │ │ │ + * The destroy method is used to perform any clean up before the control │ │ │ │ │ + * is dereferenced. Typically this is where event listeners are removed │ │ │ │ │ + * to prevent memory leaks. │ │ │ │ │ */ │ │ │ │ │ - loadMetadata: function() { │ │ │ │ │ - this._callbackId = "_callback_" + this.id.replace(/\./g, "_"); │ │ │ │ │ - // link the processMetadata method to the global scope and bind it │ │ │ │ │ - // to this instance │ │ │ │ │ - window[this._callbackId] = OpenLayers.Function.bind( │ │ │ │ │ - OpenLayers.Layer.Bing.processMetadata, this │ │ │ │ │ - ); │ │ │ │ │ - var params = OpenLayers.Util.applyDefaults({ │ │ │ │ │ - key: this.key, │ │ │ │ │ - jsonp: this._callbackId, │ │ │ │ │ - include: "ImageryProviders" │ │ │ │ │ - }, this.metadataParams); │ │ │ │ │ - var url = this.protocol + "//dev.virtualearth.net/REST/v1/Imagery/Metadata/" + │ │ │ │ │ - this.type + "?" + OpenLayers.Util.getParameterString(params); │ │ │ │ │ - var script = document.createElement("script"); │ │ │ │ │ - script.type = "text/javascript"; │ │ │ │ │ - script.src = url; │ │ │ │ │ - script.id = this._callbackId; │ │ │ │ │ - document.getElementsByTagName("head")[0].appendChild(script); │ │ │ │ │ + destroy: function() { │ │ │ │ │ + this.deactivate(); │ │ │ │ │ + │ │ │ │ │ + if (this.dragPan) { │ │ │ │ │ + this.dragPan.destroy(); │ │ │ │ │ + } │ │ │ │ │ + this.dragPan = null; │ │ │ │ │ + │ │ │ │ │ + if (this.zoomBox) { │ │ │ │ │ + this.zoomBox.destroy(); │ │ │ │ │ + } │ │ │ │ │ + this.zoomBox = null; │ │ │ │ │ + │ │ │ │ │ + if (this.pinchZoom) { │ │ │ │ │ + this.pinchZoom.destroy(); │ │ │ │ │ + } │ │ │ │ │ + this.pinchZoom = null; │ │ │ │ │ + │ │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: initLayer │ │ │ │ │ - * │ │ │ │ │ - * Sets layer properties according to the metadata provided by the API │ │ │ │ │ + * Method: activate │ │ │ │ │ */ │ │ │ │ │ - initLayer: function() { │ │ │ │ │ - var res = this.metadata.resourceSets[0].resources[0]; │ │ │ │ │ - var url = res.imageUrl.replace("{quadkey}", "${quadkey}"); │ │ │ │ │ - url = url.replace("{culture}", this.culture); │ │ │ │ │ - url = url.replace(this.protocolRegex, this.protocol); │ │ │ │ │ - this.url = []; │ │ │ │ │ - for (var i = 0; i < res.imageUrlSubdomains.length; ++i) { │ │ │ │ │ - this.url.push(url.replace("{subdomain}", res.imageUrlSubdomains[i])); │ │ │ │ │ + activate: function() { │ │ │ │ │ + this.dragPan.activate(); │ │ │ │ │ + if (this.zoomWheelEnabled) { │ │ │ │ │ + this.handlers.wheel.activate(); │ │ │ │ │ } │ │ │ │ │ - this.addOptions({ │ │ │ │ │ - maxResolution: Math.min( │ │ │ │ │ - this.serverResolutions[res.zoomMin], │ │ │ │ │ - this.maxResolution || Number.POSITIVE_INFINITY │ │ │ │ │ - ), │ │ │ │ │ - numZoomLevels: Math.min( │ │ │ │ │ - res.zoomMax + 1 - res.zoomMin, this.numZoomLevels │ │ │ │ │ - ) │ │ │ │ │ - }, true); │ │ │ │ │ - if (!this.isBaseLayer) { │ │ │ │ │ - this.redraw(); │ │ │ │ │ + this.handlers.click.activate(); │ │ │ │ │ + if (this.zoomBoxEnabled) { │ │ │ │ │ + this.zoomBox.activate(); │ │ │ │ │ } │ │ │ │ │ - this.updateAttribution(); │ │ │ │ │ + if (this.pinchZoom) { │ │ │ │ │ + this.pinchZoom.activate(); │ │ │ │ │ + } │ │ │ │ │ + return OpenLayers.Control.prototype.activate.apply(this, arguments); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: getURL │ │ │ │ │ - * │ │ │ │ │ - * Paramters: │ │ │ │ │ - * bounds - {} │ │ │ │ │ + * Method: deactivate │ │ │ │ │ */ │ │ │ │ │ - getURL: function(bounds) { │ │ │ │ │ - if (!this.url) { │ │ │ │ │ - return; │ │ │ │ │ - } │ │ │ │ │ - var xyz = this.getXYZ(bounds), │ │ │ │ │ - x = xyz.x, │ │ │ │ │ - y = xyz.y, │ │ │ │ │ - z = xyz.z; │ │ │ │ │ - var quadDigits = []; │ │ │ │ │ - for (var i = z; i > 0; --i) { │ │ │ │ │ - var digit = '0'; │ │ │ │ │ - var mask = 1 << (i - 1); │ │ │ │ │ - if ((x & mask) != 0) { │ │ │ │ │ - digit++; │ │ │ │ │ - } │ │ │ │ │ - if ((y & mask) != 0) { │ │ │ │ │ - digit++; │ │ │ │ │ - digit++; │ │ │ │ │ - } │ │ │ │ │ - quadDigits.push(digit); │ │ │ │ │ + deactivate: function() { │ │ │ │ │ + if (this.pinchZoom) { │ │ │ │ │ + this.pinchZoom.deactivate(); │ │ │ │ │ } │ │ │ │ │ - var quadKey = quadDigits.join(""); │ │ │ │ │ - var url = this.selectUrl('' + x + y + z, this.url); │ │ │ │ │ - │ │ │ │ │ - return OpenLayers.String.format(url, { │ │ │ │ │ - 'quadkey': quadKey │ │ │ │ │ - }); │ │ │ │ │ + this.zoomBox.deactivate(); │ │ │ │ │ + this.dragPan.deactivate(); │ │ │ │ │ + this.handlers.click.deactivate(); │ │ │ │ │ + this.handlers.wheel.deactivate(); │ │ │ │ │ + return OpenLayers.Control.prototype.deactivate.apply(this, arguments); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: updateAttribution │ │ │ │ │ - * Updates the attribution according to the requirements outlined in │ │ │ │ │ - * http://gis.638310.n2.nabble.com/Bing-imagery-td5789168.html │ │ │ │ │ + * Method: draw │ │ │ │ │ */ │ │ │ │ │ - updateAttribution: function() { │ │ │ │ │ - var metadata = this.metadata; │ │ │ │ │ - if (!metadata.resourceSets || !this.map || !this.map.center) { │ │ │ │ │ - return; │ │ │ │ │ + draw: function() { │ │ │ │ │ + // disable right mouse context menu for support of right click events │ │ │ │ │ + if (this.handleRightClicks) { │ │ │ │ │ + this.map.viewPortDiv.oncontextmenu = OpenLayers.Function.False; │ │ │ │ │ } │ │ │ │ │ - var res = metadata.resourceSets[0].resources[0]; │ │ │ │ │ - var extent = this.map.getExtent().transform( │ │ │ │ │ - this.map.getProjectionObject(), │ │ │ │ │ - new OpenLayers.Projection("EPSG:4326") │ │ │ │ │ + │ │ │ │ │ + var clickCallbacks = { │ │ │ │ │ + 'click': this.defaultClick, │ │ │ │ │ + 'dblclick': this.defaultDblClick, │ │ │ │ │ + 'dblrightclick': this.defaultDblRightClick │ │ │ │ │ + }; │ │ │ │ │ + var clickOptions = { │ │ │ │ │ + 'double': true, │ │ │ │ │ + 'stopDouble': true │ │ │ │ │ + }; │ │ │ │ │ + this.handlers.click = new OpenLayers.Handler.Click( │ │ │ │ │ + this, clickCallbacks, clickOptions │ │ │ │ │ ); │ │ │ │ │ - var providers = res.imageryProviders || [], │ │ │ │ │ - zoom = OpenLayers.Util.indexOf(this.serverResolutions, │ │ │ │ │ - this.getServerResolution()), │ │ │ │ │ - copyrights = "", │ │ │ │ │ - provider, i, ii, j, jj, bbox, coverage; │ │ │ │ │ - for (i = 0, ii = providers.length; i < ii; ++i) { │ │ │ │ │ - provider = providers[i]; │ │ │ │ │ - for (j = 0, jj = provider.coverageAreas.length; j < jj; ++j) { │ │ │ │ │ - coverage = provider.coverageAreas[j]; │ │ │ │ │ - // axis order provided is Y,X │ │ │ │ │ - bbox = OpenLayers.Bounds.fromArray(coverage.bbox, true); │ │ │ │ │ - if (extent.intersectsBounds(bbox) && │ │ │ │ │ - zoom <= coverage.zoomMax && zoom >= coverage.zoomMin) { │ │ │ │ │ - copyrights += provider.attribution + " "; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - var logo = metadata.brandLogoUri.replace(this.protocolRegex, this.protocol); │ │ │ │ │ - this.attribution = OpenLayers.String.format(this.attributionTemplate, { │ │ │ │ │ - type: this.type.toLowerCase(), │ │ │ │ │ - logo: logo, │ │ │ │ │ - copyrights: copyrights │ │ │ │ │ - }); │ │ │ │ │ - this.map && this.map.events.triggerEvent("changelayer", { │ │ │ │ │ - layer: this, │ │ │ │ │ - property: "attribution" │ │ │ │ │ + this.dragPan = new OpenLayers.Control.DragPan( │ │ │ │ │ + OpenLayers.Util.extend({ │ │ │ │ │ + map: this.map, │ │ │ │ │ + documentDrag: this.documentDrag │ │ │ │ │ + }, this.dragPanOptions) │ │ │ │ │ + ); │ │ │ │ │ + this.zoomBox = new OpenLayers.Control.ZoomBox({ │ │ │ │ │ + map: this.map, │ │ │ │ │ + keyMask: this.zoomBoxKeyMask │ │ │ │ │ }); │ │ │ │ │ + this.dragPan.draw(); │ │ │ │ │ + this.zoomBox.draw(); │ │ │ │ │ + var wheelOptions = this.map.fractionalZoom ? {} : { │ │ │ │ │ + cumulative: false, │ │ │ │ │ + interval: 50, │ │ │ │ │ + maxDelta: 6 │ │ │ │ │ + }; │ │ │ │ │ + this.handlers.wheel = new OpenLayers.Handler.MouseWheel( │ │ │ │ │ + this, { │ │ │ │ │ + up: this.wheelUp, │ │ │ │ │ + down: this.wheelDown │ │ │ │ │ + }, │ │ │ │ │ + OpenLayers.Util.extend(wheelOptions, this.mouseWheelOptions) │ │ │ │ │ + ); │ │ │ │ │ + if (OpenLayers.Control.PinchZoom) { │ │ │ │ │ + this.pinchZoom = new OpenLayers.Control.PinchZoom( │ │ │ │ │ + OpenLayers.Util.extend({ │ │ │ │ │ + map: this.map │ │ │ │ │ + }, this.pinchZoomOptions)); │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: setMap │ │ │ │ │ + * Method: defaultClick │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {Event} │ │ │ │ │ */ │ │ │ │ │ - setMap: function() { │ │ │ │ │ - OpenLayers.Layer.XYZ.prototype.setMap.apply(this, arguments); │ │ │ │ │ - this.map.events.register("moveend", this, this.updateAttribution); │ │ │ │ │ + defaultClick: function(evt) { │ │ │ │ │ + if (evt.lastTouches && evt.lastTouches.length == 2) { │ │ │ │ │ + this.map.zoomOut(); │ │ │ │ │ + } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: clone │ │ │ │ │ + * Method: defaultDblClick │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * obj - {Object} │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} An exact clone of this │ │ │ │ │ + * evt - {Event} │ │ │ │ │ */ │ │ │ │ │ - clone: function(obj) { │ │ │ │ │ - if (obj == null) { │ │ │ │ │ - obj = new OpenLayers.Layer.Bing(this.options); │ │ │ │ │ - } │ │ │ │ │ - //get all additions from superclasses │ │ │ │ │ - obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); │ │ │ │ │ - // copy/set any non-init, non-simple values here │ │ │ │ │ - return obj; │ │ │ │ │ + defaultDblClick: function(evt) { │ │ │ │ │ + this.map.zoomTo(this.map.zoom + 1, evt.xy); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: destroy │ │ │ │ │ + * Method: defaultDblRightClick │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * evt - {Event} │ │ │ │ │ */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - this.map && │ │ │ │ │ - this.map.events.unregister("moveend", this, this.updateAttribution); │ │ │ │ │ - OpenLayers.Layer.XYZ.prototype.destroy.apply(this, arguments); │ │ │ │ │ + defaultDblRightClick: function(evt) { │ │ │ │ │ + this.map.zoomTo(this.map.zoom - 1, evt.xy); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Bing" │ │ │ │ │ -}); │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Function: OpenLayers.Layer.Bing.processMetadata │ │ │ │ │ - * This function will be bound to an instance, linked to the global scope with │ │ │ │ │ - * an id, and called by the JSONP script returned by the API. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * metadata - {Object} metadata as returned by the API │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Layer.Bing.processMetadata = function(metadata) { │ │ │ │ │ - this.metadata = metadata; │ │ │ │ │ - this.initLayer(); │ │ │ │ │ - var script = document.getElementById(this._callbackId); │ │ │ │ │ - script.parentNode.removeChild(script); │ │ │ │ │ - window[this._callbackId] = undefined; // cannot delete from window in IE │ │ │ │ │ - delete this._callbackId; │ │ │ │ │ -}; │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Layer/Markers.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Layer.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Layer.Markers │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Layer.Markers = OpenLayers.Class(OpenLayers.Layer, { │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ │ - * {Boolean} Markers layer is never a base layer. │ │ │ │ │ - */ │ │ │ │ │ - isBaseLayer: false, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: markers │ │ │ │ │ - * {Array()} internal marker list │ │ │ │ │ - */ │ │ │ │ │ - markers: null, │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: drawn │ │ │ │ │ - * {Boolean} internal state of drawing. This is a workaround for the fact │ │ │ │ │ - * that the map does not call moveTo with a zoomChanged when the map is │ │ │ │ │ - * first starting up. This lets us catch the case where we have *never* │ │ │ │ │ - * drawn the layer, and draw it even if the zoom hasn't changed. │ │ │ │ │ - */ │ │ │ │ │ - drawn: false, │ │ │ │ │ - │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Layer.Markers │ │ │ │ │ - * Create a Markers layer. │ │ │ │ │ + * Method: wheelChange │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * name - {String} │ │ │ │ │ - * options - {Object} Hashtable of extra options to tag onto the layer │ │ │ │ │ - */ │ │ │ │ │ - initialize: function(name, options) { │ │ │ │ │ - OpenLayers.Layer.prototype.initialize.apply(this, arguments); │ │ │ │ │ - this.markers = []; │ │ │ │ │ - }, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ + * evt - {Event} │ │ │ │ │ + * deltaZ - {Integer} │ │ │ │ │ */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - this.clearMarkers(); │ │ │ │ │ - this.markers = null; │ │ │ │ │ - OpenLayers.Layer.prototype.destroy.apply(this, arguments); │ │ │ │ │ + wheelChange: function(evt, deltaZ) { │ │ │ │ │ + if (!this.map.fractionalZoom) { │ │ │ │ │ + deltaZ = Math.round(deltaZ); │ │ │ │ │ + } │ │ │ │ │ + var currentZoom = this.map.getZoom(), │ │ │ │ │ + newZoom = currentZoom + deltaZ; │ │ │ │ │ + newZoom = Math.max(newZoom, 0); │ │ │ │ │ + newZoom = Math.min(newZoom, this.map.getNumZoomLevels()); │ │ │ │ │ + if (newZoom === currentZoom) { │ │ │ │ │ + return; │ │ │ │ │ + } │ │ │ │ │ + this.map.zoomTo(newZoom, evt.xy); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: setOpacity │ │ │ │ │ - * Sets the opacity for all the markers. │ │ │ │ │ + /** │ │ │ │ │ + * Method: wheelUp │ │ │ │ │ + * User spun scroll wheel up │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * opacity - {Float} │ │ │ │ │ + * evt - {Event} │ │ │ │ │ + * delta - {Integer} │ │ │ │ │ */ │ │ │ │ │ - setOpacity: function(opacity) { │ │ │ │ │ - if (opacity != this.opacity) { │ │ │ │ │ - this.opacity = opacity; │ │ │ │ │ - for (var i = 0, len = this.markers.length; i < len; i++) { │ │ │ │ │ - this.markers[i].setOpacity(this.opacity); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ + wheelUp: function(evt, delta) { │ │ │ │ │ + this.wheelChange(evt, delta || 1); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: moveTo │ │ │ │ │ - * │ │ │ │ │ + * Method: wheelDown │ │ │ │ │ + * User spun scroll wheel down │ │ │ │ │ + * │ │ │ │ │ * Parameters: │ │ │ │ │ - * bounds - {} │ │ │ │ │ - * zoomChanged - {Boolean} │ │ │ │ │ - * dragging - {Boolean} │ │ │ │ │ + * evt - {Event} │ │ │ │ │ + * delta - {Integer} │ │ │ │ │ */ │ │ │ │ │ - moveTo: function(bounds, zoomChanged, dragging) { │ │ │ │ │ - OpenLayers.Layer.prototype.moveTo.apply(this, arguments); │ │ │ │ │ - │ │ │ │ │ - if (zoomChanged || !this.drawn) { │ │ │ │ │ - for (var i = 0, len = this.markers.length; i < len; i++) { │ │ │ │ │ - this.drawMarker(this.markers[i]); │ │ │ │ │ - } │ │ │ │ │ - this.drawn = true; │ │ │ │ │ - } │ │ │ │ │ + wheelDown: function(evt, delta) { │ │ │ │ │ + this.wheelChange(evt, delta || -1); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: addMarker │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * marker - {} │ │ │ │ │ + * Method: disableZoomBox │ │ │ │ │ */ │ │ │ │ │ - addMarker: function(marker) { │ │ │ │ │ - this.markers.push(marker); │ │ │ │ │ - │ │ │ │ │ - if (this.opacity < 1) { │ │ │ │ │ - marker.setOpacity(this.opacity); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (this.map && this.map.getExtent()) { │ │ │ │ │ - marker.map = this.map; │ │ │ │ │ - this.drawMarker(marker); │ │ │ │ │ - } │ │ │ │ │ + disableZoomBox: function() { │ │ │ │ │ + this.zoomBoxEnabled = false; │ │ │ │ │ + this.zoomBox.deactivate(); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: removeMarker │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * marker - {} │ │ │ │ │ + * Method: enableZoomBox │ │ │ │ │ */ │ │ │ │ │ - removeMarker: function(marker) { │ │ │ │ │ - if (this.markers && this.markers.length) { │ │ │ │ │ - OpenLayers.Util.removeItem(this.markers, marker); │ │ │ │ │ - marker.erase(); │ │ │ │ │ + enableZoomBox: function() { │ │ │ │ │ + this.zoomBoxEnabled = true; │ │ │ │ │ + if (this.active) { │ │ │ │ │ + this.zoomBox.activate(); │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: clearMarkers │ │ │ │ │ - * This method removes all markers from a layer. The markers are not │ │ │ │ │ - * destroyed by this function, but are removed from the list of markers. │ │ │ │ │ + * Method: disableZoomWheel │ │ │ │ │ */ │ │ │ │ │ - clearMarkers: function() { │ │ │ │ │ - if (this.markers != null) { │ │ │ │ │ - while (this.markers.length > 0) { │ │ │ │ │ - this.removeMarker(this.markers[0]); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * Method: drawMarker │ │ │ │ │ - * Calculate the pixel location for the marker, create it, and │ │ │ │ │ - * add it to the layer's div │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * marker - {} │ │ │ │ │ - */ │ │ │ │ │ - drawMarker: function(marker) { │ │ │ │ │ - var px = this.map.getLayerPxFromLonLat(marker.lonlat); │ │ │ │ │ - if (px == null) { │ │ │ │ │ - marker.display(false); │ │ │ │ │ - } else { │ │ │ │ │ - if (!marker.isDrawn()) { │ │ │ │ │ - var markerImg = marker.draw(px); │ │ │ │ │ - this.div.appendChild(markerImg); │ │ │ │ │ - } else if (marker.icon) { │ │ │ │ │ - marker.icon.moveTo(px); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ + disableZoomWheel: function() { │ │ │ │ │ + this.zoomWheelEnabled = false; │ │ │ │ │ + this.handlers.wheel.deactivate(); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIMethod: getDataExtent │ │ │ │ │ - * Calculates the max extent which includes all of the markers. │ │ │ │ │ - * │ │ │ │ │ - * Returns: │ │ │ │ │ - * {} │ │ │ │ │ + /** │ │ │ │ │ + * Method: enableZoomWheel │ │ │ │ │ */ │ │ │ │ │ - getDataExtent: function() { │ │ │ │ │ - var maxExtent = null; │ │ │ │ │ │ │ │ │ │ - if (this.markers && (this.markers.length > 0)) { │ │ │ │ │ - var maxExtent = new OpenLayers.Bounds(); │ │ │ │ │ - for (var i = 0, len = this.markers.length; i < len; i++) { │ │ │ │ │ - var marker = this.markers[i]; │ │ │ │ │ - maxExtent.extend(marker.lonlat); │ │ │ │ │ - } │ │ │ │ │ + enableZoomWheel: function() { │ │ │ │ │ + this.zoomWheelEnabled = true; │ │ │ │ │ + if (this.active) { │ │ │ │ │ + this.handlers.wheel.activate(); │ │ │ │ │ } │ │ │ │ │ - │ │ │ │ │ - return maxExtent; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Markers" │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.Navigation" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Format/Text.js │ │ │ │ │ + OpenLayers/Handler/Polygon.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Feature/Vector.js │ │ │ │ │ - * @requires OpenLayers/Geometry/Point.js │ │ │ │ │ + * @requires OpenLayers/Handler/Path.js │ │ │ │ │ + * @requires OpenLayers/Geometry/Polygon.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Format.Text │ │ │ │ │ - * Read Text format. Create a new instance with the │ │ │ │ │ - * constructor. This reads text which is formatted like CSV text, using │ │ │ │ │ - * tabs as the seperator by default. It provides parsing of data originally │ │ │ │ │ - * used in the MapViewerService, described on the wiki. This Format is used │ │ │ │ │ - * by the class. │ │ │ │ │ + * Class: OpenLayers.Handler.Polygon │ │ │ │ │ + * Handler to draw a polygon on the map. Polygon is displayed on mouse down, │ │ │ │ │ + * moves on mouse move, and is finished on mouse up. │ │ │ │ │ * │ │ │ │ │ * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * - │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Format.Text = OpenLayers.Class(OpenLayers.Format, { │ │ │ │ │ +OpenLayers.Handler.Polygon = OpenLayers.Class(OpenLayers.Handler.Path, { │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: holeModifier │ │ │ │ │ + * {String} Key modifier to trigger hole digitizing. Acceptable values are │ │ │ │ │ + * "altKey", "shiftKey", or "ctrlKey". If not set, no hole digitizing │ │ │ │ │ + * will take place. Default is null. │ │ │ │ │ + */ │ │ │ │ │ + holeModifier: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: defaultStyle │ │ │ │ │ - * defaultStyle allows one to control the default styling of the features. │ │ │ │ │ - * It should be a symbolizer hash. By default, this is set to match the │ │ │ │ │ - * Layer.Text behavior, which is to use the default OpenLayers Icon. │ │ │ │ │ + * Property: drawingHole │ │ │ │ │ + * {Boolean} Currently drawing an interior ring. │ │ │ │ │ */ │ │ │ │ │ - defaultStyle: null, │ │ │ │ │ + drawingHole: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: extractStyles │ │ │ │ │ - * set to true to extract styles from the TSV files, using information │ │ │ │ │ - * from the image or icon, iconSize and iconOffset fields. This will result │ │ │ │ │ - * in features with a symbolizer (style) property set, using the │ │ │ │ │ - * default symbolizer specified in . Set to false if you │ │ │ │ │ - * wish to use a styleMap or OpenLayers.Style options to style your │ │ │ │ │ - * layer instead. │ │ │ │ │ + * Property: polygon │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - extractStyles: true, │ │ │ │ │ + polygon: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Format.Text │ │ │ │ │ - * Create a new parser for TSV Text. │ │ │ │ │ + * Constructor: OpenLayers.Handler.Polygon │ │ │ │ │ + * Create a Polygon Handler. │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * options - {Object} An optional object whose properties will be set on │ │ │ │ │ - * this instance. │ │ │ │ │ + * control - {} The control that owns this handler │ │ │ │ │ + * callbacks - {Object} An object with a properties whose values are │ │ │ │ │ + * functions. Various callbacks described below. │ │ │ │ │ + * options - {Object} An optional object with properties to be set on the │ │ │ │ │ + * handler │ │ │ │ │ + * │ │ │ │ │ + * Named callbacks: │ │ │ │ │ + * create - Called when a sketch is first created. Callback called with │ │ │ │ │ + * the creation point geometry and sketch feature. │ │ │ │ │ + * modify - Called with each move of a vertex with the vertex (point) │ │ │ │ │ + * geometry and the sketch feature. │ │ │ │ │ + * point - Called as each point is added. Receives the new point geometry. │ │ │ │ │ + * done - Called when the point drawing is finished. The callback will │ │ │ │ │ + * recieve a single argument, the polygon geometry. │ │ │ │ │ + * cancel - Called when the handler is deactivated while drawing. The │ │ │ │ │ + * cancel callback will receive a geometry. │ │ │ │ │ */ │ │ │ │ │ - initialize: function(options) { │ │ │ │ │ - options = options || {}; │ │ │ │ │ │ │ │ │ │ - if (options.extractStyles !== false) { │ │ │ │ │ - options.defaultStyle = { │ │ │ │ │ - 'externalGraphic': OpenLayers.Util.getImageLocation("marker.png"), │ │ │ │ │ - 'graphicWidth': 21, │ │ │ │ │ - 'graphicHeight': 25, │ │ │ │ │ - 'graphicXOffset': -10.5, │ │ │ │ │ - 'graphicYOffset': -12.5 │ │ │ │ │ - }; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - OpenLayers.Format.prototype.initialize.apply(this, [options]); │ │ │ │ │ + /** │ │ │ │ │ + * Method: createFeature │ │ │ │ │ + * Add temporary geometries │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * pixel - {} The initial pixel location for the new │ │ │ │ │ + * feature. │ │ │ │ │ + */ │ │ │ │ │ + createFeature: function(pixel) { │ │ │ │ │ + var lonlat = this.layer.getLonLatFromViewPortPx(pixel); │ │ │ │ │ + var geometry = new OpenLayers.Geometry.Point( │ │ │ │ │ + lonlat.lon, lonlat.lat │ │ │ │ │ + ); │ │ │ │ │ + this.point = new OpenLayers.Feature.Vector(geometry); │ │ │ │ │ + this.line = new OpenLayers.Feature.Vector( │ │ │ │ │ + new OpenLayers.Geometry.LinearRing([this.point.geometry]) │ │ │ │ │ + ); │ │ │ │ │ + this.polygon = new OpenLayers.Feature.Vector( │ │ │ │ │ + new OpenLayers.Geometry.Polygon([this.line.geometry]) │ │ │ │ │ + ); │ │ │ │ │ + this.callback("create", [this.point.geometry, this.getSketch()]); │ │ │ │ │ + this.point.geometry.clearBounds(); │ │ │ │ │ + this.layer.addFeatures([this.polygon, this.point], { │ │ │ │ │ + silent: true │ │ │ │ │ + }); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: read │ │ │ │ │ - * Return a list of features from a Tab Seperated Values text string. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * text - {String} │ │ │ │ │ + * Method: addPoint │ │ │ │ │ + * Add point to geometry. │ │ │ │ │ * │ │ │ │ │ - * Returns: │ │ │ │ │ - * Array({}) │ │ │ │ │ + * Parameters: │ │ │ │ │ + * pixel - {} The pixel location for the new point. │ │ │ │ │ */ │ │ │ │ │ - read: function(text) { │ │ │ │ │ - var lines = text.split('\n'); │ │ │ │ │ - var columns; │ │ │ │ │ - var features = []; │ │ │ │ │ - // length - 1 to allow for trailing new line │ │ │ │ │ - for (var lcv = 0; lcv < (lines.length - 1); lcv++) { │ │ │ │ │ - var currLine = lines[lcv].replace(/^\s*/, '').replace(/\s*$/, ''); │ │ │ │ │ - │ │ │ │ │ - if (currLine.charAt(0) != '#') { │ │ │ │ │ - /* not a comment */ │ │ │ │ │ - │ │ │ │ │ - if (!columns) { │ │ │ │ │ - //First line is columns │ │ │ │ │ - columns = currLine.split('\t'); │ │ │ │ │ - } else { │ │ │ │ │ - var vals = currLine.split('\t'); │ │ │ │ │ - var geometry = new OpenLayers.Geometry.Point(0, 0); │ │ │ │ │ - var attributes = {}; │ │ │ │ │ - var style = this.defaultStyle ? │ │ │ │ │ - OpenLayers.Util.applyDefaults({}, this.defaultStyle) : │ │ │ │ │ - null; │ │ │ │ │ - var icon, iconSize, iconOffset, overflow; │ │ │ │ │ - var set = false; │ │ │ │ │ - for (var valIndex = 0; valIndex < vals.length; valIndex++) { │ │ │ │ │ - if (vals[valIndex]) { │ │ │ │ │ - if (columns[valIndex] == 'point') { │ │ │ │ │ - var coords = vals[valIndex].split(','); │ │ │ │ │ - geometry.y = parseFloat(coords[0]); │ │ │ │ │ - geometry.x = parseFloat(coords[1]); │ │ │ │ │ - set = true; │ │ │ │ │ - } else if (columns[valIndex] == 'lat') { │ │ │ │ │ - geometry.y = parseFloat(vals[valIndex]); │ │ │ │ │ - set = true; │ │ │ │ │ - } else if (columns[valIndex] == 'lon') { │ │ │ │ │ - geometry.x = parseFloat(vals[valIndex]); │ │ │ │ │ - set = true; │ │ │ │ │ - } else if (columns[valIndex] == 'title') │ │ │ │ │ - attributes['title'] = vals[valIndex]; │ │ │ │ │ - else if (columns[valIndex] == 'image' || │ │ │ │ │ - columns[valIndex] == 'icon' && style) { │ │ │ │ │ - style['externalGraphic'] = vals[valIndex]; │ │ │ │ │ - } else if (columns[valIndex] == 'iconSize' && style) { │ │ │ │ │ - var size = vals[valIndex].split(','); │ │ │ │ │ - style['graphicWidth'] = parseFloat(size[0]); │ │ │ │ │ - style['graphicHeight'] = parseFloat(size[1]); │ │ │ │ │ - } else if (columns[valIndex] == 'iconOffset' && style) { │ │ │ │ │ - var offset = vals[valIndex].split(','); │ │ │ │ │ - style['graphicXOffset'] = parseFloat(offset[0]); │ │ │ │ │ - style['graphicYOffset'] = parseFloat(offset[1]); │ │ │ │ │ - } else if (columns[valIndex] == 'description') { │ │ │ │ │ - attributes['description'] = vals[valIndex]; │ │ │ │ │ - } else if (columns[valIndex] == 'overflow') { │ │ │ │ │ - attributes['overflow'] = vals[valIndex]; │ │ │ │ │ - } else { │ │ │ │ │ - // For StyleMap filtering, allow additional │ │ │ │ │ - // columns to be stored as attributes. │ │ │ │ │ - attributes[columns[valIndex]] = vals[valIndex]; │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - if (set) { │ │ │ │ │ - if (this.internalProjection && this.externalProjection) { │ │ │ │ │ - geometry.transform(this.externalProjection, │ │ │ │ │ - this.internalProjection); │ │ │ │ │ - } │ │ │ │ │ - var feature = new OpenLayers.Feature.Vector(geometry, attributes, style); │ │ │ │ │ - features.push(feature); │ │ │ │ │ - } │ │ │ │ │ + addPoint: function(pixel) { │ │ │ │ │ + if (!this.drawingHole && this.holeModifier && │ │ │ │ │ + this.evt && this.evt[this.holeModifier]) { │ │ │ │ │ + var geometry = this.point.geometry; │ │ │ │ │ + var features = this.control.layer.features; │ │ │ │ │ + var candidate, polygon; │ │ │ │ │ + // look for intersections, last drawn gets priority │ │ │ │ │ + for (var i = features.length - 1; i >= 0; --i) { │ │ │ │ │ + candidate = features[i].geometry; │ │ │ │ │ + if ((candidate instanceof OpenLayers.Geometry.Polygon || │ │ │ │ │ + candidate instanceof OpenLayers.Geometry.MultiPolygon) && │ │ │ │ │ + candidate.intersects(geometry)) { │ │ │ │ │ + polygon = features[i]; │ │ │ │ │ + this.control.layer.removeFeatures([polygon], { │ │ │ │ │ + silent: true │ │ │ │ │ + }); │ │ │ │ │ + this.control.layer.events.registerPriority( │ │ │ │ │ + "sketchcomplete", this, this.finalizeInteriorRing │ │ │ │ │ + ); │ │ │ │ │ + this.control.layer.events.registerPriority( │ │ │ │ │ + "sketchmodified", this, this.enforceTopology │ │ │ │ │ + ); │ │ │ │ │ + polygon.geometry.addComponent(this.line.geometry); │ │ │ │ │ + this.polygon = polygon; │ │ │ │ │ + this.drawingHole = true; │ │ │ │ │ + break; │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ } │ │ │ │ │ - return features; │ │ │ │ │ + OpenLayers.Handler.Path.prototype.addPoint.apply(this, arguments); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Format.Text" │ │ │ │ │ -}); │ │ │ │ │ -/* ====================================================================== │ │ │ │ │ - OpenLayers/Layer/Text.js │ │ │ │ │ - ====================================================================== */ │ │ │ │ │ - │ │ │ │ │ -/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ - * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ - * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ - * full text of the license. */ │ │ │ │ │ - │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * @requires OpenLayers/Layer/Markers.js │ │ │ │ │ - * @requires OpenLayers/Format/Text.js │ │ │ │ │ - * @requires OpenLayers/Request/XMLHttpRequest.js │ │ │ │ │ - */ │ │ │ │ │ - │ │ │ │ │ -/** │ │ │ │ │ - * Class: OpenLayers.Layer.Text │ │ │ │ │ - * This layer creates markers given data in a text file. The │ │ │ │ │ - * property of the layer (specified as a property of the options argument │ │ │ │ │ - * in the constructor) points to a tab delimited │ │ │ │ │ - * file with data used to create markers. │ │ │ │ │ - * │ │ │ │ │ - * The first row of the data file should be a header line with the column names │ │ │ │ │ - * of the data. Each column should be delimited by a tab space. The │ │ │ │ │ - * possible columns are: │ │ │ │ │ - * - *point* lat,lon of the point where a marker is to be placed │ │ │ │ │ - * - *lat* Latitude of the point where a marker is to be placed │ │ │ │ │ - * - *lon* Longitude of the point where a marker is to be placed │ │ │ │ │ - * - *icon* or *image* URL of marker icon to use. │ │ │ │ │ - * - *iconSize* Size of Icon to use. │ │ │ │ │ - * - *iconOffset* Where the top-left corner of the icon is to be placed │ │ │ │ │ - * relative to the latitude and longitude of the point. │ │ │ │ │ - * - *title* The text of the 'title' is placed inside an 'h2' marker │ │ │ │ │ - * inside a popup, which opens when the marker is clicked. │ │ │ │ │ - * - *description* The text of the 'description' is placed below the h2 │ │ │ │ │ - * in the popup. this can be plain text or HTML. │ │ │ │ │ - * │ │ │ │ │ - * Example text file: │ │ │ │ │ - * (code) │ │ │ │ │ - * lat lon title description iconSize iconOffset icon │ │ │ │ │ - * 10 20 title description 21,25 -10,-25 http://www.openlayers.org/dev/img/marker.png │ │ │ │ │ - * (end) │ │ │ │ │ - * │ │ │ │ │ - * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ - */ │ │ │ │ │ -OpenLayers.Layer.Text = OpenLayers.Class(OpenLayers.Layer.Markers, { │ │ │ │ │ - │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: location │ │ │ │ │ - * {String} URL of text file. Must be specified in the "options" argument │ │ │ │ │ - * of the constructor. Can not be changed once passed in. │ │ │ │ │ - */ │ │ │ │ │ - location: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: features │ │ │ │ │ - * {Array()} │ │ │ │ │ + * Method: getCurrentPointIndex │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {Number} The index of the most recently drawn point. │ │ │ │ │ */ │ │ │ │ │ - features: null, │ │ │ │ │ + getCurrentPointIndex: function() { │ │ │ │ │ + return this.line.geometry.components.length - 2; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: formatOptions │ │ │ │ │ - * {Object} Hash of options which should be passed to the format when it is │ │ │ │ │ - * created. Must be passed in the constructor. │ │ │ │ │ - */ │ │ │ │ │ - formatOptions: null, │ │ │ │ │ - │ │ │ │ │ - /** │ │ │ │ │ - * Property: selectedFeature │ │ │ │ │ - * {} │ │ │ │ │ + * Method: enforceTopology │ │ │ │ │ + * Simple topology enforcement for drawing interior rings. Ensures vertices │ │ │ │ │ + * of interior rings are contained by exterior ring. Other topology │ │ │ │ │ + * rules are enforced in to allow drawing of │ │ │ │ │ + * rings that intersect only during the sketch (e.g. a "C" shaped ring │ │ │ │ │ + * that nearly encloses another ring). │ │ │ │ │ */ │ │ │ │ │ - selectedFeature: null, │ │ │ │ │ + enforceTopology: function(event) { │ │ │ │ │ + var point = event.vertex; │ │ │ │ │ + var components = this.line.geometry.components; │ │ │ │ │ + // ensure that vertices of interior ring are contained by exterior ring │ │ │ │ │ + if (!this.polygon.geometry.intersects(point)) { │ │ │ │ │ + var last = components[components.length - 3]; │ │ │ │ │ + point.x = last.x; │ │ │ │ │ + point.y = last.y; │ │ │ │ │ + } │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Layer.Text │ │ │ │ │ - * Create a text layer. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * name - {String} │ │ │ │ │ - * options - {Object} Object with properties to be set on the layer. │ │ │ │ │ - * Must include property. │ │ │ │ │ + * Method: finishGeometry │ │ │ │ │ + * Finish the geometry and send it back to the control. │ │ │ │ │ */ │ │ │ │ │ - initialize: function(name, options) { │ │ │ │ │ - OpenLayers.Layer.Markers.prototype.initialize.apply(this, arguments); │ │ │ │ │ - this.features = []; │ │ │ │ │ + finishGeometry: function() { │ │ │ │ │ + var index = this.line.geometry.components.length - 2; │ │ │ │ │ + this.line.geometry.removeComponent(this.line.geometry.components[index]); │ │ │ │ │ + this.removePoint(); │ │ │ │ │ + this.finalize(); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIMethod: destroy │ │ │ │ │ + * Method: finalizeInteriorRing │ │ │ │ │ + * Enforces that new ring has some area and doesn't contain vertices of any │ │ │ │ │ + * other rings. │ │ │ │ │ */ │ │ │ │ │ - destroy: function() { │ │ │ │ │ - // Warning: Layer.Markers.destroy() must be called prior to calling │ │ │ │ │ - // clearFeatures() here, otherwise we leak memory. Indeed, if │ │ │ │ │ - // Layer.Markers.destroy() is called after clearFeatures(), it won't be │ │ │ │ │ - // able to remove the marker image elements from the layer's div since │ │ │ │ │ - // the markers will have been destroyed by clearFeatures(). │ │ │ │ │ - OpenLayers.Layer.Markers.prototype.destroy.apply(this, arguments); │ │ │ │ │ - this.clearFeatures(); │ │ │ │ │ - this.features = null; │ │ │ │ │ + finalizeInteriorRing: function() { │ │ │ │ │ + var ring = this.line.geometry; │ │ │ │ │ + // ensure that ring has some area │ │ │ │ │ + var modified = (ring.getArea() !== 0); │ │ │ │ │ + if (modified) { │ │ │ │ │ + // ensure that new ring doesn't intersect any other rings │ │ │ │ │ + var rings = this.polygon.geometry.components; │ │ │ │ │ + for (var i = rings.length - 2; i >= 0; --i) { │ │ │ │ │ + if (ring.intersects(rings[i])) { │ │ │ │ │ + modified = false; │ │ │ │ │ + break; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + if (modified) { │ │ │ │ │ + // ensure that new ring doesn't contain any other rings │ │ │ │ │ + var target; │ │ │ │ │ + outer: for (var i = rings.length - 2; i > 0; --i) { │ │ │ │ │ + var points = rings[i].components; │ │ │ │ │ + for (var j = 0, jj = points.length; j < jj; ++j) { │ │ │ │ │ + if (ring.containsPoint(points[j])) { │ │ │ │ │ + modified = false; │ │ │ │ │ + break outer; │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + } │ │ │ │ │ + if (modified) { │ │ │ │ │ + if (this.polygon.state !== OpenLayers.State.INSERT) { │ │ │ │ │ + this.polygon.state = OpenLayers.State.UPDATE; │ │ │ │ │ + } │ │ │ │ │ + } else { │ │ │ │ │ + this.polygon.geometry.removeComponent(ring); │ │ │ │ │ + } │ │ │ │ │ + this.restoreFeature(); │ │ │ │ │ + return false; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: loadText │ │ │ │ │ - * Start the load of the Text data. Don't do this when we first add the layer, │ │ │ │ │ - * since we may not be visible at any point, and it would therefore be a waste. │ │ │ │ │ + * APIMethod: cancel │ │ │ │ │ + * Finish the geometry and call the "cancel" callback. │ │ │ │ │ */ │ │ │ │ │ - loadText: function() { │ │ │ │ │ - if (!this.loaded) { │ │ │ │ │ - if (this.location != null) { │ │ │ │ │ - │ │ │ │ │ - var onFail = function(e) { │ │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ │ - }; │ │ │ │ │ - │ │ │ │ │ - this.events.triggerEvent("loadstart"); │ │ │ │ │ - OpenLayers.Request.GET({ │ │ │ │ │ - url: this.location, │ │ │ │ │ - success: this.parseData, │ │ │ │ │ - failure: onFail, │ │ │ │ │ - scope: this │ │ │ │ │ - }); │ │ │ │ │ - this.loaded = true; │ │ │ │ │ - } │ │ │ │ │ + cancel: function() { │ │ │ │ │ + if (this.drawingHole) { │ │ │ │ │ + this.polygon.geometry.removeComponent(this.line.geometry); │ │ │ │ │ + this.restoreFeature(true); │ │ │ │ │ } │ │ │ │ │ + return OpenLayers.Handler.Path.prototype.cancel.apply(this, arguments); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: moveTo │ │ │ │ │ - * If layer is visible and Text has not been loaded, load Text. │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * bounds - {Object} │ │ │ │ │ - * zoomChanged - {Object} │ │ │ │ │ - * minor - {Object} │ │ │ │ │ + * Method: restoreFeature │ │ │ │ │ + * Move the feature from the sketch layer to the target layer. │ │ │ │ │ + * │ │ │ │ │ + * Properties: │ │ │ │ │ + * cancel - {Boolean} Cancel drawing. If falsey, the "sketchcomplete" event │ │ │ │ │ + * will be fired. │ │ │ │ │ */ │ │ │ │ │ - moveTo: function(bounds, zoomChanged, minor) { │ │ │ │ │ - OpenLayers.Layer.Markers.prototype.moveTo.apply(this, arguments); │ │ │ │ │ - if (this.visibility && !this.loaded) { │ │ │ │ │ - this.loadText(); │ │ │ │ │ + restoreFeature: function(cancel) { │ │ │ │ │ + this.control.layer.events.unregister( │ │ │ │ │ + "sketchcomplete", this, this.finalizeInteriorRing │ │ │ │ │ + ); │ │ │ │ │ + this.control.layer.events.unregister( │ │ │ │ │ + "sketchmodified", this, this.enforceTopology │ │ │ │ │ + ); │ │ │ │ │ + this.layer.removeFeatures([this.polygon], { │ │ │ │ │ + silent: true │ │ │ │ │ + }); │ │ │ │ │ + this.control.layer.addFeatures([this.polygon], { │ │ │ │ │ + silent: true │ │ │ │ │ + }); │ │ │ │ │ + this.drawingHole = false; │ │ │ │ │ + if (!cancel) { │ │ │ │ │ + // Re-trigger "sketchcomplete" so other listeners can do their │ │ │ │ │ + // business. While this is somewhat sloppy (if a listener is │ │ │ │ │ + // registered with registerPriority - not common - between the start │ │ │ │ │ + // and end of a single ring drawing - very uncommon - it will be │ │ │ │ │ + // called twice). │ │ │ │ │ + // TODO: In 3.0, collapse sketch handlers into geometry specific │ │ │ │ │ + // drawing controls. │ │ │ │ │ + this.control.layer.events.triggerEvent( │ │ │ │ │ + "sketchcomplete", { │ │ │ │ │ + feature: this.polygon │ │ │ │ │ + } │ │ │ │ │ + ); │ │ │ │ │ } │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: parseData │ │ │ │ │ + * Method: destroyFeature │ │ │ │ │ + * Destroy temporary geometries │ │ │ │ │ * │ │ │ │ │ * Parameters: │ │ │ │ │ - * ajaxRequest - {} │ │ │ │ │ + * force - {Boolean} Destroy even if persist is true. │ │ │ │ │ */ │ │ │ │ │ - parseData: function(ajaxRequest) { │ │ │ │ │ - var text = ajaxRequest.responseText; │ │ │ │ │ - │ │ │ │ │ - var options = {}; │ │ │ │ │ - │ │ │ │ │ - OpenLayers.Util.extend(options, this.formatOptions); │ │ │ │ │ - │ │ │ │ │ - if (this.map && !this.projection.equals(this.map.getProjectionObject())) { │ │ │ │ │ - options.externalProjection = this.projection; │ │ │ │ │ - options.internalProjection = this.map.getProjectionObject(); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - var parser = new OpenLayers.Format.Text(options); │ │ │ │ │ - var features = parser.read(text); │ │ │ │ │ - for (var i = 0, len = features.length; i < len; i++) { │ │ │ │ │ - var data = {}; │ │ │ │ │ - var feature = features[i]; │ │ │ │ │ - var location; │ │ │ │ │ - var iconSize, iconOffset; │ │ │ │ │ - │ │ │ │ │ - location = new OpenLayers.LonLat(feature.geometry.x, │ │ │ │ │ - feature.geometry.y); │ │ │ │ │ - │ │ │ │ │ - if (feature.style.graphicWidth && │ │ │ │ │ - feature.style.graphicHeight) { │ │ │ │ │ - iconSize = new OpenLayers.Size( │ │ │ │ │ - feature.style.graphicWidth, │ │ │ │ │ - feature.style.graphicHeight); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - // FIXME: At the moment, we only use this if we have an │ │ │ │ │ - // externalGraphic, because icon has no setOffset API Method. │ │ │ │ │ - /** │ │ │ │ │ - * FIXME FIRST!! │ │ │ │ │ - * The Text format does all sorts of parseFloating │ │ │ │ │ - * The result of a parseFloat for a bogus string is NaN. That │ │ │ │ │ - * means the three possible values here are undefined, NaN, or a │ │ │ │ │ - * number. The previous check was an identity check for null. This │ │ │ │ │ - * means it was failing for all undefined or NaN. A slightly better │ │ │ │ │ - * check is for undefined. An even better check is to see if the │ │ │ │ │ - * value is a number (see #1441). │ │ │ │ │ - */ │ │ │ │ │ - if (feature.style.graphicXOffset !== undefined && │ │ │ │ │ - feature.style.graphicYOffset !== undefined) { │ │ │ │ │ - iconOffset = new OpenLayers.Pixel( │ │ │ │ │ - feature.style.graphicXOffset, │ │ │ │ │ - feature.style.graphicYOffset); │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if (feature.style.externalGraphic != null) { │ │ │ │ │ - data.icon = new OpenLayers.Icon(feature.style.externalGraphic, │ │ │ │ │ - iconSize, │ │ │ │ │ - iconOffset); │ │ │ │ │ - } else { │ │ │ │ │ - data.icon = OpenLayers.Marker.defaultIcon(); │ │ │ │ │ - │ │ │ │ │ - //allows for the case where the image url is not │ │ │ │ │ - // specified but the size is. use a default icon │ │ │ │ │ - // but change the size │ │ │ │ │ - if (iconSize != null) { │ │ │ │ │ - data.icon.setSize(iconSize); │ │ │ │ │ - } │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - if ((feature.attributes.title != null) && │ │ │ │ │ - (feature.attributes.description != null)) { │ │ │ │ │ - data['popupContentHTML'] = │ │ │ │ │ - '

' + feature.attributes.title + '

' + │ │ │ │ │ - '

' + feature.attributes.description + '

'; │ │ │ │ │ - } │ │ │ │ │ - │ │ │ │ │ - data['overflow'] = feature.attributes.overflow || "auto"; │ │ │ │ │ + destroyFeature: function(force) { │ │ │ │ │ + OpenLayers.Handler.Path.prototype.destroyFeature.call( │ │ │ │ │ + this, force); │ │ │ │ │ + this.polygon = null; │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ - var markerFeature = new OpenLayers.Feature(this, location, data); │ │ │ │ │ - this.features.push(markerFeature); │ │ │ │ │ - var marker = markerFeature.createMarker(); │ │ │ │ │ - if ((feature.attributes.title != null) && │ │ │ │ │ - (feature.attributes.description != null)) { │ │ │ │ │ - marker.events.register('click', markerFeature, this.markerClick); │ │ │ │ │ - } │ │ │ │ │ - this.addMarker(marker); │ │ │ │ │ - } │ │ │ │ │ - this.events.triggerEvent("loadend"); │ │ │ │ │ + /** │ │ │ │ │ + * Method: drawFeature │ │ │ │ │ + * Render geometries on the temporary layer. │ │ │ │ │ + */ │ │ │ │ │ + drawFeature: function() { │ │ │ │ │ + this.layer.drawFeature(this.polygon, this.style); │ │ │ │ │ + this.layer.drawFeature(this.point, this.style); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: markerClick │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * evt - {Event} │ │ │ │ │ + * Method: getSketch │ │ │ │ │ + * Return the sketch feature. │ │ │ │ │ * │ │ │ │ │ - * Context: │ │ │ │ │ - * - {} │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - markerClick: function(evt) { │ │ │ │ │ - var sameMarkerClicked = (this == this.layer.selectedFeature); │ │ │ │ │ - this.layer.selectedFeature = (!sameMarkerClicked) ? this : null; │ │ │ │ │ - for (var i = 0, len = this.layer.map.popups.length; i < len; i++) { │ │ │ │ │ - this.layer.map.removePopup(this.layer.map.popups[i]); │ │ │ │ │ - } │ │ │ │ │ - if (!sameMarkerClicked) { │ │ │ │ │ - this.layer.map.addPopup(this.createPopup()); │ │ │ │ │ - } │ │ │ │ │ - OpenLayers.Event.stop(evt); │ │ │ │ │ + getSketch: function() { │ │ │ │ │ + return this.polygon; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Method: clearFeatures │ │ │ │ │ + * Method: getGeometry │ │ │ │ │ + * Return the sketch geometry. If is true, this will return │ │ │ │ │ + * a multi-part geometry. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {} │ │ │ │ │ */ │ │ │ │ │ - clearFeatures: function() { │ │ │ │ │ - if (this.features != null) { │ │ │ │ │ - while (this.features.length > 0) { │ │ │ │ │ - var feature = this.features[0]; │ │ │ │ │ - OpenLayers.Util.removeItem(this.features, feature); │ │ │ │ │ - feature.destroy(); │ │ │ │ │ - } │ │ │ │ │ + getGeometry: function() { │ │ │ │ │ + var geometry = this.polygon && this.polygon.geometry; │ │ │ │ │ + if (geometry && this.multi) { │ │ │ │ │ + geometry = new OpenLayers.Geometry.MultiPolygon([geometry]); │ │ │ │ │ } │ │ │ │ │ + return geometry; │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ - CLASS_NAME: "OpenLayers.Layer.Text" │ │ │ │ │ + CLASS_NAME: "OpenLayers.Handler.Polygon" │ │ │ │ │ }); │ │ │ │ │ /* ====================================================================== │ │ │ │ │ - OpenLayers/Layer/WMTS.js │ │ │ │ │ + OpenLayers/Control/EditingToolbar.js │ │ │ │ │ ====================================================================== */ │ │ │ │ │ │ │ │ │ │ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ * full text of the license. */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * @requires OpenLayers/Layer/Grid.js │ │ │ │ │ + * @requires OpenLayers/Control/Panel.js │ │ │ │ │ + * @requires OpenLayers/Control/Navigation.js │ │ │ │ │ + * @requires OpenLayers/Control/DrawFeature.js │ │ │ │ │ + * @requires OpenLayers/Handler/Point.js │ │ │ │ │ + * @requires OpenLayers/Handler/Path.js │ │ │ │ │ + * @requires OpenLayers/Handler/Polygon.js │ │ │ │ │ */ │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Class: OpenLayers.Layer.WMTS │ │ │ │ │ - * Instances of the WMTS class allow viewing of tiles from a service that │ │ │ │ │ - * implements the OGC WMTS specification version 1.0.0. │ │ │ │ │ + * Class: OpenLayers.Control.EditingToolbar │ │ │ │ │ + * The EditingToolbar is a panel of 4 controls to draw polygons, lines, │ │ │ │ │ + * points, or to navigate the map by panning. By default it appears in the │ │ │ │ │ + * upper right corner of the map. │ │ │ │ │ * │ │ │ │ │ * Inherits from: │ │ │ │ │ - * - │ │ │ │ │ + * - │ │ │ │ │ */ │ │ │ │ │ -OpenLayers.Layer.WMTS = OpenLayers.Class(OpenLayers.Layer.Grid, { │ │ │ │ │ +OpenLayers.Control.EditingToolbar = OpenLayers.Class( │ │ │ │ │ + OpenLayers.Control.Panel, { │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: isBaseLayer │ │ │ │ │ - * {Boolean} The layer will be considered a base layer. Default is true. │ │ │ │ │ - */ │ │ │ │ │ - isBaseLayer: true, │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: citeCompliant │ │ │ │ │ + * {Boolean} If set to true, coordinates of features drawn in a map extent │ │ │ │ │ + * crossing the date line won't exceed the world bounds. Default is false. │ │ │ │ │ + */ │ │ │ │ │ + citeCompliant: false, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Constructor: OpenLayers.Control.EditingToolbar │ │ │ │ │ + * Create an editing toolbar for a given layer. │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * layer - {} │ │ │ │ │ + * options - {Object} │ │ │ │ │ + */ │ │ │ │ │ + initialize: function(layer, options) { │ │ │ │ │ + OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]); │ │ │ │ │ + │ │ │ │ │ + this.addControls( │ │ │ │ │ + [new OpenLayers.Control.Navigation()] │ │ │ │ │ + ); │ │ │ │ │ + var controls = [ │ │ │ │ │ + new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Point, { │ │ │ │ │ + displayClass: 'olControlDrawFeaturePoint', │ │ │ │ │ + handlerOptions: { │ │ │ │ │ + citeCompliant: this.citeCompliant │ │ │ │ │ + } │ │ │ │ │ + }), │ │ │ │ │ + new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Path, { │ │ │ │ │ + displayClass: 'olControlDrawFeaturePath', │ │ │ │ │ + handlerOptions: { │ │ │ │ │ + citeCompliant: this.citeCompliant │ │ │ │ │ + } │ │ │ │ │ + }), │ │ │ │ │ + new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Polygon, { │ │ │ │ │ + displayClass: 'olControlDrawFeaturePolygon', │ │ │ │ │ + handlerOptions: { │ │ │ │ │ + citeCompliant: this.citeCompliant │ │ │ │ │ + } │ │ │ │ │ + }) │ │ │ │ │ + ]; │ │ │ │ │ + this.addControls(controls); │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + /** │ │ │ │ │ + * Method: draw │ │ │ │ │ + * calls the default draw, and then activates mouse defaults. │ │ │ │ │ + * │ │ │ │ │ + * Returns: │ │ │ │ │ + * {DOMElement} │ │ │ │ │ + */ │ │ │ │ │ + draw: function() { │ │ │ │ │ + var div = OpenLayers.Control.Panel.prototype.draw.apply(this, arguments); │ │ │ │ │ + if (this.defaultControl === null) { │ │ │ │ │ + this.defaultControl = this.controls[0]; │ │ │ │ │ + } │ │ │ │ │ + return div; │ │ │ │ │ + }, │ │ │ │ │ + │ │ │ │ │ + CLASS_NAME: "OpenLayers.Control.EditingToolbar" │ │ │ │ │ + }); │ │ │ │ │ +/* ====================================================================== │ │ │ │ │ + OpenLayers/Control/OverviewMap.js │ │ │ │ │ + ====================================================================== */ │ │ │ │ │ + │ │ │ │ │ +/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for │ │ │ │ │ + * full list of contributors). Published under the 2-clause BSD license. │ │ │ │ │ + * See license.txt in the OpenLayers distribution or repository for the │ │ │ │ │ + * full text of the license. */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * @requires OpenLayers/Control.js │ │ │ │ │ + * @requires OpenLayers/BaseTypes.js │ │ │ │ │ + * @requires OpenLayers/Events/buttonclick.js │ │ │ │ │ + * @requires OpenLayers/Map.js │ │ │ │ │ + * @requires OpenLayers/Handler/Click.js │ │ │ │ │ + * @requires OpenLayers/Handler/Drag.js │ │ │ │ │ + */ │ │ │ │ │ + │ │ │ │ │ +/** │ │ │ │ │ + * Class: OpenLayers.Control.OverviewMap │ │ │ │ │ + * The OverMap control creates a small overview map, useful to display the │ │ │ │ │ + * extent of a zoomed map and your main map and provide additional │ │ │ │ │ + * navigation options to the User. By default the overview map is drawn in │ │ │ │ │ + * the lower right corner of the main map. Create a new overview map with the │ │ │ │ │ + * constructor. │ │ │ │ │ + * │ │ │ │ │ + * Inherits from: │ │ │ │ │ + * - │ │ │ │ │ + */ │ │ │ │ │ +OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, { │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: version │ │ │ │ │ - * {String} WMTS version. Default is "1.0.0". │ │ │ │ │ + * Property: element │ │ │ │ │ + * {DOMElement} The DOM element that contains the overview map │ │ │ │ │ */ │ │ │ │ │ - version: "1.0.0", │ │ │ │ │ + element: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: requestEncoding │ │ │ │ │ - * {String} Request encoding. Can be "REST" or "KVP". Default is "KVP". │ │ │ │ │ + * APIProperty: ovmap │ │ │ │ │ + * {} A reference to the overview map itself. │ │ │ │ │ */ │ │ │ │ │ - requestEncoding: "KVP", │ │ │ │ │ + ovmap: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: url │ │ │ │ │ - * {String|Array(String)} The base URL or request URL template for the WMTS │ │ │ │ │ - * service. Must be provided. Array is only supported for base URLs, not │ │ │ │ │ - * for request URL templates. URL templates are only supported for │ │ │ │ │ - * REST . │ │ │ │ │ + * APIProperty: size │ │ │ │ │ + * {} The overvew map size in pixels. Note that this is │ │ │ │ │ + * the size of the map itself - the element that contains the map (default │ │ │ │ │ + * class name olControlOverviewMapElement) may have padding or other style │ │ │ │ │ + * attributes added via CSS. │ │ │ │ │ */ │ │ │ │ │ - url: null, │ │ │ │ │ + size: { │ │ │ │ │ + w: 180, │ │ │ │ │ + h: 90 │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: layer │ │ │ │ │ - * {String} The layer identifier advertised by the WMTS service. Must be │ │ │ │ │ - * provided. │ │ │ │ │ + * APIProperty: layers │ │ │ │ │ + * {Array()} Ordered list of layers in the overview map. │ │ │ │ │ + * If none are sent at construction, the base layer for the main map is used. │ │ │ │ │ */ │ │ │ │ │ - layer: null, │ │ │ │ │ + layers: null, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: matrixSet │ │ │ │ │ - * {String} One of the advertised matrix set identifiers. Must be provided. │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: minRectSize │ │ │ │ │ + * {Integer} The minimum width or height (in pixels) of the extent │ │ │ │ │ + * rectangle on the overview map. When the extent rectangle reaches │ │ │ │ │ + * this size, it will be replaced depending on the value of the │ │ │ │ │ + * property. Default is 15 pixels. │ │ │ │ │ */ │ │ │ │ │ - matrixSet: null, │ │ │ │ │ + minRectSize: 15, │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: style │ │ │ │ │ - * {String} One of the advertised layer styles. Must be provided. │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: minRectDisplayClass │ │ │ │ │ + * {String} Replacement style class name for the extent rectangle when │ │ │ │ │ + * is reached. This string will be suffixed on to the │ │ │ │ │ + * displayClass. Default is "RectReplacement". │ │ │ │ │ + * │ │ │ │ │ + * Example CSS declaration: │ │ │ │ │ + * (code) │ │ │ │ │ + * .olControlOverviewMapRectReplacement { │ │ │ │ │ + * overflow: hidden; │ │ │ │ │ + * cursor: move; │ │ │ │ │ + * background-image: url("img/overview_replacement.gif"); │ │ │ │ │ + * background-repeat: no-repeat; │ │ │ │ │ + * background-position: center; │ │ │ │ │ + * } │ │ │ │ │ + * (end) │ │ │ │ │ */ │ │ │ │ │ - style: null, │ │ │ │ │ + minRectDisplayClass: "RectReplacement", │ │ │ │ │ │ │ │ │ │ - /** │ │ │ │ │ - * APIProperty: format │ │ │ │ │ - * {String} The image MIME type. Default is "image/jpeg". │ │ │ │ │ + /** │ │ │ │ │ + * APIProperty: minRatio │ │ │ │ │ + * {Float} The ratio of the overview map resolution to the main map │ │ │ │ │ + * resolution at which to zoom farther out on the overview map. │ │ │ │ │ */ │ │ │ │ │ - format: "image/jpeg", │ │ │ │ │ + minRatio: 8, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: tileOrigin │ │ │ │ │ - * {} The top-left corner of the tile matrix in map │ │ │ │ │ - * units. If the tile origin for each matrix in a set is different, │ │ │ │ │ - * the should include a topLeftCorner property. If │ │ │ │ │ - * not provided, the tile origin will default to the top left corner │ │ │ │ │ - * of the layer . │ │ │ │ │ + * APIProperty: maxRatio │ │ │ │ │ + * {Float} The ratio of the overview map resolution to the main map │ │ │ │ │ + * resolution at which to zoom farther in on the overview map. │ │ │ │ │ */ │ │ │ │ │ - tileOrigin: null, │ │ │ │ │ + maxRatio: 32, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: tileFullExtent │ │ │ │ │ - * {} The full extent of the tile set. If not supplied, │ │ │ │ │ - * the layer's property will be used. │ │ │ │ │ + * APIProperty: mapOptions │ │ │ │ │ + * {Object} An object containing any non-default properties to be sent to │ │ │ │ │ + * the overview map's map constructor. These should include any │ │ │ │ │ + * non-default options that the main map was constructed with. │ │ │ │ │ */ │ │ │ │ │ - tileFullExtent: null, │ │ │ │ │ + mapOptions: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: formatSuffix │ │ │ │ │ - * {String} For REST request encoding, an image format suffix must be │ │ │ │ │ - * included in the request. If not provided, the suffix will be derived │ │ │ │ │ - * from the property. │ │ │ │ │ + * APIProperty: autoPan │ │ │ │ │ + * {Boolean} Always pan the overview map, so the extent marker remains in │ │ │ │ │ + * the center. Default is false. If true, when you drag the extent │ │ │ │ │ + * marker, the overview map will update itself so the marker returns │ │ │ │ │ + * to the center. │ │ │ │ │ */ │ │ │ │ │ - formatSuffix: null, │ │ │ │ │ + autoPan: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: matrixIds │ │ │ │ │ - * {Array} A list of tile matrix identifiers. If not provided, the matrix │ │ │ │ │ - * identifiers will be assumed to be integers corresponding to the │ │ │ │ │ - * map zoom level. If a list of strings is provided, each item should │ │ │ │ │ - * be the matrix identifier that corresponds to the map zoom level. │ │ │ │ │ - * Additionally, a list of objects can be provided. Each object should │ │ │ │ │ - * describe the matrix as presented in the WMTS capabilities. These │ │ │ │ │ - * objects should have the propertes shown below. │ │ │ │ │ - * │ │ │ │ │ - * Matrix properties: │ │ │ │ │ - * identifier - {String} The matrix identifier (required). │ │ │ │ │ - * scaleDenominator - {Number} The matrix scale denominator. │ │ │ │ │ - * topLeftCorner - {} The top left corner of the │ │ │ │ │ - * matrix. Must be provided if different than the layer . │ │ │ │ │ - * tileWidth - {Number} The tile width for the matrix. Must be provided │ │ │ │ │ - * if different than the width given in the layer . │ │ │ │ │ - * tileHeight - {Number} The tile height for the matrix. Must be provided │ │ │ │ │ - * if different than the height given in the layer . │ │ │ │ │ + * Property: handlers │ │ │ │ │ + * {Object} │ │ │ │ │ */ │ │ │ │ │ - matrixIds: null, │ │ │ │ │ + handlers: null, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: dimensions │ │ │ │ │ - * {Array} For RESTful request encoding, extra dimensions may be specified. │ │ │ │ │ - * Items in this list should be property names in the object. │ │ │ │ │ - * Values of extra dimensions will be determined from the corresponding │ │ │ │ │ - * values in the object. │ │ │ │ │ + * Property: resolutionFactor │ │ │ │ │ + * {Object} │ │ │ │ │ */ │ │ │ │ │ - dimensions: null, │ │ │ │ │ + resolutionFactor: 1, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: params │ │ │ │ │ - * {Object} Extra parameters to include in tile requests. For KVP │ │ │ │ │ - * , these properties will be encoded in the request │ │ │ │ │ - * query string. For REST , these properties will │ │ │ │ │ - * become part of the request path, with order determined by the │ │ │ │ │ - * list. │ │ │ │ │ + * APIProperty: maximized │ │ │ │ │ + * {Boolean} Start as maximized (visible). Defaults to false. │ │ │ │ │ */ │ │ │ │ │ - params: null, │ │ │ │ │ + maximized: false, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: zoomOffset │ │ │ │ │ - * {Number} If your cache has more levels than you want to provide │ │ │ │ │ - * access to with this layer, supply a zoomOffset. This zoom offset │ │ │ │ │ - * is added to the current map zoom level to determine the level │ │ │ │ │ - * for a requested tile. For example, if you supply a zoomOffset │ │ │ │ │ - * of 3, when the map is at the zoom 0, tiles will be requested from │ │ │ │ │ - * level 3 of your cache. Default is 0 (assumes cache level and map │ │ │ │ │ - * zoom are equivalent). Additionally, if this layer is to be used │ │ │ │ │ - * as an overlay and the cache has fewer zoom levels than the base │ │ │ │ │ - * layer, you can supply a negative zoomOffset. For example, if a │ │ │ │ │ - * map zoom level of 1 corresponds to your cache level zero, you would │ │ │ │ │ - * supply a -1 zoomOffset (and set the maxResolution of the layer │ │ │ │ │ - * appropriately). The zoomOffset value has no effect if complete │ │ │ │ │ - * matrix definitions (including scaleDenominator) are supplied in │ │ │ │ │ - * the property. Defaults to 0 (no zoom offset). │ │ │ │ │ + * APIProperty: maximizeTitle │ │ │ │ │ + * {String} This property is used for showing a tooltip over the │ │ │ │ │ + * maximize div. Defaults to "" (no title). │ │ │ │ │ */ │ │ │ │ │ - zoomOffset: 0, │ │ │ │ │ + maximizeTitle: "", │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * APIProperty: serverResolutions │ │ │ │ │ - * {Array} A list of all resolutions available on the server. Only set this │ │ │ │ │ - * property if the map resolutions differ from the server. This │ │ │ │ │ - * property serves two purposes. (a) can include │ │ │ │ │ - * resolutions that the server supports and that you don't want to │ │ │ │ │ - * provide with this layer; you can also look at , which is │ │ │ │ │ - * an alternative to for that specific purpose. │ │ │ │ │ - * (b) The map can work with resolutions that aren't supported by │ │ │ │ │ - * the server, i.e. that aren't in . When the │ │ │ │ │ - * map is displayed in such a resolution data for the closest │ │ │ │ │ - * server-supported resolution is loaded and the layer div is │ │ │ │ │ - * stretched as necessary. │ │ │ │ │ + * APIProperty: minimizeTitle │ │ │ │ │ + * {String} This property is used for showing a tooltip over the │ │ │ │ │ + * minimize div. Defaults to "" (no title). │ │ │ │ │ */ │ │ │ │ │ - serverResolutions: null, │ │ │ │ │ + minimizeTitle: "", │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: formatSuffixMap │ │ │ │ │ - * {Object} a map between WMTS 'format' request parameter and tile image file suffix │ │ │ │ │ + * Constructor: OpenLayers.Control.OverviewMap │ │ │ │ │ + * Create a new overview map │ │ │ │ │ + * │ │ │ │ │ + * Parameters: │ │ │ │ │ + * options - {Object} Properties of this object will be set on the overview │ │ │ │ │ + * map object. Note, to set options on the map object contained in this │ │ │ │ │ + * control, set as one of the options properties. │ │ │ │ │ */ │ │ │ │ │ - formatSuffixMap: { │ │ │ │ │ - "image/png": "png", │ │ │ │ │ - "image/png8": "png", │ │ │ │ │ - "image/png24": "png", │ │ │ │ │ - "image/png32": "png", │ │ │ │ │ - "png": "png", │ │ │ │ │ - "image/jpeg": "jpg", │ │ │ │ │ - "image/jpg": "jpg", │ │ │ │ │ - "jpeg": "jpg", │ │ │ │ │ - "jpg": "jpg" │ │ │ │ │ + initialize: function(options) { │ │ │ │ │ + this.layers = []; │ │ │ │ │ + this.handlers = {}; │ │ │ │ │ + OpenLayers.Control.prototype.initialize.apply(this, [options]); │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Property: matrix │ │ │ │ │ - * {Object} Matrix definition for the current map resolution. Updated by │ │ │ │ │ - * the method. │ │ │ │ │ + * APIMethod: destroy │ │ │ │ │ + * Deconstruct the control │ │ │ │ │ */ │ │ │ │ │ - matrix: null, │ │ │ │ │ + destroy: function() { │ │ │ │ │ + if (!this.mapDiv) { // we've already been destroyed │ │ │ │ │ + return; │ │ │ │ │ + } │ │ │ │ │ + if (this.handlers.click) { │ │ │ │ │ + this.handlers.click.destroy(); │ │ │ │ │ + } │ │ │ │ │ + if (this.handlers.drag) { │ │ │ │ │ + this.handlers.drag.destroy(); │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.ovmap && this.ovmap.viewPortDiv.removeChild(this.extentRectangle); │ │ │ │ │ + this.extentRectangle = null; │ │ │ │ │ + │ │ │ │ │ + if (this.rectEvents) { │ │ │ │ │ + this.rectEvents.destroy(); │ │ │ │ │ + this.rectEvents = null; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (this.ovmap) { │ │ │ │ │ + this.ovmap.destroy(); │ │ │ │ │ + this.ovmap = null; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.element.removeChild(this.mapDiv); │ │ │ │ │ + this.mapDiv = null; │ │ │ │ │ + │ │ │ │ │ + this.div.removeChild(this.element); │ │ │ │ │ + this.element = null; │ │ │ │ │ + │ │ │ │ │ + if (this.maximizeDiv) { │ │ │ │ │ + this.div.removeChild(this.maximizeDiv); │ │ │ │ │ + this.maximizeDiv = null; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + if (this.minimizeDiv) { │ │ │ │ │ + this.div.removeChild(this.minimizeDiv); │ │ │ │ │ + this.minimizeDiv = null; │ │ │ │ │ + } │ │ │ │ │ + │ │ │ │ │ + this.map.events.un({ │ │ │ │ │ + buttonclick: this.onButtonClick, │ │ │ │ │ + moveend: this.update, │ │ │ │ │ + changebaselayer: this.baseLayerDraw, │ │ │ │ │ + scope: this │ │ │ │ │ + }); │ │ │ │ │ + │ │ │ │ │ + OpenLayers.Control.prototype.destroy.apply(this, arguments); │ │ │ │ │ + }, │ │ │ │ │ │ │ │ │ │ /** │ │ │ │ │ - * Constructor: OpenLayers.Layer.WMTS │ │ │ │ │ - * Create a new WMTS layer. │ │ │ │ │ - * │ │ │ │ │ - * Example: │ │ │ │ │ - * (code) │ │ │ │ │ - * var wmts = new OpenLayers.Layer.WMTS({ │ │ │ │ │ - * name: "My WMTS Layer", │ │ │ │ │ - * url: "http://example.com/wmts", │ │ │ │ │ - * layer: "layer_id", │ │ │ │ │ - * style: "default", │ │ │ │ │ - * matrixSet: "matrix_id" │ │ │ │ │ - * }); │ │ │ │ │ - * (end) │ │ │ │ │ - * │ │ │ │ │ - * Parameters: │ │ │ │ │ - * config - {Object} Configuration properties for the layer. │ │ │ │ │ - * │ │ │ │ │ - * Required configuration properties: │ │ │ │ │ - * url - {String} The base url for the service. See the property. │ │ │ │ │ - * layer - {String} The layer identifier. See the property. │ │ │ │ │ - * style - {String} The layer style identifier. See the