⚝
One Hat Cyber Team
⚝
Your IP:
216.73.216.91
Server IP:
157.245.101.34
Server:
Linux skvinfotech-website 5.4.0-131-generic #147-Ubuntu SMP Fri Oct 14 17:07:22 UTC 2022 x86_64
Server Software:
Apache/2.4.41 (Ubuntu)
PHP Version:
7.4.33
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
usr
/
share
/
phpmyadmin
/
js
/
vendor
/
openlayers
/
Edit File: OpenLayers.js
/* OpenLayers.js -- OpenLayers Map Viewer Library Copyright (c) 2006-2013 by OpenLayers Contributors Published under the 2-clause BSD license. See http://openlayers.org/dev/license.txt for the full text of the license, and http://openlayers.org/dev/authors.txt for full list of contributors. Includes compressed code under the following licenses: (For uncompressed versions of the code used, please see the OpenLayers Github repository:
) */ /** * Contains XMLHttpRequest.js
* Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 */ /** * OpenLayers.Util.pagePosition is based on Yahoo's getXY method, which is * Copyright (c) 2006, Yahoo! Inc. * All rights reserved. * * Redistribution and use of this software in source and binary forms, with or * without modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * * Neither the name of Yahoo! Inc. nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission of Yahoo! Inc. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* ====================================================================== OpenLayers/SingleFile.js ====================================================================== */ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ var OpenLayers = { /** * Constant: VERSION_NUMBER */ VERSION_NUMBER: "Release 2.13.1", /** * Constant: singleFile * TODO: remove this in 3.0 when we stop supporting build profiles that * include OpenLayers.js */ singleFile: true, /** * Method: _getScriptLocation * Return the path to this script. This is also implemented in * OpenLayers.js * * Returns: * {String} Path to this script */ _getScriptLocation: (function() { var r = new RegExp("(^|(.*?\\/))(OpenLayers[^\\/]*?\\.js)(\\?|$)"), s = document.getElementsByTagName('script'), src, m, l = ""; for(var i=0, len=s.length; i
* * (end code) * * Please remember that when your OpenLayers script is not named * "OpenLayers.js" you will have to make sure that the default theme is * loaded into the page by including an appropriate
-tag, * e.g.: * * (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
} 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/BaseTypes.js ====================================================================== */ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** * @requires OpenLayers/SingleFile.js */ /** * Header: OpenLayers Base Types * OpenLayers custom string, number and function functions are described here. */ /** * Namespace: OpenLayers.String * Contains convenience functions for string manipulation. */ OpenLayers.String = { /** * APIFunction: startsWith * Test whether a string starts with another string. * * Parameters: * str - {String} The string to test. * sub - {String} The substring to look for. * * Returns: * {Boolean} The first string starts with the second. */ startsWith: function(str, sub) { return (str.indexOf(sub) == 0); }, /** * APIFunction: contains * Test whether a string contains another string. * * Parameters: * str - {String} The string to test. * sub - {String} The substring to look for. * * Returns: * {Boolean} The first string contains the second. */ contains: function(str, sub) { return (str.indexOf(sub) != -1); }, /** * APIFunction: trim * Removes leading and trailing whitespace characters from a string. * * Parameters: * str - {String} The (potentially) space padded string. This string is not * modified. * * Returns: * {String} A trimmed version of the string with all leading and * trailing spaces removed. */ trim: function(str) { return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }, /** * APIFunction: camelize * Camel-case a hyphenated string. * Ex. "chicken-head" becomes "chickenHead", and * "-chicken-head" becomes "ChickenHead". * * Parameters: * str - {String} The string to be camelized. The original is not modified. * * Returns: * {String} The string, camelized */ camelize: function(str) { var oStringList = str.split('-'); var camelizedString = oStringList[0]; for (var i=1, len=oStringList.length; i
replacement = context[a]; // 1 -> replacement = context[a][b]; // 2 -> replacement = context[a][b][c]; var subs = match.split(/\.+/); for (var i=0; i< subs.length; i++) { if (i == 0) { replacement = context; } if (replacement === undefined) { break; } replacement = replacement[subs[i]]; } if(typeof replacement == "function") { replacement = args ? replacement.apply(null, args) : replacement(); } // If replacement is undefined, return the string 'undefined'. // This is a workaround for a bugs in browsers not properly // dealing with non-participating groups in regular expressions: // http://blog.stevenlevithan.com/archives/npcg-javascript if (typeof replacement == 'undefined') { return 'undefined'; } else { return replacement; } }; return template.replace(OpenLayers.String.tokenRegEx, replacer); }, /** * Property: tokenRegEx * Used to find tokens in a string. * Examples: ${a}, ${a.b.c}, ${a-b}, ${5} */ tokenRegEx: /\$\{([\w.]+?)\}/g, /** * Property: numberRegEx * Used to test strings as numbers. */ numberRegEx: /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/, /** * APIFunction: isNumeric * Determine whether a string contains only a numeric value. * * Examples: * (code) * OpenLayers.String.isNumeric("6.02e23") // true * OpenLayers.String.isNumeric("12 dozen") // false * OpenLayers.String.isNumeric("4") // true * OpenLayers.String.isNumeric(" 4 ") // false * (end) * * Returns: * {Boolean} String contains only a number. */ isNumeric: function(value) { return OpenLayers.String.numberRegEx.test(value); }, /** * APIFunction: numericIf * Converts a string that appears to be a numeric value into a number. * * Parameters: * value - {String} * trimWhitespace - {Boolean} * * Returns: * {Number|String} a Number if the passed value is a number, a String * otherwise. */ numericIf: function(value, trimWhitespace) { var originalValue = value; if (trimWhitespace === true && value != null && value.replace) { value = value.replace(/^\s*|\s*$/g, ""); } return OpenLayers.String.isNumeric(value) ? parseFloat(value) : originalValue; } }; /** * Namespace: OpenLayers.Number * Contains convenience functions for manipulating numbers. */ OpenLayers.Number = { /** * Property: decimalSeparator * Decimal separator to use when formatting numbers. */ decimalSeparator: ".", /** * Property: thousandsSeparator * Thousands separator to use when formatting numbers. */ thousandsSeparator: ",", /** * APIFunction: limitSigDigs * Limit the number of significant digits on a float. * * Parameters: * num - {Float} * sig - {Integer} * * Returns: * {Float} The number, rounded to the specified number of significant * digits. */ limitSigDigs: function(num, sig) { var fig = 0; if (sig > 0) { fig = parseFloat(num.toPrecision(sig)); } return fig; }, /** * APIFunction: format * Formats a number for output. * * Parameters: * num - {Float} * dec - {Integer} Number of decimal places to round to. * Defaults to 0. Set to null to leave decimal places unchanged. * tsep - {String} Thousands separator. * Default is ",". * dsep - {String} Decimal separator. * Default is ".". * * Returns: * {String} A string representing the formatted number. */ format: function(num, dec, tsep, dsep) { dec = (typeof dec != "undefined") ? dec : 0; tsep = (typeof tsep != "undefined") ? tsep : OpenLayers.Number.thousandsSeparator; dsep = (typeof dsep != "undefined") ? dsep : OpenLayers.Number.decimalSeparator; if (dec != null) { num = parseFloat(num.toFixed(dec)); } var parts = num.toString().split("."); if (parts.length == 1 && dec == null) { // integer where we do not want to touch the decimals dec = 0; } var integer = parts[0]; if (tsep) { var thousands = /(-?[0-9]+)([0-9]{3})/; while(thousands.test(integer)) { integer = integer.replace(thousands, "$1" + tsep + "$2"); } } var str; if (dec == 0) { str = integer; } else { var rem = parts.length > 1 ? parts[1] : "0"; if (dec != null) { rem = rem + new Array(dec - rem.length + 1).join("0"); } str = integer + dsep + rem; } return str; }, /** * Method: zeroPad * Create a zero padded string optionally with a radix for casting numbers. * * Parameters: * num - {Number} The number to be zero padded. * len - {Number} The length of the string to be returned. * radix - {Number} An integer between 2 and 36 specifying the base to use * for representing numeric values. */ zeroPad: function(num, len, radix) { var str = num.toString(radix || 10); while (str.length < len) { str = "0" + str; } return str; } }; /** * Namespace: OpenLayers.Function * Contains convenience functions for function manipulation. */ OpenLayers.Function = { /** * APIFunction: bind * Bind a function to an object. Method to easily create closures with * 'this' altered. * * Parameters: * func - {Function} Input function. * object - {Object} The object to bind to the input function (as this). * * Returns: * {Function} A closure with 'this' set to the passed in object. */ bind: function(func, object) { // create a reference to all arguments past the second one var args = Array.prototype.slice.apply(arguments, [2]); return function() { // Push on any additional arguments from the actual function call. // These will come after those sent to the bind call. var newArgs = args.concat( Array.prototype.slice.apply(arguments, [0]) ); return func.apply(object, newArgs); }; }, /** * APIFunction: bindAsEventListener * Bind a function to an object, and configure it to receive the event * object as first parameter when called. * * Parameters: * func - {Function} Input function to serve as an event listener. * object - {Object} A reference to this. * * Returns: * {Function} */ bindAsEventListener: function(func, object) { return function(event) { return func.call(object, event || window.event); }; }, /** * APIFunction: False * A simple function to that just does "return false". We use this to * avoid attaching anonymous functions to DOM event handlers, which * causes "issues" on IE<8. * * Usage: * document.onclick = OpenLayers.Function.False; * * Returns: * {Boolean} */ False : function() { return false; }, /** * APIFunction: True * A simple function to that just does "return true". We use this to * avoid attaching anonymous functions to DOM event handlers, which * causes "issues" on IE<8. * * Usage: * document.onclick = OpenLayers.Function.True; * * Returns: * {Boolean} */ True : function() { return true; }, /** * APIFunction: Void * A reusable function that returns ``undefined``. * * Returns: * {undefined} */ Void: function() {} }; /** * Namespace: OpenLayers.Array * Contains convenience functions for array manipulation. */ OpenLayers.Array = { /** * APIMethod: filter * Filter an array. Provides the functionality of the * Array.prototype.filter extension to the ECMA-262 standard. Where * available, Array.prototype.filter will be used. * * Based on well known example from http://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Array/filter * * Parameters: * array - {Array} The array to be filtered. This array is not mutated. * Elements added to this array by the callback will not be visited. * callback - {Function} A function that is called for each element in * the array. If this function returns true, the element will be * included in the return. The function will be called with three * arguments: the element in the array, the index of that element, and * the array itself. If the optional caller parameter is specified * the callback will be called with this set to caller. * caller - {Object} Optional object to be set as this when the callback * is called. * * Returns: * {Array} An array of elements from the passed in array for which the * callback returns true. */ filter: function(array, callback, caller) { var selected = []; if (Array.prototype.filter) { selected = array.filter(callback, caller); } else { var len = array.length; if (typeof callback != "function") { throw new TypeError(); } for(var i=0; i
} A cached center location. This should not be * accessed directly. Use
instead. */ centerLonLat: null, /** * Constructor: OpenLayers.Bounds * Construct a new bounds object. Coordinates can either be passed as four * arguments, or as a single argument. * * Parameters (four arguments): * left - {Number} The left bounds of the box. Note that for width * calculations, this is assumed to be less than the right value. * bottom - {Number} The bottom bounds of the box. Note that for height * calculations, this is assumed to be less than the top value. * right - {Number} The right bounds. * top - {Number} The top bounds. * * Parameters (single argument): * bounds - {Array(Number)} [left, bottom, right, top] */ initialize: function(left, bottom, right, top) { if (OpenLayers.Util.isArray(left)) { top = left[3]; right = left[2]; bottom = left[1]; left = left[0]; } if (left != null) { this.left = OpenLayers.Util.toFloat(left); } if (bottom != null) { this.bottom = OpenLayers.Util.toFloat(bottom); } if (right != null) { this.right = OpenLayers.Util.toFloat(right); } if (top != null) { this.top = OpenLayers.Util.toFloat(top); } }, /** * Method: clone * Create a cloned instance of this bounds. * * Returns: * {
} A fresh copy of the bounds */ clone:function() { return new OpenLayers.Bounds(this.left, this.bottom, this.right, this.top); }, /** * Method: equals * Test a two bounds for equivalence. * * Parameters: * bounds - {
} * * Returns: * {Boolean} The passed-in bounds object has the same left, * right, top, bottom components as this. Note that if bounds * passed in is null, returns false. */ equals:function(bounds) { var equals = false; if (bounds != null) { equals = ((this.left == bounds.left) && (this.right == bounds.right) && (this.top == bounds.top) && (this.bottom == bounds.bottom)); } return equals; }, /** * APIMethod: toString * Returns a string representation of the bounds object. * * Returns: * {String} String representation of bounds object. */ toString:function() { return [this.left, this.bottom, this.right, this.top].join(","); }, /** * APIMethod: toArray * Returns an array representation of the bounds object. * * Returns an array of left, bottom, right, top properties, or -- when the * optional parameter is true -- an array of the bottom, left, top, * right properties. * * Parameters: * reverseAxisOrder - {Boolean} Should we reverse the axis order? * * Returns: * {Array} array of left, bottom, right, top */ toArray: function(reverseAxisOrder) { if (reverseAxisOrder === true) { return [this.bottom, this.left, this.top, this.right]; } else { return [this.left, this.bottom, this.right, this.top]; } }, /** * APIMethod: toBBOX * Returns a boundingbox-string representation of the bounds object. * * Parameters: * decimal - {Integer} How many significant digits in the bbox coords? * Default is 6 * reverseAxisOrder - {Boolean} Should we reverse the axis order? * * Returns: * {String} Simple String representation of bounds object. * (e.g. "5,42,10,45") */ toBBOX:function(decimal, reverseAxisOrder) { if (decimal== null) { decimal = 6; } var mult = Math.pow(10, decimal); var xmin = Math.round(this.left * mult) / mult; var ymin = Math.round(this.bottom * mult) / mult; var xmax = Math.round(this.right * mult) / mult; var ymax = Math.round(this.top * mult) / mult; if (reverseAxisOrder === true) { return ymin + "," + xmin + "," + ymax + "," + xmax; } else { return xmin + "," + ymin + "," + xmax + "," + ymax; } }, /** * APIMethod: toGeometry * Create a new polygon geometry based on this bounds. * * Returns: * {
} A new polygon with the coordinates * of this bounds. */ toGeometry: function() { return new OpenLayers.Geometry.Polygon([ new OpenLayers.Geometry.LinearRing([ new OpenLayers.Geometry.Point(this.left, this.bottom), new OpenLayers.Geometry.Point(this.right, this.bottom), new OpenLayers.Geometry.Point(this.right, this.top), new OpenLayers.Geometry.Point(this.left, this.top) ]) ]); }, /** * APIMethod: getWidth * Returns the width of the bounds. * * Returns: * {Float} The width of the bounds (right minus left). */ getWidth:function() { return (this.right - this.left); }, /** * APIMethod: getHeight * Returns the height of the bounds. * * Returns: * {Float} The height of the bounds (top minus bottom). */ getHeight:function() { return (this.top - this.bottom); }, /** * APIMethod: getSize * Returns an
object of the bounds. * * Returns: * {
} The size of the bounds. */ getSize:function() { return new OpenLayers.Size(this.getWidth(), this.getHeight()); }, /** * APIMethod: getCenterPixel * Returns the
object which represents the center of the * bounds. * * Returns: * {
} The center of the bounds in pixel space. */ getCenterPixel:function() { return new OpenLayers.Pixel( (this.left + this.right) / 2, (this.bottom + this.top) / 2); }, /** * APIMethod: getCenterLonLat * Returns the
object which represents the center of the * bounds. * * Returns: * {
} The center of the bounds in map space. */ getCenterLonLat:function() { if(!this.centerLonLat) { this.centerLonLat = new OpenLayers.LonLat( (this.left + this.right) / 2, (this.bottom + this.top) / 2 ); } return this.centerLonLat; }, /** * APIMethod: scale * Scales the bounds around a pixel or lonlat. Note that the new * bounds may return non-integer properties, even if a pixel * is passed. * * Parameters: * ratio - {Float} * origin - {
or
} * Default is center. * * Returns: * {
} A new bounds that is scaled by ratio * from origin. */ scale: function(ratio, origin){ if(origin == null){ origin = this.getCenterLonLat(); } var origx,origy; // get origin coordinates if(origin.CLASS_NAME == "OpenLayers.LonLat"){ origx = origin.lon; origy = origin.lat; } else { origx = origin.x; origy = origin.y; } var left = (this.left - origx) * ratio + origx; var bottom = (this.bottom - origy) * ratio + origy; var right = (this.right - origx) * ratio + origx; var top = (this.top - origy) * ratio + origy; return new OpenLayers.Bounds(left, bottom, right, top); }, /** * APIMethod: add * Shifts the coordinates of the bound by the given horizontal and vertical * deltas. * * (start code) * var bounds = new OpenLayers.Bounds(0, 0, 10, 10); * bounds.toString(); * // => "0,0,10,10" * * bounds.add(-1.5, 4).toString(); * // => "-1.5,4,8.5,14" * (end) * * This method will throw a TypeError if it is passed null as an argument. * * Parameters: * x - {Float} horizontal delta * y - {Float} vertical delta * * Returns: * {
} A new bounds whose coordinates are the same as * this, but shifted by the passed-in x and y values. */ add:function(x, y) { if ( (x == null) || (y == null) ) { throw new TypeError('Bounds.add cannot receive null values'); } return new OpenLayers.Bounds(this.left + x, this.bottom + y, this.right + x, this.top + y); }, /** * APIMethod: extend * Extend the bounds to include the
, *
or
specified. * * Please note that this function assumes that left < right and * bottom < top. * * Parameters: * object - {
,
or *
} The object to be included in the new bounds * object. */ extend:function(object) { if (object) { switch(object.CLASS_NAME) { case "OpenLayers.LonLat": this.extendXY(object.lon, object.lat); break; case "OpenLayers.Geometry.Point": this.extendXY(object.x, object.y); break; case "OpenLayers.Bounds": // clear cached center location this.centerLonLat = null; if ( (this.left == null) || (object.left < this.left)) { this.left = object.left; } if ( (this.bottom == null) || (object.bottom < this.bottom) ) { this.bottom = object.bottom; } if ( (this.right == null) || (object.right > this.right) ) { this.right = object.right; } if ( (this.top == null) || (object.top > this.top) ) { this.top = object.top; } break; } } }, /** * APIMethod: extendXY * Extend the bounds to include the XY coordinate specified. * * Parameters: * x - {number} The X part of the the coordinate. * y - {number} The Y part of the the coordinate. */ extendXY:function(x, y) { // clear cached center location this.centerLonLat = null; if ((this.left == null) || (x < this.left)) { this.left = x; } if ((this.bottom == null) || (y < this.bottom)) { this.bottom = y; } if ((this.right == null) || (x > this.right)) { this.right = x; } if ((this.top == null) || (y > this.top)) { this.top = y; } }, /** * APIMethod: containsLonLat * Returns whether the bounds object contains the given
. * * Parameters: * ll - {
|Object} OpenLayers.LonLat or an * object with a 'lon' and 'lat' properties. * options - {Object} Optional parameters * * Acceptable options: * inclusive - {Boolean} Whether or not to include the border. * Default is true. * worldBounds - {
} If a worldBounds is provided, the * ll will be considered as contained if it exceeds the world bounds, * but can be wrapped around the dateline so it is contained by this * bounds. * * Returns: * {Boolean} The passed-in lonlat is within this bounds. */ containsLonLat: function(ll, options) { if (typeof options === "boolean") { options = {inclusive: options}; } options = options || {}; var contains = this.contains(ll.lon, ll.lat, options.inclusive), worldBounds = options.worldBounds; if (worldBounds && !contains) { var worldWidth = worldBounds.getWidth(); var worldCenterX = (worldBounds.left + worldBounds.right) / 2; var worldsAway = Math.round((ll.lon - worldCenterX) / worldWidth); contains = this.containsLonLat({ lon: ll.lon - worldsAway * worldWidth, lat: ll.lat }, {inclusive: options.inclusive}); } return contains; }, /** * APIMethod: containsPixel * Returns whether the bounds object contains the given
. * * Parameters: * px - {
} * inclusive - {Boolean} Whether or not to include the border. Default is * true. * * Returns: * {Boolean} The passed-in pixel is within this bounds. */ containsPixel:function(px, inclusive) { return this.contains(px.x, px.y, inclusive); }, /** * APIMethod: contains * Returns whether the bounds object contains the given x and y. * * Parameters: * x - {Float} * y - {Float} * inclusive - {Boolean} Whether or not to include the border. Default is * true. * * Returns: * {Boolean} Whether or not the passed-in coordinates are within this * bounds. */ contains:function(x, y, inclusive) { //set default if (inclusive == null) { inclusive = true; } if (x == null || y == null) { return false; } x = OpenLayers.Util.toFloat(x); y = OpenLayers.Util.toFloat(y); var contains = false; if (inclusive) { contains = ((x >= this.left) && (x <= this.right) && (y >= this.bottom) && (y <= this.top)); } else { contains = ((x > this.left) && (x < this.right) && (y > this.bottom) && (y < this.top)); } return contains; }, /** * APIMethod: intersectsBounds * Determine whether the target bounds intersects this bounds. Bounds are * considered intersecting if any of their edges intersect or if one * bounds contains the other. * * Parameters: * bounds - {
} The target bounds. * options - {Object} Optional parameters. * * Acceptable options: * inclusive - {Boolean} Treat coincident borders as intersecting. Default * is true. If false, bounds that do not overlap but only touch at the * border will not be considered as intersecting. * worldBounds - {
} If a worldBounds is provided, two * bounds will be considered as intersecting if they intersect when * shifted to within the world bounds. This applies only to bounds that * cross or are completely outside the world bounds. * * Returns: * {Boolean} The passed-in bounds object intersects this bounds. */ intersectsBounds:function(bounds, options) { if (typeof options === "boolean") { options = {inclusive: options}; } options = options || {}; if (options.worldBounds) { var self = this.wrapDateLine(options.worldBounds); bounds = bounds.wrapDateLine(options.worldBounds); } else { self = this; } if (options.inclusive == null) { options.inclusive = true; } var intersects = false; var mightTouch = ( self.left == bounds.right || self.right == bounds.left || self.top == bounds.bottom || self.bottom == bounds.top ); // if the two bounds only touch at an edge, and inclusive is false, // then the bounds don't *really* intersect. if (options.inclusive || !mightTouch) { // otherwise, if one of the boundaries even partially contains another, // inclusive of the edges, then they do intersect. var inBottom = ( ((bounds.bottom >= self.bottom) && (bounds.bottom <= self.top)) || ((self.bottom >= bounds.bottom) && (self.bottom <= bounds.top)) ); var inTop = ( ((bounds.top >= self.bottom) && (bounds.top <= self.top)) || ((self.top > bounds.bottom) && (self.top < bounds.top)) ); var inLeft = ( ((bounds.left >= self.left) && (bounds.left <= self.right)) || ((self.left >= bounds.left) && (self.left <= bounds.right)) ); var inRight = ( ((bounds.right >= self.left) && (bounds.right <= self.right)) || ((self.right >= bounds.left) && (self.right <= bounds.right)) ); intersects = ((inBottom || inTop) && (inLeft || inRight)); } // document me if (options.worldBounds && !intersects) { var world = options.worldBounds; var width = world.getWidth(); var selfCrosses = !world.containsBounds(self); var boundsCrosses = !world.containsBounds(bounds); if (selfCrosses && !boundsCrosses) { bounds = bounds.add(-width, 0); intersects = self.intersectsBounds(bounds, {inclusive: options.inclusive}); } else if (boundsCrosses && !selfCrosses) { self = self.add(-width, 0); intersects = bounds.intersectsBounds(self, {inclusive: options.inclusive}); } } return intersects; }, /** * APIMethod: containsBounds * Returns whether the bounds object contains the given
. * * bounds - {
} The target bounds. * partial - {Boolean} If any of the target corners is within this bounds * consider the bounds contained. Default is false. If false, the * entire target bounds must be contained within this bounds. * inclusive - {Boolean} Treat shared edges as contained. Default is * true. * * Returns: * {Boolean} The passed-in bounds object is contained within this bounds. */ containsBounds:function(bounds, partial, inclusive) { if (partial == null) { partial = false; } if (inclusive == null) { inclusive = true; } var bottomLeft = this.contains(bounds.left, bounds.bottom, inclusive); var bottomRight = this.contains(bounds.right, bounds.bottom, inclusive); var topLeft = this.contains(bounds.left, bounds.top, inclusive); var topRight = this.contains(bounds.right, bounds.top, inclusive); return (partial) ? (bottomLeft || bottomRight || topLeft || topRight) : (bottomLeft && bottomRight && topLeft && topRight); }, /** * APIMethod: determineQuadrant * Returns the the quadrant ("br", "tr", "tl", "bl") in which the given *
lies. * * Parameters: * lonlat - {
} * * Returns: * {String} The quadrant ("br" "tr" "tl" "bl") of the bounds in which the * coordinate lies. */ determineQuadrant: function(lonlat) { var quadrant = ""; var center = this.getCenterLonLat(); quadrant += (lonlat.lat < center.lat) ? "b" : "t"; quadrant += (lonlat.lon < center.lon) ? "l" : "r"; return quadrant; }, /** * APIMethod: transform * Transform the Bounds object from source to dest. * * Parameters: * source - {
} Source projection. * dest - {
} Destination projection. * * Returns: * {
} Itself, for use in chaining operations. */ transform: function(source, dest) { // clear cached center location this.centerLonLat = null; var ll = OpenLayers.Projection.transform( {'x': this.left, 'y': this.bottom}, source, dest); var lr = OpenLayers.Projection.transform( {'x': this.right, 'y': this.bottom}, source, dest); var ul = OpenLayers.Projection.transform( {'x': this.left, 'y': this.top}, source, dest); var ur = OpenLayers.Projection.transform( {'x': this.right, 'y': this.top}, source, dest); this.left = Math.min(ll.x, ul.x); this.bottom = Math.min(ll.y, lr.y); this.right = Math.max(lr.x, ur.x); this.top = Math.max(ul.y, ur.y); return this; }, /** * APIMethod: wrapDateLine * Wraps the bounds object around the dateline. * * Parameters: * maxExtent - {
} * options - {Object} Some possible options are: * * Allowed Options: * leftTolerance - {float} Allow for a margin of error * with the 'left' value of this * bound. * Default is 0. * rightTolerance - {float} Allow for a margin of error * with the 'right' value of * this bound. * Default is 0. * * Returns: * {
} A copy of this bounds, but wrapped around the * "dateline" (as specified by the borders of * maxExtent). Note that this function only returns * a different bounds value if this bounds is * *entirely* outside of the maxExtent. If this * bounds straddles the dateline (is part in/part * out of maxExtent), the returned bounds will always * cross the left edge of the given maxExtent. *. */ wrapDateLine: function(maxExtent, options) { options = options || {}; var leftTolerance = options.leftTolerance || 0; var rightTolerance = options.rightTolerance || 0; var newBounds = this.clone(); if (maxExtent) { var width = maxExtent.getWidth(); //shift right? while (newBounds.left < maxExtent.left && newBounds.right - rightTolerance <= maxExtent.left ) { newBounds = newBounds.add(width, 0); } //shift left? while (newBounds.left + leftTolerance >= maxExtent.right && newBounds.right > maxExtent.right ) { newBounds = newBounds.add(-width, 0); } // crosses right only? force left var newLeft = newBounds.left + leftTolerance; if (newLeft < maxExtent.right && newLeft > maxExtent.left && newBounds.right - rightTolerance > maxExtent.right) { newBounds = newBounds.add(-width, 0); } } return newBounds; }, CLASS_NAME: "OpenLayers.Bounds" }); /** * APIFunction: fromString * Alternative constructor that builds a new OpenLayers.Bounds from a * parameter string. * * (begin code) * OpenLayers.Bounds.fromString("5,42,10,45"); * // => equivalent to ... * new OpenLayers.Bounds(5, 42, 10, 45); * (end) * * Parameters: * str - {String} Comma-separated bounds string. (e.g. "5,42,10,45") * reverseAxisOrder - {Boolean} Does the string use reverse axis order? * * Returns: * {
} New bounds object built from the * passed-in String. */ OpenLayers.Bounds.fromString = function(str, reverseAxisOrder) { var bounds = str.split(","); return OpenLayers.Bounds.fromArray(bounds, reverseAxisOrder); }; /** * APIFunction: fromArray * Alternative constructor that builds a new OpenLayers.Bounds from an array. * * (begin code) * OpenLayers.Bounds.fromArray( [5, 42, 10, 45] ); * // => equivalent to ... * new OpenLayers.Bounds(5, 42, 10, 45); * (end) * * Parameters: * bbox - {Array(Float)} Array of bounds values (e.g. [5,42,10,45]) * reverseAxisOrder - {Boolean} Does the array use reverse axis order? * * Returns: * {
} New bounds object built from the passed-in Array. */ OpenLayers.Bounds.fromArray = function(bbox, reverseAxisOrder) { return reverseAxisOrder === true ? new OpenLayers.Bounds(bbox[1], bbox[0], bbox[3], bbox[2]) : new OpenLayers.Bounds(bbox[0], bbox[1], bbox[2], bbox[3]); }; /** * APIFunction: fromSize * Alternative constructor that builds a new OpenLayers.Bounds from a size. * * (begin code) * OpenLayers.Bounds.fromSize( new OpenLayers.Size(10, 20) ); * // => equivalent to ... * new OpenLayers.Bounds(0, 20, 10, 0); * (end) * * Parameters: * size - {
or Object}
or an object with * both 'w' and 'h' properties. * * Returns: * {
} New bounds object built from the passed-in size. */ OpenLayers.Bounds.fromSize = function(size) { return new OpenLayers.Bounds(0, size.h, size.w, 0); }; /** * Function: oppositeQuadrant * Get the opposite quadrant for a given quadrant string. * * (begin code) * OpenLayers.Bounds.oppositeQuadrant( "tl" ); * // => "br" * * OpenLayers.Bounds.oppositeQuadrant( "tr" ); * // => "bl" * (end) * * Parameters: * quadrant - {String} two character quadrant shortstring * * Returns: * {String} The opposing quadrant ("br" "tr" "tl" "bl"). For Example, if * you pass in "bl" it returns "tr", if you pass in "br" it * returns "tl", etc. */ OpenLayers.Bounds.oppositeQuadrant = function(quadrant) { var opp = ""; opp += (quadrant.charAt(0) == 't') ? 'b' : 't'; opp += (quadrant.charAt(1) == 'l') ? 'r' : 'l'; return opp; }; /* ====================================================================== OpenLayers/BaseTypes/Element.js ====================================================================== */ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** * @requires OpenLayers/Util.js * @requires OpenLayers/BaseTypes.js */ /** * Namespace: OpenLayers.Element */ OpenLayers.Element = { /** * APIFunction: visible * * Parameters: * element - {DOMElement} * * Returns: * {Boolean} Is the element visible? */ visible: function(element) { return OpenLayers.Util.getElement(element).style.display != 'none'; }, /** * APIFunction: toggle * Toggle the visibility of element(s) passed in * * Parameters: * element - {DOMElement} Actually user can pass any number of elements */ toggle: function() { for (var i=0, len=arguments.length; i
"lon=5,lat=42") */ toString:function() { return ("lon=" + this.lon + ",lat=" + this.lat); }, /** * APIMethod: toShortString * * Returns: * {String} Shortened String representation of OpenLayers.LonLat object. * (e.g.
"5, 42"
) */ toShortString:function() { return (this.lon + ", " + this.lat); }, /** * APIMethod: clone * * Returns: * {
} New OpenLayers.LonLat object with the same lon * and lat values */ clone:function() { return new OpenLayers.LonLat(this.lon, this.lat); }, /** * APIMethod: add * * Parameters: * lon - {Float} * lat - {Float} * * Returns: * {
} A new OpenLayers.LonLat object with the lon and * lat passed-in added to this's. */ add:function(lon, lat) { if ( (lon == null) || (lat == null) ) { throw new TypeError('LonLat.add cannot receive null values'); } return new OpenLayers.LonLat(this.lon + OpenLayers.Util.toFloat(lon), this.lat + OpenLayers.Util.toFloat(lat)); }, /** * APIMethod: equals * * Parameters: * ll - {
} * * Returns: * {Boolean} Boolean value indicating whether the passed-in *
object has the same lon and lat * components as this. * Note: if ll passed in is null, returns false */ equals:function(ll) { var equals = false; if (ll != null) { equals = ((this.lon == ll.lon && this.lat == ll.lat) || (isNaN(this.lon) && isNaN(this.lat) && isNaN(ll.lon) && isNaN(ll.lat))); } return equals; }, /** * APIMethod: transform * Transform the LonLat object from source to dest. This transformation is * *in place*: if you want a *new* lonlat, use .clone() first. * * Parameters: * source - {
} Source projection. * dest - {
} Destination projection. * * Returns: * {
} Itself, for use in chaining operations. */ transform: function(source, dest) { var point = OpenLayers.Projection.transform( {'x': this.lon, 'y': this.lat}, source, dest); this.lon = point.x; this.lat = point.y; return this; }, /** * APIMethod: wrapDateLine * * Parameters: * maxExtent - {
} * * Returns: * {
} A copy of this lonlat, but wrapped around the * "dateline" (as specified by the borders of * maxExtent) */ wrapDateLine: function(maxExtent) { var newLonLat = this.clone(); if (maxExtent) { //shift right? while (newLonLat.lon < maxExtent.left) { newLonLat.lon += maxExtent.getWidth(); } //shift left? while (newLonLat.lon > maxExtent.right) { newLonLat.lon -= maxExtent.getWidth(); } } return newLonLat; }, CLASS_NAME: "OpenLayers.LonLat" }); /** * Function: fromString * Alternative constructor that builds a new
from a * parameter string * * Parameters: * str - {String} Comma-separated Lon,Lat coordinate string. * (e.g.
"5,40"
) * * Returns: * {
} New
object built from the * passed-in String. */ OpenLayers.LonLat.fromString = function(str) { var pair = str.split(","); return new OpenLayers.LonLat(pair[0], pair[1]); }; /** * Function: fromArray * Alternative constructor that builds a new
from an * array of two numbers that represent lon- and lat-values. * * Parameters: * arr - {Array(Float)} Array of lon/lat values (e.g. [5,-42]) * * Returns: * {
} New
object built from the * passed-in array. */ OpenLayers.LonLat.fromArray = function(arr) { var gotArr = OpenLayers.Util.isArray(arr), lon = gotArr && arr[0], lat = gotArr && arr[1]; return new OpenLayers.LonLat(lon, lat); }; /* ====================================================================== OpenLayers/BaseTypes/Pixel.js ====================================================================== */ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** * @requires OpenLayers/BaseTypes/Class.js */ /** * Class: OpenLayers.Pixel * This class represents a screen coordinate, in x and y coordinates */ OpenLayers.Pixel = OpenLayers.Class({ /** * APIProperty: x * {Number} The x coordinate */ x: 0.0, /** * APIProperty: y * {Number} The y coordinate */ y: 0.0, /** * Constructor: OpenLayers.Pixel * Create a new OpenLayers.Pixel instance * * Parameters: * x - {Number} The x coordinate * y - {Number} The y coordinate * * Returns: * An instance of OpenLayers.Pixel */ initialize: function(x, y) { this.x = parseFloat(x); this.y = parseFloat(y); }, /** * Method: toString * Cast this object into a string * * Returns: * {String} The string representation of Pixel. ex: "x=200.4,y=242.2" */ toString:function() { return ("x=" + this.x + ",y=" + this.y); }, /** * APIMethod: clone * Return a clone of this pixel object * * Returns: * {
} A clone pixel */ clone:function() { return new OpenLayers.Pixel(this.x, this.y); }, /** * APIMethod: equals * Determine whether one pixel is equivalent to another * * Parameters: * px - {
|Object} An OpenLayers.Pixel or an object with * a 'x' and 'y' properties. * * Returns: * {Boolean} The point passed in as parameter is equal to this. Note that * if px passed in is null, returns false. */ equals:function(px) { var equals = false; if (px != null) { equals = ((this.x == px.x && this.y == px.y) || (isNaN(this.x) && isNaN(this.y) && isNaN(px.x) && isNaN(px.y))); } return equals; }, /** * APIMethod: distanceTo * Returns the distance to the pixel point passed in as a parameter. * * Parameters: * px - {
} * * Returns: * {Float} The pixel point passed in as parameter to calculate the * distance to. */ distanceTo:function(px) { return Math.sqrt( Math.pow(this.x - px.x, 2) + Math.pow(this.y - px.y, 2) ); }, /** * APIMethod: add * * Parameters: * x - {Integer} * y - {Integer} * * Returns: * {
} A new Pixel with this pixel's x&y augmented by the * values passed in. */ add:function(x, y) { if ( (x == null) || (y == null) ) { throw new TypeError('Pixel.add cannot receive null values'); } return new OpenLayers.Pixel(this.x + x, this.y + y); }, /** * APIMethod: offset * * Parameters * px - {
|Object} An OpenLayers.Pixel or an object with * a 'x' and 'y' properties. * * Returns: * {
} A new Pixel with this pixel's x&y augmented by the * x&y values of the pixel passed in. */ offset:function(px) { var newPx = this.clone(); if (px) { newPx = this.add(px.x, px.y); } return newPx; }, CLASS_NAME: "OpenLayers.Pixel" }); /* ====================================================================== OpenLayers/BaseTypes/Size.js ====================================================================== */ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** * @requires OpenLayers/BaseTypes/Class.js */ /** * Class: OpenLayers.Size * Instances of this class represent a width/height pair */ OpenLayers.Size = OpenLayers.Class({ /** * APIProperty: w * {Number} width */ w: 0.0, /** * APIProperty: h * {Number} height */ h: 0.0, /** * Constructor: OpenLayers.Size * Create an instance of OpenLayers.Size * * Parameters: * w - {Number} width * h - {Number} height */ initialize: function(w, h) { this.w = parseFloat(w); this.h = parseFloat(h); }, /** * Method: toString * Return the string representation of a size object * * Returns: * {String} The string representation of OpenLayers.Size object. * (e.g.
"w=55,h=66"
) */ toString:function() { return ("w=" + this.w + ",h=" + this.h); }, /** * APIMethod: clone * Create a clone of this size object * * Returns: * {
} A new OpenLayers.Size object with the same w and h * values */ clone:function() { return new OpenLayers.Size(this.w, this.h); }, /** * * APIMethod: equals * Determine where this size is equal to another * * Parameters: * sz - {
|Object} An OpenLayers.Size or an object with * a 'w' and 'h' properties. * * Returns: * {Boolean} The passed in size has the same h and w properties as this one. * Note that if sz passed in is null, returns false. */ equals:function(sz) { var equals = false; if (sz != null) { equals = ((this.w == sz.w && this.h == sz.h) || (isNaN(this.w) && isNaN(this.h) && isNaN(sz.w) && isNaN(sz.h))); } return equals; }, CLASS_NAME: "OpenLayers.Size" }); /* ====================================================================== OpenLayers/Console.js ====================================================================== */ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** * @requires OpenLayers/BaseTypes/Class.js */ /** * Namespace: OpenLayers.Console * The OpenLayers.Console namespace is used for debugging and error logging. * If the Firebug Lite (../Firebug/firebug.js) is included before this script, * calls to OpenLayers.Console methods will get redirected to window.console. * This makes use of the Firebug extension where available and allows for * cross-browser debugging Firebug style. * * Note: * Note that behavior will differ with the Firebug extention and Firebug Lite. * Most notably, the Firebug Lite console does not currently allow for * hyperlinks to code or for clicking on object to explore their properties. * */ OpenLayers.Console = { /** * Create empty functions for all console methods. The real value of these * properties will be set if Firebug Lite (../Firebug/firebug.js script) is * included. We explicitly require the Firebug Lite script to trigger * functionality of the OpenLayers.Console methods. */ /** * APIFunction: log * Log an object in the console. The Firebug Lite console logs string * representation of objects. Given multiple arguments, they will * be cast to strings and logged with a space delimiter. If the first * argument is a string with printf-like formatting, subsequent arguments * will be used in string substitution. Any additional arguments (beyond * the number substituted in a format string) will be appended in a space- * delimited line. * * Parameters: * object - {Object} */ log: function() {}, /** * APIFunction: debug * Writes a message to the console, including a hyperlink to the line * where it was called. * * May be called with multiple arguments as with OpenLayers.Console.log(). * * Parameters: * object - {Object} */ debug: function() {}, /** * APIFunction: info * Writes a message to the console with the visual "info" icon and color * coding and a hyperlink to the line where it was called. * * May be called with multiple arguments as with OpenLayers.Console.log(). * * Parameters: * object - {Object} */ info: function() {}, /** * APIFunction: warn * Writes a message to the console with the visual "warning" icon and * color coding and a hyperlink to the line where it was called. * * May be called with multiple arguments as with OpenLayers.Console.log(). * * Parameters: * object - {Object} */ warn: function() {}, /** * APIFunction: error * Writes a message to the console with the visual "error" icon and color * coding and a hyperlink to the line where it was called. * * May be called with multiple arguments as with OpenLayers.Console.log(). * * Parameters: * object - {Object} */ error: function() {}, /** * APIFunction: userError * A single interface for showing error messages to the user. The default * behavior is a Javascript alert, though this can be overridden by * reassigning OpenLayers.Console.userError to a different function. * * Expects a single error message * * Parameters: * error - {Object} */ userError: function(error) { alert(error); }, /** * APIFunction: assert * Tests that an expression is true. If not, it will write a message to * the console and throw an exception. * * May be called with multiple arguments as with OpenLayers.Console.log(). * * Parameters: * object - {Object} */ assert: function() {}, /** * APIFunction: dir * Prints an interactive listing of all properties of the object. This * looks identical to the view that you would see in the DOM tab. * * Parameters: * object - {Object} */ dir: function() {}, /** * APIFunction: dirxml * Prints the XML source tree of an HTML or XML element. This looks * identical to the view that you would see in the HTML tab. You can click * on any node to inspect it in the HTML tab. * * Parameters: * object - {Object} */ dirxml: function() {}, /** * APIFunction: trace * Prints an interactive stack trace of JavaScript execution at the point * where it is called. The stack trace details the functions on the stack, * as well as the values that were passed as arguments to each function. * You can click each function to take you to its source in the Script tab, * and click each argument value to inspect it in the DOM or HTML tabs. * */ trace: function() {}, /** * APIFunction: group * Writes a message to the console and opens a nested block to indent all * future messages sent to the console. Call OpenLayers.Console.groupEnd() * to close the block. * * May be called with multiple arguments as with OpenLayers.Console.log(). * * Parameters: * object - {Object} */ group: function() {}, /** * APIFunction: groupEnd * Closes the most recently opened block created by a call to * OpenLayers.Console.group */ groupEnd: function() {}, /** * APIFunction: time * Creates a new timer under the given name. Call * OpenLayers.Console.timeEnd(name) * with the same name to stop the timer and print the time elapsed. * * Parameters: * name - {String} */ time: function() {}, /** * APIFunction: timeEnd * Stops a timer created by a call to OpenLayers.Console.time(name) and * writes the time elapsed. * * Parameters: * name - {String} */ timeEnd: function() {}, /** * APIFunction: profile * Turns on the JavaScript profiler. The optional argument title would * contain the text to be printed in the header of the profile report. * * This function is not currently implemented in Firebug Lite. * * Parameters: * title - {String} Optional title for the profiler */ profile: function() {}, /** * APIFunction: profileEnd * Turns off the JavaScript profiler and prints its report. * * This function is not currently implemented in Firebug Lite. */ profileEnd: function() {}, /** * APIFunction: count * Writes the number of times that the line of code where count was called * was executed. The optional argument title will print a message in * addition to the number of the count. * * This function is not currently implemented in Firebug Lite. * * Parameters: * title - {String} Optional title to be printed with count */ count: function() {}, CLASS_NAME: "OpenLayers.Console" }; /** * Execute an anonymous function to extend the OpenLayers.Console namespace * if the firebug.js script is included. This closure is used so that the * "scripts" and "i" variables don't pollute the global namespace. */ (function() { /** * If Firebug Lite is included (before this script), re-route all * OpenLayers.Console calls to the console object. */ var scripts = document.getElementsByTagName("script"); for(var i=0, len=scripts.length; i
method to set this value and the
method to * retrieve it. */ code: null, /** * APIProperty: defaultCode * {String} Default language to use when a specific language can't be * found. Default is "en". */ defaultCode: "en", /** * APIFunction: getCode * Get the current language code. * * Returns: * {String} The current language code. */ getCode: function() { if(!OpenLayers.Lang.code) { OpenLayers.Lang.setCode(); } return OpenLayers.Lang.code; }, /** * APIFunction: setCode * Set the language code for string translation. This code is used by * the
method. * * Parameters: * code - {String} These codes follow the IETF recommendations at * http://www.ietf.org/rfc/rfc3066.txt. If no value is set, the * browser's language setting will be tested. If no
* dictionary exists for the code, the
* will be used. */ setCode: function(code) { var lang; if(!code) { code = (OpenLayers.BROWSER_NAME == "msie") ? navigator.userLanguage : navigator.language; } var parts = code.split('-'); parts[0] = parts[0].toLowerCase(); if(typeof OpenLayers.Lang[parts[0]] == "object") { lang = parts[0]; } // check for regional extensions if(parts[1]) { var testLang = parts[0] + '-' + parts[1].toUpperCase(); if(typeof OpenLayers.Lang[testLang] == "object") { lang = testLang; } } if(!lang) { OpenLayers.Console.warn( 'Failed to find OpenLayers.Lang.' + parts.join("-") + ' dictionary, falling back to default language' ); lang = OpenLayers.Lang.defaultCode; } OpenLayers.Lang.code = lang; }, /** * APIMethod: translate * Looks up a key from a dictionary based on the current language string. * The value of
will be used to determine the appropriate * dictionary. Dictionaries are stored in
. * * Parameters: * key - {String} The key for an i18n string value in the dictionary. * context - {Object} Optional context to be used with *
. * * Returns: * {String} A internationalized string. */ translate: function(key, context) { var dictionary = OpenLayers.Lang[OpenLayers.Lang.getCode()]; var message = dictionary && dictionary[key]; if(!message) { // Message not found, fall back to message key message = key; } if(context) { message = OpenLayers.String.format(message, context); } return message; } }; /** * APIMethod: OpenLayers.i18n * Alias for
. Looks up a key from a dictionary * based on the current language string. The value of *
will be used to determine the appropriate * dictionary. Dictionaries are stored in
. * * Parameters: * key - {String} The key for an i18n string value in the dictionary. * context - {Object} Optional context to be used with *
. * * Returns: * {String} A internationalized string. */ OpenLayers.i18n = OpenLayers.Lang.translate; /* ====================================================================== OpenLayers/Util.js ====================================================================== */ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** * @requires OpenLayers/BaseTypes.js * @requires OpenLayers/BaseTypes/Bounds.js * @requires OpenLayers/BaseTypes/Element.js * @requires OpenLayers/BaseTypes/LonLat.js * @requires OpenLayers/BaseTypes/Pixel.js * @requires OpenLayers/BaseTypes/Size.js * @requires OpenLayers/Lang.js */ /** * Namespace: Util */ OpenLayers.Util = OpenLayers.Util || {}; /** * Function: getElement * This is the old $() from prototype * * Parameters: * e - {String or DOMElement or Window} * * Returns: * {Array(DOMElement) or DOMElement} */ OpenLayers.Util.getElement = function() { var elements = []; for (var i=0, len=arguments.length; i
= 0; i--) { if(array[i] == item) { array.splice(i,1); //break;more than once?? } } return array; }; /** * Function: indexOf * Seems to exist already in FF, but not in MOZ. * * Parameters: * array - {Array} * obj - {*} * * Returns: * {Integer} The index at which the first object was found in the array. * If not found, returns -1. */ OpenLayers.Util.indexOf = function(array, obj) { // use the build-in function if available. if (typeof array.indexOf == "function") { return array.indexOf(obj); } else { for (var i = 0, len = array.length; i < len; i++) { if (array[i] == obj) { return i; } } return -1; } }; /** * Property: dotless * {RegExp} * Compiled regular expression to match dots ("."). This is used for replacing * dots in identifiers. Because object identifiers are frequently used for * DOM element identifiers by the library, we avoid using dots to make for * more sensible CSS selectors. * * TODO: Use a module pattern to avoid bloating the API with stuff like this. */ OpenLayers.Util.dotless = /\./g; /** * Function: modifyDOMElement * * Modifies many properties of a DOM element all at once. Passing in * null to an individual parameter will avoid setting the attribute. * * Parameters: * element - {DOMElement} DOM element to modify. * id - {String} The element id attribute to set. Note that dots (".") will be * replaced with underscore ("_") in setting the element id. * px - {
|Object} The element left and top position, * OpenLayers.Pixel or an object with * a 'x' and 'y' properties. * sz - {
|Object} The element width and height, * OpenLayers.Size or an object with a * 'w' and 'h' properties. * position - {String} The position attribute. eg: absolute, * relative, etc. * border - {String} The style.border attribute. eg: * solid black 2px * overflow - {String} The style.overview attribute. * opacity - {Float} Fractional value (0.0 - 1.0) */ OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position, border, overflow, opacity) { if (id) { element.id = id.replace(OpenLayers.Util.dotless, "_"); } if (px) { element.style.left = px.x + "px"; element.style.top = px.y + "px"; } if (sz) { element.style.width = sz.w + "px"; element.style.height = sz.h + "px"; } if (position) { element.style.position = position; } if (border) { element.style.border = border; } if (overflow) { element.style.overflow = overflow; } if (parseFloat(opacity) >= 0.0 && parseFloat(opacity) < 1.0) { element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')'; element.style.opacity = opacity; } else if (parseFloat(opacity) == 1.0) { element.style.filter = ''; element.style.opacity = ''; } }; /** * Function: createDiv * Creates a new div and optionally set some standard attributes. * Null may be passed to each parameter if you do not wish to * set a particular attribute. * Note - zIndex is NOT set on the resulting div. * * Parameters: * id - {String} An identifier for this element. If no id is * passed an identifier will be created * automatically. Note that dots (".") will be replaced with * underscore ("_") when generating ids. * px - {
|Object} The element left and top position, * OpenLayers.Pixel or an object with * a 'x' and 'y' properties. * sz - {
|Object} The element width and height, * OpenLayers.Size or an object with a * 'w' and 'h' properties. * imgURL - {String} A url pointing to an image to use as a * background image. * position - {String} The style.position value. eg: absolute, * relative etc. * border - {String} The the style.border value. * eg: 2px solid black * overflow - {String} The style.overflow value. Eg. hidden * opacity - {Float} Fractional value (0.0 - 1.0) * * Returns: * {DOMElement} A DOM Div created with the specified attributes. */ OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position, border, overflow, opacity) { var dom = document.createElement('div'); if (imgURL) { dom.style.backgroundImage = 'url(' + imgURL + ')'; } //set generic properties if (!id) { id = OpenLayers.Util.createUniqueID("OpenLayersDiv"); } if (!position) { position = "absolute"; } OpenLayers.Util.modifyDOMElement(dom, id, px, sz, position, border, overflow, opacity); return dom; }; /** * Function: createImage * Creates an img element with specific attribute values. * * Parameters: * id - {String} The id field for the img. If none assigned one will be * automatically generated. * px - {
|Object} The element left and top position, * OpenLayers.Pixel or an object with * a 'x' and 'y' properties. * sz - {
|Object} The element width and height, * OpenLayers.Size or an object with a * 'w' and 'h' properties. * imgURL - {String} The url to use as the image source. * position - {String} The style.position value. * border - {String} The border to place around the image. * opacity - {Float} Fractional value (0.0 - 1.0) * delayDisplay - {Boolean} If true waits until the image has been * loaded. * * Returns: * {DOMElement} A DOM Image created with the specified attributes. */ OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border, opacity, delayDisplay) { var image = document.createElement("img"); //set generic properties if (!id) { id = OpenLayers.Util.createUniqueID("OpenLayersDiv"); } if (!position) { position = "relative"; } OpenLayers.Util.modifyDOMElement(image, id, px, sz, position, border, null, opacity); if (delayDisplay) { image.style.display = "none"; function display() { image.style.display = ""; OpenLayers.Event.stopObservingElement(image); } OpenLayers.Event.observe(image, "load", display); OpenLayers.Event.observe(image, "error", display); } //set special properties image.style.alt = id; image.galleryImg = "no"; if (imgURL) { image.src = imgURL; } return image; }; /** * Property: IMAGE_RELOAD_ATTEMPTS * {Integer} How many times should we try to reload an image before giving up? * Default is 0 */ OpenLayers.IMAGE_RELOAD_ATTEMPTS = 0; /** * Property: alphaHackNeeded * {Boolean} true if the png alpha hack is necessary and possible, false otherwise. */ OpenLayers.Util.alphaHackNeeded = null; /** * Function: alphaHack * Checks whether it's necessary (and possible) to use the png alpha * hack which allows alpha transparency for png images under Internet * Explorer. * * Returns: * {Boolean} true if the png alpha hack is necessary and possible, false otherwise. */ OpenLayers.Util.alphaHack = function() { if (OpenLayers.Util.alphaHackNeeded == null) { var arVersion = navigator.appVersion.split("MSIE"); var version = parseFloat(arVersion[1]); var filter = false; // IEs4Lin dies when trying to access document.body.filters, because // the property is there, but requires a DLL that can't be provided. This // means that we need to wrap this in a try/catch so that this can // continue. try { filter = !!(document.body.filters); } catch (e) {} OpenLayers.Util.alphaHackNeeded = (filter && (version >= 5.5) && (version < 7)); } return OpenLayers.Util.alphaHackNeeded; }; /** * Function: modifyAlphaImageDiv * * Parameters: * div - {DOMElement} Div containing Alpha-adjusted Image * id - {String} * px - {
|Object} OpenLayers.Pixel or an object with * a 'x' and 'y' properties. * sz - {
|Object} OpenLayers.Size or an object with * a 'w' and 'h' properties. * imgURL - {String} * position - {String} * border - {String} * sizing - {String} 'crop', 'scale', or 'image'. Default is "scale" * opacity - {Float} Fractional value (0.0 - 1.0) */ OpenLayers.Util.modifyAlphaImageDiv = function(div, id, px, sz, imgURL, position, border, sizing, opacity) { OpenLayers.Util.modifyDOMElement(div, id, px, sz, position, null, null, opacity); var img = div.childNodes[0]; if (imgURL) { img.src = imgURL; } OpenLayers.Util.modifyDOMElement(img, div.id + "_innerImage", null, sz, "relative", border); if (OpenLayers.Util.alphaHack()) { if(div.style.display != "none") { div.style.display = "inline-block"; } if (sizing == null) { sizing = "scale"; } div.style.filter = "progid:DXImageTransform.Microsoft" + ".AlphaImageLoader(src='" + img.src + "', " + "sizingMethod='" + sizing + "')"; if (parseFloat(div.style.opacity) >= 0.0 && parseFloat(div.style.opacity) < 1.0) { div.style.filter += " alpha(opacity=" + div.style.opacity * 100 + ")"; } img.style.filter = "alpha(opacity=0)"; } }; /** * Function: createAlphaImageDiv * * Parameters: * id - {String} * px - {
|Object} OpenLayers.Pixel or an object with * a 'x' and 'y' properties. * sz - {
|Object} OpenLayers.Size or an object with * a 'w' and 'h' properties. * imgURL - {String} * position - {String} * border - {String} * sizing - {String} 'crop', 'scale', or 'image'. Default is "scale" * opacity - {Float} Fractional value (0.0 - 1.0) * delayDisplay - {Boolean} If true waits until the image has been * loaded. * * Returns: * {DOMElement} A DOM Div created with a DOM Image inside it. If the hack is * needed for transparency in IE, it is added. */ OpenLayers.Util.createAlphaImageDiv = function(id, px, sz, imgURL, position, border, sizing, opacity, delayDisplay) { var div = OpenLayers.Util.createDiv(); var img = OpenLayers.Util.createImage(null, null, null, null, null, null, null, delayDisplay); img.className = "olAlphaImg"; div.appendChild(img); OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL, position, border, sizing, opacity); return div; }; /** * Function: upperCaseObject * Creates a new hashtable and copies over all the keys from the * passed-in object, but storing them under an uppercased * version of the key at which they were stored. * * Parameters: * object - {Object} * * Returns: * {Object} A new Object with all the same keys but uppercased */ OpenLayers.Util.upperCaseObject = function (object) { var uObject = {}; for (var key in object) { uObject[key.toUpperCase()] = object[key]; } return uObject; }; /** * Function: applyDefaults * Takes an object and copies any properties that don't exist from * another properties, by analogy with OpenLayers.Util.extend() from * Prototype.js. * * Parameters: * to - {Object} The destination object. * from - {Object} The source object. Any properties of this object that * are undefined in the to object will be set on the to object. * * Returns: * {Object} A reference to the to object. Note that the to argument is modified * in place and returned by this function. */ OpenLayers.Util.applyDefaults = function (to, from) { to = to || {}; /* * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative * prototype object" when calling hawOwnProperty if the source object is an * instance of window.Event. */ var fromIsEvt = typeof window.Event == "function" && from instanceof window.Event; for (var key in from) { if (to[key] === undefined || (!fromIsEvt && from.hasOwnProperty && from.hasOwnProperty(key) && !to.hasOwnProperty(key))) { to[key] = from[key]; } } /** * IE doesn't include the toString property when iterating over an object's * properties with the for(property in object) syntax. Explicitly check if * the source has its own toString property. */ if(!fromIsEvt && from && from.hasOwnProperty && from.hasOwnProperty('toString') && !to.hasOwnProperty('toString')) { to.toString = from.toString; } return to; }; /** * Function: getParameterString * * Parameters: * params - {Object} * * Returns: * {String} A concatenation of the properties of an object in * http parameter notation. * (ex.
"key1=value1&key2=value2&key3=value3"
) * If a parameter is actually a list, that parameter will then * be set to a comma-seperated list of values (foo,bar) instead * of being URL escaped (foo%3Abar). */ OpenLayers.Util.getParameterString = function(params) { var paramsArray = []; for (var key in params) { var value = params[key]; if ((value != null) && (typeof value != 'function')) { var encodedValue; if (typeof value == 'object' && value.constructor == Array) { /* value is an array; encode items and separate with "," */ var encodedItemArray = []; var item; for (var itemIndex=0, len=value.length; itemIndex
} (or any object with both .lat, .lon properties) * p2 - {
} (or any object with both .lat, .lon properties) * * Returns: * {Float} The distance (in km) between the two input points as measured on an * ellipsoid. Note that the input point objects must be in geographic * coordinates (decimal degrees) and the return distance is in kilometers. */ OpenLayers.Util.distVincenty = function(p1, p2) { var ct = OpenLayers.Util.VincentyConstants; var a = ct.a, b = ct.b, f = ct.f; var L = OpenLayers.Util.rad(p2.lon - p1.lon); var U1 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p1.lat))); var U2 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p2.lat))); var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1); var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2); var lambda = L, lambdaP = 2*Math.PI; var iterLimit = 20; while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0) { var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda); var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) + (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda)); if (sinSigma==0) { return 0; // co-incident points } var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda; var sigma = Math.atan2(sinSigma, cosSigma); var alpha = Math.asin(cosU1 * cosU2 * sinLambda / sinSigma); var cosSqAlpha = Math.cos(alpha) * Math.cos(alpha); var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha; var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha)); lambdaP = lambda; lambda = L + (1-C) * f * Math.sin(alpha) * (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM))); } if (iterLimit==0) { return NaN; // formula failed to converge } var uSq = cosSqAlpha * (a*a - b*b) / (b*b); var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq))); var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq))); var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)- B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM))); var s = b*A*(sigma-deltaSigma); var d = s.toFixed(3)/1000; // round to 1mm precision return d; }; /** * APIFunction: destinationVincenty * Calculate destination point given start point lat/long (numeric degrees), * bearing (numeric degrees) & distance (in m). * Adapted from Chris Veness work, see * http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html * * Parameters: * lonlat - {
} (or any object with both .lat, .lon * properties) The start point. * brng - {Float} The bearing (degrees). * dist - {Float} The ground distance (meters). * * Returns: * {
} The destination point. */ OpenLayers.Util.destinationVincenty = function(lonlat, brng, dist) { var u = OpenLayers.Util; var ct = u.VincentyConstants; var a = ct.a, b = ct.b, f = ct.f; var lon1 = lonlat.lon; var lat1 = lonlat.lat; var s = dist; var alpha1 = u.rad(brng); var sinAlpha1 = Math.sin(alpha1); var cosAlpha1 = Math.cos(alpha1); var tanU1 = (1-f) * Math.tan(u.rad(lat1)); var cosU1 = 1 / Math.sqrt((1 + tanU1*tanU1)), sinU1 = tanU1*cosU1; var sigma1 = Math.atan2(tanU1, cosAlpha1); var sinAlpha = cosU1 * sinAlpha1; var cosSqAlpha = 1 - sinAlpha*sinAlpha; var uSq = cosSqAlpha * (a*a - b*b) / (b*b); var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq))); var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq))); var sigma = s / (b*A), sigmaP = 2*Math.PI; while (Math.abs(sigma-sigmaP) > 1e-12) { var cos2SigmaM = Math.cos(2*sigma1 + sigma); var sinSigma = Math.sin(sigma); var cosSigma = Math.cos(sigma); var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)- B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM))); sigmaP = sigma; sigma = s / (b*A) + deltaSigma; } var tmp = sinU1*sinSigma - cosU1*cosSigma*cosAlpha1; var lat2 = Math.atan2(sinU1*cosSigma + cosU1*sinSigma*cosAlpha1, (1-f)*Math.sqrt(sinAlpha*sinAlpha + tmp*tmp)); var lambda = Math.atan2(sinSigma*sinAlpha1, cosU1*cosSigma - sinU1*sinSigma*cosAlpha1); var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha)); var L = lambda - (1-C) * f * sinAlpha * (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM))); var revAz = Math.atan2(sinAlpha, -tmp); // final bearing return new OpenLayers.LonLat(lon1+u.deg(L), u.deg(lat2)); }; /** * Function: getParameters * Parse the parameters from a URL or from the current page itself into a * JavaScript Object. Note that parameter values with commas are separated * out into an Array. * * Parameters: * url - {String} Optional url used to extract the query string. * If url is null or is not supplied, query string is taken * from the page location. * options - {Object} Additional options. Optional. * * Valid options: * splitArgs - {Boolean} Split comma delimited params into arrays? Default is * true. * * Returns: * {Object} An object of key/value pairs from the query string. */ OpenLayers.Util.getParameters = function(url, options) { options = options || {}; // if no url specified, take it from the location bar url = (url === null || url === undefined) ? window.location.href : url; //parse out parameters portion of url string var paramsString = ""; if (OpenLayers.String.contains(url, '?')) { var start = url.indexOf('?') + 1; var end = OpenLayers.String.contains(url, "#") ? url.indexOf('#') : url.length; paramsString = url.substring(start, end); } var parameters = {}; var pairs = paramsString.split(/[&;]/); for(var i=0, len=pairs.length; i
1.0) ? (1.0 / scale) : scale; return normScale; }; /** * Function: getResolutionFromScale * * Parameters: * scale - {Float} * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable. * Default is degrees * * Returns: * {Float} The corresponding resolution given passed-in scale and unit * parameters. If the given scale is falsey, the returned resolution will * be undefined. */ OpenLayers.Util.getResolutionFromScale = function (scale, units) { var resolution; if (scale) { if (units == null) { units = "degrees"; } var normScale = OpenLayers.Util.normalizeScale(scale); resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units] * OpenLayers.DOTS_PER_INCH); } return resolution; }; /** * Function: getScaleFromResolution * * Parameters: * resolution - {Float} * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable. * Default is degrees * * Returns: * {Float} The corresponding scale given passed-in resolution and unit * parameters. */ OpenLayers.Util.getScaleFromResolution = function (resolution, units) { if (units == null) { units = "degrees"; } var scale = resolution * OpenLayers.INCHES_PER_UNIT[units] * OpenLayers.DOTS_PER_INCH; return scale; }; /** * Function: pagePosition * Calculates the position of an element on the page (see * http://code.google.com/p/doctype/wiki/ArticlePageOffset) * * OpenLayers.Util.pagePosition is based on Yahoo's getXY method, which is * Copyright (c) 2006, Yahoo! Inc. * All rights reserved. * * Redistribution and use of this software in source and binary forms, with or * without modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * * Neither the name of Yahoo! Inc. nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission of Yahoo! Inc. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Parameters: * forElement - {DOMElement} * * Returns: * {Array} two item array, Left value then Top value. */ OpenLayers.Util.pagePosition = function(forElement) { // NOTE: If element is hidden (display none or disconnected or any the // ancestors are hidden) we get (0,0) by default but we still do the // accumulation of scroll position. var pos = [0, 0]; var viewportElement = OpenLayers.Util.getViewportElement(); if (!forElement || forElement == window || forElement == viewportElement) { // viewport is always at 0,0 as that defined the coordinate system for // this function - this avoids special case checks in the code below return pos; } // Gecko browsers normally use getBoxObjectFor to calculate the position. // When invoked for an element with an implicit absolute position though it // can be off by one. Therefore the recursive implementation is used in // those (relatively rare) cases. var BUGGY_GECKO_BOX_OBJECT = OpenLayers.IS_GECKO && document.getBoxObjectFor && OpenLayers.Element.getStyle(forElement, 'position') == 'absolute' && (forElement.style.top == '' || forElement.style.left == ''); var parent = null; var box; if (forElement.getBoundingClientRect) { // IE box = forElement.getBoundingClientRect(); var scrollTop = window.pageYOffset || viewportElement.scrollTop; var scrollLeft = window.pageXOffset || viewportElement.scrollLeft; pos[0] = box.left + scrollLeft; pos[1] = box.top + scrollTop; } else if (document.getBoxObjectFor && !BUGGY_GECKO_BOX_OBJECT) { // gecko // Gecko ignores the scroll values for ancestors, up to 1.9. See: // https://bugzilla.mozilla.org/show_bug.cgi?id=328881 and // https://bugzilla.mozilla.org/show_bug.cgi?id=330619 box = document.getBoxObjectFor(forElement); var vpBox = document.getBoxObjectFor(viewportElement); pos[0] = box.screenX - vpBox.screenX; pos[1] = box.screenY - vpBox.screenY; } else { // safari/opera pos[0] = forElement.offsetLeft; pos[1] = forElement.offsetTop; parent = forElement.offsetParent; if (parent != forElement) { while (parent) { pos[0] += parent.offsetLeft; pos[1] += parent.offsetTop; parent = parent.offsetParent; } } var browser = OpenLayers.BROWSER_NAME; // opera & (safari absolute) incorrectly account for body offsetTop if (browser == "opera" || (browser == "safari" && OpenLayers.Element.getStyle(forElement, 'position') == 'absolute')) { pos[1] -= document.body.offsetTop; } // accumulate the scroll positions for everything but the body element parent = forElement.offsetParent; while (parent && parent != document.body) { pos[0] -= parent.scrollLeft; // see https://bugs.opera.com/show_bug.cgi?id=249965 if (browser != "opera" || parent.tagName != 'TR') { pos[1] -= parent.scrollTop; } parent = parent.offsetParent; } } return pos; }; /** * Function: getViewportElement * Returns die viewport element of the document. The viewport element is * usually document.documentElement, except in IE,where it is either * document.body or document.documentElement, depending on the document's * compatibility mode (see * http://code.google.com/p/doctype/wiki/ArticleClientViewportElement) * * Returns: * {DOMElement} */ OpenLayers.Util.getViewportElement = function() { var viewportElement = arguments.callee.viewportElement; if (viewportElement == undefined) { viewportElement = (OpenLayers.BROWSER_NAME == "msie" && document.compatMode != 'CSS1Compat') ? document.body : document.documentElement; arguments.callee.viewportElement = viewportElement; } return viewportElement; }; /** * Function: isEquivalentUrl * Test two URLs for equivalence. * * Setting 'ignoreCase' allows for case-independent comparison. * * Comparison is based on: * - Protocol * - Host (evaluated without the port) * - Port (set 'ignorePort80' to ignore "80" values) * - Hash ( set 'ignoreHash' to disable) * - Pathname (for relative <-> absolute comparison) * - Arguments (so they can be out of order) * * Parameters: * url1 - {String} * url2 - {String} * options - {Object} Allows for customization of comparison: * 'ignoreCase' - Default is True * 'ignorePort80' - Default is True * 'ignoreHash' - Default is True * * Returns: * {Boolean} Whether or not the two URLs are equivalent */ OpenLayers.Util.isEquivalentUrl = function(url1, url2, options) { options = options || {}; OpenLayers.Util.applyDefaults(options, { ignoreCase: true, ignorePort80: true, ignoreHash: true, splitArgs: false }); var urlObj1 = OpenLayers.Util.createUrlObject(url1, options); var urlObj2 = OpenLayers.Util.createUrlObject(url2, options); //compare all keys except for "args" (treated below) for(var key in urlObj1) { if(key !== "args") { if(urlObj1[key] != urlObj2[key]) { return false; } } } // compare search args - irrespective of order for(var key in urlObj1.args) { if(urlObj1.args[key] != urlObj2.args[key]) { return false; } delete urlObj2.args[key]; } // urlObj2 shouldn't have any args left for(var key in urlObj2.args) { return false; } return true; }; /** * Function: createUrlObject * * Parameters: * url - {String} * options - {Object} A hash of options. * * Valid options: * ignoreCase - {Boolean} lowercase url, * ignorePort80 - {Boolean} don't include explicit port if port is 80, * ignoreHash - {Boolean} Don't include part of url after the hash (#). * splitArgs - {Boolean} Split comma delimited params into arrays? Default is * true. * * Returns: * {Object} An object with separate url, a, port, host, and args parsed out * and ready for comparison */ OpenLayers.Util.createUrlObject = function(url, options) { options = options || {}; // deal with relative urls first if(!(/^\w+:\/\//).test(url)) { var loc = window.location; var port = loc.port ? ":" + loc.port : ""; var fullUrl = loc.protocol + "//" + loc.host.split(":").shift() + port; if(url.indexOf("/") === 0) { // full pathname url = fullUrl + url; } else { // relative to current path var parts = loc.pathname.split("/"); parts.pop(); url = fullUrl + parts.join("/") + "/" + url; } } if (options.ignoreCase) { url = url.toLowerCase(); } var a = document.createElement('a'); a.href = url; var urlObject = {}; //host (without port) urlObject.host = a.host.split(":").shift(); //protocol urlObject.protocol = a.protocol; //port (get uniform browser behavior with port 80 here) if(options.ignorePort80) { urlObject.port = (a.port == "80" || a.port == "0") ? "" : a.port; } else { urlObject.port = (a.port == "" || a.port == "0") ? "80" : a.port; } //hash urlObject.hash = (options.ignoreHash || a.hash === "#") ? "" : a.hash; //args var queryString = a.search; if (!queryString) { var qMark = url.indexOf("?"); queryString = (qMark != -1) ? url.substr(qMark) : ""; } urlObject.args = OpenLayers.Util.getParameters(queryString, {splitArgs: options.splitArgs}); // pathname // // This is a workaround for Internet Explorer where // window.location.pathname has a leading "/", but // a.pathname has no leading "/". urlObject.pathname = (a.pathname.charAt(0) == "/") ? a.pathname : "/" + a.pathname; return urlObject; }; /** * Function: removeTail * Takes a url and removes everything after the ? and # * * Parameters: * url - {String} The url to process * * Returns: * {String} The string with all queryString and Hash removed */ OpenLayers.Util.removeTail = function(url) { var head = null; var qMark = url.indexOf("?"); var hashMark = url.indexOf("#"); if (qMark == -1) { head = (hashMark != -1) ? url.substr(0,hashMark) : url; } else { head = (hashMark != -1) ? url.substr(0,Math.min(qMark, hashMark)) : url.substr(0, qMark); } return head; }; /** * Constant: IS_GECKO * {Boolean} True if the userAgent reports the browser to use the Gecko engine */ OpenLayers.IS_GECKO = (function() { var ua = navigator.userAgent.toLowerCase(); return ua.indexOf("webkit") == -1 && ua.indexOf("gecko") != -1; })(); /** * Constant: CANVAS_SUPPORTED * {Boolean} True if canvas 2d is supported. */ OpenLayers.CANVAS_SUPPORTED = (function() { var elem = document.createElement('canvas'); return !!(elem.getContext && elem.getContext('2d')); })(); /** * Constant: BROWSER_NAME * {String} * A substring of the navigator.userAgent property. Depending on the userAgent * property, this will be the empty string or one of the following: * * "opera" -- Opera * * "msie" -- Internet Explorer * * "safari" -- Safari * * "firefox" -- Firefox * * "mozilla" -- Mozilla */ OpenLayers.BROWSER_NAME = (function() { var name = ""; var ua = navigator.userAgent.toLowerCase(); if (ua.indexOf("opera") != -1) { name = "opera"; } else if (ua.indexOf("msie") != -1) { name = "msie"; } else if (ua.indexOf("safari") != -1) { name = "safari"; } else if (ua.indexOf("mozilla") != -1) { if (ua.indexOf("firefox") != -1) { name = "firefox"; } else { name = "mozilla"; } } return name; })(); /** * Function: getBrowserName * * Returns: * {String} A string which specifies which is the current * browser in which we are running. * * Currently-supported browser detection and codes: * * 'opera' -- Opera * * 'msie' -- Internet Explorer * * 'safari' -- Safari * * 'firefox' -- Firefox * * 'mozilla' -- Mozilla * * If we are unable to property identify the browser, we * return an empty string. */ OpenLayers.Util.getBrowserName = function() { return OpenLayers.BROWSER_NAME; }; /** * Method: getRenderedDimensions * Renders the contentHTML offscreen to determine actual dimensions for * popup sizing. As we need layout to determine dimensions the content * is rendered -9999px to the left and absolute to ensure the * scrollbars do not flicker * * Parameters: * contentHTML * size - {
} If either the 'w' or 'h' properties is * specified, we fix that dimension of the div to be measured. This is * useful in the case where we have a limit in one dimension and must * therefore meaure the flow in the other dimension. * options - {Object} * * Allowed Options: * displayClass - {String} Optional parameter. A CSS class name(s) string * to provide the CSS context of the rendered content. * containerElement - {DOMElement} Optional parameter. Insert the HTML to * this node instead of the body root when calculating dimensions. * * Returns: * {
} */ OpenLayers.Util.getRenderedDimensions = function(contentHTML, size, options) { var w, h; // create temp container div with restricted size var container = document.createElement("div"); container.style.visibility = "hidden"; var containerElement = (options && options.containerElement) ? options.containerElement : document.body; // Opera and IE7 can't handle a node with position:aboslute if it inherits // position:absolute from a parent. var parentHasPositionAbsolute = false; var superContainer = null; var parent = containerElement; while (parent && parent.tagName.toLowerCase()!="body") { var parentPosition = OpenLayers.Element.getStyle(parent, "position"); if(parentPosition == "absolute") { parentHasPositionAbsolute = true; break; } else if (parentPosition && parentPosition != "static") { break; } parent = parent.parentNode; } if(parentHasPositionAbsolute && (containerElement.clientHeight === 0 || containerElement.clientWidth === 0) ){ superContainer = document.createElement("div"); superContainer.style.visibility = "hidden"; superContainer.style.position = "absolute"; superContainer.style.overflow = "visible"; superContainer.style.width = document.body.clientWidth + "px"; superContainer.style.height = document.body.clientHeight + "px"; superContainer.appendChild(container); } container.style.position = "absolute"; //fix a dimension, if specified. if (size) { if (size.w) { w = size.w; container.style.width = w + "px"; } else if (size.h) { h = size.h; container.style.height = h + "px"; } } //add css classes, if specified if (options && options.displayClass) { container.className = options.displayClass; } // create temp content div and assign content var content = document.createElement("div"); content.innerHTML = contentHTML; // we need overflow visible when calculating the size content.style.overflow = "visible"; if (content.childNodes) { for (var i=0, l=content.childNodes.length; i
= 60) { coordinateseconds -= 60; coordinateminutes += 1; if( coordinateminutes >= 60) { coordinateminutes -= 60; coordinatedegrees += 1; } } if( coordinatedegrees < 10 ) { coordinatedegrees = "0" + coordinatedegrees; } var str = coordinatedegrees + "\u00B0"; if (dmsOption.indexOf('dm') >= 0) { if( coordinateminutes < 10 ) { coordinateminutes = "0" + coordinateminutes; } str += coordinateminutes + "'"; if (dmsOption.indexOf('dms') >= 0) { if( coordinateseconds < 10 ) { coordinateseconds = "0" + coordinateseconds; } str += coordinateseconds + '"'; } } if (axis == "lon") { str += coordinate < 0 ? OpenLayers.i18n("W") : OpenLayers.i18n("E"); } else { str += coordinate < 0 ? OpenLayers.i18n("S") : OpenLayers.i18n("N"); } return str; }; /* ====================================================================== OpenLayers/Events.js ====================================================================== */ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** * @requires OpenLayers/Util.js */ /** * Namespace: OpenLayers.Event * Utility functions for event handling. */ OpenLayers.Event = { /** * Property: observers * {Object} A hashtable cache of the event observers. Keyed by * element._eventCacheID */ observers: false, /** * Constant: KEY_SPACE * {int} */ KEY_SPACE: 32, /** * Constant: KEY_BACKSPACE * {int} */ KEY_BACKSPACE: 8, /** * Constant: KEY_TAB * {int} */ KEY_TAB: 9, /** * Constant: KEY_RETURN * {int} */ KEY_RETURN: 13, /** * Constant: KEY_ESC * {int} */ KEY_ESC: 27, /** * Constant: KEY_LEFT * {int} */ KEY_LEFT: 37, /** * Constant: KEY_UP * {int} */ KEY_UP: 38, /** * Constant: KEY_RIGHT * {int} */ KEY_RIGHT: 39, /** * Constant: KEY_DOWN * {int} */ KEY_DOWN: 40, /** * Constant: KEY_DELETE * {int} */ KEY_DELETE: 46, /** * Method: element * Cross browser event element detection. * * Parameters: * event - {Event} * * Returns: * {DOMElement} The element that caused the event */ element: function(event) { return event.target || event.srcElement; }, /** * Method: isSingleTouch * Determine whether event was caused by a single touch * * Parameters: * event - {Event} * * Returns: * {Boolean} */ isSingleTouch: function(event) { return event.touches && event.touches.length == 1; }, /** * Method: isMultiTouch * Determine whether event was caused by a multi touch * * Parameters: * event - {Event} * * Returns: * {Boolean} */ isMultiTouch: function(event) { return event.touches && event.touches.length > 1; }, /** * Method: isLeftClick * Determine whether event was caused by a left click. * * Parameters: * event - {Event} * * Returns: * {Boolean} */ isLeftClick: function(event) { return (((event.which) && (event.which == 1)) || ((event.button) && (event.button == 1))); }, /** * Method: isRightClick * Determine whether event was caused by a right mouse click. * * Parameters: * event - {Event} * * Returns: * {Boolean} */ isRightClick: function(event) { return (((event.which) && (event.which == 3)) || ((event.button) && (event.button == 2))); }, /** * Method: stop * Stops an event from propagating. * * Parameters: * event - {Event} * allowDefault - {Boolean} If true, we stop the event chain but * still allow the default browser behaviour (text selection, * radio-button clicking, etc). Default is false. */ stop: function(event, allowDefault) { if (!allowDefault) { OpenLayers.Event.preventDefault(event); } if (event.stopPropagation) { event.stopPropagation(); } else { event.cancelBubble = true; } }, /** * Method: preventDefault * Cancels the event if it is cancelable, without stopping further * propagation of the event. * * Parameters: * event - {Event} */ preventDefault: function(event) { if (event.preventDefault) { event.preventDefault(); } else { event.returnValue = false; } }, /** * Method: findElement * * Parameters: * event - {Event} * tagName - {String} * * Returns: * {DOMElement} The first node with the given tagName, starting from the * node the event was triggered on and traversing the DOM upwards */ findElement: function(event, tagName) { var element = OpenLayers.Event.element(event); while (element.parentNode && (!element.tagName || (element.tagName.toUpperCase() != tagName.toUpperCase()))){ element = element.parentNode; } return element; }, /** * Method: observe * * Parameters: * elementParam - {DOMElement || String} * name - {String} * observer - {function} * useCapture - {Boolean} */ observe: function(elementParam, name, observer, useCapture) { var element = OpenLayers.Util.getElement(elementParam); useCapture = useCapture || false; if (name == 'keypress' && (navigator.appVersion.match(/Konqueror|Safari|KHTML/) || element.attachEvent)) { name = 'keydown'; } //if observers cache has not yet been created, create it if (!this.observers) { this.observers = {}; } //if not already assigned, make a new unique cache ID if (!element._eventCacheID) { var idPrefix = "eventCacheID_"; if (element.id) { idPrefix = element.id + "_" + idPrefix; } element._eventCacheID = OpenLayers.Util.createUniqueID(idPrefix); } var cacheID = element._eventCacheID; //if there is not yet a hash entry for this element, add one if (!this.observers[cacheID]) { this.observers[cacheID] = []; } //add a new observer to this element's list this.observers[cacheID].push({ 'element': element, 'name': name, 'observer': observer, 'useCapture': useCapture }); //add the actual browser event listener if (element.addEventListener) { element.addEventListener(name, observer, useCapture); } else if (element.attachEvent) { element.attachEvent('on' + name, observer); } }, /** * Method: stopObservingElement * Given the id of an element to stop observing, cycle through the * element's cached observers, calling stopObserving on each one, * skipping those entries which can no longer be removed. * * parameters: * elementParam - {DOMElement || String} */ stopObservingElement: function(elementParam) { var element = OpenLayers.Util.getElement(elementParam); var cacheID = element._eventCacheID; this._removeElementObservers(OpenLayers.Event.observers[cacheID]); }, /** * Method: _removeElementObservers * * Parameters: * elementObservers - {Array(Object)} Array of (element, name, * observer, usecapture) objects, * taken directly from hashtable */ _removeElementObservers: function(elementObservers) { if (elementObservers) { for(var i = elementObservers.length-1; i >= 0; i--) { var entry = elementObservers[i]; OpenLayers.Event.stopObserving.apply(this, [ entry.element, entry.name, entry.observer, entry.useCapture ]); } } }, /** * Method: stopObserving * * Parameters: * elementParam - {DOMElement || String} * name - {String} * observer - {function} * useCapture - {Boolean} * * Returns: * {Boolean} Whether or not the event observer was removed */ stopObserving: function(elementParam, name, observer, useCapture) { useCapture = useCapture || false; var element = OpenLayers.Util.getElement(elementParam); var cacheID = element._eventCacheID; if (name == 'keypress') { if ( navigator.appVersion.match(/Konqueror|Safari|KHTML/) || element.detachEvent) { name = 'keydown'; } } // find element's entry in this.observers cache and remove it var foundEntry = false; var elementObservers = OpenLayers.Event.observers[cacheID]; if (elementObservers) { // find the specific event type in the element's list var i=0; while(!foundEntry && i < elementObservers.length) { var cacheEntry = elementObservers[i]; if ((cacheEntry.name == name) && (cacheEntry.observer == observer) && (cacheEntry.useCapture == useCapture)) { elementObservers.splice(i, 1); if (elementObservers.length == 0) { delete OpenLayers.Event.observers[cacheID]; } foundEntry = true; break; } i++; } } //actually remove the event listener from browser if (foundEntry) { if (element.removeEventListener) { element.removeEventListener(name, observer, useCapture); } else if (element && element.detachEvent) { element.detachEvent('on' + name, observer); } } return foundEntry; }, /** * Method: unloadCache * Cycle through all the element entries in the events cache and call * stopObservingElement on each. */ unloadCache: function() { // check for OpenLayers.Event before checking for observers, because // OpenLayers.Event may be undefined in IE if no map instance was // created if (OpenLayers.Event && OpenLayers.Event.observers) { for (var cacheID in OpenLayers.Event.observers) { var elementObservers = OpenLayers.Event.observers[cacheID]; OpenLayers.Event._removeElementObservers.apply(this, [elementObservers]); } OpenLayers.Event.observers = false; } }, CLASS_NAME: "OpenLayers.Event" }; /* prevent memory leaks in IE */ OpenLayers.Event.observe(window, 'unload', OpenLayers.Event.unloadCache, false); /** * Class: OpenLayers.Events */ OpenLayers.Events = OpenLayers.Class({ /** * Constant: BROWSER_EVENTS * {Array(String)} supported events */ BROWSER_EVENTS: [ "mouseover", "mouseout", "mousedown", "mouseup", "mousemove", "click", "dblclick", "rightclick", "dblrightclick", "resize", "focus", "blur", "touchstart", "touchmove", "touchend", "keydown" ], /** * Property: listeners * {Object} Hashtable of Array(Function): events listener functions */ listeners: null, /** * Property: object * {Object} the code object issuing application events */ object: null, /** * Property: element * {DOMElement} the DOM element receiving browser events */ element: null, /** * Property: eventHandler * {Function} bound event handler attached to elements */ eventHandler: null, /** * APIProperty: fallThrough * {Boolean} */ fallThrough: null, /** * APIProperty: includeXY * {Boolean} Should the .xy property automatically be created for browser * mouse events? In general, this should be false. If it is true, then * mouse events will automatically generate a '.xy' property on the * event object that is passed. (Prior to OpenLayers 2.7, this was true * by default.) Otherwise, you can call the getMousePosition on the * relevant events handler on the object available via the 'evt.object' * property of the evt object. So, for most events, you can call: * function named(evt) { * this.xy = this.object.events.getMousePosition(evt) * } * * This option typically defaults to false for performance reasons: * when creating an events object whose primary purpose is to manage * relatively positioned mouse events within a div, it may make * sense to set it to true. * * This option is also used to control whether the events object caches * offsets. If this is false, it will not: the reason for this is that * it is only expected to be called many times if the includeXY property * is set to true. If you set this to true, you are expected to clear * the offset cache manually (using this.clearMouseCache()) if: * the border of the element changes * the location of the element in the page changes */ includeXY: false, /** * APIProperty: extensions * {Object} Event extensions registered with this instance. Keys are * event types, values are {OpenLayers.Events.*} extension instances or * {Boolean} for events that an instantiated extension provides in * addition to the one it was created for. * * Extensions create an event in addition to browser events, which usually * fires when a sequence of browser events is completed. Extensions are * automatically instantiated when a listener is registered for an event * provided by an extension. * * Extensions are created in the
namespace using *
, and named after the event they provide. * The constructor receives the target
instance as * argument. Extensions that need to capture browser events before they * propagate can register their listeners events using
, with * {extension: true} as 4th argument. * * If an extension creates more than one event, an alias for each event * type should be created and reference the same class. The constructor * should set a reference in the target's extensions registry to itself. * * Below is a minimal extension that provides the "foostart" and "fooend" * event types, which replace the native "click" event type if clicked on * an element with the css class "foo": * * (code) * OpenLayers.Events.foostart = OpenLayers.Class({ * initialize: function(target) { * this.target = target; * this.target.register("click", this, this.doStuff, {extension: true}); * // only required if extension provides more than one event type * this.target.extensions["foostart"] = true; * this.target.extensions["fooend"] = true; * }, * destroy: function() { * var target = this.target; * target.unregister("click", this, this.doStuff); * delete this.target; * // only required if extension provides more than one event type * delete target.extensions["foostart"]; * delete target.extensions["fooend"]; * }, * doStuff: function(evt) { * var propagate = true; * if (OpenLayers.Event.element(evt).className === "foo") { * propagate = false; * var target = this.target; * target.triggerEvent("foostart"); * window.setTimeout(function() { * target.triggerEvent("fooend"); * }, 1000); * } * return propagate; * } * }); * // only required if extension provides more than one event type * OpenLayers.Events.fooend = OpenLayers.Events.foostart; * (end) * */ extensions: null, /** * Property: extensionCount * {Object} Keys are event types (like in
), values are the * number of extension listeners for each event type. */ extensionCount: null, /** * Method: clearMouseListener * A version of
that is bound to this instance so that * it can be used with
and *
. */ clearMouseListener: null, /** * Constructor: OpenLayers.Events * Construct an OpenLayers.Events object. * * Parameters: * object - {Object} The js object to which this Events object is being added * element - {DOMElement} A dom element to respond to browser events * eventTypes - {Array(String)} Deprecated. Array of custom application * events. A listener may be registered for any named event, regardless * of the values provided here. * fallThrough - {Boolean} Allow events to fall through after these have * been handled? * options - {Object} Options for the events object. */ initialize: function (object, element, eventTypes, fallThrough, options) { OpenLayers.Util.extend(this, options); this.object = object; this.fallThrough = fallThrough; this.listeners = {}; this.extensions = {}; this.extensionCount = {}; this._msTouches = []; // if a dom element is specified, add a listeners list // for browser events on the element and register them if (element != null) { this.attachToElement(element); } }, /** * APIMethod: destroy */ destroy: function () { for (var e in this.extensions) { if (typeof this.extensions[e] !== "boolean") { this.extensions[e].destroy(); } } this.extensions = null; if (this.element) { OpenLayers.Event.stopObservingElement(this.element); if(this.element.hasScrollEvent) { OpenLayers.Event.stopObserving( window, "scroll", this.clearMouseListener ); } } this.element = null; this.listeners = null; this.object = null; this.fallThrough = null; this.eventHandler = null; }, /** * APIMethod: addEventType * Deprecated. Any event can be triggered without adding it first. * * Parameters: * eventName - {String} */ addEventType: function(eventName) { }, /** * Method: attachToElement * * Parameters: * element - {HTMLDOMElement} a DOM element to attach browser events to */ attachToElement: function (element) { if (this.element) { OpenLayers.Event.stopObservingElement(this.element); } else { // keep a bound copy of handleBrowserEvent() so that we can // pass the same function to both Event.observe() and .stopObserving() this.eventHandler = OpenLayers.Function.bindAsEventListener( this.handleBrowserEvent, this ); // to be used with observe and stopObserving this.clearMouseListener = OpenLayers.Function.bind( this.clearMouseCache, this ); } this.element = element; var msTouch = !!window.navigator.msMaxTouchPoints; var type; for (var i = 0, len = this.BROWSER_EVENTS.length; i < len; i++) { type = this.BROWSER_EVENTS[i]; // register the event cross-browser OpenLayers.Event.observe(element, type, this.eventHandler ); if (msTouch && type.indexOf('touch') === 0) { this.addMsTouchListener(element, type, this.eventHandler); } } // disable dragstart in IE so that mousedown/move/up works normally OpenLayers.Event.observe(element, "dragstart", OpenLayers.Event.stop); }, /** * APIMethod: on * Convenience method for registering listeners with a common scope. * Internally, this method calls
as shown in the examples * below. * * Example use: * (code) * // register a single listener for the "loadstart" event * events.on({"loadstart": loadStartListener}); * * // this is equivalent to the following * events.register("loadstart", undefined, loadStartListener); * * // register multiple listeners to be called with the same `this` object * events.on({ * "loadstart": loadStartListener, * "loadend": loadEndListener, * scope: object * }); * * // this is equivalent to the following * events.register("loadstart", object, loadStartListener); * events.register("loadend", object, loadEndListener); * (end) * * Parameters: * object - {Object} */ on: function(object) { for(var type in object) { if(type != "scope" && object.hasOwnProperty(type)) { this.register(type, object.scope, object[type]); } } }, /** * APIMethod: register * Register an event on the events object. * * When the event is triggered, the 'func' function will be called, in the * context of 'obj'. Imagine we were to register an event, specifying an * OpenLayers.Bounds Object as 'obj'. When the event is triggered, the * context in the callback function will be our Bounds object. This means * that within our callback function, we can access the properties and * methods of the Bounds object through the "this" variable. So our * callback could execute something like: * : leftStr = "Left: " + this.left; * * or * * : centerStr = "Center: " + this.getCenterLonLat(); * * Parameters: * type - {String} Name of the event to register * obj - {Object} The object to bind the context to for the callback#. * If no object is specified, default is the Events's 'object' property. * func - {Function} The callback function. If no callback is * specified, this function does nothing. * priority - {Boolean|Object} If true, adds the new listener to the * *front* of the events queue instead of to the end. * * Valid options for priority: * extension - {Boolean} If true, then the event will be registered as * extension event. Extension events are handled before all other * events. */ register: function (type, obj, func, priority) { if (type in OpenLayers.Events && !this.extensions[type]) { this.extensions[type] = new OpenLayers.Events[type](this); } if (func != null) { if (obj == null) { obj = this.object; } var listeners = this.listeners[type]; if (!listeners) { listeners = []; this.listeners[type] = listeners; this.extensionCount[type] = 0; } var listener = {obj: obj, func: func}; if (priority) { listeners.splice(this.extensionCount[type], 0, listener); if (typeof priority === "object" && priority.extension) { this.extensionCount[type]++; } } else { listeners.push(listener); } } }, /** * APIMethod: registerPriority * Same as register() but adds the new listener to the *front* of the * events queue instead of to the end. * * TODO: get rid of this in 3.0 - Decide whether listeners should be * called in the order they were registered or in reverse order. * * * Parameters: * type - {String} Name of the event to register * obj - {Object} The object to bind the context to for the callback#. * If no object is specified, default is the Events's * 'object' property. * func - {Function} The callback function. If no callback is * specified, this function does nothing. */ registerPriority: function (type, obj, func) { this.register(type, obj, func, true); }, /** * APIMethod: un * Convenience method for unregistering listeners with a common scope. * Internally, this method calls
as shown in the examples * below. * * Example use: * (code) * // unregister a single listener for the "loadstart" event * events.un({"loadstart": loadStartListener}); * * // this is equivalent to the following * events.unregister("loadstart", undefined, loadStartListener); * * // unregister multiple listeners with the same `this` object * events.un({ * "loadstart": loadStartListener, * "loadend": loadEndListener, * scope: object * }); * * // this is equivalent to the following * events.unregister("loadstart", object, loadStartListener); * events.unregister("loadend", object, loadEndListener); * (end) */ un: function(object) { for(var type in object) { if(type != "scope" && object.hasOwnProperty(type)) { this.unregister(type, object.scope, object[type]); } } }, /** * APIMethod: unregister * * Parameters: * type - {String} * obj - {Object} If none specified, defaults to this.object * func - {Function} */ unregister: function (type, obj, func) { if (obj == null) { obj = this.object; } var listeners = this.listeners[type]; if (listeners != null) { for (var i=0, len=listeners.length; i
Math.floor(evt.pageY) || evt.pageX === 0 && Math.floor(x) > Math.floor(evt.pageX)) { // iOS4 include scroll offset in clientX/Y x = x - winPageX; y = y - winPageY; } else if (y < (evt.pageY - winPageY) || x < (evt.pageX - winPageX) ) { // Some Android browsers have totally bogus values for clientX/Y // when scrolling/zooming a page x = evt.pageX - winPageX; y = evt.pageY - winPageY; } evt.olClientX = x; evt.olClientY = y; return { clientX: x, clientY: y }; }, /** * APIMethod: clearMouseCache * Clear cached data about the mouse position. This should be called any * time the element that events are registered on changes position * within the page. */ clearMouseCache: function() { this.element.scrolls = null; this.element.lefttop = null; this.element.offsets = null; }, /** * Method: getMousePosition * * Parameters: * evt - {Event} * * Returns: * {
} The current xy coordinate of the mouse, adjusted * for offsets */ getMousePosition: function (evt) { if (!this.includeXY) { this.clearMouseCache(); } else if (!this.element.hasScrollEvent) { OpenLayers.Event.observe(window, "scroll", this.clearMouseListener); this.element.hasScrollEvent = true; } if (!this.element.scrolls) { var viewportElement = OpenLayers.Util.getViewportElement(); this.element.scrolls = [ window.pageXOffset || viewportElement.scrollLeft, window.pageYOffset || viewportElement.scrollTop ]; } if (!this.element.lefttop) { this.element.lefttop = [ (document.documentElement.clientLeft || 0), (document.documentElement.clientTop || 0) ]; } if (!this.element.offsets) { this.element.offsets = OpenLayers.Util.pagePosition(this.element); } return new OpenLayers.Pixel( (evt.clientX + this.element.scrolls[0]) - this.element.offsets[0] - this.element.lefttop[0], (evt.clientY + this.element.scrolls[1]) - this.element.offsets[1] - this.element.lefttop[1] ); }, /** * Method: addMsTouchListener * * Parameters: * element - {DOMElement} The DOM element to register the listener on * type - {String} The event type * handler - {Function} the handler */ addMsTouchListener: function (element, type, handler) { var eventHandler = this.eventHandler; var touches = this._msTouches; function msHandler(evt) { handler(OpenLayers.Util.applyDefaults({ stopPropagation: function() { for (var i=touches.length-1; i>=0; --i) { touches[i].stopPropagation(); } }, preventDefault: function() { for (var i=touches.length-1; i>=0; --i) { touches[i].preventDefault(); } }, type: type }, evt)); } switch (type) { case 'touchstart': return this.addMsTouchListenerStart(element, type, msHandler); case 'touchend': return this.addMsTouchListenerEnd(element, type, msHandler); case 'touchmove': return this.addMsTouchListenerMove(element, type, msHandler); default: throw 'Unknown touch event type'; } }, /** * Method: addMsTouchListenerStart * * Parameters: * element - {DOMElement} The DOM element to register the listener on * type - {String} The event type * handler - {Function} the handler */ addMsTouchListenerStart: function(element, type, handler) { var touches = this._msTouches; var cb = function(e) { var alreadyInArray = false; for (var i=0, ii=touches.length; i
constructor. This is a base class, * typical geometry types are described by subclasses of this class. * * Note that if you use the
method, you must * explicitly include the OpenLayers.Format.WKT in your build. */ OpenLayers.Geometry = OpenLayers.Class({ /** * Property: id * {String} A unique identifier for this geometry. */ id: null, /** * Property: parent * {
}This is set when a Geometry is added as component * of another geometry */ parent: null, /** * Property: bounds * {
} The bounds of this geometry */ bounds: null, /** * Constructor: OpenLayers.Geometry * Creates a geometry object. */ initialize: function() { this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME+ "_"); }, /** * Method: destroy * Destroy this geometry. */ destroy: function() { this.id = null; this.bounds = null; }, /** * APIMethod: clone * Create a clone of this geometry. Does not set any non-standard * properties of the cloned geometry. * * Returns: * {
} An exact clone of this geometry. */ clone: function() { return new OpenLayers.Geometry(); }, /** * Method: setBounds * Set the bounds for this Geometry. * * Parameters: * bounds - {
} */ setBounds: function(bounds) { if (bounds) { this.bounds = bounds.clone(); } }, /** * Method: clearBounds * Nullify this components bounds and that of its parent as well. */ clearBounds: function() { this.bounds = null; if (this.parent) { this.parent.clearBounds(); } }, /** * Method: extendBounds * Extend the existing bounds to include the new bounds. * If geometry's bounds is not yet set, then set a new Bounds. * * Parameters: * newBounds - {
} */ extendBounds: function(newBounds){ var bounds = this.getBounds(); if (!bounds) { this.setBounds(newBounds); } else { this.bounds.extend(newBounds); } }, /** * APIMethod: getBounds * Get the bounds for this Geometry. If bounds is not set, it * is calculated again, this makes queries faster. * * Returns: * {
} */ getBounds: function() { if (this.bounds == null) { this.calculateBounds(); } return this.bounds; }, /** * APIMethod: calculateBounds * Recalculate the bounds for the geometry. */ calculateBounds: function() { // // This should be overridden by subclasses. // }, /** * APIMethod: distanceTo * Calculate the closest distance between two geometries (on the x-y plane). * * Parameters: * geometry - {
} The target geometry. * options - {Object} Optional properties for configuring the distance * calculation. * * Valid options depend on the specific geometry type. * * Returns: * {Number | Object} The distance between this geometry and the target. * If details is true, the return will be an object with distance, * x0, y0, x1, and x2 properties. The x0 and y0 properties represent * the coordinates of the closest point on this geometry. The x1 and y1 * properties represent the coordinates of the closest point on the * target geometry. */ distanceTo: function(geometry, options) { }, /** * APIMethod: getVertices * Return a list of all points in this geometry. * * Parameters: * nodes - {Boolean} For lines, only return vertices that are * endpoints. If false, for lines, only vertices that are not * endpoints will be returned. If not provided, all vertices will * be returned. * * Returns: * {Array} A list of all vertices in the geometry. */ getVertices: function(nodes) { }, /** * Method: atPoint * Note - This is only an approximation based on the bounds of the * geometry. * * Parameters: * lonlat - {
|Object} OpenLayers.LonLat or an * object with a 'lon' and 'lat' properties. * toleranceLon - {float} Optional tolerance in Geometric Coords * toleranceLat - {float} Optional tolerance in Geographic Coords * * Returns: * {Boolean} Whether or not the geometry is at the specified location */ atPoint: function(lonlat, toleranceLon, toleranceLat) { var atPoint = false; var bounds = this.getBounds(); if ((bounds != null) && (lonlat != null)) { var dX = (toleranceLon != null) ? toleranceLon : 0; var dY = (toleranceLat != null) ? toleranceLat : 0; var toleranceBounds = new OpenLayers.Bounds(this.bounds.left - dX, this.bounds.bottom - dY, this.bounds.right + dX, this.bounds.top + dY); atPoint = toleranceBounds.containsLonLat(lonlat); } return atPoint; }, /** * Method: getLength * Calculate the length of this geometry. This method is defined in * subclasses. * * Returns: * {Float} The length of the collection by summing its parts */ getLength: function() { //to be overridden by geometries that actually have a length // return 0.0; }, /** * Method: getArea * Calculate the area of this geometry. This method is defined in subclasses. * * Returns: * {Float} The area of the collection by summing its parts */ getArea: function() { //to be overridden by geometries that actually have an area // return 0.0; }, /** * APIMethod: getCentroid * Calculate the centroid of this geometry. This method is defined in subclasses. * * Returns: * {
} The centroid of the collection */ getCentroid: function() { return null; }, /** * Method: toString * Returns a text representation of the geometry. If the WKT format is * included in a build, this will be the Well-Known Text * representation. * * Returns: * {String} String representation of this geometry. */ toString: function() { var string; if (OpenLayers.Format && OpenLayers.Format.WKT) { string = OpenLayers.Format.WKT.prototype.write( new OpenLayers.Feature.Vector(this) ); } else { string = Object.prototype.toString.call(this); } return string; }, CLASS_NAME: "OpenLayers.Geometry" }); /** * Function: OpenLayers.Geometry.fromWKT * Generate a geometry given a Well-Known Text string. For this method to * work, you must include the OpenLayers.Format.WKT in your build * explicitly. * * Parameters: * wkt - {String} A string representing the geometry in Well-Known Text. * * Returns: * {
} A geometry of the appropriate class. */ OpenLayers.Geometry.fromWKT = function(wkt) { var geom; if (OpenLayers.Format && OpenLayers.Format.WKT) { var format = OpenLayers.Geometry.fromWKT.format; if (!format) { format = new OpenLayers.Format.WKT(); OpenLayers.Geometry.fromWKT.format = format; } var result = format.read(wkt); if (result instanceof OpenLayers.Feature.Vector) { geom = result.geometry; } else if (OpenLayers.Util.isArray(result)) { var len = result.length; var components = new Array(len); for (var i=0; i
= seg2.x1 || seg2.x2 >= seg1.x1. In those * obvious cases where there is no intersection, the function should * not be called. * * Parameters: * seg1 - {Object} Object representing a segment with properties x1, y1, x2, * and y2. The start point is represented by x1 and y1. The end point * is represented by x2 and y2. Start and end are ordered so that x1 < x2. * seg2 - {Object} Object representing a segment with properties x1, y1, x2, * and y2. The start point is represented by x1 and y1. The end point * is represented by x2 and y2. Start and end are ordered so that x1 < x2. * options - {Object} Optional properties for calculating the intersection. * * Valid options: * point - {Boolean} Return the intersection point. If false, the actual * intersection point will not be calculated. If true and the segments * intersect, the intersection point will be returned. If true and * the segments do not intersect, false will be returned. If true and * the segments are coincident, true will be returned. * tolerance - {Number} If a non-null value is provided, if the segments are * within the tolerance distance, this will be considered an intersection. * In addition, if the point option is true and the calculated intersection * is within the tolerance distance of an end point, the endpoint will be * returned instead of the calculated intersection. Further, if the * intersection is within the tolerance of endpoints on both segments, or * if two segment endpoints are within the tolerance distance of eachother * (but no intersection is otherwise calculated), an endpoint on the * first segment provided will be returned. * * Returns: * {Boolean |
} The two segments intersect. * If the point argument is true, the return will be the intersection * point or false if none exists. If point is true and the segments * are coincident, return will be true (and the instersection is equal * to the shorter segment). */ OpenLayers.Geometry.segmentsIntersect = function(seg1, seg2, options) { var point = options && options.point; var tolerance = options && options.tolerance; var intersection = false; var x11_21 = seg1.x1 - seg2.x1; var y11_21 = seg1.y1 - seg2.y1; var x12_11 = seg1.x2 - seg1.x1; var y12_11 = seg1.y2 - seg1.y1; var y22_21 = seg2.y2 - seg2.y1; var x22_21 = seg2.x2 - seg2.x1; var d = (y22_21 * x12_11) - (x22_21 * y12_11); var n1 = (x22_21 * y11_21) - (y22_21 * x11_21); var n2 = (x12_11 * y11_21) - (y12_11 * x11_21); if(d == 0) { // parallel if(n1 == 0 && n2 == 0) { // coincident intersection = true; } } else { var along1 = n1 / d; var along2 = n2 / d; if(along1 >= 0 && along1 <= 1 && along2 >=0 && along2 <= 1) { // intersect if(!point) { intersection = true; } else { // calculate the intersection point var x = seg1.x1 + (along1 * x12_11); var y = seg1.y1 + (along1 * y12_11); intersection = new OpenLayers.Geometry.Point(x, y); } } } if(tolerance) { var dist; if(intersection) { if(point) { var segs = [seg1, seg2]; var seg, x, y; // check segment endpoints for proximity to intersection // set intersection to first endpoint within the tolerance outer: for(var i=0; i<2; ++i) { seg = segs[i]; for(var j=1; j<3; ++j) { x = seg["x" + j]; y = seg["y" + j]; dist = Math.sqrt( Math.pow(x - intersection.x, 2) + Math.pow(y - intersection.y, 2) ); if(dist < tolerance) { intersection.x = x; intersection.y = y; break outer; } } } } } else { // no calculated intersection, but segments could be within // the tolerance of one another var segs = [seg1, seg2]; var source, target, x, y, p, result; // check segment endpoints for proximity to intersection // set intersection to first endpoint within the tolerance outer: for(var i=0; i<2; ++i) { source = segs[i]; target = segs[(i+1)%2]; for(var j=1; j<3; ++j) { p = {x: source["x"+j], y: source["y"+j]}; result = OpenLayers.Geometry.distanceToSegment(p, target); if(result.distance < tolerance) { if(point) { intersection = new OpenLayers.Geometry.Point(p.x, p.y); } else { intersection = true; } break outer; } } } } } return intersection; }; /** * Function: OpenLayers.Geometry.distanceToSegment * * Parameters: * point - {Object} An object with x and y properties representing the * point coordinates. * segment - {Object} An object with x1, y1, x2, and y2 properties * representing endpoint coordinates. * * Returns: * {Object} An object with distance, along, x, and y properties. The distance * will be the shortest distance between the input point and segment. * The x and y properties represent the coordinates along the segment * where the shortest distance meets the segment. The along attribute * describes how far between the two segment points the given point is. */ OpenLayers.Geometry.distanceToSegment = function(point, segment) { var result = OpenLayers.Geometry.distanceSquaredToSegment(point, segment); result.distance = Math.sqrt(result.distance); return result; }; /** * Function: OpenLayers.Geometry.distanceSquaredToSegment * * Usually the distanceToSegment function should be used. This variant however * can be used for comparisons where the exact distance is not important. * * Parameters: * point - {Object} An object with x and y properties representing the * point coordinates. * segment - {Object} An object with x1, y1, x2, and y2 properties * representing endpoint coordinates. * * Returns: * {Object} An object with squared distance, along, x, and y properties. * The distance will be the shortest distance between the input point and * segment. The x and y properties represent the coordinates along the * segment where the shortest distance meets the segment. The along * attribute describes how far between the two segment points the given * point is. */ OpenLayers.Geometry.distanceSquaredToSegment = function(point, segment) { var x0 = point.x; var y0 = point.y; var x1 = segment.x1; var y1 = segment.y1; var x2 = segment.x2; var y2 = segment.y2; var dx = x2 - x1; var dy = y2 - y1; var along = ((dx * (x0 - x1)) + (dy * (y0 - y1))) / (Math.pow(dx, 2) + Math.pow(dy, 2)); var x, y; if(along <= 0.0) { x = x1; y = y1; } else if(along >= 1.0) { x = x2; y = y2; } else { x = x1 + along * dx; y = y1 + along * dy; } return { distance: Math.pow(x - x0, 2) + Math.pow(y - y0, 2), x: x, y: y, along: along }; }; /* ====================================================================== OpenLayers/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. */ /** * @requires OpenLayers/BaseTypes/Class.js * @requires OpenLayers/Util.js */ /** * Class: OpenLayers.Format * Base class for format reading/writing a variety of formats. Subclasses * of OpenLayers.Format are expected to have read and write methods. */ OpenLayers.Format = OpenLayers.Class({ /** * Property: options * {Object} A reference to options passed to the constructor. */ options: null, /** * APIProperty: externalProjection * {
} When passed a externalProjection and * internalProjection, the format will reproject the geometries it * reads or writes. The externalProjection is the projection used by * the content which is passed into read or which comes out of write. * In order to reproject, a projection transformation function for the * specified projections must be available. This support may be * provided via proj4js or via a custom transformation function. See * {
} for more information on * custom transformations. */ externalProjection: null, /** * APIProperty: internalProjection * {
} When passed a externalProjection and * internalProjection, the format will reproject the geometries it * reads or writes. The internalProjection is the projection used by * the geometries which are returned by read or which are passed into * write. In order to reproject, a projection transformation function * for the specified projections must be available. This support may be * provided via proj4js or via a custom transformation function. See * {
} for more information on * custom transformations. */ internalProjection: null, /** * APIProperty: data * {Object} When
is true, this is the parsed string sent to *
. */ data: null, /** * APIProperty: keepData * {Object} Maintain a reference (
) to the most recently read data. * Default is false. */ keepData: false, /** * Constructor: OpenLayers.Format * Instances of this class are not useful. See one of the subclasses. * * Parameters: * options - {Object} An optional object with properties to set on the * format * * Valid options: * keepData - {Boolean} If true, upon
, the data property will be * set to the parsed object (e.g. the json or xml object). * * Returns: * An instance of OpenLayers.Format */ initialize: function(options) { OpenLayers.Util.extend(this, options); this.options = options; }, /** * APIMethod: destroy * Clean up. */ destroy: function() { }, /** * Method: read * Read data from a string, and return an object whose type depends on the * subclass. * * Parameters: * data - {string} Data to read/parse. * * Returns: * Depends on the subclass */ read: function(data) { throw new Error('Read not implemented.'); }, /** * Method: write * Accept an object, and return a string. * * Parameters: * object - {Object} Object to be serialized * * Returns: * {String} A string representation of the object. */ write: function(object) { throw new Error('Write not implemented.'); }, CLASS_NAME: "OpenLayers.Format" }); /* ====================================================================== OpenLayers/Geometry/Point.js ====================================================================== */ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** * @requires OpenLayers/Geometry.js */ /** * Class: OpenLayers.Geometry.Point * Point geometry class. * * Inherits from: * -
*/ OpenLayers.Geometry.Point = OpenLayers.Class(OpenLayers.Geometry, { /** * APIProperty: x * {float} */ x: null, /** * APIProperty: y * {float} */ y: null, /** * Constructor: OpenLayers.Geometry.Point * Construct a point geometry. * * Parameters: * x - {float} * y - {float} * */ initialize: function(x, y) { OpenLayers.Geometry.prototype.initialize.apply(this, arguments); this.x = parseFloat(x); this.y = parseFloat(y); }, /** * APIMethod: clone * * Returns: * {
} An exact clone of this OpenLayers.Geometry.Point */ clone: function(obj) { if (obj == null) { obj = new OpenLayers.Geometry.Point(this.x, this.y); } // catch any randomly tagged-on properties OpenLayers.Util.applyDefaults(obj, this); return obj; }, /** * Method: calculateBounds * Create a new Bounds based on the lon/lat */ calculateBounds: function () { this.bounds = new OpenLayers.Bounds(this.x, this.y, this.x, this.y); }, /** * APIMethod: distanceTo * Calculate the closest distance between two geometries (on the x-y plane). * * Parameters: * geometry - {
} The target geometry. * options - {Object} Optional properties for configuring the distance * calculation. * * Valid options: * details - {Boolean} Return details from the distance calculation. * Default is false. * edge - {Boolean} Calculate the distance from this geometry to the * nearest edge of the target geometry. Default is true. If true, * calling distanceTo from a geometry that is wholly contained within * the target will result in a non-zero distance. If false, whenever * geometries intersect, calling distanceTo will return 0. If false, * details cannot be returned. * * Returns: * {Number | Object} The distance between this geometry and the target. * If details is true, the return will be an object with distance, * x0, y0, x1, and x2 properties. The x0 and y0 properties represent * the coordinates of the closest point on this geometry. The x1 and y1 * properties represent the coordinates of the closest point on the * target geometry. */ distanceTo: function(geometry, options) { var edge = !(options && options.edge === false); var details = edge && options && options.details; var distance, x0, y0, x1, y1, result; if(geometry instanceof OpenLayers.Geometry.Point) { x0 = this.x; y0 = this.y; x1 = geometry.x; y1 = geometry.y; distance = Math.sqrt(Math.pow(x0 - x1, 2) + Math.pow(y0 - y1, 2)); result = !details ? distance : {x0: x0, y0: y0, x1: x1, y1: y1, distance: distance}; } else { result = geometry.distanceTo(this, options); if(details) { // switch coord order since this geom is target result = { x0: result.x1, y0: result.y1, x1: result.x0, y1: result.y0, distance: result.distance }; } } return result; }, /** * APIMethod: equals * Determine whether another geometry is equivalent to this one. Geometries * are considered equivalent if all components have the same coordinates. * * Parameters: * geom - {
} The geometry to test. * * Returns: * {Boolean} The supplied geometry is equivalent to this geometry. */ equals: function(geom) { var equals = false; if (geom != null) { equals = ((this.x == geom.x && this.y == geom.y) || (isNaN(this.x) && isNaN(this.y) && isNaN(geom.x) && isNaN(geom.y))); } return equals; }, /** * Method: toShortString * * Returns: * {String} Shortened String representation of Point object. * (ex.
"5, 42"
) */ toShortString: function() { return (this.x + ", " + this.y); }, /** * APIMethod: move * Moves a geometry by the given displacement along positive x and y axes. * This modifies the position of the geometry and clears the cached * bounds. * * Parameters: * x - {Float} Distance to move geometry in positive x direction. * y - {Float} Distance to move geometry in positive y direction. */ move: function(x, y) { this.x = this.x + x; this.y = this.y + y; this.clearBounds(); }, /** * APIMethod: rotate * Rotate a point around another. * * Parameters: * angle - {Float} Rotation angle in degrees (measured counterclockwise * from the positive x-axis) * origin - {
} Center point for the rotation */ rotate: function(angle, origin) { angle *= Math.PI / 180; var radius = this.distanceTo(origin); var theta = angle + Math.atan2(this.y - origin.y, this.x - origin.x); this.x = origin.x + (radius * Math.cos(theta)); this.y = origin.y + (radius * Math.sin(theta)); this.clearBounds(); }, /** * APIMethod: getCentroid * * Returns: * {
} The centroid of the collection */ getCentroid: function() { return new OpenLayers.Geometry.Point(this.x, this.y); }, /** * APIMethod: resize * Resize a point relative to some origin. For points, this has the effect * of scaling a vector (from the origin to the point). This method is * more useful on geometry collection subclasses. * * Parameters: * scale - {Float} Ratio of the new distance from the origin to the old * distance from the origin. A scale of 2 doubles the * distance between the point and origin. * origin - {
} Point of origin for resizing * ratio - {Float} Optional x:y ratio for resizing. Default ratio is 1. * * Returns: * {
} - The current geometry. */ resize: function(scale, origin, ratio) { ratio = (ratio == undefined) ? 1 : ratio; this.x = origin.x + (scale * ratio * (this.x - origin.x)); this.y = origin.y + (scale * (this.y - origin.y)); this.clearBounds(); return this; }, /** * APIMethod: intersects * Determine if the input geometry intersects this one. * * Parameters: * geometry - {
} Any type of geometry. * * Returns: * {Boolean} The input geometry intersects this one. */ intersects: function(geometry) { var intersect = false; if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { intersect = this.equals(geometry); } else { intersect = geometry.intersects(this); } return intersect; }, /** * APIMethod: transform * Translate the x,y properties of the point from source to dest. * * Parameters: * source - {
} * dest - {
} * * Returns: * {
} */ transform: function(source, dest) { if ((source && dest)) { OpenLayers.Projection.transform( this, source, dest); this.bounds = null; } return this; }, /** * APIMethod: getVertices * Return a list of all points in this geometry. * * Parameters: * nodes - {Boolean} For lines, only return vertices that are * endpoints. If false, for lines, only vertices that are not * endpoints will be returned. If not provided, all vertices will * be returned. * * Returns: * {Array} A list of all vertices in the geometry. */ getVertices: function(nodes) { return [this]; }, CLASS_NAME: "OpenLayers.Geometry.Point" }); /* ====================================================================== OpenLayers/Geometry/Collection.js ====================================================================== */ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** * @requires OpenLayers/Geometry.js */ /** * Class: OpenLayers.Geometry.Collection * A Collection is exactly what it sounds like: A collection of different * Geometries. These are stored in the local parameter
(which * can be passed as a parameter to the constructor). * * As new geometries are added to the collection, they are NOT cloned. * When removing geometries, they need to be specified by reference (ie you * have to pass in the *exact* geometry to be removed). * * The
and
functions here merely iterate through * the components, summing their respective areas and lengths. * * Create a new instance with the
constructor. * * Inherits from: * -
*/ OpenLayers.Geometry.Collection = OpenLayers.Class(OpenLayers.Geometry, { /** * APIProperty: components * {Array(
)} The component parts of this geometry */ components: null, /** * Property: componentTypes * {Array(String)} An array of class names representing the types of * components that the collection can include. A null value means the * component types are not restricted. */ componentTypes: null, /** * Constructor: OpenLayers.Geometry.Collection * Creates a Geometry Collection -- a list of geoms. * * Parameters: * components - {Array(
)} Optional array of geometries * */ initialize: function (components) { OpenLayers.Geometry.prototype.initialize.apply(this, arguments); this.components = []; if (components != null) { this.addComponents(components); } }, /** * APIMethod: destroy * Destroy this geometry. */ destroy: function () { this.components.length = 0; this.components = null; OpenLayers.Geometry.prototype.destroy.apply(this, arguments); }, /** * APIMethod: clone * Clone this geometry. * * Returns: * {
} An exact clone of this collection */ clone: function() { var geometry = eval("new " + this.CLASS_NAME + "()"); for(var i=0, len=this.components.length; i
)} An array of geometries to add */ addComponents: function(components){ if(!(OpenLayers.Util.isArray(components))) { components = [components]; } for(var i=0, len=components.length; i
} A geometry to add * index - {int} Optional index into the array to insert the component * * Returns: * {Boolean} The component geometry was successfully added */ addComponent: function(component, index) { var added = false; if(component) { if(this.componentTypes == null || (OpenLayers.Util.indexOf(this.componentTypes, component.CLASS_NAME) > -1)) { if(index != null && (index < this.components.length)) { var components1 = this.components.slice(0, index); var components2 = this.components.slice(index, this.components.length); components1.push(component); this.components = components1.concat(components2); } else { this.components.push(component); } component.parent = this; this.clearBounds(); added = true; } } return added; }, /** * APIMethod: removeComponents * Remove components from this geometry. * * Parameters: * components - {Array(
)} The components to be removed * * Returns: * {Boolean} A component was removed. */ removeComponents: function(components) { var removed = false; if(!(OpenLayers.Util.isArray(components))) { components = [components]; } for(var i=components.length-1; i>=0; --i) { removed = this.removeComponent(components[i]) || removed; } return removed; }, /** * Method: removeComponent * Remove a component from this geometry. * * Parameters: * component - {
} * * Returns: * {Boolean} The component was removed. */ removeComponent: function(component) { OpenLayers.Util.removeItem(this.components, component); // clearBounds() so that it gets recalculated on the next call // to this.getBounds(); this.clearBounds(); return true; }, /** * APIMethod: getLength * Calculate the length of this geometry * * Returns: * {Float} The length of the geometry */ getLength: function() { var length = 0.0; for (var i=0, len=this.components.length; i
. * * Returns: * {Float} The area of the collection by summing its parts */ getArea: function() { var area = 0.0; for (var i=0, len=this.components.length; i
} The spatial reference system * for the geometry coordinates. If not provided, Geographic/WGS84 is * assumed. * * Reference: * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409 * * Returns: * {float} The approximate geodesic area of the geometry in square meters. */ getGeodesicArea: function(projection) { var area = 0.0; for(var i=0, len=this.components.length; i
} The centroid of the collection */ getCentroid: function(weighted) { if (!weighted) { return this.components.length && this.components[0].getCentroid(); } var len = this.components.length; if (!len) { return false; } var areas = []; var centroids = []; var areaSum = 0; var minArea = Number.MAX_VALUE; var component; for (var i=0; i
0) ? area : minArea; centroids.push(centroid); } len = areas.length; if (areaSum === 0) { // all the components in this collection have 0 area // probably a collection of points -- weight all the points the same for (var i=0; i
} The spatial reference system * for the geometry coordinates. If not provided, Geographic/WGS84 is * assumed. * * Returns: * {Float} The appoximate geodesic length of the geometry in meters. */ getGeodesicLength: function(projection) { var length = 0.0; for(var i=0, len=this.components.length; i
} Center point for the rotation */ rotate: function(angle, origin) { for(var i=0, len=this.components.length; i
} Point of origin for resizing * ratio - {Float} Optional x:y ratio for resizing. Default ratio is 1. * * Returns: * {
} - The current geometry. */ resize: function(scale, origin, ratio) { for(var i=0; i
} The target geometry. * options - {Object} Optional properties for configuring the distance * calculation. * * Valid options: * details - {Boolean} Return details from the distance calculation. * Default is false. * edge - {Boolean} Calculate the distance from this geometry to the * nearest edge of the target geometry. Default is true. If true, * calling distanceTo from a geometry that is wholly contained within * the target will result in a non-zero distance. If false, whenever * geometries intersect, calling distanceTo will return 0. If false, * details cannot be returned. * * Returns: * {Number | Object} The distance between this geometry and the target. * If details is true, the return will be an object with distance, * x0, y0, x1, and y1 properties. The x0 and y0 properties represent * the coordinates of the closest point on this geometry. The x1 and y1 * properties represent the coordinates of the closest point on the * target geometry. */ distanceTo: function(geometry, options) { var edge = !(options && options.edge === false); var details = edge && options && options.details; var result, best, distance; var min = Number.POSITIVE_INFINITY; for(var i=0, len=this.components.length; i
} The geometry to test. * * Returns: * {Boolean} The supplied geometry is equivalent to this geometry. */ equals: function(geometry) { var equivalent = true; if(!geometry || !geometry.CLASS_NAME || (this.CLASS_NAME != geometry.CLASS_NAME)) { equivalent = false; } else if(!(OpenLayers.Util.isArray(geometry.components)) || (geometry.components.length != this.components.length)) { equivalent = false; } else { for(var i=0, len=this.components.length; i
} * dest - {
} * * Returns: * {
} */ transform: function(source, dest) { if (source && dest) { for (var i=0, len=this.components.length; i
} Any type of geometry. * * Returns: * {Boolean} The input geometry intersects this one. */ intersects: function(geometry) { var intersect = false; for(var i=0, len=this.components.length; i
constructor. * * Inherits from: * -
* -
*/ OpenLayers.Geometry.MultiPoint = OpenLayers.Class( OpenLayers.Geometry.Collection, { /** * Property: componentTypes * {Array(String)} An array of class names representing the types of * components that the collection can include. A null value means the * component types are not restricted. */ componentTypes: ["OpenLayers.Geometry.Point"], /** * Constructor: OpenLayers.Geometry.MultiPoint * Create a new MultiPoint Geometry * * Parameters: * components - {Array(
)} * * Returns: * {
} */ /** * APIMethod: addPoint * Wrapper for
* * Parameters: * point - {
} Point to be added * index - {Integer} Optional index */ addPoint: function(point, index) { this.addComponent(point, index); }, /** * APIMethod: removePoint * Wrapper for
* * Parameters: * point - {
} Point to be removed */ removePoint: function(point){ this.removeComponent(point); }, CLASS_NAME: "OpenLayers.Geometry.MultiPoint" }); /* ====================================================================== OpenLayers/Geometry/Curve.js ====================================================================== */ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** * @requires OpenLayers/Geometry/MultiPoint.js */ /** * Class: OpenLayers.Geometry.Curve * A Curve is a MultiPoint, whose points are assumed to be connected. To * this end, we provide a "getLength()" function, which iterates through * the points, summing the distances between them. * * Inherits: * -
*/ OpenLayers.Geometry.Curve = OpenLayers.Class(OpenLayers.Geometry.MultiPoint, { /** * Property: componentTypes * {Array(String)} An array of class names representing the types of * components that the collection can include. A null * value means the component types are not restricted. */ componentTypes: ["OpenLayers.Geometry.Point"], /** * Constructor: OpenLayers.Geometry.Curve * * Parameters: * point - {Array(
)} */ /** * APIMethod: getLength * * Returns: * {Float} The length of the curve */ getLength: function() { var length = 0.0; if ( this.components && (this.components.length > 1)) { for(var i=1, len=this.components.length; i
} The spatial reference system * for the geometry coordinates. If not provided, Geographic/WGS84 is * assumed. * * Returns: * {Float} The appoximate geodesic length of the geometry in meters. */ getGeodesicLength: function(projection) { var geom = this; // so we can work with a clone if needed if(projection) { var gg = new OpenLayers.Projection("EPSG:4326"); if(!gg.equals(projection)) { geom = this.clone().transform(projection, gg); } } var length = 0.0; if(geom.components && (geom.components.length > 1)) { var p1, p2; for(var i=1, len=geom.components.length; i
*/ OpenLayers.Geometry.LineString = OpenLayers.Class(OpenLayers.Geometry.Curve, { /** * Constructor: OpenLayers.Geometry.LineString * Create a new LineString geometry * * Parameters: * points - {Array(
)} An array of points used to * generate the linestring * */ /** * APIMethod: removeComponent * Only allows removal of a point if there are three or more points in * the linestring. (otherwise the result would be just a single point) * * Parameters: * point - {
} The point to be removed * * Returns: * {Boolean} The component was removed. */ removeComponent: function(point) { var removed = this.components && (this.components.length > 2); if (removed) { OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, arguments); } return removed; }, /** * APIMethod: intersects * Test for instersection between two geometries. This is a cheapo * implementation of the Bently-Ottmann algorigithm. It doesn't * really keep track of a sweep line data structure. It is closer * to the brute force method, except that segments are sorted and * potential intersections are only calculated when bounding boxes * intersect. * * Parameters: * geometry - {
} * * Returns: * {Boolean} The input geometry intersects this geometry. */ intersects: function(geometry) { var intersect = false; var type = geometry.CLASS_NAME; if(type == "OpenLayers.Geometry.LineString" || type == "OpenLayers.Geometry.LinearRing" || type == "OpenLayers.Geometry.Point") { var segs1 = this.getSortedSegments(); var segs2; if(type == "OpenLayers.Geometry.Point") { segs2 = [{ x1: geometry.x, y1: geometry.y, x2: geometry.x, y2: geometry.y }]; } else { segs2 = geometry.getSortedSegments(); } var seg1, seg1x1, seg1x2, seg1y1, seg1y2, seg2, seg2y1, seg2y2; // sweep right outer: for(var i=0, len=segs1.length; i
seg1x2) { // seg1 still left of seg2 break; } if(seg2.x2 < seg1x1) { // seg2 still left of seg1 continue; } seg2y1 = seg2.y1; seg2y2 = seg2.y2; if(Math.min(seg2y1, seg2y2) > Math.max(seg1y1, seg1y2)) { // seg2 above seg1 continue; } if(Math.max(seg2y1, seg2y2) < Math.min(seg1y1, seg1y2)) { // seg2 below seg1 continue; } if(OpenLayers.Geometry.segmentsIntersect(seg1, seg2)) { intersect = true; break outer; } } } } else { intersect = geometry.intersects(this); } return intersect; }, /** * Method: getSortedSegments * * Returns: * {Array} An array of segment objects. Segment objects have properties * x1, y1, x2, and y2. The start point is represented by x1 and y1. * The end point is represented by x2 and y2. Start and end are * ordered so that x1 < x2. */ getSortedSegments: function() { var numSeg = this.components.length - 1; var segments = new Array(numSeg), point1, point2; for(var i=0; i
0) { // sort intersections along segment var xDir = seg.x1 < seg.x2 ? 1 : -1; var yDir = seg.y1 < seg.y2 ? 1 : -1; result = { lines: lines, points: intersections.sort(function(p1, p2) { return (xDir * p1.x - xDir * p2.x) || (yDir * p1.y - yDir * p2.y); }) }; } return result; }, /** * Method: split * Use this geometry (the source) to attempt to split a target geometry. * * Parameters: * target - {
} The target geometry. * options - {Object} Properties of this object will be used to determine * how the split is conducted. * * Valid options: * mutual - {Boolean} Split the source geometry in addition to the target * geometry. Default is false. * edge - {Boolean} Allow splitting when only edges intersect. Default is * true. If false, a vertex on the source must be within the tolerance * distance of the intersection to be considered a split. * tolerance - {Number} If a non-null value is provided, intersections * within the tolerance distance of an existing vertex on the source * will be assumed to occur at the vertex. * * Returns: * {Array} A list of geometries (of this same type as the target) that * result from splitting the target with the source geometry. The * source and target geometry will remain unmodified. If no split * results, null will be returned. If mutual is true and a split * results, return will be an array of two arrays - the first will be * all geometries that result from splitting the source geometry and * the second will be all geometries that result from splitting the * target geometry. */ split: function(target, options) { var results = null; var mutual = options && options.mutual; var sourceSplit, targetSplit, sourceParts, targetParts; if(target instanceof OpenLayers.Geometry.LineString) { var verts = this.getVertices(); var vert1, vert2, seg, splits, lines, point; var points = []; sourceParts = []; for(var i=0, stop=verts.length-2; i<=stop; ++i) { vert1 = verts[i]; vert2 = verts[i+1]; seg = { x1: vert1.x, y1: vert1.y, x2: vert2.x, y2: vert2.y }; targetParts = targetParts || [target]; if(mutual) { points.push(vert1.clone()); } for(var j=0; j
0) { lines.unshift(j, 1); Array.prototype.splice.apply(targetParts, lines); j += lines.length - 2; } if(mutual) { for(var k=0, len=splits.points.length; k
0 && points.length > 0) { points.push(vert2.clone()); sourceParts.push(new OpenLayers.Geometry.LineString(points)); } } else { results = target.splitWith(this, options); } if(targetParts && targetParts.length > 1) { targetSplit = true; } else { targetParts = []; } if(sourceParts && sourceParts.length > 1) { sourceSplit = true; } else { sourceParts = []; } if(targetSplit || sourceSplit) { if(mutual) { results = [sourceParts, targetParts]; } else { results = targetParts; } } return results; }, /** * Method: splitWith * Split this geometry (the target) with the given geometry (the source). * * Parameters: * geometry - {
} A geometry used to split this * geometry (the source). * options - {Object} Properties of this object will be used to determine * how the split is conducted. * * Valid options: * mutual - {Boolean} Split the source geometry in addition to the target * geometry. Default is false. * edge - {Boolean} Allow splitting when only edges intersect. Default is * true. If false, a vertex on the source must be within the tolerance * distance of the intersection to be considered a split. * tolerance - {Number} If a non-null value is provided, intersections * within the tolerance distance of an existing vertex on the source * will be assumed to occur at the vertex. * * Returns: * {Array} A list of geometries (of this same type as the target) that * result from splitting the target with the source geometry. The * source and target geometry will remain unmodified. If no split * results, null will be returned. If mutual is true and a split * results, return will be an array of two arrays - the first will be * all geometries that result from splitting the source geometry and * the second will be all geometries that result from splitting the * target geometry. */ splitWith: function(geometry, options) { return geometry.split(this, options); }, /** * APIMethod: getVertices * Return a list of all points in this geometry. * * Parameters: * nodes - {Boolean} For lines, only return vertices that are * endpoints. If false, for lines, only vertices that are not * endpoints will be returned. If not provided, all vertices will * be returned. * * Returns: * {Array} A list of all vertices in the geometry. */ getVertices: function(nodes) { var vertices; if(nodes === true) { vertices = [ this.components[0], this.components[this.components.length-1] ]; } else if (nodes === false) { vertices = this.components.slice(1, this.components.length-1); } else { vertices = this.components.slice(); } return vertices; }, /** * APIMethod: distanceTo * Calculate the closest distance between two geometries (on the x-y plane). * * Parameters: * geometry - {
} The target geometry. * options - {Object} Optional properties for configuring the distance * calculation. * * Valid options: * details - {Boolean} Return details from the distance calculation. * Default is false. * edge - {Boolean} Calculate the distance from this geometry to the * nearest edge of the target geometry. Default is true. If true, * calling distanceTo from a geometry that is wholly contained within * the target will result in a non-zero distance. If false, whenever * geometries intersect, calling distanceTo will return 0. If false, * details cannot be returned. * * Returns: * {Number | Object} The distance between this geometry and the target. * If details is true, the return will be an object with distance, * x0, y0, x1, and x2 properties. The x0 and y0 properties represent * the coordinates of the closest point on this geometry. The x1 and y1 * properties represent the coordinates of the closest point on the * target geometry. */ distanceTo: function(geometry, options) { var edge = !(options && options.edge === false); var details = edge && options && options.details; var result, best = {}; var min = Number.POSITIVE_INFINITY; if(geometry instanceof OpenLayers.Geometry.Point) { var segs = this.getSortedSegments(); var x = geometry.x; var y = geometry.y; var seg; for(var i=0, len=segs.length; i
x && ((y > seg.y1 && y < seg.y2) || (y < seg.y1 && y > seg.y2))) { break; } } } if(details) { best = { distance: best.distance, x0: best.x, y0: best.y, x1: x, y1: y }; } else { best = best.distance; } } else if(geometry instanceof OpenLayers.Geometry.LineString) { var segs0 = this.getSortedSegments(); var segs1 = geometry.getSortedSegments(); var seg0, seg1, intersection, x0, y0; var len1 = segs1.length; var interOptions = {point: true}; outer: for(var i=0, len=segs0.length; i
maxDistance) { maxDistance = distance; indexFarthest = index; } } if (maxDistance > tolerance && indexFarthest != firstPoint) { //Add the largest point that exceeds the tolerance pointIndexsToKeep.push(indexFarthest); douglasPeuckerReduction(points, firstPoint, indexFarthest, tolerance); douglasPeuckerReduction(points, indexFarthest, lastPoint, tolerance); } }; /** * Private function calculating the perpendicular distance * TODO: check whether OpenLayers.Geometry.LineString::distanceTo() is faster or slower */ var perpendicularDistance = function(point1, point2, point){ //Area = |(1/2)(x1y2 + x2y3 + x3y1 - x2y1 - x3y2 - x1y3)| *Area of triangle //Base = v((x1-x2)²+(x1-x2)²) *Base of Triangle* //Area = .5*Base*H *Solve for height //Height = Area/.5/Base var area = Math.abs(0.5 * (point1.x * point2.y + point2.x * point.y + point.x * point1.y - point2.x * point1.y - point.x * point2.y - point1.x * point.y)); var bottom = Math.sqrt(Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2)); var height = area / bottom * 2; return height; }; var firstPoint = 0; var lastPoint = points.length - 1; var pointIndexsToKeep = []; //Add the first and last index to the keepers pointIndexsToKeep.push(firstPoint); pointIndexsToKeep.push(lastPoint); //The first and the last point cannot be the same while (points[firstPoint].equals(points[lastPoint])) { lastPoint--; //Addition: the first point not equal to first point in the LineString is kept as well pointIndexsToKeep.push(lastPoint); } douglasPeuckerReduction(points, firstPoint, lastPoint, tolerance); var returnPoints = []; pointIndexsToKeep.sort(compareNumbers); for (var index = 0; index < pointIndexsToKeep.length; index++) { returnPoints.push(points[pointIndexsToKeep[index]]); } return new OpenLayers.Geometry.LineString(returnPoints); } else { return this; } }, CLASS_NAME: "OpenLayers.Geometry.LineString" }); /* ====================================================================== OpenLayers/Geometry/MultiLineString.js ====================================================================== */ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** * @requires OpenLayers/Geometry/Collection.js * @requires OpenLayers/Geometry/LineString.js */ /** * Class: OpenLayers.Geometry.MultiLineString * A MultiLineString is a geometry with multiple
* components. * * Inherits from: * -
* -
*/ OpenLayers.Geometry.MultiLineString = OpenLayers.Class( OpenLayers.Geometry.Collection, { /** * Property: componentTypes * {Array(String)} An array of class names representing the types of * components that the collection can include. A null value means the * component types are not restricted. */ componentTypes: ["OpenLayers.Geometry.LineString"], /** * Constructor: OpenLayers.Geometry.MultiLineString * Constructor for a MultiLineString Geometry. * * Parameters: * components - {Array(
)} * */ /** * Method: split * Use this geometry (the source) to attempt to split a target geometry. * * Parameters: * geometry - {
} The target geometry. * options - {Object} Properties of this object will be used to determine * how the split is conducted. * * Valid options: * mutual - {Boolean} Split the source geometry in addition to the target * geometry. Default is false. * edge - {Boolean} Allow splitting when only edges intersect. Default is * true. If false, a vertex on the source must be within the tolerance * distance of the intersection to be considered a split. * tolerance - {Number} If a non-null value is provided, intersections * within the tolerance distance of an existing vertex on the source * will be assumed to occur at the vertex. * * Returns: * {Array} A list of geometries (of this same type as the target) that * result from splitting the target with the source geometry. The * source and target geometry will remain unmodified. If no split * results, null will be returned. If mutual is true and a split * results, return will be an array of two arrays - the first will be * all geometries that result from splitting the source geometry and * the second will be all geometries that result from splitting the * target geometry. */ split: function(geometry, options) { var results = null; var mutual = options && options.mutual; var splits, sourceLine, sourceLines, sourceSplit, targetSplit; var sourceParts = []; var targetParts = [geometry]; for(var i=0, len=this.components.length; i
1) { sourceSplit = true; } else { sourceParts = []; } if(targetParts && targetParts.length > 1) { targetSplit = true; } else { targetParts = []; } if(sourceSplit || targetSplit) { if(mutual) { results = [sourceParts, targetParts]; } else { results = targetParts; } } return results; }, /** * Method: splitWith * Split this geometry (the target) with the given geometry (the source). * * Parameters: * geometry - {
} A geometry used to split this * geometry (the source). * options - {Object} Properties of this object will be used to determine * how the split is conducted. * * Valid options: * mutual - {Boolean} Split the source geometry in addition to the target * geometry. Default is false. * edge - {Boolean} Allow splitting when only edges intersect. Default is * true. If false, a vertex on the source must be within the tolerance * distance of the intersection to be considered a split. * tolerance - {Number} If a non-null value is provided, intersections * within the tolerance distance of an existing vertex on the source * will be assumed to occur at the vertex. * * Returns: * {Array} A list of geometries (of this same type as the target) that * result from splitting the target with the source geometry. The * source and target geometry will remain unmodified. If no split * results, null will be returned. If mutual is true and a split * results, return will be an array of two arrays - the first will be * all geometries that result from splitting the source geometry and * the second will be all geometries that result from splitting the * target geometry. */ splitWith: function(geometry, options) { var results = null; var mutual = options && options.mutual; var splits, targetLine, sourceLines, sourceSplit, targetSplit, sourceParts, targetParts; if(geometry instanceof OpenLayers.Geometry.LineString) { targetParts = []; sourceParts = [geometry]; for(var i=0, len=this.components.length; i
1) { sourceSplit = true; } else { sourceParts = []; } if(targetParts && targetParts.length > 1) { targetSplit = true; } else { targetParts = []; } if(sourceSplit || targetSplit) { if(mutual) { results = [sourceParts, targetParts]; } else { results = targetParts; } } return results; }, CLASS_NAME: "OpenLayers.Geometry.MultiLineString" }); /* ====================================================================== OpenLayers/Geometry/LinearRing.js ====================================================================== */ /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** * @requires OpenLayers/Geometry/LineString.js */ /** * Class: OpenLayers.Geometry.LinearRing * * A Linear Ring is a special LineString which is closed. It closes itself * automatically on every addPoint/removePoint by adding a copy of the first * point as the last point. * * Also, as it is the first in the line family to close itself, a getArea() * function is defined to calculate the enclosed area of the linearRing * * Inherits: * -
*/ OpenLayers.Geometry.LinearRing = OpenLayers.Class( OpenLayers.Geometry.LineString, { /** * Property: componentTypes * {Array(String)} An array of class names representing the types of * components that the collection can include. A null * value means the component types are not restricted. */ componentTypes: ["OpenLayers.Geometry.Point"], /** * Constructor: OpenLayers.Geometry.LinearRing * Linear rings are constructed with an array of points. This array * can represent a closed or open ring. If the ring is open (the last * point does not equal the first point), the constructor will close * the ring. If the ring is already closed (the last point does equal * the first point), it will be left closed. * * Parameters: * points - {Array(
)} points */ /** * APIMethod: addComponent * Adds a point to geometry components. If the point is to be added to * the end of the components array and it is the same as the last point * already in that array, the duplicate point is not added. This has * the effect of closing the ring if it is not already closed, and * doing the right thing if it is already closed. This behavior can * be overridden by calling the method with a non-null index as the * second argument. * * Parameters: * point - {
} * index - {Integer} Index into the array to insert the component * * Returns: * {Boolean} Was the Point successfully added? */ addComponent: function(point, index) { var added = false; //remove last point var lastPoint = this.components.pop(); // given an index, add the point // without an index only add non-duplicate points if(index != null || !point.equals(lastPoint)) { added = OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, arguments); } //append copy of first point var firstPoint = this.components[0]; OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, [firstPoint]); return added; }, /** * APIMethod: removeComponent * Removes a point from geometry components. * * Parameters: * point - {
} * * Returns: * {Boolean} The component was removed. */ removeComponent: function(point) { var removed = this.components && (this.components.length > 3); if (removed) { //remove last point this.components.pop(); //remove our point OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, arguments); //append copy of first point var firstPoint = this.components[0]; OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, [firstPoint]); } return removed; }, /** * APIMethod: move * Moves a geometry by the given displacement along positive x and y axes. * This modifies the position of the geometry and clears the cached * bounds. * * Parameters: * x - {Float} Distance to move geometry in positive x direction. * y - {Float} Distance to move geometry in positive y direction. */ move: function(x, y) { for(var i = 0, len=this.components.length; i
} Center point for the rotation */ rotate: function(angle, origin) { for(var i=0, len=this.components.length; i
} Point of origin for resizing * ratio - {Float} Optional x:y ratio for resizing. Default ratio is 1. * * Returns: * {
} - The current geometry. */ resize: function(scale, origin, ratio) { for(var i=0, len=this.components.length; i
} * dest - {
} * * Returns: * {
} */ transform: function(source, dest) { if (source && dest) { for (var i=0, len=this.components.length; i
} The centroid of the collection */ getCentroid: function() { if (this.components) { var len = this.components.length; if (len > 0 && len <= 2) { return this.components[0].clone(); } else if (len > 2) { var sumX = 0.0; var sumY = 0.0; var x0 = this.components[0].x; var y0 = this.components[0].y; var area = -1 * this.getArea(); if (area != 0) { for (var i = 0; i < len - 1; i++) { var b = this.components[i]; var c = this.components[i+1]; sumX += (b.x + c.x - 2 * x0) * ((b.x - x0) * (c.y - y0) - (c.x - x0) * (b.y - y0)); sumY += (b.y + c.y - 2 * y0) * ((b.x - x0) * (c.y - y0) - (c.x - x0) * (b.y - y0)); } var x = x0 + sumX / (6 * area); var y = y0 + sumY / (6 * area); } else { for (var i = 0; i < len - 1; i++) { sumX += this.components[i].x; sumY += this.components[i].y; } var x = sumX / (len - 1); var y = sumY / (len - 1); } return new OpenLayers.Geometry.Point(x, y); } else { return null; } } }, /** * APIMethod: getArea * Note - The area is positive if the ring is oriented CW, otherwise * it will be negative. * * Returns: * {Float} The signed area for a ring. */ getArea: function() { var area = 0.0; if ( this.components && (this.components.length > 2)) { var sum = 0.0; for (var i=0, len=this.components.length; i
} The spatial reference system * for the geometry coordinates. If not provided, Geographic/WGS84 is * assumed. * * Reference: * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409 * * Returns: * {float} The approximate signed geodesic area of the polygon in square * meters. */ getGeodesicArea: function(projection) { var ring = this; // so we can work with a clone if needed if(projection) { var gg = new OpenLayers.Projection("EPSG:4326"); if(!gg.equals(projection)) { ring = this.clone().transform(projection, gg); } } var area = 0.0; var len = ring.components && ring.components.length; if(len > 2) { var p1, p2; for(var i=0; i
} * * Returns: * {Boolean | Number} The point is inside the linear ring. Returns 1 if * the point is coincident with an edge. Returns boolean otherwise. */ containsPoint: function(point) { var approx = OpenLayers.Number.limitSigDigs; var digs = 14; var px = approx(point.x, digs); var py = approx(point.y, digs); function getX(y, x1, y1, x2, y2) { return (y - y2) * ((x2 - x1) / (y2 - y1)) + x2; } var numSeg = this.components.length - 1; var start, end, x1, y1, x2, y2, cx, cy; var crosses = 0; for(var i=0; i
= x1 && px <= x2) || // right or vert x1 >= x2 && (px <= x1 && px >= x2)) { // left or vert // point on edge crosses = -1; break; } } // ignore other horizontal edges continue; } cx = approx(getX(py, x1, y1, x2, y2), digs); if(cx == px) { // point on line if(y1 < y2 && (py >= y1 && py <= y2) || // upward y1 > y2 && (py <= y1 && py >= y2)) { // downward // point on edge crosses = -1; break; } } if(cx <= px) { // no crossing to the right continue; } if(x1 != x2 && (cx < Math.min(x1, x2) || cx > Math.max(x1, x2))) { // no crossing continue; } if(y1 < y2 && (py >= y1 && py < y2) || // upward y1 > y2 && (py < y1 && py >= y2)) { // downward ++crosses; } } var contained = (crosses == -1) ? // on edge 1 : // even (out) or odd (in) !!(crosses & 1); return contained; }, /** * APIMethod: intersects * Determine if the input geometry intersects this one. * * Parameters: * geometry - {
} Any type of geometry. * * Returns: * {Boolean} The input geometry intersects this one. */ intersects: function(geometry) { var intersect = false; if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { intersect = this.containsPoint(geometry); } else if(geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") { intersect = geometry.intersects(this); } else if(geometry.CLASS_NAME == "OpenLayers.Geometry.LinearRing") { intersect = OpenLayers.Geometry.LineString.prototype.intersects.apply( this, [geometry] ); } else { // check for component intersections for(var i=0, len=geometry.components.length; i