[fusion-commits] r2323 - in branches/fusion-2.2: . lib
lib/OpenLayers
svn_fusion at osgeo.org
svn_fusion at osgeo.org
Thu Jan 20 14:57:00 EST 2011
Author: madair
Date: 2011-01-20 11:56:47 -0800 (Thu, 20 Jan 2011)
New Revision: 2323
Modified:
branches/fusion-2.2/fusion.cfg
branches/fusion-2.2/lib/OpenLayers/OpenLayers.js
branches/fusion-2.2/lib/proj4js-combined.js
branches/fusion-2.2/lib/proj4js-compressed.js
Log:
re #430: update to OL and Proj4js libraries applied to the 2.2 branch
Modified: branches/fusion-2.2/fusion.cfg
===================================================================
--- branches/fusion-2.2/fusion.cfg 2011-01-20 19:46:05 UTC (rev 2322)
+++ branches/fusion-2.2/fusion.cfg 2011-01-20 19:56:47 UTC (rev 2323)
@@ -2,17 +2,6 @@
# for Fusion
[first]
-OpenLayers/SingleFile.js
-OpenLayers.js
-OpenLayers/Util.js
-OpenLayers/Console.js
-OpenLayers/BaseTypes.js
-OpenLayers/BaseTypes/Class.js
-OpenLayers/BaseTypes/Size.js
-OpenLayers/BaseTypes/Bounds.js
-OpenLayers/BaseTypes/Element.js
-OpenLayers/BaseTypes/LonLat.js
-OpenLayers/BaseTypes/Pixel.js
[last]
@@ -43,8 +32,19 @@
OpenLayers/Control/DrawFeature.js
OpenLayers/Control/Measure.js
OpenLayers/Control/ScaleLine.js
+OpenLayers/Control/MousePosition.js
+OpenLayers/Filter.js
+OpenLayers/Filter/FeatureId.js
+OpenLayers/Filter/Spatial.js
+OpenLayers/Filter/Logical.js
+OpenLayers/Filter/Comparison.js
OpenLayers/Format/GML/v2.js
OpenLayers/Format/GML/v3.js
+OpenLayers/Format/WFSCapabilities.js
+OpenLayers/Format/WFSCapabilities/v1.js
+OpenLayers/Format/WFSCapabilities/v1_0_0.js
+OpenLayers/Format/WFSCapabilities/v1_1_0.js
+OpenLayers/Format/WFSDescribeFeatureType.js
OpenLayers/Handler/Box.js
OpenLayers/Handler/Click.js
OpenLayers/Handler/Drag.js
@@ -57,7 +57,17 @@
OpenLayers/Handler/RegularPolygon.js
OpenLayers/Projection.js
OpenLayers/Protocol/HTTP.js
+OpenLayers/Protocol/WFS.js
+OpenLayers/Protocol/WFS/v1.js
+OpenLayers/Protocol/WFS/v1_0_0.js
+OpenLayers/Protocol/WFS/v1_1_0.js
OpenLayers/Strategy/Fixed.js
+OpenLayers/Strategy/BBOX.js
+OpenLayers/Strategy/Filter.js
+OpenLayers/Strategy/Save.js
+OpenLayers/Strategy/Paging.js
+OpenLayers/Strategy/Refresh.js
+OpenLayers/Strategy/Cluster.js
OpenLayers/Feature.js
OpenLayers/Marker.js
OpenLayers/Icon.js
Modified: branches/fusion-2.2/lib/OpenLayers/OpenLayers.js
===================================================================
--- branches/fusion-2.2/lib/OpenLayers/OpenLayers.js 2011-01-20 19:46:05 UTC (rev 2322)
+++ branches/fusion-2.2/lib/OpenLayers/OpenLayers.js 2011-01-20 19:56:47 UTC (rev 2323)
@@ -2,7 +2,7 @@
OpenLayers.js -- OpenLayers Map Viewer Library
- Copyright 2005-2010 OpenLayers Contributors, released under the Clear BSD
+ Copyright 2005-2011 OpenLayers Contributors, released under the Clear BSD
license. Please see http://svn.openlayers.org/trunk/openlayers/license.txt
for the full text of the license.
@@ -90,430 +90,201 @@
* issues. Applications that use the code below will continue to work seamlessly
* when that happens.
*/
-/* ======================================================================
+
+/**
+ * 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-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
var OpenLayers = {
- singleFile: true
-};
-
-
-/* ======================================================================
- OpenLayers.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/*
- * @requires OpenLayers/BaseTypes.js
- * @requires OpenLayers/Lang/en.js
- * @requires OpenLayers/Console.js
- */
-
-(function() {
/**
- * Before creating the OpenLayers namespace, check to see if
- * OpenLayers.singleFile is true. This occurs if the
- * OpenLayers/SingleFile.js script is included before this one - as is the
- * case with single file builds.
+ * Constant: VERSION_NUMBER
*/
- var singleFile = (typeof OpenLayers == "object" && OpenLayers.singleFile);
-
+ VERSION_NUMBER: "$Revision$",
+
/**
- * Cache for the script location returned from
- * OpenLayers._getScriptLocation
+ * Constant: singleFile
+ * TODO: remove this in 3.0 when we stop supporting build profiles that
+ * include OpenLayers.js
*/
- var scriptLocation;
-
+ singleFile: true,
+
/**
- * Namespace: OpenLayers
- * The OpenLayers object provides a namespace for all things OpenLayers
+ * Method: _getScriptLocation
+ * Return the path to this script. This is also implemented in
+ * OpenLayers.js
+ *
+ * Returns:
+ * {String} Path to this script
*/
- window.OpenLayers = {
-
- /**
- * Property: _scriptName
- * {String} Relative path of this script.
- */
- _scriptName: (!singleFile) ? "lib/OpenLayers.js" : "OpenLayers.js",
-
- /**
- * Function: _getScriptLocation
- * Return the path to this script.
- *
- * Returns:
- * {String} Path to this script
- */
- _getScriptLocation: function () {
- if (scriptLocation != undefined) {
- return scriptLocation;
- }
- scriptLocation = "";
- var isOL = new RegExp("(^|(.*?\\/))(" + OpenLayers._scriptName + ")(\\?|$)");
-
- var scripts = document.getElementsByTagName('script');
- for (var i=0, len=scripts.length; i<len; i++) {
- var src = scripts[i].getAttribute('src');
- if (src) {
- var match = src.match(isOL);
- if(match) {
- scriptLocation = match[1];
- break;
- }
+ _getScriptLocation: (function() {
+ var r = new RegExp("(^|(.*?\\/))(OpenLayers\.js)(\\?|$)"),
+ s = document.getElementsByTagName('script'),
+ src, m, l = "";
+ for(var i=0, len=s.length; i<len; i++) {
+ src = s[i].getAttribute('src');
+ if(src) {
+ var m = src.match(r);
+ if(m) {
+ l = m[1];
+ break;
}
}
- return scriptLocation;
}
- };
- /**
- * OpenLayers.singleFile is a flag indicating this file is being included
- * in a Single File Library build of the OpenLayers Library.
- *
- * When we are *not* part of a SFL build we dynamically include the
- * OpenLayers library code.
- *
- * When we *are* part of a SFL build we do not dynamically include the
- * OpenLayers library code as it will be appended at the end of this file.
- */
- if(!singleFile) {
- var jsfiles = new Array(
- "OpenLayers/Util.js",
- "OpenLayers/BaseTypes.js",
- "OpenLayers/BaseTypes/Class.js",
- "OpenLayers/BaseTypes/Bounds.js",
- "OpenLayers/BaseTypes/Element.js",
- "OpenLayers/BaseTypes/LonLat.js",
- "OpenLayers/BaseTypes/Pixel.js",
- "OpenLayers/BaseTypes/Size.js",
- "OpenLayers/Console.js",
- "OpenLayers/Tween.js",
- "Rico/Corner.js",
- "Rico/Color.js",
- "OpenLayers/Ajax.js",
- "OpenLayers/Events.js",
- "OpenLayers/Request.js",
- "OpenLayers/Request/XMLHttpRequest.js",
- "OpenLayers/Projection.js",
- "OpenLayers/Map.js",
- "OpenLayers/Layer.js",
- "OpenLayers/Icon.js",
- "OpenLayers/Marker.js",
- "OpenLayers/Marker/Box.js",
- "OpenLayers/Popup.js",
- "OpenLayers/Tile.js",
- "OpenLayers/Tile/Image.js",
- "OpenLayers/Tile/Image/IFrame.js",
- "OpenLayers/Tile/WFS.js",
- "OpenLayers/Layer/Image.js",
- "OpenLayers/Layer/SphericalMercator.js",
- "OpenLayers/Layer/EventPane.js",
- "OpenLayers/Layer/FixedZoomLevels.js",
- "OpenLayers/Layer/Google.js",
- "OpenLayers/Layer/Google/v3.js",
- "OpenLayers/Layer/VirtualEarth.js",
- "OpenLayers/Layer/Yahoo.js",
- "OpenLayers/Layer/HTTPRequest.js",
- "OpenLayers/Layer/Grid.js",
- "OpenLayers/Layer/MapGuide.js",
- "OpenLayers/Layer/MapServer.js",
- "OpenLayers/Layer/MapServer/Untiled.js",
- "OpenLayers/Layer/KaMap.js",
- "OpenLayers/Layer/KaMapCache.js",
- "OpenLayers/Layer/MultiMap.js",
- "OpenLayers/Layer/Markers.js",
- "OpenLayers/Layer/Text.js",
- "OpenLayers/Layer/WorldWind.js",
- "OpenLayers/Layer/ArcGIS93Rest.js",
- "OpenLayers/Layer/WMS.js",
- "OpenLayers/Layer/WMS/Untiled.js",
- "OpenLayers/Layer/WMS/Post.js",
- "OpenLayers/Layer/WMTS.js",
- "OpenLayers/Layer/ArcIMS.js",
- "OpenLayers/Layer/GeoRSS.js",
- "OpenLayers/Layer/Boxes.js",
- "OpenLayers/Layer/XYZ.js",
- "OpenLayers/Layer/TMS.js",
- "OpenLayers/Layer/TileCache.js",
- "OpenLayers/Layer/Zoomify.js",
- "OpenLayers/Popup/Anchored.js",
- "OpenLayers/Popup/AnchoredBubble.js",
- "OpenLayers/Popup/Framed.js",
- "OpenLayers/Popup/FramedCloud.js",
- "OpenLayers/Feature.js",
- "OpenLayers/Feature/Vector.js",
- "OpenLayers/Feature/WFS.js",
- "OpenLayers/Handler.js",
- "OpenLayers/Handler/Click.js",
- "OpenLayers/Handler/Hover.js",
- "OpenLayers/Handler/Point.js",
- "OpenLayers/Handler/Path.js",
- "OpenLayers/Handler/Polygon.js",
- "OpenLayers/Handler/Feature.js",
- "OpenLayers/Handler/Drag.js",
- "OpenLayers/Handler/RegularPolygon.js",
- "OpenLayers/Handler/Box.js",
- "OpenLayers/Handler/MouseWheel.js",
- "OpenLayers/Handler/Keyboard.js",
- "OpenLayers/Control.js",
- "OpenLayers/Control/Attribution.js",
- "OpenLayers/Control/Button.js",
- "OpenLayers/Control/ZoomBox.js",
- "OpenLayers/Control/ZoomToMaxExtent.js",
- "OpenLayers/Control/DragPan.js",
- "OpenLayers/Control/Navigation.js",
- "OpenLayers/Control/MouseDefaults.js",
- "OpenLayers/Control/MousePosition.js",
- "OpenLayers/Control/OverviewMap.js",
- "OpenLayers/Control/KeyboardDefaults.js",
- "OpenLayers/Control/PanZoom.js",
- "OpenLayers/Control/PanZoomBar.js",
- "OpenLayers/Control/ArgParser.js",
- "OpenLayers/Control/Permalink.js",
- "OpenLayers/Control/Scale.js",
- "OpenLayers/Control/ScaleLine.js",
- "OpenLayers/Control/Snapping.js",
- "OpenLayers/Control/Split.js",
- "OpenLayers/Control/LayerSwitcher.js",
- "OpenLayers/Control/DrawFeature.js",
- "OpenLayers/Control/DragFeature.js",
- "OpenLayers/Control/ModifyFeature.js",
- "OpenLayers/Control/Panel.js",
- "OpenLayers/Control/SelectFeature.js",
- "OpenLayers/Control/NavigationHistory.js",
- "OpenLayers/Control/Measure.js",
- "OpenLayers/Control/WMSGetFeatureInfo.js",
- "OpenLayers/Control/WMTSGetFeatureInfo.js",
- "OpenLayers/Control/Graticule.js",
- "OpenLayers/Control/TransformFeature.js",
- "OpenLayers/Control/SLDSelect.js",
- "OpenLayers/Geometry.js",
- "OpenLayers/Geometry/Rectangle.js",
- "OpenLayers/Geometry/Collection.js",
- "OpenLayers/Geometry/Point.js",
- "OpenLayers/Geometry/MultiPoint.js",
- "OpenLayers/Geometry/Curve.js",
- "OpenLayers/Geometry/LineString.js",
- "OpenLayers/Geometry/LinearRing.js",
- "OpenLayers/Geometry/Polygon.js",
- "OpenLayers/Geometry/MultiLineString.js",
- "OpenLayers/Geometry/MultiPolygon.js",
- "OpenLayers/Geometry/Surface.js",
- "OpenLayers/Renderer.js",
- "OpenLayers/Renderer/Elements.js",
- "OpenLayers/Renderer/SVG.js",
- "OpenLayers/Renderer/Canvas.js",
- "OpenLayers/Renderer/VML.js",
- "OpenLayers/Layer/Vector.js",
- "OpenLayers/Layer/Vector/RootContainer.js",
- "OpenLayers/Strategy.js",
- "OpenLayers/Strategy/Filter.js",
- "OpenLayers/Strategy/Fixed.js",
- "OpenLayers/Strategy/Cluster.js",
- "OpenLayers/Strategy/Paging.js",
- "OpenLayers/Strategy/BBOX.js",
- "OpenLayers/Strategy/Save.js",
- "OpenLayers/Strategy/Refresh.js",
- "OpenLayers/Filter.js",
- "OpenLayers/Filter/FeatureId.js",
- "OpenLayers/Filter/Logical.js",
- "OpenLayers/Filter/Comparison.js",
- "OpenLayers/Filter/Spatial.js",
- "OpenLayers/Protocol.js",
- "OpenLayers/Protocol/HTTP.js",
- "OpenLayers/Protocol/SQL.js",
- "OpenLayers/Protocol/SQL/Gears.js",
- "OpenLayers/Protocol/WFS.js",
- "OpenLayers/Protocol/WFS/v1.js",
- "OpenLayers/Protocol/WFS/v1_0_0.js",
- "OpenLayers/Protocol/WFS/v1_1_0.js",
- "OpenLayers/Protocol/SOS.js",
- "OpenLayers/Protocol/SOS/v1_0_0.js",
- "OpenLayers/Layer/PointTrack.js",
- "OpenLayers/Layer/GML.js",
- "OpenLayers/Style.js",
- "OpenLayers/Style2.js",
- "OpenLayers/StyleMap.js",
- "OpenLayers/Rule.js",
- "OpenLayers/Format.js",
- "OpenLayers/Format/XML.js",
- "OpenLayers/Format/Context.js",
- "OpenLayers/Format/ArcXML.js",
- "OpenLayers/Format/ArcXML/Features.js",
- "OpenLayers/Format/GML.js",
- "OpenLayers/Format/GML/Base.js",
- "OpenLayers/Format/GML/v2.js",
- "OpenLayers/Format/GML/v3.js",
- "OpenLayers/Format/Atom.js",
- "OpenLayers/Format/KML.js",
- "OpenLayers/Format/GeoRSS.js",
- "OpenLayers/Format/WFS.js",
- "OpenLayers/Format/WFSCapabilities.js",
- "OpenLayers/Format/WFSCapabilities/v1.js",
- "OpenLayers/Format/WFSCapabilities/v1_0_0.js",
- "OpenLayers/Format/WFSCapabilities/v1_1_0.js",
- "OpenLayers/Format/WFSDescribeFeatureType.js",
- "OpenLayers/Format/WMSDescribeLayer.js",
- "OpenLayers/Format/WMSDescribeLayer/v1_1.js",
- "OpenLayers/Format/WKT.js",
- "OpenLayers/Format/OSM.js",
- "OpenLayers/Format/GPX.js",
- "OpenLayers/Format/Filter.js",
- "OpenLayers/Format/Filter/v1.js",
- "OpenLayers/Format/Filter/v1_0_0.js",
- "OpenLayers/Format/Filter/v1_1_0.js",
- "OpenLayers/Format/SLD.js",
- "OpenLayers/Format/SLD/v1.js",
- "OpenLayers/Format/SLD/v1_0_0.js",
- "OpenLayers/Format/OWSCommon/v1.js",
- "OpenLayers/Format/OWSCommon/v1_0_0.js",
- "OpenLayers/Format/OWSCommon/v1_1_0.js",
- "OpenLayers/Format/CSWGetDomain.js",
- "OpenLayers/Format/CSWGetDomain/v2_0_2.js",
- "OpenLayers/Format/CSWGetRecords.js",
- "OpenLayers/Format/CSWGetRecords/v2_0_2.js",
- "OpenLayers/Format/WFST.js",
- "OpenLayers/Format/WFST/v1.js",
- "OpenLayers/Format/WFST/v1_0_0.js",
- "OpenLayers/Format/WFST/v1_1_0.js",
- "OpenLayers/Format/Text.js",
- "OpenLayers/Format/JSON.js",
- "OpenLayers/Format/GeoJSON.js",
- "OpenLayers/Format/WMC.js",
- "OpenLayers/Format/WMC/v1.js",
- "OpenLayers/Format/WMC/v1_0_0.js",
- "OpenLayers/Format/WMC/v1_1_0.js",
- "OpenLayers/Format/WMSCapabilities.js",
- "OpenLayers/Format/WMSCapabilities/v1.js",
- "OpenLayers/Format/WMSCapabilities/v1_1.js",
- "OpenLayers/Format/WMSCapabilities/v1_1_0.js",
- "OpenLayers/Format/WMSCapabilities/v1_1_1.js",
- "OpenLayers/Format/WMSCapabilities/v1_3.js",
- "OpenLayers/Format/WMSCapabilities/v1_3_0.js",
- "OpenLayers/Format/WMSGetFeatureInfo.js",
- "OpenLayers/Format/SOSCapabilities.js",
- "OpenLayers/Format/SOSCapabilities/v1_0_0.js",
- "OpenLayers/Format/SOSGetObservation.js",
- "OpenLayers/Format/SOSGetFeatureOfInterest.js",
- "OpenLayers/Format/OWSContext.js",
- "OpenLayers/Format/OWSContext/v0_3_1.js",
- "OpenLayers/Format/WMTSCapabilities.js",
- "OpenLayers/Format/WMTSCapabilities/v1_0_0.js",
- "OpenLayers/Layer/WFS.js",
- "OpenLayers/Control/GetFeature.js",
- "OpenLayers/Control/MouseToolbar.js",
- "OpenLayers/Control/NavToolbar.js",
- "OpenLayers/Control/PanPanel.js",
- "OpenLayers/Control/Pan.js",
- "OpenLayers/Control/ZoomIn.js",
- "OpenLayers/Control/ZoomOut.js",
- "OpenLayers/Control/ZoomPanel.js",
- "OpenLayers/Control/EditingToolbar.js",
- "OpenLayers/Symbolizer.js",
- "OpenLayers/Symbolizer/Point.js",
- "OpenLayers/Symbolizer/Line.js",
- "OpenLayers/Symbolizer/Polygon.js",
- "OpenLayers/Symbolizer/Text.js",
- "OpenLayers/Symbolizer/Raster.js",
- "OpenLayers/Lang.js",
- "OpenLayers/Lang/en.js"
- ); // etc.
-
- var agent = navigator.userAgent;
- var docWrite = (agent.match("MSIE") || agent.match("Safari"));
- if(docWrite) {
- var allScriptTags = new Array(jsfiles.length);
- }
- var host = OpenLayers._getScriptLocation() + "lib/";
- for (var i=0, len=jsfiles.length; i<len; i++) {
- if (docWrite) {
- allScriptTags[i] = "<script src='" + host + jsfiles[i] +
- "'></script>";
- } else {
- var s = document.createElement("script");
- s.src = host + jsfiles[i];
- var h = document.getElementsByTagName("head").length ?
- document.getElementsByTagName("head")[0] :
- document.body;
- h.appendChild(s);
- }
- }
- if (docWrite) {
- document.write(allScriptTags.join(""));
- }
- }
-})();
-
-/**
- * Constant: VERSION_NUMBER
- */
-OpenLayers.VERSION_NUMBER="OpenLayers 2.10 -- $Revision$";
+ return (function() { return l; });
+ })()
+};
/* ======================================================================
- OpenLayers/Util.js
+ OpenLayers/BaseTypes/Class.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
- * @requires OpenLayers/Console.js
+ * @requires OpenLayers/SingleFile.js
*/
/**
- * Namespace: Util
+ * 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:
+ * > var MyClass = OpenLayers.Class(prototype);
+ *
+ * To create a new OpenLayers-style class with multiple inheritance, use the
+ * following syntax:
+ * > var MyClass = OpenLayers.Class(Class1, Class2, prototype);
+ * Note that instanceof reflection will only reveil Class1 as superclass.
+ * Class2 ff are mixins.
+ *
*/
-OpenLayers.Util = {};
+OpenLayers.Class = function() {
+ var len = arguments.length;
+ var P = arguments[0];
+ var F = arguments[len-1];
-/**
- * Function: getElement
- * This is the old $() from prototype
+ var C = typeof F.initialize == "function" ?
+ F.initialize :
+ function(){ P.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;
+};
+
+/**
+ * Property: isPrototype
+ * *Deprecated*. This is no longer needed and will be removed at 3.0.
*/
-OpenLayers.Util.getElement = function() {
- var elements = [];
+OpenLayers.Class.isPrototype = function () {};
- for (var i=0, len=arguments.length; i<len; i++) {
- var element = arguments[i];
- if (typeof element == 'string') {
- element = document.getElementById(element);
+/**
+ * APIFunction: OpenLayers.create
+ * *Deprecated*. Old method to create an OpenLayers style class. Use the
+ * <OpenLayers.Class> constructor instead.
+ *
+ * Returns:
+ * An OpenLayers class
+ */
+OpenLayers.Class.create = function() {
+ return function() {
+ if (arguments && arguments[0] != OpenLayers.Class.isPrototype) {
+ this.initialize.apply(this, arguments);
}
- if (arguments.length == 1) {
- return element;
- }
- elements.push(element);
- }
- return elements;
+ };
};
/**
- * Function: isElement
- * A cross-browser implementation of "e instanceof Element".
+ * APIFunction: inherit
+ * *Deprecated*. Old method to inherit from one or more OpenLayers style
+ * classes. Use the <OpenLayers.Class> constructor instead.
*
* Parameters:
- * o - {Object} The object to test.
+ * class - One or more classes can be provided as arguments
*
* Returns:
- * {Boolean}
+ * An object prototype
*/
-OpenLayers.Util.isElement = function(o) {
- return !!(o && o.nodeType === 1);
+OpenLayers.Class.inherit = function (P) {
+ var C = function() {
+ P.call(this);
+ };
+ var newArgs = [C].concat(Array.prototype.slice.call(arguments));
+ OpenLayers.inherit.apply(null, newArgs);
+ return C.prototype;
};
-/**
- * Maintain existing definition of $.
+/**
+ * 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.
*/
-if(typeof window.$ === "undefined") {
- //window.$ = OpenLayers.Util.getElement;
-}
+OpenLayers.inherit = function(C, P) {
+ var F = function() {};
+ F.prototype = P.prototype;
+ C.prototype = new F;
+ var i, l, o;
+ for(i=2, l=arguments.length; i<l; i++) {
+ o = arguments[i];
+ if(typeof o === "function") {
+ o = o.prototype;
+ }
+ OpenLayers.Util.extend(C.prototype, o);
+ }
+};
/**
* APIFunction: extend
@@ -528,12 +299,13 @@
* Returns:
* {Object} The destination object.
*/
+OpenLayers.Util = OpenLayers.Util || {};
OpenLayers.Util.extend = function(destination, source) {
destination = destination || {};
- if(source) {
- for(var property in source) {
+ if (source) {
+ for (var property in source) {
var value = source[property];
- if(value !== undefined) {
+ if (value !== undefined) {
destination[property] = value;
}
}
@@ -553,1720 +325,27 @@
var sourceIsEvt = typeof window.Event == "function"
&& source instanceof window.Event;
- if(!sourceIsEvt
- && source.hasOwnProperty && source.hasOwnProperty('toString')) {
+ if (!sourceIsEvt
+ && source.hasOwnProperty && source.hasOwnProperty("toString")) {
destination.toString = source.toString;
}
}
return destination;
};
-
-
-/**
- * Function: removeItem
- * Remove an object from an array. Iterates through the array
- * to find the item, then removes it.
- *
- * Parameters:
- * array - {Array}
- * item - {Object}
- *
- * Return
- * {Array} A reference to the array
- */
-OpenLayers.Util.removeItem = function(array, item) {
- for(var i = array.length - 1; i >= 0; i--) {
- if(array[i] == item) {
- array.splice(i,1);
- //break;more than once??
- }
- }
- return array;
-};
-
-/**
- * Function: clearArray
- * *Deprecated*. This function will disappear in 3.0.
- * Please use "array.length = 0" instead.
- *
- * Parameters:
- * array - {Array}
- */
-OpenLayers.Util.clearArray = function(array) {
- OpenLayers.Console.warn(
- OpenLayers.i18n(
- "methodDeprecated", {'newMethod': 'array = []'}
- )
- );
- array.length = 0;
-};
-
-/**
- * Function: indexOf
- * Seems to exist already in FF, but not in MOZ.
- *
- * Parameters:
- * array - {Array}
- * obj - {Object}
- *
- * 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;
- }
-};
-
-
-
-/**
- * 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:
- * id - {String} The element id attribute to set.
- * px - {<OpenLayers.Pixel>} The left and top style position.
- * sz - {<OpenLayers.Size>} The width and height style attributes.
- * 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;
- }
- 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.
- * px - {<OpenLayers.Pixel>} The element left and top position.
- * sz - {<OpenLayers.Size>} The element width and height.
- * 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 - {<OpenLayers.Pixel>} The left and top positions.
- * sz - {<OpenLayers.Size>} The style.width and style.height values.
- * 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";
- OpenLayers.Event.observe(image, "load",
- OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, image));
- OpenLayers.Event.observe(image, "error",
- OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, image));
-
- }
-
- //set special properties
- image.style.alt = id;
- image.galleryImg = "no";
- if (imgURL) {
- image.src = imgURL;
- }
-
-
-
- return image;
-};
-
-/**
- * Function: setOpacity
- * *Deprecated*. This function has been deprecated. Instead, please use
- * <OpenLayers.Util.modifyDOMElement>
- * or
- * <OpenLayers.Util.modifyAlphaImageDiv>
- *
- * Set the opacity of a DOM Element
- * Note that for this function to work in IE, elements must "have layout"
- * according to:
- * http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp
- *
- * Parameters:
- * element - {DOMElement} Set the opacity on this DOM element
- * opacity - {Float} Opacity value (0.0 - 1.0)
- */
-OpenLayers.Util.setOpacity = function(element, opacity) {
- OpenLayers.Util.modifyDOMElement(element, null, null, null,
- null, null, null, opacity);
-};
-
-/**
- * Function: onImageLoad
- * Bound to image load events. For all images created with <createImage> or
- * <createAlphaImageDiv>, this function will be bound to the load event.
- */
-OpenLayers.Util.onImageLoad = function() {
- // The complex check here is to solve issues described in #480.
- // Every time a map view changes, it increments the 'viewRequestID'
- // property. As the requests for the images for the new map view are sent
- // out, they are tagged with this unique viewRequestID.
- //
- // If an image has no viewRequestID property set, we display it regardless,
- // but if it does have a viewRequestID property, we check that it matches
- // the viewRequestID set on the map.
- //
- // If the viewRequestID on the map has changed, that means that the user
- // has changed the map view since this specific request was sent out, and
- // therefore this tile does not need to be displayed (so we do not execute
- // this code that turns its display on).
- //
- if (!this.viewRequestID ||
- (this.map && this.viewRequestID == this.map.viewRequestID)) {
- this.style.display = "";
- }
- OpenLayers.Element.removeClass(this, "olImageLoadError");
-};
-
-/**
- * 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;
-
-/**
- * Function: onImageLoadError
- */
-OpenLayers.Util.onImageLoadError = function() {
- this._attempts = (this._attempts) ? (this._attempts + 1) : 1;
- if (this._attempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
- var urls = this.urls;
- if (urls && urls instanceof Array && urls.length > 1){
- var src = this.src.toString();
- var current_url, k;
- for (k = 0; current_url = urls[k]; k++){
- if(src.indexOf(current_url) != -1){
- break;
- }
- }
- var guess = Math.floor(urls.length * Math.random());
- var new_url = urls[guess];
- k = 0;
- while(new_url == current_url && k++ < 4){
- guess = Math.floor(urls.length * Math.random());
- new_url = urls[guess];
- }
- this.src = src.replace(current_url, new_url);
- } else {
- this.src = this.src;
- }
- } else {
- OpenLayers.Element.addClass(this, "olImageLoadError");
- }
- this.style.display = "";
-};
-
-/**
- * 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
- *
- * div - {DOMElement} Div containing Alpha-adjusted Image
- * id - {String}
- * px - {<OpenLayers.Pixel>}
- * sz - {<OpenLayers.Size>}
- * 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
- *
- * id - {String}
- * px - {<OpenLayers.Pixel>}
- * sz - {<OpenLayers.Size>}
- * 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, false);
- div.appendChild(img);
-
- if (delayDisplay) {
- img.style.display = "none";
- OpenLayers.Event.observe(img, "load",
- OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, div));
- OpenLayers.Event.observe(img, "error",
- OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, div));
- }
-
- 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. <i>"key1=value1&key2=value2&key3=value3"</i>)
- * 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<len; itemIndex++) {
- item = value[itemIndex];
- encodedItemArray.push(encodeURIComponent(
- (item === null || item === undefined) ? "" : item)
- );
- }
- encodedValue = encodedItemArray.join(",");
- }
- else {
- /* value is a string; simply encode */
- encodedValue = encodeURIComponent(value);
- }
- paramsArray.push(encodeURIComponent(key) + "=" + encodedValue);
- }
- }
-
- return paramsArray.join("&");
-};
-
-/**
- * Function: urlAppend
- * Appends a parameter string to a url. This function includes the logic for
- * using the appropriate character (none, & or ?) to append to the url before
- * appending the param string.
- *
- * Parameters:
- * url - {String} The url to append to
- * paramStr - {String} The param string to append
- *
- * Returns:
- * {String} The new url
- */
-OpenLayers.Util.urlAppend = function(url, paramStr) {
- var newUrl = url;
- if(paramStr) {
- var parts = (url + " ").split(/[?&]/);
- newUrl += (parts.pop() === " " ?
- paramStr :
- parts.length ? "&" + paramStr : "?" + paramStr);
- }
- return newUrl;
-};
-
-/**
- * Property: ImgPath
- * {String} Default is ''.
- */
-OpenLayers.ImgPath = '';
-
-/**
- * Function: getImagesLocation
- *
- * Returns:
- * {String} The fully formatted image location string
- */
-OpenLayers.Util.getImagesLocation = function() {
- return OpenLayers.ImgPath || (OpenLayers._getScriptLocation() + "img/");
-};
-
-
-/**
- * Function: Try
- * Execute functions until one of them doesn't throw an error.
- * Capitalized because "try" is a reserved word in JavaScript.
- * Taken directly from OpenLayers.Util.Try()
- *
- * Parameters:
- * [*] - {Function} Any number of parameters may be passed to Try()
- * It will attempt to execute each of them until one of them
- * successfully executes.
- * If none executes successfully, returns null.
- *
- * Returns:
- * {*} The value returned by the first successfully executed function.
- */
-OpenLayers.Util.Try = function() {
- var returnValue = null;
-
- for (var i=0, len=arguments.length; i<len; i++) {
- var lambda = arguments[i];
- try {
- returnValue = lambda();
- break;
- } catch (e) {}
- }
-
- return returnValue;
-};
-
-
-/**
- * Function: getNodes
- *
- * These could/should be made namespace aware?
- *
- * Parameters:
- * p - {}
- * tagName - {String}
- *
- * Returns:
- * {Array}
- */
-OpenLayers.Util.getNodes=function(p, tagName) {
- var nodes = OpenLayers.Util.Try(
- function () {
- return OpenLayers.Util._getNodes(p.documentElement.childNodes,
- tagName);
- },
- function () {
- return OpenLayers.Util._getNodes(p.childNodes, tagName);
- }
- );
- return nodes;
-};
-
-/**
- * Function: _getNodes
- *
- * Parameters:
- * nodes - {Array}
- * tagName - {String}
- *
- * Returns:
- * {Array}
- */
-OpenLayers.Util._getNodes=function(nodes, tagName) {
- var retArray = [];
- for (var i=0, len=nodes.length; i<len; i++) {
- if (nodes[i].nodeName==tagName) {
- retArray.push(nodes[i]);
- }
- }
-
- return retArray;
-};
-
-
-
-/**
- * Function: getTagText
- *
- * Parameters:
- * parent - {}
- * item - {String}
- * index - {Integer}
- *
- * Returns:
- * {String}
- */
-OpenLayers.Util.getTagText = function (parent, item, index) {
- var result = OpenLayers.Util.getNodes(parent, item);
- if (result && (result.length > 0))
- {
- if (!index) {
- index=0;
- }
- if (result[index].childNodes.length > 1) {
- return result.childNodes[1].nodeValue;
- }
- else if (result[index].childNodes.length == 1) {
- return result[index].firstChild.nodeValue;
- }
- } else {
- return "";
- }
-};
-
-/**
- * Function: getXmlNodeValue
- *
- * Parameters:
- * node - {XMLNode}
- *
- * Returns:
- * {String} The text value of the given node, without breaking in firefox or IE
- */
-OpenLayers.Util.getXmlNodeValue = function(node) {
- var val = null;
- OpenLayers.Util.Try(
- function() {
- val = node.text;
- if (!val) {
- val = node.textContent;
- }
- if (!val) {
- val = node.firstChild.nodeValue;
- }
- },
- function() {
- val = node.textContent;
- });
- return val;
-};
-
-/**
- * Function: mouseLeft
- *
- * Parameters:
- * evt - {Event}
- * div - {HTMLDivElement}
- *
- * Returns:
- * {Boolean}
- */
-OpenLayers.Util.mouseLeft = function (evt, div) {
- // start with the element to which the mouse has moved
- var target = (evt.relatedTarget) ? evt.relatedTarget : evt.toElement;
- // walk up the DOM tree.
- while (target != div && target != null) {
- target = target.parentNode;
- }
- // if the target we stop at isn't the div, then we've left the div.
- return (target != div);
-};
-
-/**
- * Property: precision
- * {Number} The number of significant digits to retain to avoid
- * floating point precision errors.
- *
- * We use 14 as a "safe" default because, although IEEE 754 double floats
- * (standard on most modern operating systems) support up to about 16
- * significant digits, 14 significant digits are sufficient to represent
- * sub-millimeter accuracy in any coordinate system that anyone is likely to
- * use with OpenLayers.
- *
- * If DEFAULT_PRECISION is set to 0, the original non-truncating behavior
- * of OpenLayers <2.8 is preserved. Be aware that this will cause problems
- * with certain projections, e.g. spherical Mercator.
- *
- */
-OpenLayers.Util.DEFAULT_PRECISION = 14;
-
-/**
- * Function: toFloat
- * Convenience method to cast an object to a Number, rounded to the
- * desired floating point precision.
- *
- * Parameters:
- * number - {Number} The number to cast and round.
- * precision - {Number} An integer suitable for use with
- * Number.toPrecision(). Defaults to OpenLayers.Util.DEFAULT_PRECISION.
- * If set to 0, no rounding is performed.
- *
- * Returns:
- * {Number} The cast, rounded number.
- */
-OpenLayers.Util.toFloat = function (number, precision) {
- if (precision == null) {
- precision = OpenLayers.Util.DEFAULT_PRECISION;
- }
- var number;
- if (precision == 0) {
- number = parseFloat(number);
- } else {
- number = parseFloat(parseFloat(number).toPrecision(precision));
- }
- return number;
-};
-
-/**
- * Function: rad
- *
- * Parameters:
- * x - {Float}
- *
- * Returns:
- * {Float}
- */
-OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
-
-/**
- * Function: deg
- *
- * Parameters:
- * x - {Float}
- *
- * Returns:
- * {Float}
- */
-OpenLayers.Util.deg = function(x) {return x*180/Math.PI;};
-
-/**
- * Property: VincentyConstants
- * {Object} Constants for Vincenty functions.
- */
-OpenLayers.Util.VincentyConstants = {
- a: 6378137,
- b: 6356752.3142,
- f: 1/298.257223563
-};
-
-/**
- * APIFunction: distVincenty
- * Given two objects representing points with geographic coordinates, this
- * calculates the distance between those points on the surface of an
- * ellipsoid.
- *
- * Parameters:
- * p1 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
- * p2 - {<OpenLayers.LonLat>} (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 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon
- * properties) The start point.
- * brng - {Float} The bearing (degrees).
- * distance - {Float} The ground distance (meters).
- *
- * Returns:
- * {<OpenLayers.LonLat>} 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 null, query string is taken from page location.
- *
- * Returns:
- * {Object} An object of key/value pairs from the query string.
- */
-OpenLayers.Util.getParameters = function(url) {
- // if no url specified, take it from the location bar
- url = url || window.location.href;
-
- //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<len; ++i) {
- var keyValue = pairs[i].split('=');
- if (keyValue[0]) {
- var key = decodeURIComponent(keyValue[0]);
- var value = keyValue[1] || ''; //empty string if no value
-
- //decode individual values (being liberal by replacing "+" with " ")
- value = decodeURIComponent(value.replace(/\+/g, " ")).split(",");
-
- //if there's only one value, do not return as array
- if (value.length == 1) {
- value = value[0];
- }
-
- parameters[key] = value;
- }
- }
- return parameters;
-};
-
-/**
- * Function: getArgs
- * *Deprecated*. Will be removed in 3.0. Please use instead
- * <OpenLayers.Util.getParameters>
- *
- * Parameters:
- * url - {String} Optional url used to extract the query string.
- * If null, query string is taken from page location.
- *
- * Returns:
- * {Object} An object of key/value pairs from the query string.
- */
-OpenLayers.Util.getArgs = function(url) {
- OpenLayers.Console.warn(
- OpenLayers.i18n(
- "methodDeprecated", {'newMethod': 'OpenLayers.Util.getParameters'}
- )
- );
- return OpenLayers.Util.getParameters(url);
-};
-
-/**
- * Property: lastSeqID
- * {Integer} The ever-incrementing count variable.
- * Used for generating unique ids.
- */
-OpenLayers.Util.lastSeqID = 0;
-
-/**
- * Function: createUniqueID
- * Create a unique identifier for this session. Each time this function
- * is called, a counter is incremented. The return will be the optional
- * prefix (defaults to "id_") appended with the counter value.
- *
- * Parameters:
- * prefix {String} Optionsal string to prefix unique id. Default is "id_".
- *
- * Returns:
- * {String} A unique id string, built on the passed in prefix.
- */
-OpenLayers.Util.createUniqueID = function(prefix) {
- if (prefix == null) {
- prefix = "id_";
- }
- OpenLayers.Util.lastSeqID += 1;
- return prefix + OpenLayers.Util.lastSeqID;
-};
-
-/**
- * Constant: INCHES_PER_UNIT
- * {Object} Constant inches per unit -- borrowed from MapServer mapscale.c
- * derivation of nautical miles from http://en.wikipedia.org/wiki/Nautical_mile
- * Includes the full set of units supported by CS-MAP (http://trac.osgeo.org/csmap/)
- * and PROJ.4 (http://trac.osgeo.org/proj/)
- * The hardcoded table is maintain in a CS-MAP source code module named CSdataU.c
- * The hardcoded table of PROJ.4 units are in pj_units.c.
- */
-OpenLayers.INCHES_PER_UNIT = {
- 'inches': 1.0,
- 'ft': 12.0,
- 'mi': 63360.0,
- 'm': 39.3701,
- 'km': 39370.1,
- 'dd': 4374754,
- 'yd': 36
-};
-OpenLayers.INCHES_PER_UNIT["in"]= OpenLayers.INCHES_PER_UNIT.inches;
-OpenLayers.INCHES_PER_UNIT["degrees"] = OpenLayers.INCHES_PER_UNIT.dd;
-OpenLayers.INCHES_PER_UNIT["nmi"] = 1852 * OpenLayers.INCHES_PER_UNIT.m;
-
-// Units from CS-Map
-OpenLayers.METERS_PER_INCH = 0.02540005080010160020;
-OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, {
- "Inch": OpenLayers.INCHES_PER_UNIT.inches,
- "Meter": 1.0 / OpenLayers.METERS_PER_INCH, //EPSG:9001
- "Foot": 0.30480060960121920243 / OpenLayers.METERS_PER_INCH, //EPSG:9003
- "IFoot": 0.30480000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9002
- "ClarkeFoot": 0.3047972651151 / OpenLayers.METERS_PER_INCH, //EPSG:9005
- "SearsFoot": 0.30479947153867624624 / OpenLayers.METERS_PER_INCH, //EPSG:9041
- "GoldCoastFoot": 0.30479971018150881758 / OpenLayers.METERS_PER_INCH, //EPSG:9094
- "IInch": 0.02540000000000000000 / OpenLayers.METERS_PER_INCH,
- "MicroInch": 0.00002540000000000000 / OpenLayers.METERS_PER_INCH,
- "Mil": 0.00000002540000000000 / OpenLayers.METERS_PER_INCH,
- "Centimeter": 0.01000000000000000000 / OpenLayers.METERS_PER_INCH,
- "Kilometer": 1000.00000000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9036
- "Yard": 0.91440182880365760731 / OpenLayers.METERS_PER_INCH,
- "SearsYard": 0.914398414616029 / OpenLayers.METERS_PER_INCH, //EPSG:9040
- "IndianYard": 0.91439853074444079983 / OpenLayers.METERS_PER_INCH, //EPSG:9084
- "IndianYd37": 0.91439523 / OpenLayers.METERS_PER_INCH, //EPSG:9085
- "IndianYd62": 0.9143988 / OpenLayers.METERS_PER_INCH, //EPSG:9086
- "IndianYd75": 0.9143985 / OpenLayers.METERS_PER_INCH, //EPSG:9087
- "IndianFoot": 0.30479951 / OpenLayers.METERS_PER_INCH, //EPSG:9080
- "IndianFt37": 0.30479841 / OpenLayers.METERS_PER_INCH, //EPSG:9081
- "IndianFt62": 0.3047996 / OpenLayers.METERS_PER_INCH, //EPSG:9082
- "IndianFt75": 0.3047995 / OpenLayers.METERS_PER_INCH, //EPSG:9083
- "Mile": 1609.34721869443738887477 / OpenLayers.METERS_PER_INCH,
- "IYard": 0.91440000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9096
- "IMile": 1609.34400000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9093
- "NautM": 1852.00000000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9030
- "Lat-66": 110943.316488932731 / OpenLayers.METERS_PER_INCH,
- "Lat-83": 110946.25736872234125 / OpenLayers.METERS_PER_INCH,
- "Decimeter": 0.10000000000000000000 / OpenLayers.METERS_PER_INCH,
- "Millimeter": 0.00100000000000000000 / OpenLayers.METERS_PER_INCH,
- "Dekameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH,
- "Decameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH,
- "Hectometer": 100.00000000000000000000 / OpenLayers.METERS_PER_INCH,
- "GermanMeter": 1.0000135965 / OpenLayers.METERS_PER_INCH, //EPSG:9031
- "CaGrid": 0.999738 / OpenLayers.METERS_PER_INCH,
- "ClarkeChain": 20.1166194976 / OpenLayers.METERS_PER_INCH, //EPSG:9038
- "GunterChain": 20.11684023368047 / OpenLayers.METERS_PER_INCH, //EPSG:9033
- "BenoitChain": 20.116782494375872 / OpenLayers.METERS_PER_INCH, //EPSG:9062
- "SearsChain": 20.11676512155 / OpenLayers.METERS_PER_INCH, //EPSG:9042
- "ClarkeLink": 0.201166194976 / OpenLayers.METERS_PER_INCH, //EPSG:9039
- "GunterLink": 0.2011684023368047 / OpenLayers.METERS_PER_INCH, //EPSG:9034
- "BenoitLink": 0.20116782494375872 / OpenLayers.METERS_PER_INCH, //EPSG:9063
- "SearsLink": 0.2011676512155 / OpenLayers.METERS_PER_INCH, //EPSG:9043
- "Rod": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
- "IntnlChain": 20.1168 / OpenLayers.METERS_PER_INCH, //EPSG:9097
- "IntnlLink": 0.201168 / OpenLayers.METERS_PER_INCH, //EPSG:9098
- "Perch": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
- "Pole": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
- "Furlong": 201.1684023368046 / OpenLayers.METERS_PER_INCH,
- "Rood": 3.778266898 / OpenLayers.METERS_PER_INCH,
- "CapeFoot": 0.3047972615 / OpenLayers.METERS_PER_INCH,
- "Brealey": 375.00000000000000000000 / OpenLayers.METERS_PER_INCH,
- "ModAmFt": 0.304812252984505969011938 / OpenLayers.METERS_PER_INCH,
- "Fathom": 1.8288 / OpenLayers.METERS_PER_INCH,
- "NautM-UK": 1853.184 / OpenLayers.METERS_PER_INCH,
- "50kilometers": 50000.0 / OpenLayers.METERS_PER_INCH,
- "150kilometers": 150000.0 / OpenLayers.METERS_PER_INCH
-});
-
-//unit abbreviations supported by PROJ.4
-OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, {
- "mm": OpenLayers.INCHES_PER_UNIT["Meter"] / 1000.0,
- "cm": OpenLayers.INCHES_PER_UNIT["Meter"] / 100.0,
- "dm": OpenLayers.INCHES_PER_UNIT["Meter"] * 100.0,
- "km": OpenLayers.INCHES_PER_UNIT["Meter"] * 1000.0,
- "kmi": OpenLayers.INCHES_PER_UNIT["nmi"], //International Nautical Mile
- "fath": OpenLayers.INCHES_PER_UNIT["Fathom"], //International Fathom
- "ch": OpenLayers.INCHES_PER_UNIT["IntnlChain"], //International Chain
- "link": OpenLayers.INCHES_PER_UNIT["IntnlLink"], //International Link
- "us-in": OpenLayers.INCHES_PER_UNIT["inches"], //U.S. Surveyor's Inch
- "us-ft": OpenLayers.INCHES_PER_UNIT["Foot"], //U.S. Surveyor's Foot
- "us-yd": OpenLayers.INCHES_PER_UNIT["Yard"], //U.S. Surveyor's Yard
- "us-ch": OpenLayers.INCHES_PER_UNIT["GunterChain"], //U.S. Surveyor's Chain
- "us-mi": OpenLayers.INCHES_PER_UNIT["Mile"], //U.S. Surveyor's Statute Mile
- "ind-yd": OpenLayers.INCHES_PER_UNIT["IndianYd37"], //Indian Yard
- "ind-ft": OpenLayers.INCHES_PER_UNIT["IndianFt37"], //Indian Foot
- "ind-ch": 20.11669506 / OpenLayers.METERS_PER_INCH //Indian Chain
-});
-
-/**
- * Constant: DOTS_PER_INCH
- * {Integer} 72 (A sensible default)
- */
-OpenLayers.DOTS_PER_INCH = 72;
-
-/**
- * Function: normalizeScale
- *
- * Parameters:
- * scale - {float}
- *
- * Returns:
- * {Float} A normalized scale value, in 1 / X format.
- * This means that if a value less than one ( already 1/x) is passed
- * in, it just returns scale directly. Otherwise, it returns
- * 1 / scale
- */
-OpenLayers.Util.normalizeScale = function (scale) {
- var normScale = (scale > 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: safeStopPropagation
- * *Deprecated*. This function has been deprecated. Please use directly
- * <OpenLayers.Event.stop> passing 'true' as the 2nd
- * argument (preventDefault)
- *
- * Safely stop the propagation of an event *without* preventing
- * the default browser action from occurring.
- *
- * Parameter:
- * evt - {Event}
- */
-OpenLayers.Util.safeStopPropagation = function(evt) {
- OpenLayers.Event.stop(evt, true);
-};
-
-/**
- * Function: pagePositon
- * Calculates the position of an element on the page.
- *
- * Parameters:
- * forElement - {DOMElement}
- *
- * Returns:
- * {Array} two item array, L value then T value.
- */
-OpenLayers.Util.pagePosition = function(forElement) {
- var valueT = 0, valueL = 0;
-
- var element = forElement;
- var child = forElement;
- while(element) {
-
- if(element == document.body) {
- if(OpenLayers.Element.getStyle(child, 'position') == 'absolute') {
- break;
- }
- }
-
- valueT += element.offsetTop || 0;
- valueL += element.offsetLeft || 0;
-
- child = element;
- try {
- // wrapping this in a try/catch because IE chokes on the offsetParent
- element = element.offsetParent;
- } catch(e) {
- OpenLayers.Console.error(OpenLayers.i18n(
- "pagePositionFailed",{'elemId':element.id}));
- break;
- }
- }
-
- element = forElement;
- while(element) {
- valueT -= element.scrollTop || 0;
- valueL -= element.scrollLeft || 0;
- element = element.parentNode;
- }
-
- return [valueL, valueT];
-};
-
-
-/**
- * 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
- });
-
- 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. Can be one of:
- * ignoreCase: lowercase url,
- * ignorePort80: don't include explicit port if port is 80,
- * ignoreHash: Don't include part of url after the hash (#).
- *
- * 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);
-
- //pathname (uniform browser behavior with 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;
-};
-
-
-/**
- * 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() {
- var browserName = "";
-
- var ua = navigator.userAgent.toLowerCase();
- if ( ua.indexOf( "opera" ) != -1 ) {
- browserName = "opera";
- } else if ( ua.indexOf( "msie" ) != -1 ) {
- browserName = "msie";
- } else if ( ua.indexOf( "safari" ) != -1 ) {
- browserName = "safari";
- } else if ( ua.indexOf( "mozilla" ) != -1 ) {
- if ( ua.indexOf( "firefox" ) != -1 ) {
- browserName = "firefox";
- } else {
- browserName = "mozilla";
- }
- }
-
- return browserName;
-};
-
-
-
-
-/**
- * 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 - {<OpenLayers.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}
- * 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.Size}
- */
-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;
-
- //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<l; i++) {
- if (!content.childNodes[i].style) continue;
- content.childNodes[i].style.overflow = "visible";
- }
- }
-
- // add content to restricted container
- container.appendChild(content);
-
- // append container to body for rendering
- containerElement.appendChild(container);
-
- // Opera and IE7 can't handle a node with position:aboslute if it inherits
- // position:absolute from a parent.
- var parentHasPositionAbsolute = false;
- var parent = container.parentNode;
- 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) {
- container.style.position = "absolute";
- }
-
- // calculate scroll width of content and add corners and shadow width
- if (!w) {
- w = parseInt(content.scrollWidth);
-
- // update container width to allow height to adjust
- container.style.width = w + "px";
- }
- // capture height and add shadow and corner image widths
- if (!h) {
- h = parseInt(content.scrollHeight);
- }
-
- // remove elements
- container.removeChild(content);
- containerElement.removeChild(container);
-
- return new OpenLayers.Size(w, h);
-};
-
-/**
- * APIFunction: getScrollbarWidth
- * This function has been modified by the OpenLayers from the original version,
- * written by Matthew Eernisse and released under the Apache 2
- * license here:
- *
- * http://www.fleegix.org/articles/2006/05/30/getting-the-scrollbar-width-in-pixels
- *
- * It has been modified simply to cache its value, since it is physically
- * impossible that this code could ever run in more than one browser at
- * once.
- *
- * Returns:
- * {Integer}
- */
-OpenLayers.Util.getScrollbarWidth = function() {
-
- var scrollbarWidth = OpenLayers.Util._scrollbarWidth;
-
- if (scrollbarWidth == null) {
- var scr = null;
- var inn = null;
- var wNoScroll = 0;
- var wScroll = 0;
-
- // Outer scrolling div
- scr = document.createElement('div');
- scr.style.position = 'absolute';
- scr.style.top = '-1000px';
- scr.style.left = '-1000px';
- scr.style.width = '100px';
- scr.style.height = '50px';
- // Start with no scrollbar
- scr.style.overflow = 'hidden';
-
- // Inner content div
- inn = document.createElement('div');
- inn.style.width = '100%';
- inn.style.height = '200px';
-
- // Put the inner div in the scrolling div
- scr.appendChild(inn);
- // Append the scrolling div to the doc
- document.body.appendChild(scr);
-
- // Width of the inner div sans scrollbar
- wNoScroll = inn.offsetWidth;
-
- // Add the scrollbar
- scr.style.overflow = 'scroll';
- // Width of the inner div width scrollbar
- wScroll = inn.offsetWidth;
-
- // Remove the scrolling div from the doc
- document.body.removeChild(document.body.lastChild);
-
- // Pixel width of the scroller
- OpenLayers.Util._scrollbarWidth = (wNoScroll - wScroll);
- scrollbarWidth = OpenLayers.Util._scrollbarWidth;
- }
-
- return scrollbarWidth;
-};
-
-/**
- * APIFunction: getFormattedLonLat
- * This function will return latitude or longitude value formatted as
- *
- * Parameters:
- * coordinate - {Float} the coordinate value to be formatted
- * axis - {String} value of either 'lat' or 'lon' to indicate which axis is to
- * to be formatted (default = lat)
- * dmsOption - {String} specify the precision of the output can be one of:
- * 'dms' show degrees minutes and seconds
- * 'dm' show only degrees and minutes
- * 'd' show only degrees
- *
- * Returns:
- * {String} the coordinate value formatted as a string
- */
-OpenLayers.Util.getFormattedLonLat = function(coordinate, axis, dmsOption) {
- if (!dmsOption) {
- dmsOption = 'dms'; //default to show degree, minutes, seconds
- }
- var abscoordinate = Math.abs(coordinate)
- var coordinatedegrees = Math.floor(abscoordinate);
-
- var coordinateminutes = (abscoordinate - coordinatedegrees)/(1/60);
- var tempcoordinateminutes = coordinateminutes;
- coordinateminutes = Math.floor(coordinateminutes);
- var coordinateseconds = (tempcoordinateminutes - coordinateminutes)/(1/60);
- coordinateseconds = Math.round(coordinateseconds*10);
- coordinateseconds /= 10;
-
- 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/Console.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt 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,
@@ -2508,22 +587,154 @@
}
})();
/* ======================================================================
+ OpenLayers/Lang.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/BaseTypes.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Namespace: OpenLayers.Lang
+ * Internationalization namespace. Contains dictionaries in various languages
+ * and methods to set and get the current language.
+ */
+OpenLayers.Lang = {
+
+ /**
+ * Property: code
+ * {String} Current language code to use in OpenLayers. Use the
+ * <setCode> method to set this value and the <getCode> 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:
+ * 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 <OpenLayers.Lang.translate> 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 <OpenLayers.Lang>
+ * dictionary exists for the code, the <OpenLayers.String.defaultLang>
+ * 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 <getCode> will be used to determine the appropriate
+ * dictionary. Dictionaries are stored in <OpenLayers.Lang>.
+ *
+ * Parameters:
+ * key - {String} The key for an i18n string value in the dictionary.
+ * context - {Object} Optional context to be used with
+ * <OpenLayers.String.format>.
+ *
+ * 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 <OpenLayers.Lang.translate>. Looks up a key from a dictionary
+ * based on the current language string. The value of
+ * <OpenLayers.Lang.getCode> will be used to determine the appropriate
+ * dictionary. Dictionaries are stored in <OpenLayers.Lang>.
+ *
+ * Parameters:
+ * key - {String} The key for an i18n string value in the dictionary.
+ * context - {Object} Optional context to be used with
+ * <OpenLayers.String.format>.
+ *
+ * Returns:
+ * {String} A internationalized string.
+ */
+OpenLayers.i18n = OpenLayers.Lang.translate;
+/* ======================================================================
OpenLayers/BaseTypes.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
- * @requires OpenLayers/BaseTypes/Class.js
- * @requires OpenLayers/BaseTypes/LonLat.js
- * @requires OpenLayers/BaseTypes/Size.js
- * @requires OpenLayers/BaseTypes/Pixel.js
- * @requires OpenLayers/BaseTypes/Bounds.js
- * @requires OpenLayers/BaseTypes/Element.js
- * @requires OpenLayers/Lang/en.js
+ * @requires OpenLayers/Lang.js
* @requires OpenLayers/Console.js
*/
@@ -3106,7 +1317,7 @@
if ("toISOString" in Date.prototype) {
return function(date) {
return date.toISOString();
- }
+ };
} else {
function pad(num, len) {
var str = num + "";
@@ -3132,7 +1343,7 @@
pad(date.getUTCMilliseconds(), 3) + "Z";
}
return str;
- }
+ };
}
})(),
@@ -3162,7 +1373,6 @@
date = new Date(elapsed);
} else {
var match = str.match(/^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{1,2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|(?:[+-]\d{1,2}(?::(\d{2}))?)))?$/);
- var date;
if (match && (match[1] || match[7])) { // must have at least year or time
var year = parseInt(match[1], 10) || 0;
var month = (parseInt(match[2], 10) - 1) || 0;
@@ -3180,7 +1390,7 @@
// check offset
if (type !== "Z") {
var hoursOffset = parseInt(type, 10);
- var minutesOffset = parseInt(match[8]) || 0;
+ var minutesOffset = parseInt(match[8], 10) || 0;
var offset = -1000 * (60 * (hoursOffset * 60) + minutesOffset * 60);
date = new Date(date.getTime() + offset);
}
@@ -3194,225 +1404,18 @@
};
/* ======================================================================
- OpenLayers/BaseTypes/Class.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * 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:
- * > var MyClass = OpenLayers.Class(prototype);
- *
- * To create a new OpenLayers-style class with multiple inheritance, use the
- * following syntax:
- * > var MyClass = OpenLayers.Class(Class1, Class2, prototype);
- * Note that instanceof reflection will only reveil Class1 as superclass.
- * Class2 ff are mixins.
- *
- */
-OpenLayers.Class = function() {
- var Class = function() {
- /**
- * This following condition can be removed at 3.0 - this is only for
- * backwards compatibility while the Class.inherit method is still
- * in use. So at 3.0, the following three lines would be replaced with
- * simply:
- * this.initialize.apply(this, arguments);
- */
- if (arguments && arguments[0] != OpenLayers.Class.isPrototype) {
- this.initialize.apply(this, arguments);
- }
- };
- var extended = {};
- var parent, initialize, Type;
- for(var i=0, len=arguments.length; i<len; ++i) {
- Type = arguments[i];
- if(typeof Type == "function") {
- // make the class passed as the first argument the superclass
- if(i == 0 && len > 1) {
- initialize = Type.prototype.initialize;
- // replace the initialize method with an empty function,
- // because we do not want to create a real instance here
- Type.prototype.initialize = function() {};
- // the line below makes sure that the new class has a
- // superclass
- extended = new Type();
- // restore the original initialize method
- if(initialize === undefined) {
- delete Type.prototype.initialize;
- } else {
- Type.prototype.initialize = initialize;
- }
- }
- // get the prototype of the superclass
- parent = Type.prototype;
- } else {
- // in this case we're extending with the prototype
- parent = Type;
- }
- OpenLayers.Util.extend(extended, parent);
- }
- Class.prototype = extended;
- return Class;
-};
-
-/**
- * Property: isPrototype
- * *Deprecated*. This is no longer needed and will be removed at 3.0.
- */
-OpenLayers.Class.isPrototype = function () {};
-
-/**
- * APIFunction: OpenLayers.create
- * *Deprecated*. Old method to create an OpenLayers style class. Use the
- * <OpenLayers.Class> constructor instead.
- *
- * Returns:
- * An OpenLayers class
- */
-OpenLayers.Class.create = function() {
- return function() {
- if (arguments && arguments[0] != OpenLayers.Class.isPrototype) {
- this.initialize.apply(this, arguments);
- }
- };
-};
-
-
-/**
- * APIFunction: inherit
- * *Deprecated*. Old method to inherit from one or more OpenLayers style
- * classes. Use the <OpenLayers.Class> constructor instead.
- *
- * Parameters:
- * class - One or more classes can be provided as arguments
- *
- * Returns:
- * An object prototype
- */
-OpenLayers.Class.inherit = function () {
- var superClass = arguments[0];
- var proto = new superClass(OpenLayers.Class.isPrototype);
- for (var i=1, len=arguments.length; i<len; i++) {
- if (typeof arguments[i] == "function") {
- var mixin = arguments[i];
- arguments[i] = new mixin(OpenLayers.Class.isPrototype);
- }
- OpenLayers.Util.extend(proto, arguments[i]);
- }
- return proto;
-};
-/* ======================================================================
- OpenLayers/BaseTypes/Size.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * 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.
- * (ex. <i>"w=55,h=66"</i>)
- */
- toString:function() {
- return ("w=" + this.w + ",h=" + this.h);
- },
-
- /**
- * APIMethod: clone
- * Create a clone of this size object
- *
- * Returns:
- * {<OpenLayers.Size>} 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 - {<OpenLayers.Size>}
- *
- * 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/BaseTypes/Bounds.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
+ * @requires OpenLayers/BaseTypes/Class.js
* @requires OpenLayers/Console.js
+ * @requires OpenLayers/Lang.js
*/
/**
@@ -4021,14 +2024,15 @@
*
* Parameters:
* str - {String}Comma-separated bounds string. (ex. <i>"5,42,10,45"</i>)
+ * reverseAxisOrder - {Boolean} Does the string use reverse axis order?
*
* Returns:
* {<OpenLayers.Bounds>} New bounds object built from the
* passed-in String.
*/
-OpenLayers.Bounds.fromString = function(str) {
+OpenLayers.Bounds.fromString = function(str, reverseAxisOrder) {
var bounds = str.split(",");
- return OpenLayers.Bounds.fromArray(bounds);
+ return OpenLayers.Bounds.fromArray(bounds, reverseAxisOrder);
};
/**
@@ -4038,12 +2042,18 @@
*
* Parameters:
* bbox - {Array(Float)} Array of bounds values (ex. <i>[5,42,10,45]</i>)
+ * reverseAxisOrder - {Boolean} Does the array use reverse axis order?
*
* Returns:
* {<OpenLayers.Bounds>} New bounds object built from the passed-in Array.
*/
-OpenLayers.Bounds.fromArray = function(bbox) {
- return new OpenLayers.Bounds(parseFloat(bbox[0]),
+OpenLayers.Bounds.fromArray = function(bbox, reverseAxisOrder) {
+ return reverseAxisOrder === true ?
+ new OpenLayers.Bounds(parseFloat(bbox[1]),
+ parseFloat(bbox[0]),
+ parseFloat(bbox[3]),
+ parseFloat(bbox[2])) :
+ new OpenLayers.Bounds(parseFloat(bbox[0]),
parseFloat(bbox[1]),
parseFloat(bbox[2]),
parseFloat(bbox[3]));
@@ -4091,12 +2101,17 @@
OpenLayers/BaseTypes/Element.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
+ * @requires OpenLayers/Util.js
+ * @requires OpenLayers/BaseTypes.js
+ */
+
+/**
* Namespace: OpenLayers.Element
*/
OpenLayers.Element = {
@@ -4346,13 +2361,15 @@
OpenLayers/BaseTypes/LonLat.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
+ * @requires OpenLayers/BaseTypes/Class.js
* @requires OpenLayers/Console.js
+ * @requires OpenLayers/Lang.js
*/
/**
@@ -4540,13 +2557,15 @@
OpenLayers/BaseTypes/Pixel.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
+ * @requires OpenLayers/BaseTypes/Class.js
* @requires OpenLayers/Console.js
+ * @requires OpenLayers/Lang.js
*/
/**
@@ -4666,5859 +2685,1985 @@
CLASS_NAME: "OpenLayers.Pixel"
});
/* ======================================================================
- OpenLayers/Icon.js
+ OpenLayers/BaseTypes/Size.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
- * Class: OpenLayers.Icon
- *
- * The icon represents a graphical icon on the screen. Typically used in
- * conjunction with a <OpenLayers.Marker> to represent markers on a screen.
- *
- * An icon has a url, size and position. It also contains an offset which
- * allows the center point to be represented correctly. This can be
- * provided either as a fixed offset or a function provided to calculate
- * the desired offset.
- *
+ * @requires OpenLayers/BaseTypes/Class.js
*/
-OpenLayers.Icon = OpenLayers.Class({
-
- /**
- * Property: url
- * {String} image url
- */
- url: null,
-
- /**
- * Property: size
- * {<OpenLayers.Size>}
- */
- size: null,
- /**
- * Property: offset
- * {<OpenLayers.Pixel>} distance in pixels to offset the image when being rendered
- */
- offset: null,
-
- /**
- * Property: calculateOffset
- * {<OpenLayers.Pixel>} Function to calculate the offset (based on the size)
- */
- calculateOffset: null,
-
- /**
- * Property: imageDiv
- * {DOMElement}
- */
- imageDiv: null,
+/**
+ * Class: OpenLayers.Size
+ * Instances of this class represent a width/height pair
+ */
+OpenLayers.Size = OpenLayers.Class({
- /**
- * Property: px
- * {<OpenLayers.Pixel>}
+ /**
+ * APIProperty: w
+ * {Number} width
*/
- px: null,
+ w: 0.0,
- /**
- * Constructor: OpenLayers.Icon
- * Creates an icon, which is an image tag in a div.
- *
- * url - {String}
- * size - {<OpenLayers.Size>}
- * offset - {<OpenLayers.Pixel>}
- * calculateOffset - {Function}
+ /**
+ * APIProperty: h
+ * {Number} height
*/
- initialize: function(url, size, offset, calculateOffset) {
- this.url = url;
- this.size = (size) ? size : new OpenLayers.Size(20,20);
- this.offset = offset ? offset : new OpenLayers.Pixel(-(this.size.w/2), -(this.size.h/2));
- this.calculateOffset = calculateOffset;
+ h: 0.0,
- var id = OpenLayers.Util.createUniqueID("OL_Icon_");
- this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);
- },
-
- /**
- * Method: destroy
- * Nullify references and remove event listeners to prevent circular
- * references and memory leaks
- */
- destroy: function() {
- // erase any drawn elements
- this.erase();
- OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);
- this.imageDiv.innerHTML = "";
- this.imageDiv = null;
- },
-
- /**
- * Method: clone
- *
- * Returns:
- * {<OpenLayers.Icon>} A fresh copy of the icon.
- */
- clone: function() {
- return new OpenLayers.Icon(this.url,
- this.size,
- this.offset,
- this.calculateOffset);
- },
-
/**
- * Method: setSize
- *
+ * Constructor: OpenLayers.Size
+ * Create an instance of OpenLayers.Size
+ *
* Parameters:
- * size - {<OpenLayers.Size>}
+ * w - {Number} width
+ * h - {Number} height
*/
- setSize: function(size) {
- if (size != null) {
- this.size = size;
- }
- this.draw();
+ initialize: function(w, h) {
+ this.w = parseFloat(w);
+ this.h = parseFloat(h);
},
-
+
/**
- * Method: setUrl
- *
- * Parameters:
- * url - {String}
+ * Method: toString
+ * Return the string representation of a size object
+ *
+ * Returns:
+ * {String} The string representation of OpenLayers.Size object.
+ * (ex. <i>"w=55,h=66"</i>)
*/
- setUrl: function(url) {
- if (url != null) {
- this.url = url;
- }
- this.draw();
+ toString:function() {
+ return ("w=" + this.w + ",h=" + this.h);
},
- /**
- * Method: draw
- * Move the div to the given pixel.
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- *
+ /**
+ * APIMethod: clone
+ * Create a clone of this size object
+ *
* Returns:
- * {DOMElement} A new DOM Image of this icon set at the location passed-in
+ * {<OpenLayers.Size>} A new OpenLayers.Size object with the same w and h
+ * values
*/
- draw: function(px) {
- OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,
- null,
- null,
- this.size,
- this.url,
- "absolute");
- this.moveTo(px);
- return this.imageDiv;
- },
+ clone:function() {
+ return new OpenLayers.Size(this.w, this.h);
+ },
- /**
- * Method: erase
- * Erase the underlying image element.
+ /**
*
- */
- erase: function() {
- if (this.imageDiv != null && this.imageDiv.parentNode != null) {
- OpenLayers.Element.remove(this.imageDiv);
- }
- },
-
- /**
- * Method: setOpacity
- * Change the icon's opacity
+ * APIMethod: equals
+ * Determine where this size is equal to another
*
* Parameters:
- * opacity - {float}
- */
- setOpacity: function(opacity) {
- OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null,
- null, null, null, null, opacity);
-
- },
-
- /**
- * Method: moveTo
- * move icon to passed in px.
+ * sz - {<OpenLayers.Size>}
*
- * Parameters:
- * px - {<OpenLayers.Pixel>}
+ * 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.
+ *
*/
- moveTo: function (px) {
- //if no px passed in, use stored location
- if (px != null) {
- this.px = px;
+ 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)));
}
-
- if (this.imageDiv != null) {
- if (this.px == null) {
- this.display(false);
- } else {
- if (this.calculateOffset) {
- this.offset = this.calculateOffset(this.size);
- }
- var offsetPx = this.px.offset(this.offset);
- OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, offsetPx);
- }
- }
+ return equals;
},
-
- /**
- * Method: display
- * Hide or show the icon
- *
- * Parameters:
- * display - {Boolean}
- */
- display: function(display) {
- this.imageDiv.style.display = (display) ? "" : "none";
- },
-
- /**
- * APIMethod: isDrawn
- *
- * Returns:
- * {Boolean} Whether or not the icon is drawn.
- */
- isDrawn: function() {
- // nodeType 11 for ie, whose nodes *always* have a parentNode
- // (of type document fragment)
- var isDrawn = (this.imageDiv && this.imageDiv.parentNode &&
- (this.imageDiv.parentNode.nodeType != 11));
-
- return isDrawn;
- },
-
- CLASS_NAME: "OpenLayers.Icon"
+ CLASS_NAME: "OpenLayers.Size"
});
/* ======================================================================
- OpenLayers/Popup.js
+ OpenLayers/Util.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt 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/Console.js
+ * @requires OpenLayers/Lang.js
+ */
/**
- * Class: OpenLayers.Popup
- * A popup is a small div that can opened and closed on the map.
- * Typically opened in response to clicking on a marker.
- * See <OpenLayers.Marker>. Popup's don't require their own
- * layer and are added the the map using the <OpenLayers.Map.addPopup>
- * method.
- *
- * Example:
- * (code)
- * popup = new OpenLayers.Popup("chicken",
- * new OpenLayers.LonLat(5,40),
- * new OpenLayers.Size(200,200),
- * "example popup",
- * true);
- *
- * map.addPopup(popup);
- * (end)
+ * Namespace: Util
*/
-OpenLayers.Popup = OpenLayers.Class({
+OpenLayers.Util = OpenLayers.Util || {};
- /**
- * Property: events
- * {<OpenLayers.Events>} custom event manager
- */
- events: null,
-
- /** Property: id
- * {String} the unique identifier assigned to this popup.
- */
- id: "",
+/**
+ * Function: getElement
+ * This is the old $() from prototype
+ */
+OpenLayers.Util.getElement = function() {
+ var elements = [];
- /**
- * Property: lonlat
- * {<OpenLayers.LonLat>} the position of this popup on the map
- */
- lonlat: null,
-
- /**
- * Property: div
- * {DOMElement} the div that contains this popup.
- */
- div: null,
-
- /**
- * Property: contentSize
- * {<OpenLayers.Size>} the width and height of the content.
- */
- contentSize: null,
-
- /**
- * Property: size
- * {<OpenLayers.Size>} the width and height of the popup.
- */
- size: null,
-
- /**
- * Property: contentHTML
- * {String} An HTML string for this popup to display.
- */
- contentHTML: null,
-
- /**
- * Property: backgroundColor
- * {String} the background color used by the popup.
- */
- backgroundColor: "",
-
- /**
- * Property: opacity
- * {float} the opacity of this popup (between 0.0 and 1.0)
- */
- opacity: "",
-
- /**
- * Property: border
- * {String} the border size of the popup. (eg 2px)
- */
- border: "",
-
- /**
- * Property: contentDiv
- * {DOMElement} a reference to the element that holds the content of
- * the div.
- */
- contentDiv: null,
-
- /**
- * Property: groupDiv
- * {DOMElement} First and only child of 'div'. The group Div contains the
- * 'contentDiv' and the 'closeDiv'.
- */
- groupDiv: null,
-
- /**
- * Property: closeDiv
- * {DOMElement} the optional closer image
- */
- closeDiv: null,
-
- /**
- * APIProperty: autoSize
- * {Boolean} Resize the popup to auto-fit the contents.
- * Default is false.
- */
- autoSize: false,
-
- /**
- * APIProperty: minSize
- * {<OpenLayers.Size>} Minimum size allowed for the popup's contents.
- */
- minSize: null,
-
- /**
- * APIProperty: maxSize
- * {<OpenLayers.Size>} Maximum size allowed for the popup's contents.
- */
- maxSize: null,
-
- /**
- * Property: displayClass
- * {String} The CSS class of the popup.
- */
- displayClass: "olPopup",
-
- /**
- * Property: contentDisplayClass
- * {String} The CSS class of the popup content div.
- */
- contentDisplayClass: "olPopupContent",
-
- /**
- * Property: padding
- * {int or <OpenLayers.Bounds>} An extra opportunity to specify internal
- * padding of the content div inside the popup. This was originally
- * confused with the css padding as specified in style.css's
- * 'olPopupContent' class. We would like to get rid of this altogether,
- * except that it does come in handy for the framed and anchoredbubble
- * popups, who need to maintain yet another barrier between their
- * content and the outer border of the popup itself.
- *
- * Note that in order to not break API, we must continue to support
- * this property being set as an integer. Really, though, we'd like to
- * have this specified as a Bounds object so that user can specify
- * distinct left, top, right, bottom paddings. With the 3.0 release
- * we can make this only a bounds.
- */
- padding: 0,
-
- /**
- * Property: disableFirefoxOverflowHack
- * {Boolean} The hack for overflow in Firefox causes all elements
- * to be re-drawn, which causes Flash elements to be
- * re-initialized, which is troublesome.
- * With this property the hack can be disabled.
- */
- disableFirefoxOverflowHack: false,
-
- /**
- * Method: fixPadding
- * To be removed in 3.0, this function merely helps us to deal with the
- * case where the user may have set an integer value for padding,
- * instead of an <OpenLayers.Bounds> object.
- */
- fixPadding: function() {
- if (typeof this.padding == "number") {
- this.padding = new OpenLayers.Bounds(
- this.padding, this.padding, this.padding, this.padding
- );
+ for (var i=0, len=arguments.length; i<len; i++) {
+ var element = arguments[i];
+ if (typeof element == 'string') {
+ element = document.getElementById(element);
}
- },
-
- /**
- * APIProperty: panMapIfOutOfView
- * {Boolean} When drawn, pan map such that the entire popup is visible in
- * the current viewport (if necessary).
- * Default is false.
- */
- panMapIfOutOfView: false,
-
- /**
- * APIProperty: keepInMap
- * {Boolean} If panMapIfOutOfView is false, and this property is true,
- * contrain the popup such that it always fits in the available map
- * space. By default, this is not set on the base class. If you are
- * creating popups that are near map edges and not allowing pannning,
- * and especially if you have a popup which has a
- * fixedRelativePosition, setting this to false may be a smart thing to
- * do. Subclasses may want to override this setting.
- *
- * Default is false.
- */
- keepInMap: false,
-
- /**
- * APIProperty: closeOnMove
- * {Boolean} When map pans, close the popup.
- * Default is false.
- */
- closeOnMove: false,
-
- /**
- * Property: map
- * {<OpenLayers.Map>} this gets set in Map.js when the popup is added to the map
- */
- map: null,
-
- /**
- * Constructor: OpenLayers.Popup
- * Create a popup.
- *
- * Parameters:
- * id - {String} a unqiue identifier for this popup. If null is passed
- * an identifier will be automatically generated.
- * lonlat - {<OpenLayers.LonLat>} The position on the map the popup will
- * be shown.
- * contentSize - {<OpenLayers.Size>} The size of the content.
- * contentHTML - {String} An HTML string to display inside the
- * popup.
- * closeBox - {Boolean} Whether to display a close box inside
- * the popup.
- * closeBoxCallback - {Function} Function to be called on closeBox click.
- */
- initialize:function(id, lonlat, contentSize, contentHTML, closeBox, closeBoxCallback) {
- if (id == null) {
- id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+ if (arguments.length == 1) {
+ return element;
}
+ elements.push(element);
+ }
+ return elements;
+};
- this.id = id;
- this.lonlat = lonlat;
+/**
+ * Function: isElement
+ * A cross-browser implementation of "e instanceof Element".
+ *
+ * Parameters:
+ * o - {Object} The object to test.
+ *
+ * Returns:
+ * {Boolean}
+ */
+OpenLayers.Util.isElement = function(o) {
+ return !!(o && o.nodeType === 1);
+};
- this.contentSize = (contentSize != null) ? contentSize
- : new OpenLayers.Size(
- OpenLayers.Popup.WIDTH,
- OpenLayers.Popup.HEIGHT);
- if (contentHTML != null) {
- this.contentHTML = contentHTML;
- }
- this.backgroundColor = OpenLayers.Popup.COLOR;
- this.opacity = OpenLayers.Popup.OPACITY;
- this.border = OpenLayers.Popup.BORDER;
+/**
+ * Maintain existing definition of $.
+ */
+if(typeof window.$ === "undefined") {
+ window.$ = OpenLayers.Util.getElement;
+}
- this.div = OpenLayers.Util.createDiv(this.id, null, null,
- null, null, null, "hidden");
- this.div.className = this.displayClass;
-
- var groupDivId = this.id + "_GroupDiv";
- this.groupDiv = OpenLayers.Util.createDiv(groupDivId, null, null,
- null, "relative", null,
- "hidden");
-
- var id = this.div.id + "_contentDiv";
- this.contentDiv = OpenLayers.Util.createDiv(id, null, this.contentSize.clone(),
- null, "relative");
- this.contentDiv.className = this.contentDisplayClass;
- this.groupDiv.appendChild(this.contentDiv);
- this.div.appendChild(this.groupDiv);
-
- if (closeBox) {
- this.addCloseBox(closeBoxCallback);
- }
-
- this.registerEvents();
- },
-
- /**
- * Method: destroy
- * nullify references to prevent circular references and memory leaks
- */
- destroy: function() {
-
- this.id = null;
- this.lonlat = null;
- this.size = null;
- this.contentHTML = null;
-
- this.backgroundColor = null;
- this.opacity = null;
- this.border = null;
-
- if (this.closeOnMove && this.map) {
- this.map.events.unregister("movestart", this, this.hide);
+/**
+ * Function: removeItem
+ * Remove an object from an array. Iterates through the array
+ * to find the item, then removes it.
+ *
+ * Parameters:
+ * array - {Array}
+ * item - {Object}
+ *
+ * Return
+ * {Array} A reference to the array
+ */
+OpenLayers.Util.removeItem = function(array, item) {
+ for(var i = array.length - 1; i >= 0; i--) {
+ if(array[i] == item) {
+ array.splice(i,1);
+ //break;more than once??
}
+ }
+ return array;
+};
- this.events.destroy();
- this.events = null;
-
- if (this.closeDiv) {
- OpenLayers.Event.stopObservingElement(this.closeDiv);
- this.groupDiv.removeChild(this.closeDiv);
- }
- this.closeDiv = null;
-
- this.div.removeChild(this.groupDiv);
- this.groupDiv = null;
+/**
+ * Function: clearArray
+ * *Deprecated*. This function will disappear in 3.0.
+ * Please use "array.length = 0" instead.
+ *
+ * Parameters:
+ * array - {Array}
+ */
+OpenLayers.Util.clearArray = function(array) {
+ OpenLayers.Console.warn(
+ OpenLayers.i18n(
+ "methodDeprecated", {'newMethod': 'array = []'}
+ )
+ );
+ array.length = 0;
+};
- if (this.map != null) {
- this.map.removePopup(this);
- }
- this.map = null;
- this.div = null;
-
- this.autoSize = null;
- this.minSize = null;
- this.maxSize = null;
- this.padding = null;
- this.panMapIfOutOfView = null;
- },
-
- /**
- * Method: draw
- * Constructs the elements that make up the popup.
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>} the position the popup in pixels.
- *
- * Returns:
- * {DOMElement} Reference to a div that contains the drawn popup
- */
- draw: function(px) {
- if (px == null) {
- if ((this.lonlat != null) && (this.map != null)) {
- px = this.map.getLayerPxFromLonLat(this.lonlat);
+/**
+ * Function: indexOf
+ * Seems to exist already in FF, but not in MOZ.
+ *
+ * Parameters:
+ * array - {Array}
+ * obj - {Object}
+ *
+ * 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;
+ }
+};
- // this assumes that this.map already exists, which is okay because
- // this.draw is only called once the popup has been added to the map.
- if (this.closeOnMove) {
- this.map.events.register("movestart", this, this.hide);
- }
-
- //listen to movestart, moveend to disable overflow (FF bug)
- if (!this.disableFirefoxOverflowHack && OpenLayers.Util.getBrowserName() == 'firefox') {
- this.map.events.register("movestart", this, function() {
- var style = document.defaultView.getComputedStyle(
- this.contentDiv, null
- );
- var currentOverflow = style.getPropertyValue("overflow");
- if (currentOverflow != "hidden") {
- this.contentDiv._oldOverflow = currentOverflow;
- this.contentDiv.style.overflow = "hidden";
- }
- });
- this.map.events.register("moveend", this, function() {
- var oldOverflow = this.contentDiv._oldOverflow;
- if (oldOverflow) {
- this.contentDiv.style.overflow = oldOverflow;
- this.contentDiv._oldOverflow = null;
- }
- });
- }
- this.moveTo(px);
- if (!this.autoSize && !this.size) {
- this.setSize(this.contentSize);
- }
- this.setBackgroundColor();
- this.setOpacity();
- this.setBorder();
- this.setContentHTML();
-
- if (this.panMapIfOutOfView) {
- this.panIntoView();
- }
- return this.div;
- },
+/**
+ * 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:
+ * id - {String} The element id attribute to set.
+ * px - {<OpenLayers.Pixel>} The left and top style position.
+ * sz - {<OpenLayers.Size>} The width and height style attributes.
+ * 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) {
- /**
- * Method: updatePosition
- * if the popup has a lonlat and its map members set,
- * then have it move itself to its proper position
- */
- updatePosition: function() {
- if ((this.lonlat) && (this.map)) {
- var px = this.map.getLayerPxFromLonLat(this.lonlat);
- if (px) {
- this.moveTo(px);
- }
- }
- },
+ if (id) {
+ element.id = id;
+ }
+ 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 = '';
+ }
+};
- /**
- * Method: moveTo
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>} the top and left position of the popup div.
- */
- moveTo: function(px) {
- if ((px != null) && (this.div != null)) {
- this.div.style.left = px.x + "px";
- this.div.style.top = px.y + "px";
- }
- },
+/**
+ * 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.
+ * px - {<OpenLayers.Pixel>} The element left and top position.
+ * sz - {<OpenLayers.Size>} The element width and height.
+ * 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) {
- /**
- * Method: visible
- *
- * Returns:
- * {Boolean} Boolean indicating whether or not the popup is visible
- */
- visible: function() {
- return OpenLayers.Element.visible(this.div);
- },
+ var dom = document.createElement('div');
- /**
- * Method: toggle
- * Toggles visibility of the popup.
- */
- toggle: function() {
- if (this.visible()) {
- this.hide();
- } else {
- this.show();
- }
- },
+ if (imgURL) {
+ dom.style.backgroundImage = 'url(' + imgURL + ')';
+ }
- /**
- * Method: show
- * Makes the popup visible.
- */
- show: function() {
- OpenLayers.Element.show(this.div);
+ //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);
- if (this.panMapIfOutOfView) {
- this.panIntoView();
- }
- },
+ return dom;
+};
- /**
- * Method: hide
- * Makes the popup invisible.
- */
- hide: function() {
- OpenLayers.Element.hide(this.div);
- },
+/**
+ * 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 - {<OpenLayers.Pixel>} The left and top positions.
+ * sz - {<OpenLayers.Size>} The style.width and style.height values.
+ * 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) {
- /**
- * Method: setSize
- * Used to adjust the size of the popup.
- *
- * Parameters:
- * contentSize - {<OpenLayers.Size>} the new size for the popup's
- * contents div (in pixels).
- */
- setSize:function(contentSize) {
- this.size = contentSize.clone();
-
- // if our contentDiv has a css 'padding' set on it by a stylesheet, we
- // must add that to the desired "size".
- var contentDivPadding = this.getContentDivPadding();
- var wPadding = contentDivPadding.left + contentDivPadding.right;
- var hPadding = contentDivPadding.top + contentDivPadding.bottom;
+ var image = document.createElement("img");
- // take into account the popup's 'padding' property
- this.fixPadding();
- wPadding += this.padding.left + this.padding.right;
- hPadding += this.padding.top + this.padding.bottom;
+ //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);
- // make extra space for the close div
- if (this.closeDiv) {
- var closeDivWidth = parseInt(this.closeDiv.style.width);
- wPadding += closeDivWidth + contentDivPadding.right;
- }
+ if(delayDisplay) {
+ image.style.display = "none";
+ OpenLayers.Event.observe(image, "load",
+ OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, image));
+ OpenLayers.Event.observe(image, "error",
+ OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, image));
+
+ }
+
+ //set special properties
+ image.style.alt = id;
+ image.galleryImg = "no";
+ if (imgURL) {
+ image.src = imgURL;
+ }
- //increase size of the main popup div to take into account the
- // users's desired padding and close div.
- this.size.w += wPadding;
- this.size.h += hPadding;
- //now if our browser is IE, we need to actually make the contents
- // div itself bigger to take its own padding into effect. this makes
- // me want to shoot someone, but so it goes.
- if (OpenLayers.Util.getBrowserName() == "msie") {
- this.contentSize.w +=
- contentDivPadding.left + contentDivPadding.right;
- this.contentSize.h +=
- contentDivPadding.bottom + contentDivPadding.top;
- }
-
- if (this.div != null) {
- this.div.style.width = this.size.w + "px";
- this.div.style.height = this.size.h + "px";
- }
- if (this.contentDiv != null){
- this.contentDiv.style.width = contentSize.w + "px";
- this.contentDiv.style.height = contentSize.h + "px";
- }
- },
-
- /**
- * APIMethod: updateSize
- * Auto size the popup so that it precisely fits its contents (as
- * determined by this.contentDiv.innerHTML). Popup size will, of
- * course, be limited by the available space on the current map
- */
- updateSize: function() {
- // determine actual render dimensions of the contents by putting its
- // contents into a fake contentDiv (for the CSS) and then measuring it
- var preparedHTML = "<div class='" + this.contentDisplayClass+ "'>" +
- this.contentDiv.innerHTML +
- "</div>";
-
- var containerElement = (this.map) ? this.map.layerContainerDiv
- : document.body;
- var realSize = OpenLayers.Util.getRenderedDimensions(
- preparedHTML, null, {
- displayClass: this.displayClass,
- containerElement: containerElement
- }
- );
+ return image;
+};
- // is the "real" size of the div is safe to display in our map?
- var safeSize = this.getSafeContentSize(realSize);
+/**
+ * Function: setOpacity
+ * *Deprecated*. This function has been deprecated. Instead, please use
+ * <OpenLayers.Util.modifyDOMElement>
+ * or
+ * <OpenLayers.Util.modifyAlphaImageDiv>
+ *
+ * Set the opacity of a DOM Element
+ * Note that for this function to work in IE, elements must "have layout"
+ * according to:
+ * http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp
+ *
+ * Parameters:
+ * element - {DOMElement} Set the opacity on this DOM element
+ * opacity - {Float} Opacity value (0.0 - 1.0)
+ */
+OpenLayers.Util.setOpacity = function(element, opacity) {
+ OpenLayers.Util.modifyDOMElement(element, null, null, null,
+ null, null, null, opacity);
+};
- var newSize = null;
- if (safeSize.equals(realSize)) {
- //real size of content is small enough to fit on the map,
- // so we use real size.
- newSize = realSize;
+/**
+ * Function: onImageLoad
+ * Bound to image load events. For all images created with <createImage> or
+ * <createAlphaImageDiv>, this function will be bound to the load event.
+ */
+OpenLayers.Util.onImageLoad = function() {
+ // The complex check here is to solve issues described in #480.
+ // Every time a map view changes, it increments the 'viewRequestID'
+ // property. As the requests for the images for the new map view are sent
+ // out, they are tagged with this unique viewRequestID.
+ //
+ // If an image has no viewRequestID property set, we display it regardless,
+ // but if it does have a viewRequestID property, we check that it matches
+ // the viewRequestID set on the map.
+ //
+ // If the viewRequestID on the map has changed, that means that the user
+ // has changed the map view since this specific request was sent out, and
+ // therefore this tile does not need to be displayed (so we do not execute
+ // this code that turns its display on).
+ //
+ if (!this.viewRequestID ||
+ (this.map && this.viewRequestID == this.map.viewRequestID)) {
+ this.style.display = "";
+ }
+ OpenLayers.Element.removeClass(this, "olImageLoadError");
+};
- } else {
+/**
+ * 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;
- //make a new OL.Size object with the clipped dimensions
- // set or null if not clipped.
- var fixedSize = new OpenLayers.Size();
- fixedSize.w = (safeSize.w < realSize.w) ? safeSize.w : null;
- fixedSize.h = (safeSize.h < realSize.h) ? safeSize.h : null;
-
- if (fixedSize.w && fixedSize.h) {
- //content is too big in both directions, so we will use
- // max popup size (safeSize), knowing well that it will
- // overflow both ways.
- newSize = safeSize;
- } else {
- //content is clipped in only one direction, so we need to
- // run getRenderedDimensions() again with a fixed dimension
- var clippedSize = OpenLayers.Util.getRenderedDimensions(
- preparedHTML, fixedSize, {
- displayClass: this.contentDisplayClass,
- containerElement: containerElement
- }
- );
-
- //if the clipped size is still the same as the safeSize,
- // that means that our content must be fixed in the
- // offending direction. If overflow is 'auto', this means
- // we are going to have a scrollbar for sure, so we must
- // adjust for that.
- //
- var currentOverflow = OpenLayers.Element.getStyle(
- this.contentDiv, "overflow"
- );
- if ( (currentOverflow != "hidden") &&
- (clippedSize.equals(safeSize)) ) {
- var scrollBar = OpenLayers.Util.getScrollbarWidth();
- if (fixedSize.w) {
- clippedSize.h += scrollBar;
- } else {
- clippedSize.w += scrollBar;
- }
+/**
+ * Function: onImageLoadError
+ */
+OpenLayers.Util.onImageLoadError = function() {
+ this._attempts = (this._attempts) ? (this._attempts + 1) : 1;
+ if (this._attempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
+ var urls = this.urls;
+ if (urls && urls instanceof Array && urls.length > 1){
+ var src = this.src.toString();
+ var current_url, k;
+ for (k = 0; current_url = urls[k]; k++){
+ if(src.indexOf(current_url) != -1){
+ break;
}
-
- newSize = this.getSafeContentSize(clippedSize);
}
- }
- this.setSize(newSize);
- },
-
- /**
- * Method: setBackgroundColor
- * Sets the background color of the popup.
- *
- * Parameters:
- * color - {String} the background color. eg "#FFBBBB"
- */
- setBackgroundColor:function(color) {
- if (color != undefined) {
- this.backgroundColor = color;
+ var guess = Math.floor(urls.length * Math.random());
+ var new_url = urls[guess];
+ k = 0;
+ while(new_url == current_url && k++ < 4){
+ guess = Math.floor(urls.length * Math.random());
+ new_url = urls[guess];
+ }
+ this.src = src.replace(current_url, new_url);
+ } else {
+ this.src = this.src;
}
-
- if (this.div != null) {
- this.div.style.backgroundColor = this.backgroundColor;
- }
- },
-
- /**
- * Method: setOpacity
- * Sets the opacity of the popup.
- *
- * Parameters:
- * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid).
- */
- setOpacity:function(opacity) {
- if (opacity != undefined) {
- this.opacity = opacity;
- }
-
- if (this.div != null) {
- // for Mozilla and Safari
- this.div.style.opacity = this.opacity;
+ } else {
+ OpenLayers.Element.addClass(this, "olImageLoadError");
+ }
+ this.style.display = "";
+};
- // for IE
- this.div.style.filter = 'alpha(opacity=' + this.opacity*100 + ')';
- }
- },
-
- /**
- * Method: setBorder
- * Sets the border style of the popup.
- *
- * Parameters:
- * border - {String} The border style value. eg 2px
- */
- setBorder:function(border) {
- if (border != undefined) {
- this.border = border;
- }
-
- if (this.div != null) {
- this.div.style.border = this.border;
- }
- },
-
- /**
- * Method: setContentHTML
- * Allows the user to set the HTML content of the popup.
- *
- * Parameters:
- * contentHTML - {String} HTML for the div.
- */
- setContentHTML:function(contentHTML) {
+/**
+ * Property: alphaHackNeeded
+ * {Boolean} true if the png alpha hack is necessary and possible, false otherwise.
+ */
+OpenLayers.Util.alphaHackNeeded = null;
- if (contentHTML != null) {
- this.contentHTML = contentHTML;
- }
-
- if ((this.contentDiv != null) &&
- (this.contentHTML != null) &&
- (this.contentHTML != this.contentDiv.innerHTML)) {
-
- this.contentDiv.innerHTML = this.contentHTML;
-
- if (this.autoSize) {
-
- //if popup has images, listen for when they finish
- // loading and resize accordingly
- this.registerImageListeners();
-
- //auto size the popup to its current contents
- this.updateSize();
- }
- }
-
- },
+/**
+ * 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;
- /**
- * Method: registerImageListeners
- * Called when an image contained by the popup loaded. this function
- * updates the popup size, then unregisters the image load listener.
- */
- registerImageListeners: function() {
-
- // As the images load, this function will call updateSize() to
- // resize the popup to fit the content div (which presumably is now
- // bigger than when the image was not loaded).
- //
- // If the 'panMapIfOutOfView' property is set, we will pan the newly
- // resized popup back into view.
- //
- // Note that this function, when called, will have 'popup' and
- // 'img' properties in the context.
- //
- var onImgLoad = function() {
-
- this.popup.updateSize();
-
- if ( this.popup.visible() && this.popup.panMapIfOutOfView ) {
- this.popup.panIntoView();
- }
-
- OpenLayers.Event.stopObserving(
- this.img, "load", this.img._onImageLoad
- );
+ // 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.
- };
-
- //cycle through the images and if their size is 0x0, that means that
- // they haven't been loaded yet, so we attach the listener, which
- // will fire when the images finish loading and will resize the
- // popup accordingly to its new size.
- var images = this.contentDiv.getElementsByTagName("img");
- for (var i = 0, len = images.length; i < len; i++) {
- var img = images[i];
- if (img.width == 0 || img.height == 0) {
-
- var context = {
- 'popup': this,
- 'img': img
- };
-
- //expando this function to the image itself before registering
- // it. This way we can easily and properly unregister it.
- img._onImgLoad = OpenLayers.Function.bind(onImgLoad, context);
-
- OpenLayers.Event.observe(img, 'load', img._onImgLoad);
- }
- }
- },
-
- /**
- * APIMethod: getSafeContentSize
- *
- * Parameters:
- * size - {<OpenLayers.Size>} Desired size to make the popup.
- *
- * Returns:
- * {<OpenLayers.Size>} A size to make the popup which is neither smaller
- * than the specified minimum size, nor bigger than the maximum
- * size (which is calculated relative to the size of the viewport).
- */
- getSafeContentSize: function(size) {
-
- var safeContentSize = size.clone();
-
- // if our contentDiv has a css 'padding' set on it by a stylesheet, we
- // must add that to the desired "size".
- var contentDivPadding = this.getContentDivPadding();
- var wPadding = contentDivPadding.left + contentDivPadding.right;
- var hPadding = contentDivPadding.top + contentDivPadding.bottom;
-
- // take into account the popup's 'padding' property
- this.fixPadding();
- wPadding += this.padding.left + this.padding.right;
- hPadding += this.padding.top + this.padding.bottom;
-
- if (this.closeDiv) {
- var closeDivWidth = parseInt(this.closeDiv.style.width);
- wPadding += closeDivWidth + contentDivPadding.right;
- }
-
- // prevent the popup from being smaller than a specified minimal size
- if (this.minSize) {
- safeContentSize.w = Math.max(safeContentSize.w,
- (this.minSize.w - wPadding));
- safeContentSize.h = Math.max(safeContentSize.h,
- (this.minSize.h - hPadding));
- }
-
- // prevent the popup from being bigger than a specified maximum size
- if (this.maxSize) {
- safeContentSize.w = Math.min(safeContentSize.w,
- (this.maxSize.w - wPadding));
- safeContentSize.h = Math.min(safeContentSize.h,
- (this.maxSize.h - hPadding));
- }
-
- //make sure the desired size to set doesn't result in a popup that
- // is bigger than the map's viewport.
- //
- if (this.map && this.map.size) {
-
- var extraX = 0, extraY = 0;
- if (this.keepInMap && !this.panMapIfOutOfView) {
- var px = this.map.getPixelFromLonLat(this.lonlat);
- switch (this.relativePosition) {
- case "tr":
- extraX = px.x;
- extraY = this.map.size.h - px.y;
- break;
- case "tl":
- extraX = this.map.size.w - px.x;
- extraY = this.map.size.h - px.y;
- break;
- case "bl":
- extraX = this.map.size.w - px.x;
- extraY = px.y;
- break;
- case "br":
- extraX = px.x;
- extraY = px.y;
- break;
- default:
- extraX = px.x;
- extraY = this.map.size.h - px.y;
- break;
- }
- }
-
- var maxY = this.map.size.h -
- this.map.paddingForPopups.top -
- this.map.paddingForPopups.bottom -
- hPadding - extraY;
-
- var maxX = this.map.size.w -
- this.map.paddingForPopups.left -
- this.map.paddingForPopups.right -
- wPadding - extraX;
-
- safeContentSize.w = Math.min(safeContentSize.w, maxX);
- safeContentSize.h = Math.min(safeContentSize.h, maxY);
- }
-
- return safeContentSize;
- },
+ try {
+ filter = !!(document.body.filters);
+ } catch (e) {}
- /**
- * Method: getContentDivPadding
- * Glorious, oh glorious hack in order to determine the css 'padding' of
- * the contentDiv. IE/Opera return null here unless we actually add the
- * popup's main 'div' element (which contains contentDiv) to the DOM.
- * So we make it invisible and then add it to the document temporarily.
- *
- * Once we've taken the padding readings we need, we then remove it
- * from the DOM (it will actually get added to the DOM in
- * Map.js's addPopup)
- *
- * Returns:
- * {<OpenLayers.Bounds>}
- */
- getContentDivPadding: function() {
+ OpenLayers.Util.alphaHackNeeded = (filter &&
+ (version >= 5.5) && (version < 7));
+ }
+ return OpenLayers.Util.alphaHackNeeded;
+};
- //use cached value if we have it
- var contentDivPadding = this._contentDivPadding;
- if (!contentDivPadding) {
+/**
+ * Function: modifyAlphaImageDiv
+ *
+ * div - {DOMElement} Div containing Alpha-adjusted Image
+ * id - {String}
+ * px - {<OpenLayers.Pixel>}
+ * sz - {<OpenLayers.Size>}
+ * 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) {
- if (this.div.parentNode == null) {
- //make the div invisible and add it to the page
- this.div.style.display = "none";
- document.body.appendChild(this.div);
- }
-
- //read the padding settings from css, put them in an OL.Bounds
- contentDivPadding = new OpenLayers.Bounds(
- OpenLayers.Element.getStyle(this.contentDiv, "padding-left"),
- OpenLayers.Element.getStyle(this.contentDiv, "padding-bottom"),
- OpenLayers.Element.getStyle(this.contentDiv, "padding-right"),
- OpenLayers.Element.getStyle(this.contentDiv, "padding-top")
- );
-
- //cache the value
- this._contentDivPadding = contentDivPadding;
+ OpenLayers.Util.modifyDOMElement(div, id, px, sz, position,
+ null, null, opacity);
- if (this.div.parentNode == document.body) {
- //remove the div from the page and make it visible again
- document.body.removeChild(this.div);
- this.div.style.display = "";
- }
- }
- return contentDivPadding;
- },
+ var img = div.childNodes[0];
- /**
- * Method: addCloseBox
- *
- * Parameters:
- * callback - {Function} The callback to be called when the close button
- * is clicked.
- */
- addCloseBox: function(callback) {
-
- this.closeDiv = OpenLayers.Util.createDiv(
- this.id + "_close", null, new OpenLayers.Size(17, 17)
- );
- this.closeDiv.className = "olPopupCloseBox";
-
- // use the content div's css padding to determine if we should
- // padd the close div
- var contentDivPadding = this.getContentDivPadding();
-
- this.closeDiv.style.right = contentDivPadding.right + "px";
- this.closeDiv.style.top = contentDivPadding.top + "px";
- this.groupDiv.appendChild(this.closeDiv);
-
- var closePopup = callback || function(e) {
- this.hide();
- OpenLayers.Event.stop(e);
- };
- OpenLayers.Event.observe(this.closeDiv, "click",
- OpenLayers.Function.bindAsEventListener(closePopup, this));
- },
-
- /**
- * Method: panIntoView
- * Pans the map such that the popup is totaly viewable (if necessary)
- */
- panIntoView: function() {
-
- var mapSize = this.map.getSize();
+ if (imgURL) {
+ img.src = imgURL;
+ }
+ OpenLayers.Util.modifyDOMElement(img, div.id + "_innerImage", null, sz,
+ "relative", border);
- //start with the top left corner of the popup, in px,
- // relative to the viewport
- var origTL = this.map.getViewPortPxFromLayerPx( new OpenLayers.Pixel(
- parseInt(this.div.style.left),
- parseInt(this.div.style.top)
- ));
- var newTL = origTL.clone();
-
- //new left (compare to margins, using this.size to calculate right)
- if (origTL.x < this.map.paddingForPopups.left) {
- newTL.x = this.map.paddingForPopups.left;
- } else
- if ( (origTL.x + this.size.w) > (mapSize.w - this.map.paddingForPopups.right)) {
- newTL.x = mapSize.w - this.map.paddingForPopups.right - this.size.w;
+ if (OpenLayers.Util.alphaHack()) {
+ if(div.style.display != "none") {
+ div.style.display = "inline-block";
}
-
- //new top (compare to margins, using this.size to calculate bottom)
- if (origTL.y < this.map.paddingForPopups.top) {
- newTL.y = this.map.paddingForPopups.top;
- } else
- if ( (origTL.y + this.size.h) > (mapSize.h - this.map.paddingForPopups.bottom)) {
- newTL.y = mapSize.h - this.map.paddingForPopups.bottom - this.size.h;
+ if (sizing == null) {
+ sizing = "scale";
}
- var dx = origTL.x - newTL.x;
- var dy = origTL.y - newTL.y;
-
- this.map.pan(dx, dy);
- },
-
- /**
- * Method: registerEvents
- * Registers events on the popup.
- *
- * Do this in a separate function so that subclasses can
- * choose to override it if they wish to deal differently
- * with mouse events
- *
- * Note in the following handler functions that some special
- * care is needed to deal correctly with mousing and popups.
- *
- * Because the user might select the zoom-rectangle option and
- * then drag it over a popup, we need a safe way to allow the
- * mousemove and mouseup events to pass through the popup when
- * they are initiated from outside.
- *
- * Otherwise, we want to essentially kill the event propagation
- * for all other events, though we have to do so carefully,
- * without disabling basic html functionality, like clicking on
- * hyperlinks or drag-selecting text.
- */
- registerEvents:function() {
- this.events = new OpenLayers.Events(this, this.div, null, true);
-
- this.events.on({
- "mousedown": this.onmousedown,
- "mousemove": this.onmousemove,
- "mouseup": this.onmouseup,
- "click": this.onclick,
- "mouseout": this.onmouseout,
- "dblclick": this.ondblclick,
- scope: this
- });
-
- },
-
- /**
- * Method: onmousedown
- * When mouse goes down within the popup, make a note of
- * it locally, and then do not propagate the mousedown
- * (but do so safely so that user can select text inside)
- *
- * Parameters:
- * evt - {Event}
- */
- onmousedown: function (evt) {
- this.mousedown = true;
- OpenLayers.Event.stop(evt, true);
- },
-
- /**
- * Method: onmousemove
- * If the drag was started within the popup, then
- * do not propagate the mousemove (but do so safely
- * so that user can select text inside)
- *
- * Parameters:
- * evt - {Event}
- */
- onmousemove: function (evt) {
- if (this.mousedown) {
- OpenLayers.Event.stop(evt, true);
+ 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 + ")";
}
- },
- /**
- * Method: onmouseup
- * When mouse comes up within the popup, after going down
- * in it, reset the flag, and then (once again) do not
- * propagate the event, but do so safely so that user can
- * select text inside
- *
- * Parameters:
- * evt - {Event}
- */
- onmouseup: function (evt) {
- if (this.mousedown) {
- this.mousedown = false;
- OpenLayers.Event.stop(evt, true);
- }
- },
+ img.style.filter = "alpha(opacity=0)";
+ }
+};
- /**
- * Method: onclick
- * Ignore clicks, but allowing default browser handling
- *
- * Parameters:
- * evt - {Event}
- */
- onclick: function (evt) {
- OpenLayers.Event.stop(evt, true);
- },
-
- /**
- * Method: onmouseout
- * When mouse goes out of the popup set the flag to false so that
- * if they let go and then drag back in, we won't be confused.
- *
- * Parameters:
- * evt - {Event}
- */
- onmouseout: function (evt) {
- this.mousedown = false;
- },
+/**
+ * Function: createAlphaImageDiv
+ *
+ * id - {String}
+ * px - {<OpenLayers.Pixel>}
+ * sz - {<OpenLayers.Size>}
+ * 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) {
- /**
- * Method: ondblclick
- * Ignore double-clicks, but allowing default browser handling
- *
- * Parameters:
- * evt - {Event}
- */
- ondblclick: function (evt) {
- OpenLayers.Event.stop(evt, true);
- },
+ var div = OpenLayers.Util.createDiv();
+ var img = OpenLayers.Util.createImage(null, null, null, null, null, null,
+ null, false);
+ div.appendChild(img);
- CLASS_NAME: "OpenLayers.Popup"
-});
+ if (delayDisplay) {
+ img.style.display = "none";
+ OpenLayers.Event.observe(img, "load",
+ OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, div));
+ OpenLayers.Event.observe(img, "error",
+ OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, div));
+ }
-OpenLayers.Popup.WIDTH = 200;
-OpenLayers.Popup.HEIGHT = 200;
-OpenLayers.Popup.COLOR = "white";
-OpenLayers.Popup.OPACITY = 1;
-OpenLayers.Popup.BORDER = "0px";
-/* ======================================================================
- OpenLayers/Protocol.js
- ====================================================================== */
+ OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL, position,
+ border, sizing, opacity);
+
+ return div;
+};
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-/**
- * Class: OpenLayers.Protocol
- * Abstract vector layer protocol class. Not to be instantiated directly. Use
- * one of the protocol subclasses instead.
+/**
+ * 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.Protocol = OpenLayers.Class({
-
- /**
- * Property: format
- * {<OpenLayers.Format>} The format used by this protocol.
- */
- format: null,
-
- /**
- * Property: options
- * {Object} Any options sent to the constructor.
- */
- options: null,
+OpenLayers.Util.upperCaseObject = function (object) {
+ var uObject = {};
+ for (var key in object) {
+ uObject[key.toUpperCase()] = object[key];
+ }
+ return uObject;
+};
- /**
- * Property: autoDestroy
- * {Boolean} The creator of the protocol can set autoDestroy to false
- * to fully control when the protocol is destroyed. Defaults to
- * true.
+/**
+ * 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.
*/
- autoDestroy: true,
-
- /**
- * Property: defaultFilter
- * {OpenLayers.Filter} Optional default filter to read requests
- */
- defaultFilter: null,
-
- /**
- * Constructor: OpenLayers.Protocol
- * Abstract class for vector protocols. Create instances of a subclass.
- *
- * Parameters:
- * options - {Object} Optional object whose properties will be set on the
- * instance.
- */
- initialize: function(options) {
- options = options || {};
- OpenLayers.Util.extend(this, options);
- this.options = options;
- },
+ var fromIsEvt = typeof window.Event == "function"
+ && from instanceof window.Event;
- /**
- * Method: mergeWithDefaultFilter
- * Merge filter passed to the read method with the default one
- *
- * Parameters:
- * filter - {OpenLayers.Filter}
- */
- mergeWithDefaultFilter: function(filter) {
- var merged;
- if (filter && this.defaultFilter) {
- merged = new OpenLayers.Filter.Logical({
- type: OpenLayers.Filter.Logical.AND,
- filters: [this.defaultFilter, filter]
- });
- } else {
- merged = filter || this.defaultFilter || undefined;
+ for (var key in from) {
+ if (to[key] === undefined ||
+ (!fromIsEvt && from.hasOwnProperty
+ && from.hasOwnProperty(key) && !to.hasOwnProperty(key))) {
+ to[key] = from[key];
}
- return merged;
- },
-
+ }
/**
- * APIMethod: destroy
- * Clean up the protocol.
+ * 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.
*/
- destroy: function() {
- this.options = null;
- this.format = null;
- },
+ if(!fromIsEvt && from && from.hasOwnProperty
+ && from.hasOwnProperty('toString') && !to.hasOwnProperty('toString')) {
+ to.toString = from.toString;
+ }
- /**
- * APIMethod: read
- * Construct a request for reading new features.
- *
- * Parameters:
- * options - {Object} Optional object for configuring the request.
- *
- * Returns:
- * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
- * object, the same object will be passed to the callback function passed
- * if one exists in the options object.
- */
- read: function(options) {
- options = options || {};
- options.filter = this.mergeWithDefaultFilter(options.filter);
- },
-
-
- /**
- * APIMethod: create
- * Construct a request for writing newly created features.
- *
- * Parameters:
- * features - {Array({<OpenLayers.Feature.Vector>})} or
- * {<OpenLayers.Feature.Vector>}
- * options - {Object} Optional object for configuring the request.
- *
- * Returns:
- * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
- * object, the same object will be passed to the callback function passed
- * if one exists in the options object.
- */
- create: function() {
- },
-
- /**
- * APIMethod: update
- * Construct a request updating modified features.
- *
- * Parameters:
- * features - {Array({<OpenLayers.Feature.Vector>})} or
- * {<OpenLayers.Feature.Vector>}
- * options - {Object} Optional object for configuring the request.
- *
- * Returns:
- * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
- * object, the same object will be passed to the callback function passed
- * if one exists in the options object.
- */
- update: function() {
- },
-
- /**
- * APIMethod: delete
- * Construct a request deleting a removed feature.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- * options - {Object} Optional object for configuring the request.
- *
- * Returns:
- * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
- * object, the same object will be passed to the callback function passed
- * if one exists in the options object.
- */
- "delete": function() {
- },
+ return to;
+};
- /**
- * APIMethod: commit
- * Go over the features and for each take action
- * based on the feature state. Possible actions are create,
- * update and delete.
- *
- * Parameters:
- * features - {Array({<OpenLayers.Feature.Vector>})}
- * options - {Object} Object whose possible keys are "create", "update",
- * "delete", "callback" and "scope", the values referenced by the
- * first three are objects as passed to the "create", "update", and
- * "delete" methods, the value referenced by the "callback" key is
- * a function which is called when the commit operation is complete
- * using the scope referenced by the "scope" key.
- *
- * Returns:
- * {Array({<OpenLayers.Protocol.Response>})} An array of
- * <OpenLayers.Protocol.Response> objects.
- */
- commit: function() {
- },
-
- /**
- * Method: abort
- * Abort an ongoing request.
- *
- * Parameters:
- * response - {<OpenLayers.Protocol.Response>}
- */
- abort: function(response) {
- },
-
- /**
- * Method: createCallback
- * Returns a function that applies the given public method with resp and
- * options arguments.
- *
- * Parameters:
- * method - {Function} The method to be applied by the callback.
- * response - {<OpenLayers.Protocol.Response>} The protocol response object.
- * options - {Object} Options sent to the protocol method
- */
- createCallback: function(method, response, options) {
- return OpenLayers.Function.bind(function() {
- method.apply(this, [response, options]);
- }, this);
- },
-
- CLASS_NAME: "OpenLayers.Protocol"
-});
-
/**
- * Class: OpenLayers.Protocol.Response
- * Protocols return Response objects to their users.
- */
-OpenLayers.Protocol.Response = OpenLayers.Class({
- /**
- * Property: code
- * {Number} - OpenLayers.Protocol.Response.SUCCESS or
- * OpenLayers.Protocol.Response.FAILURE
- */
- code: null,
-
- /**
- * Property: requestType
- * {String} The type of request this response corresponds to. Either
- * "create", "read", "update" or "delete".
- */
- requestType: null,
-
- /**
- * Property: last
- * {Boolean} - true if this is the last response expected in a commit,
- * false otherwise, defaults to true.
- */
- last: true,
-
- /**
- * Property: features
- * {Array({<OpenLayers.Feature.Vector>})} or {<OpenLayers.Feature.Vector>}
- * The features returned in the response by the server.
- */
- features: null,
-
- /**
- * Property: reqFeatures
- * {Array({<OpenLayers.Feature.Vector>})} or {<OpenLayers.Feature.Vector>}
- * The features provided by the user and placed in the request by the
- * protocol.
- */
- reqFeatures: null,
-
- /**
- * Property: priv
- */
- priv: null,
-
- /**
- * Constructor: OpenLayers.Protocol.Response
- *
- * Parameters:
- * options - {Object} Optional object whose properties will be set on the
- * instance.
- */
- initialize: function(options) {
- OpenLayers.Util.extend(this, options);
- },
-
- /**
- * Method: success
- *
- * Returns:
- * {Boolean} - true on success, false otherwise
- */
- success: function() {
- return this.code > 0;
- },
-
- CLASS_NAME: "OpenLayers.Protocol.Response"
-});
-
-OpenLayers.Protocol.Response.SUCCESS = 1;
-OpenLayers.Protocol.Response.FAILURE = 0;
-/* ======================================================================
- OpenLayers/Renderer.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * Class: OpenLayers.Renderer
- * This is the base class for all renderers.
- *
- * This is based on a merger code written by Paul Spencer and Bertil Chapuis.
- * It is largely composed of virtual functions that are to be implemented
- * in technology-specific subclasses, but there is some generic code too.
+ * Function: getParameterString
*
- * The functions that *are* implemented here merely deal with the maintenance
- * of the size and extent variables, as well as the cached 'resolution'
- * value.
+ * Parameters:
+ * params - {Object}
*
- * A note to the user that all subclasses should use getResolution() instead
- * of directly accessing this.resolution in order to correctly use the
- * cacheing system.
- *
+ * Returns:
+ * {String} A concatenation of the properties of an object in
+ * http parameter notation.
+ * (ex. <i>"key1=value1&key2=value2&key3=value3"</i>)
+ * 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.Renderer = OpenLayers.Class({
-
- /**
- * Property: container
- * {DOMElement}
- */
- container: null,
+OpenLayers.Util.getParameterString = function(params) {
+ var paramsArray = [];
- /**
- * Property: root
- * {DOMElement}
- */
- root: null,
-
- /**
- * Property: extent
- * {<OpenLayers.Bounds>}
- */
- extent: null,
-
- /**
- * Property: locked
- * {Boolean} If the renderer is currently in a state where many things
- * are changing, the 'locked' property is set to true. This means
- * that renderers can expect at least one more drawFeature event to be
- * called with the 'locked' property set to 'true': In some renderers,
- * this might make sense to use as a 'only update local information'
- * flag.
- */
- locked: false,
-
- /**
- * Property: size
- * {<OpenLayers.Size>}
- */
- size: null,
-
- /**
- * Property: resolution
- * {Float} cache of current map resolution
- */
- resolution: null,
-
- /**
- * Property: map
- * {<OpenLayers.Map>} Reference to the map -- this is set in Vector's setMap()
- */
- map: null,
-
- /**
- * Constructor: OpenLayers.Renderer
- *
- * Parameters:
- * containerID - {<String>}
- * options - {Object} options for this renderer. See sublcasses for
- * supported options.
- */
- initialize: function(containerID, options) {
- this.container = OpenLayers.Util.getElement(containerID);
- },
-
- /**
- * APIMethod: destroy
- */
- destroy: function() {
- this.container = null;
- this.extent = null;
- this.size = null;
- this.resolution = null;
- this.map = null;
- },
-
- /**
- * APIMethod: supported
- * This should be overridden by specific subclasses
- *
- * Returns:
- * {Boolean} Whether or not the browser supports the renderer class
- */
- supported: function() {
- return false;
- },
-
- /**
- * Method: setExtent
- * Set the visible part of the layer.
- *
- * Resolution has probably changed, so we nullify the resolution
- * cache (this.resolution) -- this way it will be re-computed when
- * next it is needed.
- * We nullify the resolution cache (this.resolution) if resolutionChanged
- * is set to true - this way it will be re-computed on the next
- * getResolution() request.
- *
- * Parameters:
- * extent - {<OpenLayers.Bounds>}
- * resolutionChanged - {Boolean}
- */
- setExtent: function(extent, resolutionChanged) {
- this.extent = extent.clone();
- if (resolutionChanged) {
- this.resolution = null;
+ 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<len; itemIndex++) {
+ item = value[itemIndex];
+ encodedItemArray.push(encodeURIComponent(
+ (item === null || item === undefined) ? "" : item)
+ );
+ }
+ encodedValue = encodedItemArray.join(",");
}
- },
-
- /**
- * Method: setSize
- * Sets the size of the drawing surface.
- *
- * Resolution has probably changed, so we nullify the resolution
- * cache (this.resolution) -- this way it will be re-computed when
- * next it is needed.
- *
- * Parameters:
- * size - {<OpenLayers.Size>}
- */
- setSize: function(size) {
- this.size = size.clone();
- this.resolution = null;
- },
-
- /**
- * Method: getResolution
- * Uses cached copy of resolution if available to minimize computing
- *
- * Returns:
- * The current map's resolution
- */
- getResolution: function() {
- this.resolution = this.resolution || this.map.getResolution();
- return this.resolution;
- },
-
- /**
- * Method: drawFeature
- * Draw the feature. The optional style argument can be used
- * to override the feature's own style. This method should only
- * be called from layer.drawFeature().
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- * style - {<Object>}
- *
- * Returns:
- * {Boolean} true if the feature has been drawn completely, false if not,
- * undefined if the feature had no geometry
- */
- drawFeature: function(feature, style) {
- if(style == null) {
- style = feature.style;
+ else {
+ /* value is a string; simply encode */
+ encodedValue = encodeURIComponent(value);
}
- if (feature.geometry) {
- var bounds = feature.geometry.getBounds();
- if(bounds) {
- if (!bounds.intersectsBounds(this.extent)) {
- style = {display: "none"};
- }
- var rendered = this.drawGeometry(feature.geometry, style, feature.id);
- if(style.display != "none" && style.label && rendered !== false) {
- var location = feature.geometry.getCentroid();
- if(style.labelXOffset || style.labelYOffset) {
- xOffset = isNaN(style.labelXOffset) ? 0 : style.labelXOffset;
- yOffset = isNaN(style.labelYOffset) ? 0 : style.labelYOffset;
- var res = this.getResolution();
- location.move(xOffset*res, yOffset*res);
- }
- this.drawText(feature.id, style, location);
- } else {
- this.removeText(feature.id);
- }
- return rendered;
- }
- }
- },
-
-
- /**
- * Method: drawGeometry
- *
- * Draw a geometry. This should only be called from the renderer itself.
- * Use layer.drawFeature() from outside the renderer.
- * virtual function
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- * featureId - {<String>}
- */
- drawGeometry: function(geometry, style, featureId) {},
-
- /**
- * Method: drawText
- * Function for drawing text labels.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * featureId - {String}
- * style -
- * location - {<OpenLayers.Geometry.Point>}
- */
- drawText: function(featureId, style, location) {},
-
- /**
- * Method: removeText
- * Function for removing text labels.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * featureId - {String}
- */
- removeText: function(featureId) {},
+ paramsArray.push(encodeURIComponent(key) + "=" + encodedValue);
+ }
+ }
- /**
- * Method: clear
- * Clear all vectors from the renderer.
- * virtual function.
- */
- clear: function() {},
+ return paramsArray.join("&");
+};
- /**
- * Method: getFeatureIdFromEvent
- * Returns a feature id from an event on the renderer.
- * How this happens is specific to the renderer. This should be
- * called from layer.getFeatureFromEvent().
- * Virtual function.
- *
- * Parameters:
- * evt - {<OpenLayers.Event>}
- *
- * Returns:
- * {String} A feature id or null.
- */
- getFeatureIdFromEvent: function(evt) {},
-
- /**
- * Method: eraseFeatures
- * This is called by the layer to erase features
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>)}
- */
- eraseFeatures: function(features) {
- if(!(features instanceof Array)) {
- features = [features];
- }
- for(var i=0, len=features.length; i<len; ++i) {
- var feature = features[i];
- this.eraseGeometry(feature.geometry, feature.id);
- this.removeText(feature.id);
- }
- },
-
- /**
- * Method: eraseGeometry
- * Remove a geometry from the renderer (by id).
- * virtual function.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * featureId - {String}
- */
- eraseGeometry: function(geometry, featureId) {},
-
- /**
- * Method: moveRoot
- * moves this renderer's root to a (different) renderer.
- * To be implemented by subclasses that require a common renderer root for
- * feature selection.
- *
- * Parameters:
- * renderer - {<OpenLayers.Renderer>} target renderer for the moved root
- */
- moveRoot: function(renderer) {},
-
- /**
- * Method: getRenderLayerId
- * Gets the layer that this renderer's output appears on. If moveRoot was
- * used, this will be different from the id of the layer containing the
- * features rendered by this renderer.
- *
- * Returns:
- * {String} the id of the output layer.
- */
- getRenderLayerId: function() {
- return this.container.id;
- },
-
- /**
- * Method: applyDefaultSymbolizer
- *
- * Parameters:
- * symbolizer - {Object}
- *
- * Returns:
- * {Object}
- */
- applyDefaultSymbolizer: function(symbolizer) {
- var result = OpenLayers.Util.extend({},
- OpenLayers.Renderer.defaultSymbolizer);
- if(symbolizer.stroke === false) {
- delete result.strokeWidth;
- delete result.strokeColor;
- }
- if(symbolizer.fill === false) {
- delete result.fillColor;
- }
- OpenLayers.Util.extend(result, symbolizer);
- return result;
- },
-
- CLASS_NAME: "OpenLayers.Renderer"
-});
-
/**
- * Constant: OpenLayers.Renderer.defaultSymbolizer
- * {Object} Properties from this symbolizer will be applied to symbolizers
- * with missing properties. This can also be used to set a global
- * symbolizer default in OpenLayers. To be SLD 1.x compliant, add the
- * following code before rendering any vector features:
- * (code)
- * OpenLayers.Renderer.defaultSymbolizer = {
- * fillColor: "#808080",
- * fillOpacity: 1,
- * strokeColor: "#000000",
- * strokeOpacity: 1,
- * strokeWidth: 1,
- * pointRadius: 3,
- * graphicName: "square"
- * };
- * (end)
+ * Function: urlAppend
+ * Appends a parameter string to a url. This function includes the logic for
+ * using the appropriate character (none, & or ?) to append to the url before
+ * appending the param string.
+ *
+ * Parameters:
+ * url - {String} The url to append to
+ * paramStr - {String} The param string to append
+ *
+ * Returns:
+ * {String} The new url
*/
-OpenLayers.Renderer.defaultSymbolizer = {
- fillColor: "#000000",
- strokeColor: "#000000",
- strokeWidth: 2,
- fillOpacity: 1,
- strokeOpacity: 1,
- pointRadius: 0
+OpenLayers.Util.urlAppend = function(url, paramStr) {
+ var newUrl = url;
+ if(paramStr) {
+ var parts = (url + " ").split(/[?&]/);
+ newUrl += (parts.pop() === " " ?
+ paramStr :
+ parts.length ? "&" + paramStr : "?" + paramStr);
+ }
+ return newUrl;
};
-
-/* ======================================================================
- OpenLayers/Strategy.js
- ====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
/**
- * Class: OpenLayers.Strategy
- * Abstract vector layer strategy class. Not to be instantiated directly. Use
- * one of the strategy subclasses instead.
+ * Property: ImgPath
+ * {String} Default is ''.
*/
-OpenLayers.Strategy = OpenLayers.Class({
-
- /**
- * Property: layer
- * {<OpenLayers.Layer.Vector>} The layer this strategy belongs to.
- */
- layer: null,
-
- /**
- * Property: options
- * {Object} Any options sent to the constructor.
- */
- options: null,
+OpenLayers.ImgPath = '';
- /**
- * Property: active
- * {Boolean} The control is active.
- */
- active: null,
+/**
+ * Function: getImagesLocation
+ *
+ * Returns:
+ * {String} The fully formatted image location string
+ */
+OpenLayers.Util.getImagesLocation = function() {
+ return OpenLayers.ImgPath || (OpenLayers._getScriptLocation() + "img/");
+};
- /**
- * Property: autoActivate
- * {Boolean} The creator of the strategy can set autoActivate to false
- * to fully control when the protocol is activated and deactivated.
- * Defaults to true.
- */
- autoActivate: true,
- /**
- * Property: autoDestroy
- * {Boolean} The creator of the strategy can set autoDestroy to false
- * to fully control when the strategy is destroyed. Defaults to
- * true.
- */
- autoDestroy: true,
-
- /**
- * Constructor: OpenLayers.Strategy
- * Abstract class for vector strategies. Create instances of a subclass.
- *
- * Parameters:
- * options - {Object} Optional object whose properties will be set on the
- * instance.
- */
- initialize: function(options) {
- OpenLayers.Util.extend(this, options);
- this.options = options;
- // set the active property here, so that user cannot override it
- this.active = false;
- },
-
- /**
- * APIMethod: destroy
- * Clean up the strategy.
- */
- destroy: function() {
- this.deactivate();
- this.layer = null;
- this.options = null;
- },
-
- /**
- * Method: setLayer
- * Called to set the <layer> property.
- *
- * Parameters:
- * {<OpenLayers.Layer.Vector>}
- */
- setLayer: function(layer) {
- this.layer = layer;
- },
-
- /**
- * Method: activate
- * Activate the strategy. Register any listeners, do appropriate setup.
- *
- * Returns:
- * {Boolean} True if the strategy was successfully activated or false if
- * the strategy was already active.
- */
- activate: function() {
- if (!this.active) {
- this.active = true;
- return true;
- }
- return false;
- },
-
- /**
- * Method: deactivate
- * Deactivate the strategy. Unregister any listeners, do appropriate
- * tear-down.
- *
- * Returns:
- * {Boolean} True if the strategy was successfully deactivated or false if
- * the strategy was already inactive.
- */
- deactivate: function() {
- if (this.active) {
- this.active = false;
- return true;
- }
- return false;
- },
-
- CLASS_NAME: "OpenLayers.Strategy"
-});
-/* ======================================================================
- OpenLayers/Symbolizer.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * Class: OpenLayers.Symbolizer
- * Base class representing a symbolizer used for feature rendering.
+/**
+ * Function: Try
+ * Execute functions until one of them doesn't throw an error.
+ * Capitalized because "try" is a reserved word in JavaScript.
+ * Taken directly from OpenLayers.Util.Try()
+ *
+ * Parameters:
+ * [*] - {Function} Any number of parameters may be passed to Try()
+ * It will attempt to execute each of them until one of them
+ * successfully executes.
+ * If none executes successfully, returns null.
+ *
+ * Returns:
+ * {*} The value returned by the first successfully executed function.
*/
-OpenLayers.Symbolizer = OpenLayers.Class({
-
+OpenLayers.Util.Try = function() {
+ var returnValue = null;
- /**
- * APIProperty: zIndex
- * {Number} The zIndex determines the rendering order for a symbolizer.
- * Symbolizers with larger zIndex values are rendered over symbolizers
- * with smaller zIndex values. Default is 0.
- */
- zIndex: 0,
-
- /**
- * Constructor: OpenLayers.Symbolizer
- * Instances of this class are not useful. See one of the subclasses.
- *
- * Parameters:
- * config - {Object} An object containing properties to be set on the
- * symbolizer. Any documented symbolizer property can be set at
- * construction.
- *
- * Returns:
- * A new symbolizer.
- */
- initialize: function(config) {
- OpenLayers.Util.extend(this, config);
- },
-
- /**
- * APIMethod: clone
- * Create a copy of this symbolizer.
- *
- * Returns a symbolizer of the same type with the same properties.
- */
- clone: function() {
- var Type = eval(this.CLASS_NAME);
- return new Type(OpenLayers.Util.extend({}, this));
- },
-
- CLASS_NAME: "OpenLayers.Symbolizer"
-
-});
+ for (var i=0, len=arguments.length; i<len; i++) {
+ var lambda = arguments[i];
+ try {
+ returnValue = lambda();
+ break;
+ } catch (e) {}
+ }
-/* ======================================================================
- OpenLayers/Control.js
- ====================================================================== */
+ return returnValue;
+};
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-/**
- * @requires OpenLayers/Console.js
+/**
+ * Function: getNodes
+ *
+ * These could/should be made namespace aware?
+ *
+ * Parameters:
+ * p - {}
+ * tagName - {String}
+ *
+ * Returns:
+ * {Array}
*/
+OpenLayers.Util.getNodes=function(p, tagName) {
+ var nodes = OpenLayers.Util.Try(
+ function () {
+ return OpenLayers.Util._getNodes(p.documentElement.childNodes,
+ tagName);
+ },
+ function () {
+ return OpenLayers.Util._getNodes(p.childNodes, tagName);
+ }
+ );
+ return nodes;
+};
/**
- * Class: OpenLayers.Control
- * Controls affect the display or behavior of the map. They allow everything
- * from panning and zooming to displaying a scale indicator. Controls by
- * default are added to the map they are contained within however it is
- * possible to add a control to an external div by passing the div in the
- * options parameter.
+ * Function: _getNodes
*
- * Example:
- * The following example shows how to add many of the common controls
- * to a map.
+ * Parameters:
+ * nodes - {Array}
+ * tagName - {String}
*
- * > var map = new OpenLayers.Map('map', { controls: [] });
- * >
- * > map.addControl(new OpenLayers.Control.PanZoomBar());
- * > map.addControl(new OpenLayers.Control.MouseToolbar());
- * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
- * > map.addControl(new OpenLayers.Control.Permalink());
- * > map.addControl(new OpenLayers.Control.Permalink('permalink'));
- * > map.addControl(new OpenLayers.Control.MousePosition());
- * > map.addControl(new OpenLayers.Control.OverviewMap());
- * > map.addControl(new OpenLayers.Control.KeyboardDefaults());
- *
- * The next code fragment is a quick example of how to intercept
- * shift-mouse click to display the extent of the bounding box
- * dragged out by the user. Usually controls are not created
- * in exactly this manner. See the source for a more complete
- * example:
- *
- * > var control = new OpenLayers.Control();
- * > OpenLayers.Util.extend(control, {
- * > draw: function () {
- * > // this Handler.Box will intercept the shift-mousedown
- * > // before Control.MouseDefault gets to see it
- * > this.box = new OpenLayers.Handler.Box( control,
- * > {"done": this.notice},
- * > {keyMask: OpenLayers.Handler.MOD_SHIFT});
- * > this.box.activate();
- * > },
- * >
- * > notice: function (bounds) {
- * > OpenLayers.Console.userError(bounds);
- * > }
- * > });
- * > map.addControl(control);
- *
+ * Returns:
+ * {Array}
*/
-OpenLayers.Control = OpenLayers.Class({
+OpenLayers.Util._getNodes=function(nodes, tagName) {
+ var retArray = [];
+ for (var i=0, len=nodes.length; i<len; i++) {
+ if (nodes[i].nodeName==tagName) {
+ retArray.push(nodes[i]);
+ }
+ }
- /**
- * Property: id
- * {String}
- */
- id: null,
-
- /**
- * Property: map
- * {<OpenLayers.Map>} this gets set in the addControl() function in
- * OpenLayers.Map
- */
- map: null,
+ return retArray;
+};
- /**
- * Property: div
- * {DOMElement}
- */
- div: null,
- /**
- * Property: type
- * {Number} Controls can have a 'type'. The type determines the type of
- * interactions which are possible with them when they are placed in an
- * <OpenLayers.Control.Panel>.
- */
- type: null,
- /**
- * Property: allowSelection
- * {Boolean} By deafault, controls do not allow selection, because
- * it may interfere with map dragging. If this is true, OpenLayers
- * will not prevent selection of the control.
- * Default is false.
- */
- allowSelection: false,
-
- /**
- * Property: displayClass
- * {string} This property is used for CSS related to the drawing of the
- * Control.
- */
- displayClass: "",
-
- /**
- * Property: title
- * {string} This property is used for showing a tooltip over the
- * Control.
- */
- title: "",
-
- /**
- * APIProperty: autoActivate
- * {Boolean} Activate the control when it is added to a map. Default is
- * false.
- */
- autoActivate: false,
-
- /**
- * Property: active
- * {Boolean} The control is active.
- */
- active: null,
-
- /**
- * Property: handler
- * {<OpenLayers.Handler>} null
- */
- handler: null,
-
- /**
- * APIProperty: eventListeners
- * {Object} If set as an option at construction, the eventListeners
- * object will be registered with <OpenLayers.Events.on>. Object
- * structure must be a listeners object as shown in the example for
- * the events.on method.
- */
- eventListeners: null,
-
- /**
- * Property: events
- * {<OpenLayers.Events>} Events instance for triggering control specific
- * events.
- */
- events: null,
-
- /**
- * Constant: EVENT_TYPES
- * {Array(String)} Supported application event types. Register a listener
- * for a particular event with the following syntax:
- * (code)
- * control.events.register(type, obj, listener);
- * (end)
- *
- * Listeners will be called with a reference to an event object. The
- * properties of this event depends on exactly what happened.
- *
- * All event objects have at least the following properties:
- * object - {Object} A reference to control.events.object (a reference
- * to the control).
- * element - {DOMElement} A reference to control.events.element (which
- * will be null unless documented otherwise).
- *
- * Supported map event types:
- * activate - Triggered when activated.
- * deactivate - Triggered when deactivated.
- */
- EVENT_TYPES: ["activate", "deactivate"],
-
- /**
- * Constructor: OpenLayers.Control
- * Create an OpenLayers Control. The options passed as a parameter
- * directly extend the control. For example passing the following:
- *
- * > var control = new OpenLayers.Control({div: myDiv});
- *
- * Overrides the default div attribute value of null.
- *
- * Parameters:
- * options - {Object}
- */
- initialize: function (options) {
- // We do this before the extend so that instances can override
- // className in options.
- this.displayClass =
- this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, "");
-
- OpenLayers.Util.extend(this, options);
-
- this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
- if(this.eventListeners instanceof Object) {
- this.events.on(this.eventListeners);
+/**
+ * Function: getTagText
+ *
+ * Parameters:
+ * parent - {}
+ * item - {String}
+ * index - {Integer}
+ *
+ * Returns:
+ * {String}
+ */
+OpenLayers.Util.getTagText = function (parent, item, index) {
+ var result = OpenLayers.Util.getNodes(parent, item);
+ if (result && (result.length > 0))
+ {
+ if (!index) {
+ index=0;
}
- if (this.id == null) {
- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+ if (result[index].childNodes.length > 1) {
+ return result.childNodes[1].nodeValue;
}
- },
-
- /**
- * Method: destroy
- * The destroy method is used to perform any clean up before the control
- * is dereferenced. Typically this is where event listeners are removed
- * to prevent memory leaks.
- */
- destroy: function () {
- if(this.events) {
- if(this.eventListeners) {
- this.events.un(this.eventListeners);
- }
- this.events.destroy();
- this.events = null;
+ else if (result[index].childNodes.length == 1) {
+ return result[index].firstChild.nodeValue;
}
- this.eventListeners = null;
+ } else {
+ return "";
+ }
+};
- // eliminate circular references
- if (this.handler) {
- this.handler.destroy();
- this.handler = null;
- }
- if(this.handlers) {
- for(var key in this.handlers) {
- if(this.handlers.hasOwnProperty(key) &&
- typeof this.handlers[key].destroy == "function") {
- this.handlers[key].destroy();
- }
+/**
+ * Function: getXmlNodeValue
+ *
+ * Parameters:
+ * node - {XMLNode}
+ *
+ * Returns:
+ * {String} The text value of the given node, without breaking in firefox or IE
+ */
+OpenLayers.Util.getXmlNodeValue = function(node) {
+ var val = null;
+ OpenLayers.Util.Try(
+ function() {
+ val = node.text;
+ if (!val) {
+ val = node.textContent;
}
- this.handlers = null;
- }
- if (this.map) {
- this.map.removeControl(this);
- this.map = null;
- }
- },
-
- /**
- * Method: setMap
- * Set the map property for the control. This is done through an accessor
- * so that subclasses can override this and take special action once
- * they have their map variable set.
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- setMap: function(map) {
- this.map = map;
- if (this.handler) {
- this.handler.setMap(map);
- }
- },
-
- /**
- * Method: draw
- * The draw method is called when the control is ready to be displayed
- * on the page. If a div has not been created one is created. Controls
- * with a visual component will almost always want to override this method
- * to customize the look of control.
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>} The top-left pixel position of the control
- * or null.
- *
- * Returns:
- * {DOMElement} A reference to the DIV DOMElement containing the control
- */
- draw: function (px) {
- if (this.div == null) {
- this.div = OpenLayers.Util.createDiv(this.id);
- this.div.className = this.displayClass;
- if (!this.allowSelection) {
- this.div.className += " olControlNoSelect";
- this.div.setAttribute("unselectable", "on", 0);
- this.div.onselectstart = OpenLayers.Function.False;
- }
- if (this.title != "") {
- this.div.title = this.title;
+ if (!val) {
+ val = node.firstChild.nodeValue;
}
- }
- if (px != null) {
- this.position = px.clone();
- }
- this.moveTo(this.position);
- return this.div;
- },
+ },
+ function() {
+ val = node.textContent;
+ });
+ return val;
+};
- /**
- * Method: moveTo
- * Sets the left and top style attributes to the passed in pixel
- * coordinates.
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- */
- moveTo: function (px) {
- if ((px != null) && (this.div != null)) {
- this.div.style.left = px.x + "px";
- this.div.style.top = px.y + "px";
- }
- },
+/**
+ * Function: mouseLeft
+ *
+ * Parameters:
+ * evt - {Event}
+ * div - {HTMLDivElement}
+ *
+ * Returns:
+ * {Boolean}
+ */
+OpenLayers.Util.mouseLeft = function (evt, div) {
+ // start with the element to which the mouse has moved
+ var target = (evt.relatedTarget) ? evt.relatedTarget : evt.toElement;
+ // walk up the DOM tree.
+ while (target != div && target != null) {
+ target = target.parentNode;
+ }
+ // if the target we stop at isn't the div, then we've left the div.
+ return (target != div);
+};
- /**
- * Method: activate
- * Explicitly activates a control and it's associated
- * handler if one has been set. Controls can be
- * deactivated by calling the deactivate() method.
- *
- * Returns:
- * {Boolean} True if the control was successfully activated or
- * false if the control was already active.
- */
- activate: function () {
- if (this.active) {
- return false;
- }
- if (this.handler) {
- this.handler.activate();
- }
- this.active = true;
- if(this.map) {
- OpenLayers.Element.addClass(
- this.map.viewPortDiv,
- this.displayClass.replace(/ /g, "") + "Active"
- );
- }
- this.events.triggerEvent("activate");
- return true;
- },
-
- /**
- * Method: deactivate
- * Deactivates a control and it's associated handler if any. The exact
- * effect of this depends on the control itself.
- *
- * Returns:
- * {Boolean} True if the control was effectively deactivated or false
- * if the control was already inactive.
- */
- deactivate: function () {
- if (this.active) {
- if (this.handler) {
- this.handler.deactivate();
- }
- this.active = false;
- if(this.map) {
- OpenLayers.Element.removeClass(
- this.map.viewPortDiv,
- this.displayClass.replace(/ /g, "") + "Active"
- );
- }
- this.events.triggerEvent("deactivate");
- return true;
- }
- return false;
- },
+/**
+ * Property: precision
+ * {Number} The number of significant digits to retain to avoid
+ * floating point precision errors.
+ *
+ * We use 14 as a "safe" default because, although IEEE 754 double floats
+ * (standard on most modern operating systems) support up to about 16
+ * significant digits, 14 significant digits are sufficient to represent
+ * sub-millimeter accuracy in any coordinate system that anyone is likely to
+ * use with OpenLayers.
+ *
+ * If DEFAULT_PRECISION is set to 0, the original non-truncating behavior
+ * of OpenLayers <2.8 is preserved. Be aware that this will cause problems
+ * with certain projections, e.g. spherical Mercator.
+ *
+ */
+OpenLayers.Util.DEFAULT_PRECISION = 14;
- CLASS_NAME: "OpenLayers.Control"
-});
-
/**
- * Constant: OpenLayers.Control.TYPE_BUTTON
+ * Function: toFloat
+ * Convenience method to cast an object to a Number, rounded to the
+ * desired floating point precision.
+ *
+ * Parameters:
+ * number - {Number} The number to cast and round.
+ * precision - {Number} An integer suitable for use with
+ * Number.toPrecision(). Defaults to OpenLayers.Util.DEFAULT_PRECISION.
+ * If set to 0, no rounding is performed.
+ *
+ * Returns:
+ * {Number} The cast, rounded number.
*/
-OpenLayers.Control.TYPE_BUTTON = 1;
+OpenLayers.Util.toFloat = function (number, precision) {
+ if (precision == null) {
+ precision = OpenLayers.Util.DEFAULT_PRECISION;
+ }
+ if (typeof number !== "number") {
+ number = parseFloat(number);
+ }
+ return precision === 0 ? number :
+ parseFloat(number.toPrecision(precision));
+};
/**
- * Constant: OpenLayers.Control.TYPE_TOGGLE
+ * Function: rad
+ *
+ * Parameters:
+ * x - {Float}
+ *
+ * Returns:
+ * {Float}
*/
-OpenLayers.Control.TYPE_TOGGLE = 2;
+OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
/**
- * Constant: OpenLayers.Control.TYPE_TOOL
+ * Function: deg
+ *
+ * Parameters:
+ * x - {Float}
+ *
+ * Returns:
+ * {Float}
*/
-OpenLayers.Control.TYPE_TOOL = 3;
-/* ======================================================================
- OpenLayers/Lang.js
- ====================================================================== */
+OpenLayers.Util.deg = function(x) {return x*180/Math.PI;};
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
/**
- * @requires OpenLayers/Console.js
+ * Property: VincentyConstants
+ * {Object} Constants for Vincenty functions.
*/
+OpenLayers.Util.VincentyConstants = {
+ a: 6378137,
+ b: 6356752.3142,
+ f: 1/298.257223563
+};
/**
- * Namespace: OpenLayers.Lang
- * Internationalization namespace. Contains dictionaries in various languages
- * and methods to set and get the current language.
+ * APIFunction: distVincenty
+ * Given two objects representing points with geographic coordinates, this
+ * calculates the distance between those points on the surface of an
+ * ellipsoid.
+ *
+ * Parameters:
+ * p1 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
+ * p2 - {<OpenLayers.LonLat>} (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.Lang = {
-
- /**
- * Property: code
- * {String} Current language code to use in OpenLayers. Use the
- * <setCode> method to set this value and the <getCode> method to
- * retrieve it.
- */
- code: null,
+OpenLayers.Util.distVincenty = function(p1, p2) {
+ var ct = OpenLayers.Util.VincentyConstants;
+ var a = ct.a, b = ct.b, f = ct.f;
- /**
- * 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:
- * The current language code.
- */
- getCode: function() {
- if(!OpenLayers.Lang.code) {
- OpenLayers.Lang.setCode();
+ 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
}
- return OpenLayers.Lang.code;
- },
-
- /**
- * APIFunction: setCode
- * Set the language code for string translation. This code is used by
- * the <OpenLayers.Lang.translate> 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 <OpenLayers.Lang>
- * dictionary exists for the code, the <OpenLayers.String.defaultLang>
- * will be used.
- */
- setCode: function(code) {
- var lang;
- if(!code) {
- code = (OpenLayers.Util.getBrowserName() == "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 <getCode> will be used to determine the appropriate
- * dictionary. Dictionaries are stored in <OpenLayers.Lang>.
- *
- * Parameters:
- * key - {String} The key for an i18n string value in the dictionary.
- * context - {Object} Optional context to be used with
- * <OpenLayers.String.format>.
- *
- * Returns:
- * {String} A internationalized string.
- */
- translate: function(key, context) {
- var dictionary = OpenLayers.Lang[OpenLayers.Lang.getCode()];
- var message = dictionary[key];
- if(!message) {
- // Message not found, fall back to message key
- message = key;
- }
- if(context) {
- message = OpenLayers.String.format(message, context);
- }
- return message;
+ 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;
};
-
/**
- * APIMethod: OpenLayers.i18n
- * Alias for <OpenLayers.Lang.translate>. Looks up a key from a dictionary
- * based on the current language string. The value of
- * <OpenLayers.Lang.getCode> will be used to determine the appropriate
- * dictionary. Dictionaries are stored in <OpenLayers.Lang>.
+ * 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:
- * key - {String} The key for an i18n string value in the dictionary.
- * context - {Object} Optional context to be used with
- * <OpenLayers.String.format>.
- *
+ * lonlat - {<OpenLayers.LonLat>} (or any object with both .lat, .lon
+ * properties) The start point.
+ * brng - {Float} The bearing (degrees).
+ * distance - {Float} The ground distance (meters).
+ *
* Returns:
- * {String} A internationalized string.
+ * {<OpenLayers.LonLat>} The destination point.
*/
-OpenLayers.i18n = OpenLayers.Lang.translate;
-/* ======================================================================
- OpenLayers/Popup/Anchored.js
- ====================================================================== */
+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;
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
+ 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);
-/**
- * @requires OpenLayers/Popup.js
- */
+ 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)));
-/**
- * Class: OpenLayers.Popup.Anchored
- *
- * Inherits from:
- * - <OpenLayers.Popup>
- */
-OpenLayers.Popup.Anchored =
- OpenLayers.Class(OpenLayers.Popup, {
+ 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;
+ }
- /**
- * Parameter: relativePosition
- * {String} Relative position of the popup ("br", "tr", "tl" or "bl").
- */
- relativePosition: null,
-
- /**
- * APIProperty: keepInMap
- * {Boolean} If panMapIfOutOfView is false, and this property is true,
- * contrain the popup such that it always fits in the available map
- * space. By default, this is set. If you are creating popups that are
- * near map edges and not allowing pannning, and especially if you have
- * a popup which has a fixedRelativePosition, setting this to false may
- * be a smart thing to do.
- *
- * For anchored popups, default is true, since subclasses will
- * usually want this functionality.
- */
- keepInMap: true,
+ 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)));
- /**
- * Parameter: anchor
- * {Object} Object to which we'll anchor the popup. Must expose a
- * 'size' (<OpenLayers.Size>) and 'offset' (<OpenLayers.Pixel>).
- */
- anchor: null,
+ var revAz = Math.atan2(sinAlpha, -tmp); // final bearing
- /**
- * Constructor: OpenLayers.Popup.Anchored
- *
- * Parameters:
- * id - {String}
- * lonlat - {<OpenLayers.LonLat>}
- * contentSize - {<OpenLayers.Size>}
- * contentHTML - {String}
- * anchor - {Object} Object which must expose a 'size' <OpenLayers.Size>
- * and 'offset' <OpenLayers.Pixel> (generally an <OpenLayers.Icon>).
- * closeBox - {Boolean}
- * closeBoxCallback - {Function} Function to be called on closeBox click.
- */
- initialize:function(id, lonlat, contentSize, contentHTML, anchor, closeBox,
- closeBoxCallback) {
- var newArguments = [
- id, lonlat, contentSize, contentHTML, closeBox, closeBoxCallback
- ];
- OpenLayers.Popup.prototype.initialize.apply(this, newArguments);
+ return new OpenLayers.LonLat(lon1+u.deg(L), u.deg(lat2));
+};
- this.anchor = (anchor != null) ? anchor
- : { size: new OpenLayers.Size(0,0),
- offset: new OpenLayers.Pixel(0,0)};
- },
-
- /**
- * APIMethod: destroy
- */
- destroy: function() {
- this.anchor = null;
- this.relativePosition = null;
-
- OpenLayers.Popup.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * APIMethod: show
- * Overridden from Popup since user might hide popup and then show() it
- * in a new location (meaning we might want to update the relative
- * position on the show)
- */
- show: function() {
- this.updatePosition();
- OpenLayers.Popup.prototype.show.apply(this, arguments);
- },
-
- /**
- * Method: moveTo
- * Since the popup is moving to a new px, it might need also to be moved
- * relative to where the marker is. We first calculate the new
- * relativePosition, and then we calculate the new px where we will
- * put the popup, based on the new relative position.
- *
- * If the relativePosition has changed, we must also call
- * updateRelativePosition() to make any visual changes to the popup
- * which are associated with putting it in a new relativePosition.
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- */
- moveTo: function(px) {
- var oldRelativePosition = this.relativePosition;
- this.relativePosition = this.calculateRelativePosition(px);
-
- var newPx = this.calculateNewPx(px);
-
- var newArguments = new Array(newPx);
- OpenLayers.Popup.prototype.moveTo.apply(this, newArguments);
-
- //if this move has caused the popup to change its relative position,
- // we need to make the appropriate cosmetic changes.
- if (this.relativePosition != oldRelativePosition) {
- this.updateRelativePosition();
- }
- },
-
- /**
- * APIMethod: setSize
- *
- * Parameters:
- * contentSize - {<OpenLayers.Size>} the new size for the popup's
- * contents div (in pixels).
- */
- setSize:function(contentSize) {
- OpenLayers.Popup.prototype.setSize.apply(this, arguments);
-
- if ((this.lonlat) && (this.map)) {
- var px = this.map.getLayerPxFromLonLat(this.lonlat);
- this.moveTo(px);
- }
- },
-
- /**
- * Method: calculateRelativePosition
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {String} The relative position ("br" "tr" "tl" "bl") at which the popup
- * should be placed.
- */
- calculateRelativePosition:function(px) {
- var lonlat = this.map.getLonLatFromLayerPx(px);
-
- var extent = this.map.getExtent();
- var quadrant = extent.determineQuadrant(lonlat);
-
- return OpenLayers.Bounds.oppositeQuadrant(quadrant);
- },
-
- /**
- * Method: updateRelativePosition
- * The popup has been moved to a new relative location, so we may want to
- * make some cosmetic adjustments to it.
- *
- * Note that in the classic Anchored popup, there is nothing to do
- * here, since the popup looks exactly the same in all four positions.
- * Subclasses such as the AnchoredBubble and Framed, however, will
- * want to do something special here.
- */
- updateRelativePosition: function() {
- //to be overridden by subclasses
- },
-
- /**
- * Method: calculateNewPx
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.Pixel>} The the new px position of the popup on the screen
- * relative to the passed-in px.
- */
- calculateNewPx:function(px) {
- var newPx = px.offset(this.anchor.offset);
-
- //use contentSize if size is not already set
- var size = this.size || this.contentSize;
-
- var top = (this.relativePosition.charAt(0) == 't');
- newPx.y += (top) ? -(size.h + this.anchor.size.h) : this.anchor.size.h;
-
- var left = (this.relativePosition.charAt(1) == 'l');
- newPx.x += (left) ? -(size.w + this.anchor.size.w) : this.anchor.size.w;
-
- return newPx;
- },
-
- CLASS_NAME: "OpenLayers.Popup.Anchored"
-});
-/* ======================================================================
- OpenLayers/Renderer/Canvas.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
/**
- * @requires OpenLayers/Renderer.js
- */
-
-/**
- * Class: OpenLayers.Renderer.Canvas
- * A renderer based on the 2D 'canvas' drawing element.element
+ * 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.
*
- * Inherits:
- * - <OpenLayers.Renderer>
+ * Parameters:
+ * url - {String} Optional url used to extract the query string.
+ * If null, query string is taken from page location.
+ *
+ * Returns:
+ * {Object} An object of key/value pairs from the query string.
*/
-OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
+OpenLayers.Util.getParameters = function(url) {
+ // if no url specified, take it from the location bar
+ url = url || window.location.href;
- /**
- * Property: canvas
- * {Canvas} The canvas context object.
- */
- canvas: null,
-
- /**
- * Property: features
- * {Object} Internal object of feature/style pairs for use in redrawing the layer.
- */
- features: null,
-
- /**
- * Constructor: OpenLayers.Renderer.Canvas
- *
- * Parameters:
- * containerID - {<String>}
- */
- initialize: function(containerID) {
- OpenLayers.Renderer.prototype.initialize.apply(this, arguments);
- this.root = document.createElement("canvas");
- this.container.appendChild(this.root);
- this.canvas = this.root.getContext("2d");
- this.features = {};
- },
-
- /**
- * Method: eraseGeometry
- * Erase a geometry from the renderer. Because the Canvas renderer has
- * 'memory' of the features that it has drawn, we have to remove the
- * feature so it doesn't redraw.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * featureId - {String}
- */
- eraseGeometry: function(geometry, featureId) {
- this.eraseFeatures(this.features[featureId][0]);
- },
+ //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);
+ }
- /**
- * APIMethod: supported
- *
- * Returns:
- * {Boolean} Whether or not the browser supports the renderer class
- */
- supported: function() {
- var canvas = document.createElement("canvas");
- return !!canvas.getContext;
- },
-
- /**
- * Method: setExtent
- * Set the visible part of the layer.
- *
- * Resolution has probably changed, so we nullify the resolution
- * cache (this.resolution), then redraw.
- *
- * Parameters:
- * extent - {<OpenLayers.Bounds>}
- */
- setExtent: function(extent) {
- this.extent = extent.clone();
- this.resolution = null;
- this.redraw();
- },
-
- /**
- * Method: setSize
- * Sets the size of the drawing surface.
- *
- * Once the size is updated, redraw the canvas.
- *
- * Parameters:
- * size - {<OpenLayers.Size>}
- */
- setSize: function(size) {
- this.size = size.clone();
- this.root.style.width = size.w + "px";
- this.root.style.height = size.h + "px";
- this.root.width = size.w;
- this.root.height = size.h;
- this.resolution = null;
- },
-
- /**
- * Method: drawFeature
- * Draw the feature. Stores the feature in the features list,
- * then redraws the layer.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- * style - {<Object>}
- */
- drawFeature: function(feature, style) {
- style = style || feature.style;
- style = this.applyDefaultSymbolizer(style);
-
- this.features[feature.id] = [feature, style];
- this.redraw();
- },
+ var parameters = {};
+ var pairs = paramsString.split(/[&;]/);
+ for(var i=0, len=pairs.length; i<len; ++i) {
+ var keyValue = pairs[i].split('=');
+ if (keyValue[0]) {
-
- /**
- * Method: drawGeometry
- * Used when looping (in redraw) over the features; draws
- * the canvas.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- */
- drawGeometry: function(geometry, style) {
- var className = geometry.CLASS_NAME;
- if ((className == "OpenLayers.Geometry.Collection") ||
- (className == "OpenLayers.Geometry.MultiPoint") ||
- (className == "OpenLayers.Geometry.MultiLineString") ||
- (className == "OpenLayers.Geometry.MultiPolygon")) {
- for (var i = 0; i < geometry.components.length; i++) {
- this.drawGeometry(geometry.components[i], style);
+ var key = keyValue[0];
+ try {
+ key = decodeURIComponent(key);
+ } catch (err) {
+ key = unescape(key);
}
- return;
- }
- switch (geometry.CLASS_NAME) {
- case "OpenLayers.Geometry.Point":
- this.drawPoint(geometry, style);
- break;
- case "OpenLayers.Geometry.LineString":
- this.drawLineString(geometry, style);
- break;
- case "OpenLayers.Geometry.LinearRing":
- this.drawLinearRing(geometry, style);
- break;
- case "OpenLayers.Geometry.Polygon":
- this.drawPolygon(geometry, style);
- break;
- default:
- break;
- }
- },
-
- /**
- * Method: drawExternalGraphic
- * Called to draw External graphics.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- */
- drawExternalGraphic: function(pt, style) {
- var img = new Image();
-
- if(style.graphicTitle) {
- img.title=style.graphicTitle;
- }
-
- var width = style.graphicWidth || style.graphicHeight;
- var height = style.graphicHeight || style.graphicWidth;
- width = width ? width : style.pointRadius*2;
- height = height ? height : style.pointRadius*2;
- var xOffset = (style.graphicXOffset != undefined) ?
- style.graphicXOffset : -(0.5 * width);
- var yOffset = (style.graphicYOffset != undefined) ?
- style.graphicYOffset : -(0.5 * height);
-
- var context = { img: img,
- x: (pt[0]+xOffset),
- y: (pt[1]+yOffset),
- width: width,
- height: height,
- opacity: style.graphicOpacity || style.fillOpacity,
- canvas: this.canvas };
-
- img.onload = OpenLayers.Function.bind( function() {
- this.canvas.globalAlpha = this.opacity;
- this.canvas.drawImage(this.img, this.x,
- this.y, this.width, this.height);
- }, context);
- img.src = style.externalGraphic;
- },
-
- /**
- * Method: setCanvasStyle
- * Prepare the canvas for drawing by setting various global settings.
- *
- * Parameters:
- * type - {String} one of 'stroke', 'fill', or 'reset'
- * style - {Object} Symbolizer hash
- */
- setCanvasStyle: function(type, style) {
- if (type == "fill") {
- this.canvas.globalAlpha = style['fillOpacity'];
- this.canvas.fillStyle = style['fillColor'];
- } else if (type == "stroke") {
- this.canvas.globalAlpha = style['strokeOpacity'];
- this.canvas.strokeStyle = style['strokeColor'];
- this.canvas.lineWidth = style['strokeWidth'];
- } else {
- this.canvas.globalAlpha = 0;
- this.canvas.lineWidth = 1;
- }
- },
-
- /**
- * Method: drawPoint
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- */
- drawPoint: function(geometry, style) {
- if(style.graphic !== false) {
- var pt = this.getLocalXY(geometry);
- if (style.externalGraphic) {
- this.drawExternalGraphic(pt, style);
- } else {
- if(style.fill !== false) {
- this.setCanvasStyle("fill", style);
- this.canvas.beginPath();
- this.canvas.arc(pt[0], pt[1], style.pointRadius, 0, Math.PI*2, true);
- this.canvas.fill();
- }
-
- if(style.stroke !== false) {
- this.setCanvasStyle("stroke", style);
- this.canvas.beginPath();
- this.canvas.arc(pt[0], pt[1], style.pointRadius, 0, Math.PI*2, true);
- this.canvas.stroke();
- this.setCanvasStyle("reset");
- }
- }
- }
- },
+ // being liberal by replacing "+" with " "
+ var value = (keyValue[1] || '').replace(/\+/g, " ");
- /**
- * Method: drawLineString
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- */
- drawLineString: function(geometry, style) {
- if(style.stroke !== false) {
- this.setCanvasStyle("stroke", style);
- this.canvas.beginPath();
- var start = this.getLocalXY(geometry.components[0]);
- this.canvas.moveTo(start[0], start[1]);
- for(var i = 1; i < geometry.components.length; i++) {
- var pt = this.getLocalXY(geometry.components[i]);
- this.canvas.lineTo(pt[0], pt[1]);
+ try {
+ value = decodeURIComponent(value);
+ } catch (err) {
+ value = unescape(value);
}
- this.canvas.stroke();
- }
- this.setCanvasStyle("reset");
- },
-
- /**
- * Method: drawLinearRing
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- */
- drawLinearRing: function(geometry, style) {
- if(style.fill !== false) {
- this.setCanvasStyle("fill", style);
- this.canvas.beginPath();
- var start = this.getLocalXY(geometry.components[0]);
- this.canvas.moveTo(start[0], start[1]);
- for(var i = 1; i < geometry.components.length - 1 ; i++) {
- var pt = this.getLocalXY(geometry.components[i]);
- this.canvas.lineTo(pt[0], pt[1]);
- }
- this.canvas.fill();
- }
-
- if(style.stroke !== false) {
- this.setCanvasStyle("stroke", style);
- this.canvas.beginPath();
- var start = this.getLocalXY(geometry.components[0]);
- this.canvas.moveTo(start[0], start[1]);
- for(var i = 1; i < geometry.components.length; i++) {
- var pt = this.getLocalXY(geometry.components[i]);
- this.canvas.lineTo(pt[0], pt[1]);
- }
- this.canvas.stroke();
- }
- this.setCanvasStyle("reset");
- },
-
- /**
- * Method: drawPolygon
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- */
- drawPolygon: function(geometry, style) {
- this.drawLinearRing(geometry.components[0], style);
- for (var i = 1; i < geometry.components.length; i++) {
- this.drawLinearRing(geometry.components[i], {
- fillOpacity: 0,
- strokeWidth: 0,
- strokeOpacity: 0,
- strokeColor: '#000000',
- fillColor: '#000000'}
- ); // inner rings are 'empty'
- }
- },
-
- /**
- * Method: drawText
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * location - {<OpenLayers.Point>}
- * style - {Object}
- */
- drawText: function(location, style) {
- style = OpenLayers.Util.extend({
- fontColor: "#000000",
- labelAlign: "cm"
- }, style);
- var pt = this.getLocalXY(location);
-
- this.setCanvasStyle("reset");
- this.canvas.fillStyle = style.fontColor;
- this.canvas.globalAlpha = style.fontOpacity || 1.0;
- var fontStyle = style.fontWeight + " " + style.fontSize + " " + style.fontFamily;
- if (this.canvas.fillText) {
- // HTML5
- var labelAlign =
- OpenLayers.Renderer.Canvas.LABEL_ALIGN[style.labelAlign[0]] ||
- "center";
- this.canvas.font = fontStyle;
- this.canvas.textAlign = labelAlign;
- this.canvas.fillText(style.label, pt[0], pt[1]);
- } else if (this.canvas.mozDrawText) {
- // Mozilla pre-Gecko1.9.1 (<FF3.1)
- this.canvas.mozTextStyle = fontStyle;
- // No built-in text alignment, so we measure and adjust the position
- var len = this.canvas.mozMeasureText(style.label);
- switch(style.labelAlign[0]) {
- case "l":
- break;
- case "r":
- pt[0] -= len;
- break;
- case "c":
- default:
- pt[0] -= len / 2;
- }
- this.canvas.translate(pt[0], pt[1]);
- this.canvas.mozDrawText(style.label);
- this.canvas.translate(-1*pt[0], -1*pt[1]);
- }
- this.setCanvasStyle("reset");
- },
+ // follow OGC convention of comma delimited values
+ value = value.split(",")
- /**
- * Method: getLocalXY
- * transform geographic xy into pixel xy
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point>}
- */
- getLocalXY: function(point) {
- var resolution = this.getResolution();
- var extent = this.extent;
- var x = (point.x / resolution + (-extent.left / resolution));
- var y = ((extent.top / resolution) - point.y / resolution);
- return [x, y];
- },
+ //if there's only one value, do not return as array
+ if (value.length == 1) {
+ value = value[0];
+ }
+
+ parameters[key] = value;
+ }
+ }
+ return parameters;
+};
- /**
- * Method: clear
- * Clear all vectors from the renderer.
- */
- clear: function() {
- this.canvas.clearRect(0, 0, this.root.width, this.root.height);
- this.features = {};
- },
-
- /**
- * Method: getFeatureIdFromEvent
- * Returns a feature id from an event on the renderer.
- *
- * Parameters:
- * evt - {<OpenLayers.Event>}
- *
- * Returns:
- * {String} A feature id or null.
- */
- getFeatureIdFromEvent: function(evt) {
- var loc = this.map.getLonLatFromPixel(evt.xy);
- var resolution = this.getResolution();
- var bounds = new OpenLayers.Bounds(loc.lon - resolution * 5,
- loc.lat - resolution * 5,
- loc.lon + resolution * 5,
- loc.lat + resolution * 5);
- var geom = bounds.toGeometry();
- for (var feat in this.features) {
- if (!this.features.hasOwnProperty(feat)) { continue; }
- if (this.features[feat][0].geometry.intersects(geom)) {
- return feat;
- }
- }
- return null;
- },
-
- /**
- * Method: eraseFeatures
- * This is called by the layer to erase features; removes the feature from
- * the list, then redraws the layer.
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>)}
- */
- eraseFeatures: function(features) {
- if(!(features instanceof Array)) {
- features = [features];
- }
- for(var i=0; i<features.length; ++i) {
- delete this.features[features[i].id];
- }
- this.redraw();
- },
-
- /**
- * Method: redraw
- * The real 'meat' of the function: any time things have changed,
- * redraw() can be called to loop over all the data and (you guessed
- * it) redraw it. Unlike Elements-based Renderers, we can't interact
- * with things once they're drawn, to remove them, for example, so
- * instead we have to just clear everything and draw from scratch.
- */
- redraw: function() {
- if (!this.locked) {
- this.canvas.clearRect(0, 0, this.root.width, this.root.height);
- var labelMap = [];
- var feature, style;
- for (var id in this.features) {
- if (!this.features.hasOwnProperty(id)) { continue; }
- feature = this.features[id][0];
- style = this.features[id][1];
- if (!feature.geometry) { continue; }
- this.drawGeometry(feature.geometry, style);
- if(style.label) {
- labelMap.push([feature, style]);
- }
- }
- var item;
- for (var i=0, len=labelMap.length; i<len; ++i) {
- item = labelMap[i];
- this.drawText(item[0].geometry.getCentroid(), item[1]);
- }
- }
- },
-
- CLASS_NAME: "OpenLayers.Renderer.Canvas"
-});
-
/**
- * Constant: OpenLayers.Renderer.Canvas.LABEL_ALIGN
- * {Object}
+ * Function: getArgs
+ * *Deprecated*. Will be removed in 3.0. Please use instead
+ * <OpenLayers.Util.getParameters>
+ *
+ * Parameters:
+ * url - {String} Optional url used to extract the query string.
+ * If null, query string is taken from page location.
+ *
+ * Returns:
+ * {Object} An object of key/value pairs from the query string.
*/
-OpenLayers.Renderer.Canvas.LABEL_ALIGN = {
- "l": "left",
- "r": "right"
+OpenLayers.Util.getArgs = function(url) {
+ OpenLayers.Console.warn(
+ OpenLayers.i18n(
+ "methodDeprecated", {'newMethod': 'OpenLayers.Util.getParameters'}
+ )
+ );
+ return OpenLayers.Util.getParameters(url);
};
-/* ======================================================================
- OpenLayers/Renderer/Elements.js
- ====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
+/**
+ * Property: lastSeqID
+ * {Integer} The ever-incrementing count variable.
+ * Used for generating unique ids.
+ */
+OpenLayers.Util.lastSeqID = 0;
/**
- * @requires OpenLayers/Renderer.js
+ * Function: createUniqueID
+ * Create a unique identifier for this session. Each time this function
+ * is called, a counter is incremented. The return will be the optional
+ * prefix (defaults to "id_") appended with the counter value.
+ *
+ * Parameters:
+ * prefix {String} Optionsal string to prefix unique id. Default is "id_".
+ *
+ * Returns:
+ * {String} A unique id string, built on the passed in prefix.
*/
+OpenLayers.Util.createUniqueID = function(prefix) {
+ if (prefix == null) {
+ prefix = "id_";
+ }
+ OpenLayers.Util.lastSeqID += 1;
+ return prefix + OpenLayers.Util.lastSeqID;
+};
/**
- * Class: OpenLayers.ElementsIndexer
- * This class takes care of figuring out which order elements should be
- * placed in the DOM based on given indexing methods.
+ * Constant: INCHES_PER_UNIT
+ * {Object} Constant inches per unit -- borrowed from MapServer mapscale.c
+ * derivation of nautical miles from http://en.wikipedia.org/wiki/Nautical_mile
+ * Includes the full set of units supported by CS-MAP (http://trac.osgeo.org/csmap/)
+ * and PROJ.4 (http://trac.osgeo.org/proj/)
+ * The hardcoded table is maintain in a CS-MAP source code module named CSdataU.c
+ * The hardcoded table of PROJ.4 units are in pj_units.c.
*/
-OpenLayers.ElementsIndexer = OpenLayers.Class({
-
- /**
- * Property: maxZIndex
- * {Integer} This is the largest-most z-index value for a node
- * contained within the indexer.
- */
- maxZIndex: null,
-
- /**
- * Property: order
- * {Array<String>} This is an array of node id's stored in the
- * order that they should show up on screen. Id's higher up in the
- * array (higher array index) represent nodes with higher z-indeces.
- */
- order: null,
-
- /**
- * Property: indices
- * {Object} This is a hash that maps node ids to their z-index value
- * stored in the indexer. This is done to make finding a nodes z-index
- * value O(1).
- */
- indices: null,
-
- /**
- * Property: compare
- * {Function} This is the function used to determine placement of
- * of a new node within the indexer. If null, this defaults to to
- * the Z_ORDER_DRAWING_ORDER comparison method.
- */
- compare: null,
-
- /**
- * APIMethod: initialize
- * Create a new indexer with
- *
- * Parameters:
- * yOrdering - {Boolean} Whether to use y-ordering.
- */
- initialize: function(yOrdering) {
+OpenLayers.INCHES_PER_UNIT = {
+ 'inches': 1.0,
+ 'ft': 12.0,
+ 'mi': 63360.0,
+ 'm': 39.3701,
+ 'km': 39370.1,
+ 'dd': 4374754,
+ 'yd': 36
+};
+OpenLayers.INCHES_PER_UNIT["in"]= OpenLayers.INCHES_PER_UNIT.inches;
+OpenLayers.INCHES_PER_UNIT["degrees"] = OpenLayers.INCHES_PER_UNIT.dd;
+OpenLayers.INCHES_PER_UNIT["nmi"] = 1852 * OpenLayers.INCHES_PER_UNIT.m;
- this.compare = yOrdering ?
- OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER :
- OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER;
-
- this.order = [];
- this.indices = {};
- this.maxZIndex = 0;
- },
-
- /**
- * APIMethod: insert
- * Insert a new node into the indexer. In order to find the correct
- * positioning for the node to be inserted, this method uses a binary
- * search. This makes inserting O(log(n)).
- *
- * Parameters:
- * newNode - {DOMElement} The new node to be inserted.
- *
- * Returns
- * {DOMElement} the node before which we should insert our newNode, or
- * null if newNode can just be appended.
- */
- insert: function(newNode) {
- // If the node is known to the indexer, remove it so we can
- // recalculate where it should go.
- if (this.exists(newNode)) {
- this.remove(newNode);
- }
-
- var nodeId = newNode.id;
-
- this.determineZIndex(newNode);
+// Units from CS-Map
+OpenLayers.METERS_PER_INCH = 0.02540005080010160020;
+OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, {
+ "Inch": OpenLayers.INCHES_PER_UNIT.inches,
+ "Meter": 1.0 / OpenLayers.METERS_PER_INCH, //EPSG:9001
+ "Foot": 0.30480060960121920243 / OpenLayers.METERS_PER_INCH, //EPSG:9003
+ "IFoot": 0.30480000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9002
+ "ClarkeFoot": 0.3047972651151 / OpenLayers.METERS_PER_INCH, //EPSG:9005
+ "SearsFoot": 0.30479947153867624624 / OpenLayers.METERS_PER_INCH, //EPSG:9041
+ "GoldCoastFoot": 0.30479971018150881758 / OpenLayers.METERS_PER_INCH, //EPSG:9094
+ "IInch": 0.02540000000000000000 / OpenLayers.METERS_PER_INCH,
+ "MicroInch": 0.00002540000000000000 / OpenLayers.METERS_PER_INCH,
+ "Mil": 0.00000002540000000000 / OpenLayers.METERS_PER_INCH,
+ "Centimeter": 0.01000000000000000000 / OpenLayers.METERS_PER_INCH,
+ "Kilometer": 1000.00000000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9036
+ "Yard": 0.91440182880365760731 / OpenLayers.METERS_PER_INCH,
+ "SearsYard": 0.914398414616029 / OpenLayers.METERS_PER_INCH, //EPSG:9040
+ "IndianYard": 0.91439853074444079983 / OpenLayers.METERS_PER_INCH, //EPSG:9084
+ "IndianYd37": 0.91439523 / OpenLayers.METERS_PER_INCH, //EPSG:9085
+ "IndianYd62": 0.9143988 / OpenLayers.METERS_PER_INCH, //EPSG:9086
+ "IndianYd75": 0.9143985 / OpenLayers.METERS_PER_INCH, //EPSG:9087
+ "IndianFoot": 0.30479951 / OpenLayers.METERS_PER_INCH, //EPSG:9080
+ "IndianFt37": 0.30479841 / OpenLayers.METERS_PER_INCH, //EPSG:9081
+ "IndianFt62": 0.3047996 / OpenLayers.METERS_PER_INCH, //EPSG:9082
+ "IndianFt75": 0.3047995 / OpenLayers.METERS_PER_INCH, //EPSG:9083
+ "Mile": 1609.34721869443738887477 / OpenLayers.METERS_PER_INCH,
+ "IYard": 0.91440000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9096
+ "IMile": 1609.34400000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9093
+ "NautM": 1852.00000000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9030
+ "Lat-66": 110943.316488932731 / OpenLayers.METERS_PER_INCH,
+ "Lat-83": 110946.25736872234125 / OpenLayers.METERS_PER_INCH,
+ "Decimeter": 0.10000000000000000000 / OpenLayers.METERS_PER_INCH,
+ "Millimeter": 0.00100000000000000000 / OpenLayers.METERS_PER_INCH,
+ "Dekameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH,
+ "Decameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH,
+ "Hectometer": 100.00000000000000000000 / OpenLayers.METERS_PER_INCH,
+ "GermanMeter": 1.0000135965 / OpenLayers.METERS_PER_INCH, //EPSG:9031
+ "CaGrid": 0.999738 / OpenLayers.METERS_PER_INCH,
+ "ClarkeChain": 20.1166194976 / OpenLayers.METERS_PER_INCH, //EPSG:9038
+ "GunterChain": 20.11684023368047 / OpenLayers.METERS_PER_INCH, //EPSG:9033
+ "BenoitChain": 20.116782494375872 / OpenLayers.METERS_PER_INCH, //EPSG:9062
+ "SearsChain": 20.11676512155 / OpenLayers.METERS_PER_INCH, //EPSG:9042
+ "ClarkeLink": 0.201166194976 / OpenLayers.METERS_PER_INCH, //EPSG:9039
+ "GunterLink": 0.2011684023368047 / OpenLayers.METERS_PER_INCH, //EPSG:9034
+ "BenoitLink": 0.20116782494375872 / OpenLayers.METERS_PER_INCH, //EPSG:9063
+ "SearsLink": 0.2011676512155 / OpenLayers.METERS_PER_INCH, //EPSG:9043
+ "Rod": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
+ "IntnlChain": 20.1168 / OpenLayers.METERS_PER_INCH, //EPSG:9097
+ "IntnlLink": 0.201168 / OpenLayers.METERS_PER_INCH, //EPSG:9098
+ "Perch": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
+ "Pole": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
+ "Furlong": 201.1684023368046 / OpenLayers.METERS_PER_INCH,
+ "Rood": 3.778266898 / OpenLayers.METERS_PER_INCH,
+ "CapeFoot": 0.3047972615 / OpenLayers.METERS_PER_INCH,
+ "Brealey": 375.00000000000000000000 / OpenLayers.METERS_PER_INCH,
+ "ModAmFt": 0.304812252984505969011938 / OpenLayers.METERS_PER_INCH,
+ "Fathom": 1.8288 / OpenLayers.METERS_PER_INCH,
+ "NautM-UK": 1853.184 / OpenLayers.METERS_PER_INCH,
+ "50kilometers": 50000.0 / OpenLayers.METERS_PER_INCH,
+ "150kilometers": 150000.0 / OpenLayers.METERS_PER_INCH
+});
- var leftIndex = -1;
- var rightIndex = this.order.length;
- var middle;
+//unit abbreviations supported by PROJ.4
+OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, {
+ "mm": OpenLayers.INCHES_PER_UNIT["Meter"] / 1000.0,
+ "cm": OpenLayers.INCHES_PER_UNIT["Meter"] / 100.0,
+ "dm": OpenLayers.INCHES_PER_UNIT["Meter"] * 100.0,
+ "km": OpenLayers.INCHES_PER_UNIT["Meter"] * 1000.0,
+ "kmi": OpenLayers.INCHES_PER_UNIT["nmi"], //International Nautical Mile
+ "fath": OpenLayers.INCHES_PER_UNIT["Fathom"], //International Fathom
+ "ch": OpenLayers.INCHES_PER_UNIT["IntnlChain"], //International Chain
+ "link": OpenLayers.INCHES_PER_UNIT["IntnlLink"], //International Link
+ "us-in": OpenLayers.INCHES_PER_UNIT["inches"], //U.S. Surveyor's Inch
+ "us-ft": OpenLayers.INCHES_PER_UNIT["Foot"], //U.S. Surveyor's Foot
+ "us-yd": OpenLayers.INCHES_PER_UNIT["Yard"], //U.S. Surveyor's Yard
+ "us-ch": OpenLayers.INCHES_PER_UNIT["GunterChain"], //U.S. Surveyor's Chain
+ "us-mi": OpenLayers.INCHES_PER_UNIT["Mile"], //U.S. Surveyor's Statute Mile
+ "ind-yd": OpenLayers.INCHES_PER_UNIT["IndianYd37"], //Indian Yard
+ "ind-ft": OpenLayers.INCHES_PER_UNIT["IndianFt37"], //Indian Foot
+ "ind-ch": 20.11669506 / OpenLayers.METERS_PER_INCH //Indian Chain
+});
- while (rightIndex - leftIndex > 1) {
- middle = parseInt((leftIndex + rightIndex) / 2);
-
- var placement = this.compare(this, newNode,
- OpenLayers.Util.getElement(this.order[middle]));
-
- if (placement > 0) {
- leftIndex = middle;
- } else {
- rightIndex = middle;
- }
- }
-
- this.order.splice(rightIndex, 0, nodeId);
- this.indices[nodeId] = this.getZIndex(newNode);
-
- // If the new node should be before another in the index
- // order, return the node before which we have to insert the new one;
- // else, return null to indicate that the new node can be appended.
- return this.getNextElement(rightIndex);
- },
-
- /**
- * APIMethod: remove
- *
- * Parameters:
- * node - {DOMElement} The node to be removed.
- */
- remove: function(node) {
- var nodeId = node.id;
- var arrayIndex = OpenLayers.Util.indexOf(this.order, nodeId);
- if (arrayIndex >= 0) {
- // Remove it from the order array, as well as deleting the node
- // from the indeces hash.
- this.order.splice(arrayIndex, 1);
- delete this.indices[nodeId];
-
- // Reset the maxium z-index based on the last item in the
- // order array.
- if (this.order.length > 0) {
- var lastId = this.order[this.order.length - 1];
- this.maxZIndex = this.indices[lastId];
- } else {
- this.maxZIndex = 0;
- }
- }
- },
-
- /**
- * APIMethod: clear
- */
- clear: function() {
- this.order = [];
- this.indices = {};
- this.maxZIndex = 0;
- },
-
- /**
- * APIMethod: exists
- *
- * Parameters:
- * node- {DOMElement} The node to test for existence.
- *
- * Returns:
- * {Boolean} Whether or not the node exists in the indexer?
- */
- exists: function(node) {
- return (this.indices[node.id] != null);
- },
+/**
+ * Constant: DOTS_PER_INCH
+ * {Integer} 72 (A sensible default)
+ */
+OpenLayers.DOTS_PER_INCH = 72;
- /**
- * APIMethod: getZIndex
- * Get the z-index value for the current node from the node data itself.
- *
- * Parameters:
- * node - {DOMElement} The node whose z-index to get.
- *
- * Returns:
- * {Integer} The z-index value for the specified node (from the node
- * data itself).
- */
- getZIndex: function(node) {
- return node._style.graphicZIndex;
- },
-
- /**
- * Method: determineZIndex
- * Determine the z-index for the current node if there isn't one,
- * and set the maximum value if we've found a new maximum.
- *
- * Parameters:
- * node - {DOMElement}
- */
- determineZIndex: function(node) {
- var zIndex = node._style.graphicZIndex;
-
- // Everything must have a zIndex. If none is specified,
- // this means the user *must* (hint: assumption) want this
- // node to succomb to drawing order. To enforce drawing order
- // over all indexing methods, we'll create a new z-index that's
- // greater than any currently in the indexer.
- if (zIndex == null) {
- zIndex = this.maxZIndex;
- node._style.graphicZIndex = zIndex;
- } else if (zIndex > this.maxZIndex) {
- this.maxZIndex = zIndex;
- }
- },
+/**
+ * Function: normalizeScale
+ *
+ * Parameters:
+ * scale - {float}
+ *
+ * Returns:
+ * {Float} A normalized scale value, in 1 / X format.
+ * This means that if a value less than one ( already 1/x) is passed
+ * in, it just returns scale directly. Otherwise, it returns
+ * 1 / scale
+ */
+OpenLayers.Util.normalizeScale = function (scale) {
+ var normScale = (scale > 1.0) ? (1.0 / scale)
+ : scale;
+ return normScale;
+};
- /**
- * APIMethod: getNextElement
- * Get the next element in the order stack.
- *
- * Parameters:
- * index - {Integer} The index of the current node in this.order.
- *
- * Returns:
- * {DOMElement} the node following the index passed in, or
- * null.
- */
- getNextElement: function(index) {
- var nextIndex = index + 1;
- if (nextIndex < this.order.length) {
- var nextElement = OpenLayers.Util.getElement(this.order[nextIndex]);
- if (nextElement == undefined) {
- nextElement = this.getNextElement(nextIndex);
- }
- return nextElement;
- } else {
- return null;
- }
- },
-
- CLASS_NAME: "OpenLayers.ElementsIndexer"
-});
-
/**
- * Namespace: OpenLayers.ElementsIndexer.IndexingMethods
- * These are the compare methods for figuring out where a new node should be
- * placed within the indexer. These methods are very similar to general
- * sorting methods in that they return -1, 0, and 1 to specify the
- * direction in which new nodes fall in the ordering.
+ * 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.ElementsIndexer.IndexingMethods = {
-
- /**
- * Method: Z_ORDER
- * This compare method is used by other comparison methods.
- * It can be used individually for ordering, but is not recommended,
- * because it doesn't subscribe to drawing order.
- *
- * Parameters:
- * indexer - {<OpenLayers.ElementsIndexer>}
- * newNode - {DOMElement}
- * nextNode - {DOMElement}
- *
- * Returns:
- * {Integer}
- */
- Z_ORDER: function(indexer, newNode, nextNode) {
- var newZIndex = indexer.getZIndex(newNode);
-
- var returnVal = 0;
- if (nextNode) {
- var nextZIndex = indexer.getZIndex(nextNode);
- returnVal = newZIndex - nextZIndex;
+OpenLayers.Util.getResolutionFromScale = function (scale, units) {
+ var resolution;
+ if (scale) {
+ if (units == null) {
+ units = "degrees";
}
-
- return returnVal;
- },
+ var normScale = OpenLayers.Util.normalizeScale(scale);
+ resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units]
+ * OpenLayers.DOTS_PER_INCH);
+ }
+ return resolution;
+};
- /**
- * APIMethod: Z_ORDER_DRAWING_ORDER
- * This method orders nodes by their z-index, but does so in a way
- * that, if there are other nodes with the same z-index, the newest
- * drawn will be the front most within that z-index. This is the
- * default indexing method.
- *
- * Parameters:
- * indexer - {<OpenLayers.ElementsIndexer>}
- * newNode - {DOMElement}
- * nextNode - {DOMElement}
- *
- * Returns:
- * {Integer}
- */
- Z_ORDER_DRAWING_ORDER: function(indexer, newNode, nextNode) {
- var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(
- indexer,
- newNode,
- nextNode
- );
-
- // Make Z_ORDER subscribe to drawing order by pushing it above
- // all of the other nodes with the same z-index.
- if (nextNode && returnVal == 0) {
- returnVal = 1;
- }
-
- return returnVal;
- },
+/**
+ * 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) {
- /**
- * APIMethod: Z_ORDER_Y_ORDER
- * This one should really be called Z_ORDER_Y_ORDER_DRAWING_ORDER, as it
- * best describes which ordering methods have precedence (though, the
- * name would be too long). This method orders nodes by their z-index,
- * but does so in a way that, if there are other nodes with the same
- * z-index, the nodes with the lower y position will be "closer" than
- * those with a higher y position. If two nodes have the exact same y
- * position, however, then this method will revert to using drawing
- * order to decide placement.
- *
- * Parameters:
- * indexer - {<OpenLayers.ElementsIndexer>}
- * newNode - {DOMElement}
- * nextNode - {DOMElement}
- *
- * Returns:
- * {Integer}
- */
- Z_ORDER_Y_ORDER: function(indexer, newNode, nextNode) {
- var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(
- indexer,
- newNode,
- nextNode
- );
-
- if (nextNode && returnVal === 0) {
- var result = nextNode._boundsBottom - newNode._boundsBottom;
- returnVal = (result === 0) ? 1 : result;
- }
-
- return returnVal;
+ if (units == null) {
+ units = "degrees";
}
+
+ var scale = resolution * OpenLayers.INCHES_PER_UNIT[units] *
+ OpenLayers.DOTS_PER_INCH;
+ return scale;
};
/**
- * Class: OpenLayers.Renderer.Elements
- * This is another virtual class in that it should never be instantiated by
- * itself as a Renderer. It exists because there is *tons* of shared
- * functionality between different vector libraries which use nodes/elements
- * as a base for rendering vectors.
+ * Function: safeStopPropagation
+ * *Deprecated*. This function has been deprecated. Please use directly
+ * <OpenLayers.Event.stop> passing 'true' as the 2nd
+ * argument (preventDefault)
*
- * The highlevel bits of code that are implemented here are the adding and
- * removing of geometries, which is essentially the same for any
- * element-based renderer. The details of creating each node and drawing the
- * paths are of course different, but the machinery is the same.
+ * Safely stop the propagation of an event *without* preventing
+ * the default browser action from occurring.
*
- * Inherits:
- * - <OpenLayers.Renderer>
+ * Parameter:
+ * evt - {Event}
*/
-OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
+OpenLayers.Util.safeStopPropagation = function(evt) {
+ OpenLayers.Event.stop(evt, true);
+};
- /**
- * Property: rendererRoot
- * {DOMElement}
- */
- rendererRoot: null,
-
- /**
- * Property: root
- * {DOMElement}
- */
- root: null,
-
- /**
- * Property: vectorRoot
- * {DOMElement}
- */
- vectorRoot: null,
+/**
+ * Function: pagePositon
+ * 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.
- /**
- * Property: textRoot
- * {DOMElement}
- */
- textRoot: null,
+ 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;
+ }
- /**
- * Property: xmlns
- * {String}
- */
- xmlns: null,
-
- /**
- * Property: Indexer
- * {<OpenLayers.ElementIndexer>} An instance of OpenLayers.ElementsIndexer
- * created upon initialization if the zIndexing or yOrdering options
- * passed to this renderer's constructor are set to true.
- */
- indexer: null,
-
- /**
- * Constant: BACKGROUND_ID_SUFFIX
- * {String}
- */
- BACKGROUND_ID_SUFFIX: "_background",
-
- /**
- * Constant: BACKGROUND_ID_SUFFIX
- * {String}
- */
- LABEL_ID_SUFFIX: "_label",
-
- /**
- * Constructor: OpenLayers.Renderer.Elements
- *
- * Parameters:
- * containerID - {String}
- * options - {Object} options for this renderer. Supported options are:
- * * yOrdering - {Boolean} Whether to use y-ordering
- * * zIndexing - {Boolean} Whether to use z-indexing. Will be ignored
- * if yOrdering is set to true.
- */
- initialize: function(containerID, options) {
- OpenLayers.Renderer.prototype.initialize.apply(this, arguments);
+ // 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 == '');
- this.rendererRoot = this.createRenderRoot();
- this.root = this.createRoot("_root");
- this.vectorRoot = this.createRoot("_vroot");
- this.textRoot = this.createRoot("_troot");
-
- this.root.appendChild(this.vectorRoot);
- this.root.appendChild(this.textRoot);
-
- this.rendererRoot.appendChild(this.root);
- this.container.appendChild(this.rendererRoot);
-
- if(options && (options.zIndexing || options.yOrdering)) {
- this.indexer = new OpenLayers.ElementsIndexer(options.yOrdering);
- }
- },
-
- /**
- * Method: destroy
- */
- destroy: function() {
+ var parent = null;
+ var box;
- this.clear();
+ if (forElement.getBoundingClientRect) { // IE
+ box = forElement.getBoundingClientRect();
+ var scrollTop = viewportElement.scrollTop;
+ var scrollLeft = viewportElement.scrollLeft;
- this.rendererRoot = null;
- this.root = null;
- this.xmlns = null;
+ pos[0] = box.left + scrollLeft;
+ pos[1] = box.top + scrollTop;
- OpenLayers.Renderer.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: clear
- * Remove all the elements from the root
- */
- clear: function() {
- var child;
- var root = this.vectorRoot;
- if (root) {
- while (child = root.firstChild) {
- root.removeChild(child);
- }
- }
- root = this.textRoot;
- if (root) {
- while (child = root.firstChild) {
- root.removeChild(child);
- }
- }
- if (this.indexer) {
- this.indexer.clear();
- }
- },
+ } 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
- /**
- * Method: getNodeType
- * This function is in charge of asking the specific renderer which type
- * of node to create for the given geometry and style. All geometries
- * in an Elements-based renderer consist of one node and some
- * attributes. We have the nodeFactory() function which creates a node
- * for us, but it takes a 'type' as input, and that is precisely what
- * this function tells us.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- *
- * Returns:
- * {String} The corresponding node type for the specified geometry
- */
- getNodeType: function(geometry, style) { },
+ box = document.getBoxObjectFor(forElement);
+ var vpBox = document.getBoxObjectFor(viewportElement);
+ pos[0] = box.screenX - vpBox.screenX;
+ pos[1] = box.screenY - vpBox.screenY;
- /**
- * Method: drawGeometry
- * Draw the geometry, creating new nodes, setting paths, setting style,
- * setting featureId on the node. This method should only be called
- * by the renderer itself.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- * featureId - {String}
- *
- * Returns:
- * {Boolean} true if the geometry has been drawn completely; null if
- * incomplete; false otherwise
- */
- drawGeometry: function(geometry, style, featureId) {
- var className = geometry.CLASS_NAME;
- var rendered = true;
- if ((className == "OpenLayers.Geometry.Collection") ||
- (className == "OpenLayers.Geometry.MultiPoint") ||
- (className == "OpenLayers.Geometry.MultiLineString") ||
- (className == "OpenLayers.Geometry.MultiPolygon")) {
- for (var i = 0, len=geometry.components.length; i<len; i++) {
- rendered = this.drawGeometry(
- geometry.components[i], style, featureId) && rendered;
+ } 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;
}
- return rendered;
- };
-
- rendered = false;
- if (style.display != "none") {
- if (style.backgroundGraphic) {
- this.redrawBackgroundNode(geometry.id, geometry, style,
- featureId);
- }
- rendered = this.redrawNode(geometry.id, geometry, style,
- featureId);
}
- if (rendered == false) {
- var node = document.getElementById(geometry.id);
- if (node) {
- if (node._style.backgroundGraphic) {
- node.parentNode.removeChild(document.getElementById(
- geometry.id + this.BACKGROUND_ID_SUFFIX));
- }
- node.parentNode.removeChild(node);
- }
- }
- return rendered;
- },
-
- /**
- * Method: redrawNode
- *
- * Parameters:
- * id - {String}
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- * featureId - {String}
- *
- * Returns:
- * {Boolean} true if the complete geometry could be drawn, null if parts of
- * the geometry could not be drawn, false otherwise
- */
- redrawNode: function(id, geometry, style, featureId) {
- style = this.applyDefaultSymbolizer(style);
- // Get the node if it's already on the map.
- var node = this.nodeFactory(id, this.getNodeType(geometry, style));
-
- // Set the data for the node, then draw it.
- node._featureId = featureId;
- node._boundsBottom = geometry.getBounds().bottom;
- node._geometryClass = geometry.CLASS_NAME;
- node._style = style;
- var drawResult = this.drawGeometryNode(node, geometry, style);
- if(drawResult === false) {
- return false;
- }
-
- node = drawResult.node;
-
- // Insert the node into the indexer so it can show us where to
- // place it. Note that this operation is O(log(n)). If there's a
- // performance problem (when dragging, for instance) this is
- // likely where it would be.
- if (this.indexer) {
- var insert = this.indexer.insert(node);
- if (insert) {
- this.vectorRoot.insertBefore(node, insert);
- } else {
- this.vectorRoot.appendChild(node);
- }
- } else {
- // if there's no indexer, simply append the node to root,
- // but only if the node is a new one
- if (node.parentNode !== this.vectorRoot){
- this.vectorRoot.appendChild(node);
- }
- }
-
- this.postDraw(node);
-
- return drawResult.complete;
- },
-
- /**
- * Method: redrawBackgroundNode
- * Redraws the node using special 'background' style properties. Basically
- * just calls redrawNode(), but instead of directly using the
- * 'externalGraphic', 'graphicXOffset', 'graphicYOffset', and
- * 'graphicZIndex' properties directly from the specified 'style'
- * parameter, we create a new style object and set those properties
- * from the corresponding 'background'-prefixed properties from
- * specified 'style' parameter.
- *
- * Parameters:
- * id - {String}
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- * featureId - {String}
- *
- * Returns:
- * {Boolean} true if the complete geometry could be drawn, null if parts of
- * the geometry could not be drawn, false otherwise
- */
- redrawBackgroundNode: function(id, geometry, style, featureId) {
- var backgroundStyle = OpenLayers.Util.extend({}, style);
-
- // Set regular style attributes to apply to the background styles.
- backgroundStyle.externalGraphic = backgroundStyle.backgroundGraphic;
- backgroundStyle.graphicXOffset = backgroundStyle.backgroundXOffset;
- backgroundStyle.graphicYOffset = backgroundStyle.backgroundYOffset;
- backgroundStyle.graphicZIndex = backgroundStyle.backgroundGraphicZIndex;
- backgroundStyle.graphicWidth = backgroundStyle.backgroundWidth || backgroundStyle.graphicWidth;
- backgroundStyle.graphicHeight = backgroundStyle.backgroundHeight || backgroundStyle.graphicHeight;
-
- // Erase background styles.
- backgroundStyle.backgroundGraphic = null;
- backgroundStyle.backgroundXOffset = null;
- backgroundStyle.backgroundYOffset = null;
- backgroundStyle.backgroundGraphicZIndex = null;
-
- return this.redrawNode(
- id + this.BACKGROUND_ID_SUFFIX,
- geometry,
- backgroundStyle,
- null
- );
- },
+ var browser = OpenLayers.BROWSER_NAME;
- /**
- * Method: drawGeometryNode
- * Given a node, draw a geometry on the specified layer.
- * node and geometry are required arguments, style is optional.
- * This method is only called by the render itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- *
- * Returns:
- * {Object} a hash with properties "node" (the drawn node) and "complete"
- * (null if parts of the geometry could not be drawn, false if nothing
- * could be drawn)
- */
- drawGeometryNode: function(node, geometry, style) {
- style = style || node._style;
-
- var options = {
- 'isFilled': style.fill === undefined ?
- true :
- style.fill,
- 'isStroked': style.stroke === undefined ?
- !!style.strokeWidth :
- style.stroke
- };
- var drawn;
- switch (geometry.CLASS_NAME) {
- case "OpenLayers.Geometry.Point":
- if(style.graphic === false) {
- options.isFilled = false;
- options.isStroked = false;
- }
- drawn = this.drawPoint(node, geometry);
- break;
- case "OpenLayers.Geometry.LineString":
- options.isFilled = false;
- drawn = this.drawLineString(node, geometry);
- break;
- case "OpenLayers.Geometry.LinearRing":
- drawn = this.drawLinearRing(node, geometry);
- break;
- case "OpenLayers.Geometry.Polygon":
- drawn = this.drawPolygon(node, geometry);
- break;
- case "OpenLayers.Geometry.Surface":
- drawn = this.drawSurface(node, geometry);
- break;
- case "OpenLayers.Geometry.Rectangle":
- drawn = this.drawRectangle(node, geometry);
- break;
- default:
- break;
+ // opera & (safari absolute) incorrectly account for body offsetTop
+ if (browser == "opera" || (browser == "safari" &&
+ OpenLayers.Element.getStyle(forElement, 'position') == 'absolute')) {
+ pos[1] -= document.body.offsetTop;
}
- node._options = options;
-
- //set style
- //TBD simplify this
- if (drawn != false) {
- return {
- node: this.setStyle(node, style, options, geometry),
- complete: drawn
- };
- } else {
- return false;
- }
- },
-
- /**
- * Method: postDraw
- * Things that have do be done after the geometry node is appended
- * to its parent node. To be overridden by subclasses.
- *
- * Parameters:
- * node - {DOMElement}
- */
- postDraw: function(node) {},
-
- /**
- * Method: drawPoint
- * Virtual function for drawing Point Geometry.
- * Should be implemented by subclasses.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or false if the renderer could not draw the point
- */
- drawPoint: function(node, geometry) {},
-
- /**
- * Method: drawLineString
- * Virtual function for drawing LineString Geometry.
- * Should be implemented by subclasses.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or null if the renderer could not draw all components of
- * the linestring, or false if nothing could be drawn
- */
- drawLineString: function(node, geometry) {},
-
- /**
- * Method: drawLinearRing
- * Virtual function for drawing LinearRing Geometry.
- * Should be implemented by subclasses.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or null if the renderer could not draw all components
- * of the linear ring, or false if nothing could be drawn
- */
- drawLinearRing: function(node, geometry) {},
-
- /**
- * Method: drawPolygon
- * Virtual function for drawing Polygon Geometry.
- * Should be implemented by subclasses.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or null if the renderer could not draw all components
- * of the polygon, or false if nothing could be drawn
- */
- drawPolygon: function(node, geometry) {},
-
- /**
- * Method: drawRectangle
- * Virtual function for drawing Rectangle Geometry.
- * Should be implemented by subclasses.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or false if the renderer could not draw the rectangle
- */
- drawRectangle: function(node, geometry) {},
-
- /**
- * Method: drawCircle
- * Virtual function for drawing Circle Geometry.
- * Should be implemented by subclasses.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or false if the renderer could not draw the circle
- */
- drawCircle: function(node, geometry) {},
-
- /**
- * Method: drawSurface
- * Virtual function for drawing Surface Geometry.
- * Should be implemented by subclasses.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or false if the renderer could not draw the surface
- */
- drawSurface: function(node, geometry) {},
-
- /**
- * Method: removeText
- * Removes a label
- *
- * Parameters:
- * featureId - {String}
- */
- removeText: function(featureId) {
- var label = document.getElementById(featureId + this.LABEL_ID_SUFFIX);
- if (label) {
- this.textRoot.removeChild(label);
- }
- },
-
- /**
- * Method: getFeatureIdFromEvent
- *
- * Parameters:
- * evt - {Object} An <OpenLayers.Event> object
- *
- * Returns:
- * {<OpenLayers.Geometry>} A geometry from an event that
- * happened on a layer.
- */
- getFeatureIdFromEvent: function(evt) {
- var target = evt.target;
- var useElement = target && target.correspondingUseElement;
- var node = useElement ? useElement : (target || evt.srcElement);
- var featureId = node._featureId;
- return featureId;
- },
-
- /**
- * Method: eraseGeometry
- * Erase a geometry from the renderer. In the case of a multi-geometry,
- * we cycle through and recurse on ourselves. Otherwise, we look for a
- * node with the geometry.id, destroy its geometry, and remove it from
- * the DOM.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * featureId - {String}
- */
- eraseGeometry: function(geometry, featureId) {
- if ((geometry.CLASS_NAME == "OpenLayers.Geometry.MultiPoint") ||
- (geometry.CLASS_NAME == "OpenLayers.Geometry.MultiLineString") ||
- (geometry.CLASS_NAME == "OpenLayers.Geometry.MultiPolygon") ||
- (geometry.CLASS_NAME == "OpenLayers.Geometry.Collection")) {
- for (var i=0, len=geometry.components.length; i<len; i++) {
- this.eraseGeometry(geometry.components[i], featureId);
+ // 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;
}
- } else {
- var element = OpenLayers.Util.getElement(geometry.id);
- if (element && element.parentNode) {
- if (element.geometry) {
- element.geometry.destroy();
- element.geometry = null;
- }
- element.parentNode.removeChild(element);
-
- if (this.indexer) {
- this.indexer.remove(element);
- }
-
- if (element._style.backgroundGraphic) {
- var backgroundId = geometry.id + this.BACKGROUND_ID_SUFFIX;
- var bElem = OpenLayers.Util.getElement(backgroundId);
- if (bElem && bElem.parentNode) {
- // No need to destroy the geometry since the element and the background
- // node share the same geometry.
- bElem.parentNode.removeChild(bElem);
- }
- }
- }
+ parent = parent.offsetParent;
}
- },
-
- /**
- * Method: nodeFactory
- * Create new node of the specified type, with the (optional) specified id.
- *
- * If node already exists with same ID and a different type, we remove it
- * and then call ourselves again to recreate it.
- *
- * Parameters:
- * id - {String}
- * type - {String} type Kind of node to draw.
- *
- * Returns:
- * {DOMElement} A new node of the given type and id.
- */
- nodeFactory: function(id, type) {
- var node = OpenLayers.Util.getElement(id);
- if (node) {
- if (!this.nodeTypeCompare(node, type)) {
- node.parentNode.removeChild(node);
- node = this.nodeFactory(id, type);
- }
- } else {
- node = this.createNode(type, id);
- }
- return node;
- },
+ }
- /**
- * Method: nodeTypeCompare
- *
- * Parameters:
- * node - {DOMElement}
- * type - {String} Kind of node
- *
- * Returns:
- * {Boolean} Whether or not the specified node is of the specified type
- * This function must be overridden by subclasses.
- */
- nodeTypeCompare: function(node, type) {},
-
- /**
- * Method: createNode
- *
- * Parameters:
- * type - {String} Kind of node to draw.
- * id - {String} Id for node.
- *
- * Returns:
- * {DOMElement} A new node of the given type and id.
- * This function must be overridden by subclasses.
- */
- createNode: function(type, id) {},
+ return pos;
+};
- /**
- * Method: moveRoot
- * moves this renderer's root to a different renderer.
- *
- * Parameters:
- * renderer - {<OpenLayers.Renderer>} target renderer for the moved root
- */
- moveRoot: function(renderer) {
- var root = this.root;
- if(renderer.root.parentNode == this.rendererRoot) {
- root = renderer.root;
- }
- root.parentNode.removeChild(root);
- renderer.rendererRoot.appendChild(root);
- },
-
- /**
- * Method: getRenderLayerId
- * Gets the layer that this renderer's output appears on. If moveRoot was
- * used, this will be different from the id of the layer containing the
- * features rendered by this renderer.
- *
- * Returns:
- * {String} the id of the output layer.
- */
- getRenderLayerId: function() {
- return this.root.parentNode.parentNode.id;
- },
-
- /**
- * Method: isComplexSymbol
- * Determines if a symbol cannot be rendered using drawCircle
- *
- * Parameters:
- * graphicName - {String}
- *
- * Returns
- * {Boolean} true if the symbol is complex, false if not
- */
- isComplexSymbol: function(graphicName) {
- return (graphicName != "circle") && !!graphicName;
- },
-
- CLASS_NAME: "OpenLayers.Renderer.Elements"
-});
-
-
/**
- * Constant: OpenLayers.Renderer.symbol
- * Coordinate arrays for well known (named) symbols.
+ * 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)
*/
-OpenLayers.Renderer.symbol = {
- "star": [350,75, 379,161, 469,161, 397,215, 423,301, 350,250, 277,301,
- 303,215, 231,161, 321,161, 350,75],
- "cross": [4,0, 6,0, 6,4, 10,4, 10,6, 6,6, 6,10, 4,10, 4,6, 0,6, 0,4, 4,4,
- 4,0],
- "x": [0,0, 25,0, 50,35, 75,0, 100,0, 65,50, 100,100, 75,100, 50,65, 25,100, 0,100, 35,50, 0,0],
- "square": [0,0, 0,1, 1,1, 1,0, 0,0],
- "triangle": [0,10, 10,10, 5,0, 0,10]
+OpenLayers.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;
};
-/* ======================================================================
- OpenLayers/Strategy/Fixed.js
- ====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Strategy.js
- */
-
-/**
- * Class: OpenLayers.Strategy.Fixed
- * A simple strategy that requests features once and never requests new data.
+/**
+ * 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
*
- * Inherits from:
- * - <OpenLayers.Strategy>
+ * Returns:
+ * {Boolean} Whether or not the two URLs are equivalent
*/
-OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, {
-
- /**
- * APIProperty: preload
- * {Boolean} Load data before layer made visible. Enabling this may result
- * in considerable overhead if your application loads many data layers
- * that are not visible by default. Default is false.
- */
- preload: false,
+OpenLayers.Util.isEquivalentUrl = function(url1, url2, options) {
+ options = options || {};
- /**
- * Constructor: OpenLayers.Strategy.Fixed
- * Create a new Fixed strategy.
- *
- * Parameters:
- * options - {Object} Optional object whose properties will be set on the
- * instance.
- */
- initialize: function(options) {
- OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
- },
+ OpenLayers.Util.applyDefaults(options, {
+ ignoreCase: true,
+ ignorePort80: true,
+ ignoreHash: true
+ });
- /**
- * APIMethod: destroy
- * Clean up the strategy.
- */
- destroy: function() {
- OpenLayers.Strategy.prototype.destroy.apply(this, arguments);
- },
+ var urlObj1 = OpenLayers.Util.createUrlObject(url1, options);
+ var urlObj2 = OpenLayers.Util.createUrlObject(url2, options);
- /**
- * Method: activate
- * Activate the strategy: load data or add listener to load when visible
- *
- * Returns:
- * {Boolean} True if the strategy was successfully activated or false if
- * the strategy was already active.
- */
- activate: function() {
- if(OpenLayers.Strategy.prototype.activate.apply(this, arguments)) {
- this.layer.events.on({
- "refresh": this.load,
- scope: this
- });
- if(this.layer.visibility == true || this.preload) {
- this.load();
- } else {
- this.layer.events.on({
- "visibilitychanged": this.load,
- scope: this
- });
+ //compare all keys except for "args" (treated below)
+ for(var key in urlObj1) {
+ if(key !== "args") {
+ if(urlObj1[key] != urlObj2[key]) {
+ return false;
}
- return true;
}
+ }
+
+ // 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;
- },
+ }
- /**
- * Method: deactivate
- * Deactivate the strategy. Undo what is done in <activate>.
- *
- * Returns:
- * {Boolean} The strategy was successfully deactivated.
- */
- deactivate: function() {
- var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
- if(deactivated) {
- this.layer.events.un({
- "refresh": this.load,
- "visibilitychanged": this.load,
- scope: this
- });
- }
- return deactivated;
- },
+ return true;
+};
- /**
- * Method: load
- * Tells protocol to load data and unhooks the visibilitychanged event
- *
- * Parameters:
- * options - {Object} options to pass to protocol read.
- */
- load: function(options) {
- this.layer.events.triggerEvent("loadstart");
- this.layer.protocol.read(OpenLayers.Util.applyDefaults({
- callback: this.merge,
- filter: this.layer.filter,
- scope: this
- }, options));
- this.layer.events.un({
- "visibilitychanged": this.load,
- scope: this
- });
- },
-
- /**
- * Method: merge
- * Add all features to the layer.
- */
- merge: function(resp) {
- this.layer.destroyFeatures();
- var features = resp.features;
- if (features && features.length > 0) {
- var remote = this.layer.projection;
- var local = this.layer.map.getProjectionObject();
- if(!local.equals(remote)) {
- var geom;
- for(var i=0, len=features.length; i<len; ++i) {
- geom = features[i].geometry;
- if(geom) {
- geom.transform(remote, local);
- }
- }
- }
- this.layer.addFeatures(features);
- }
- this.layer.events.triggerEvent("loadend");
- },
-
- CLASS_NAME: "OpenLayers.Strategy.Fixed"
-});
-/* ======================================================================
- OpenLayers/Symbolizer/Line.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
/**
- * @requires OpenLayers/Symbolizer.js
+ * Function: createUrlObject
+ *
+ * Parameters:
+ * url - {String}
+ * options - {Object} A hash of options. Can be one of:
+ * ignoreCase: lowercase url,
+ * ignorePort80: don't include explicit port if port is 80,
+ * ignoreHash: Don't include part of url after the hash (#).
+ *
+ * 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 || {};
-/**
- * Class: OpenLayers.Symbolizer.Line
- * A symbolizer used to render line features.
- */
-OpenLayers.Symbolizer.Line = OpenLayers.Class(OpenLayers.Symbolizer, {
+ // 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();
+ }
- /**
- * APIProperty: strokeColor
- * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000"
- * for red).
- */
- strokeColor: null,
+ var a = document.createElement('a');
+ a.href = url;
- /**
- * APIProperty: strokeOpacity
- * {Number} Stroke opacity (0-1).
- */
- strokeOpacity: null,
+ var urlObject = {};
- /**
- * APIProperty: strokeWidth
- * {Number} Pixel stroke width.
- */
- strokeWidth: null,
-
- /**
- * APIProperty: strokeLinecap
- * {String} Stroke cap type ("butt", "round", or "square").
- */
- strokeLinecap: null,
-
- /**
- * Property: strokeDashstyle
- * {String} Stroke dash style according to the SLD spec. Note that the
- * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot",
- * "longdash", "longdashdot", or "solid") will not work in SLD, but
- * most SLD patterns will render correctly in OpenLayers.
- */
- strokeDashstyle: null,
+ //host (without port)
+ urlObject.host = a.host.split(":").shift();
- /**
- * Constructor: OpenLayers.Symbolizer.Line
- * Create a symbolizer for rendering lines.
- *
- * Parameters:
- * config - {Object} An object containing properties to be set on the
- * symbolizer. Any documented symbolizer property can be set at
- * construction.
- *
- * Returns:
- * A new line symbolizer.
- */
- initialize: function(config) {
- OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
- },
-
- CLASS_NAME: "OpenLayers.Symbolizer.Line"
-
-});
+ //protocol
+ urlObject.protocol = a.protocol;
-/* ======================================================================
- OpenLayers/Symbolizer/Point.js
- ====================================================================== */
+ //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;
+ }
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Symbolizer.js
- */
-
-/**
- * Class: OpenLayers.Symbolizer.Point
- * A symbolizer used to render point features.
- */
-OpenLayers.Symbolizer.Point = OpenLayers.Class(OpenLayers.Symbolizer, {
+ //hash
+ urlObject.hash = (options.ignoreHash || a.hash === "#") ? "" : a.hash;
- /**
- * APIProperty: strokeColor
- * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000"
- * for red).
- */
- strokeColor: null,
-
- /**
- * APIProperty: strokeOpacity
- * {Number} Stroke opacity (0-1).
- */
- strokeOpacity: null,
-
- /**
- * APIProperty: strokeWidth
- * {Number} Pixel stroke width.
- */
- strokeWidth: null,
-
- /**
- * APIProperty: strokeLinecap
- * {String} Stroke cap type ("butt", "round", or "square").
- */
- strokeLinecap: null,
-
- /**
- * Property: strokeDashstyle
- * {String} Stroke dash style according to the SLD spec. Note that the
- * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot",
- * "longdash", "longdashdot", or "solid") will not work in SLD, but
- * most SLD patterns will render correctly in OpenLayers.
- */
- strokeDashstyle: null,
+ //args
+ var queryString = a.search;
+ if (!queryString) {
+ var qMark = url.indexOf("?");
+ queryString = (qMark != -1) ? url.substr(qMark) : "";
+ }
+ urlObject.args = OpenLayers.Util.getParameters(queryString);
- /**
- * APIProperty: fillColor
- * {String} RGB hex fill color (e.g. "#ff0000" for red).
- */
- fillColor: null,
+ //pathname (uniform browser behavior with leading "/")
+ urlObject.pathname = (a.pathname.charAt(0) == "/") ? a.pathname : "/" + a.pathname;
- /**
- * APIProperty: fillOpacity
- * {Number} Fill opacity (0-1).
- */
- fillOpacity: null,
-
- /**
- * APIProperty: pointRadius
- * {Number} Pixel point radius.
- */
- pointRadius: null,
-
- /**
- * APIProperty: externalGraphic
- * {String} Url to an external graphic that will be used for rendering
- * points.
- */
- externalGraphic: null,
-
- /**
- * APIProperty: graphicWidth
- * {Number} Pixel width for sizing an external graphic.
- */
- graphicWidth: null,
-
- /**
- * APIProperty: graphicHeight
- * {Number} Pixel height for sizing an external graphic.
- */
- graphicHeight: null,
-
- /**
- * APIProperty: graphicOpacity
- * {Number} Opacity (0-1) for an external graphic.
- */
- graphicOpacity: null,
-
- /**
- * APIProperty: graphicXOffset
- * {Number} Pixel offset along the positive x axis for displacing an
- * external graphic.
- */
- graphicXOffset: null,
-
- /**
- * APIProperty: graphicYOffset
- * {Number} Pixel offset along the positive y axis for displacing an
- * external graphic.
- */
- graphicYOffset: null,
-
- /**
- * APIProperty: rotation
- * {Number} The rotation of a graphic in the clockwise direction about its
- * center point (or any point off center as specified by
- * <graphicXOffset> and <graphicYOffset>).
- */
- rotation: null,
-
- /**
- * APIProperty: graphicName
- * {String} Named graphic to use when rendering points. Supported values
- * include "circle", "square", "star", "x", "cross", and "triangle".
- */
- graphicName: null,
-
- /**
- * Constructor: OpenLayers.Symbolizer.Point
- * Create a symbolizer for rendering points.
- *
- * Parameters:
- * config - {Object} An object containing properties to be set on the
- * symbolizer. Any documented symbolizer property can be set at
- * construction.
- *
- * Returns:
- * A new point symbolizer.
- */
- initialize: function(config) {
- OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
- },
-
- CLASS_NAME: "OpenLayers.Symbolizer.Point"
-
-});
-
-/* ======================================================================
- OpenLayers/Symbolizer/Polygon.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
+ return urlObject;
+};
+
/**
- * @requires OpenLayers/Symbolizer.js
+ * 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
*/
-
-/**
- * Class: OpenLayers.Symbolizer.Polygon
- * A symbolizer used to render line features.
- */
-OpenLayers.Symbolizer.Polygon = OpenLayers.Class(OpenLayers.Symbolizer, {
+OpenLayers.Util.removeTail = function(url) {
+ var head = null;
- /**
- * APIProperty: strokeColor
- * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000"
- * for red).
- */
- strokeColor: null,
-
- /**
- * APIProperty: strokeOpacity
- * {Number} Stroke opacity (0-1).
- */
- strokeOpacity: null,
-
- /**
- * APIProperty: strokeWidth
- * {Number} Pixel stroke width.
- */
- strokeWidth: null,
-
- /**
- * APIProperty: strokeLinecap
- * {String} Stroke cap type ("butt", "round", or "square").
- */
- strokeLinecap: null,
-
- /**
- * Property: strokeDashstyle
- * {String} Stroke dash style according to the SLD spec. Note that the
- * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot",
- * "longdash", "longdashdot", or "solid") will not work in SLD, but
- * most SLD patterns will render correctly in OpenLayers.
- */
- strokeDashstyle: null,
+ var qMark = url.indexOf("?");
+ var hashMark = url.indexOf("#");
- /**
- * APIProperty: fillColor
- * {String} RGB hex fill color (e.g. "#ff0000" for red).
- */
- fillColor: null,
-
- /**
- * APIProperty: fillOpacity
- * {Number} Fill opacity (0-1).
- */
- fillOpacity: null,
+ 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;
+};
- /**
- * Constructor: OpenLayers.Symbolizer.Polygon
- * Create a symbolizer for rendering polygons.
- *
- * Parameters:
- * config - {Object} An object containing properties to be set on the
- * symbolizer. Any documented symbolizer property can be set at
- * construction.
- *
- * Returns:
- * A new polygon symbolizer.
- */
- initialize: function(config) {
- OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
- },
-
- CLASS_NAME: "OpenLayers.Symbolizer.Polygon"
-
-});
-
-/* ======================================================================
- OpenLayers/Symbolizer/Raster.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
/**
- * @requires OpenLayers/Symbolizer.js
+ * 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;
+})();
/**
- * Class: OpenLayers.Symbolizer.Raster
- * A symbolizer used to render raster images.
+ * 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.Symbolizer.Raster = OpenLayers.Class(OpenLayers.Symbolizer, {
-
- /**
- * Constructor: OpenLayers.Symbolizer.Raster
- * Create a symbolizer for rendering rasters.
- *
- * Parameters:
- * config - {Object} An object containing properties to be set on the
- * symbolizer. Any documented symbolizer property can be set at
- * construction.
- *
- * Returns:
- * A new raster symbolizer.
- */
- initialize: function(config) {
- OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
- },
-
- CLASS_NAME: "OpenLayers.Symbolizer.Raster"
-
-});
-/* ======================================================================
- OpenLayers/Symbolizer/Text.js
- ====================================================================== */
+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;
+})();
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
/**
- * @requires OpenLayers/Symbolizer.js
+ * 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;
+};
/**
- * Class: OpenLayers.Symbolizer.Text
- * A symbolizer used to render text labels for features.
+ * 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 - {<OpenLayers.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}
+ * 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.Size}
*/
-OpenLayers.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, {
+OpenLayers.Util.getRenderedDimensions = function(contentHTML, size, options) {
- /**
- * APIProperty: label
- * {String} The text for the label.
- */
- label: null,
+ var w, h;
- /**
- * APIProperty: fontFamily
- * {String} The font family for the label.
- */
- fontFamily: null,
+ // 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;
- /**
- * APIProperty: fontSize
- * {String} The font size for the label.
- */
- fontSize: null,
+ //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";
+ }
+ }
- /**
- * APIProperty: fontWeight
- * {String} The font weight for the label.
- */
- fontWeight: null,
+ //add css classes, if specified
+ if (options && options.displayClass) {
+ container.className = options.displayClass;
+ }
- /**
- * Property: fontStyle
- * {String} The font style for the label.
- */
- fontStyle: null,
-
- /**
- * Constructor: OpenLayers.Symbolizer.Text
- * Create a symbolizer for rendering text labels.
- *
- * Parameters:
- * config - {Object} An object containing properties to be set on the
- * symbolizer. Any documented symbolizer property can be set at
- * construction.
- *
- * Returns:
- * A new text symbolizer.
- */
- initialize: function(config) {
- OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
- },
+ // create temp content div and assign content
+ var content = document.createElement("div");
+ content.innerHTML = contentHTML;
- CLASS_NAME: "OpenLayers.Symbolizer.Text"
+ // we need overflow visible when calculating the size
+ content.style.overflow = "visible";
+ if (content.childNodes) {
+ for (var i=0, l=content.childNodes.length; i<l; i++) {
+ if (!content.childNodes[i].style) continue;
+ content.childNodes[i].style.overflow = "visible";
+ }
+ }
-});
-
-/* ======================================================================
- OpenLayers/Tween.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Console.js
- */
-
-/**
- * Namespace: OpenLayers.Tween
- */
-OpenLayers.Tween = OpenLayers.Class({
+ // add content to restricted container
+ container.appendChild(content);
- /**
- * Constant: INTERVAL
- * {int} Interval in milliseconds between 2 steps
- */
- INTERVAL: 10,
+ // append container to body for rendering
+ containerElement.appendChild(container);
- /**
- * APIProperty: easing
- * {<OpenLayers.Easing>(Function)} Easing equation used for the animation
- * Defaultly set to OpenLayers.Easing.Expo.easeOut
- */
- easing: null,
-
- /**
- * APIProperty: begin
- * {Object} Values to start the animation with
- */
- begin: null,
-
- /**
- * APIProperty: finish
- * {Object} Values to finish the animation with
- */
- finish: null,
-
- /**
- * APIProperty: duration
- * {int} duration of the tween (number of steps)
- */
- duration: null,
-
- /**
- * APIProperty: callbacks
- * {Object} An object with start, eachStep and done properties whose values
- * are functions to be call during the animation. They are passed the
- * current computed value as argument.
- */
- callbacks: null,
-
- /**
- * Property: time
- * {int} Step counter
- */
- time: null,
-
- /**
- * Property: interval
- * {int} Interval id returned by window.setInterval
- */
- interval: null,
-
- /**
- * Property: playing
- * {Boolean} Tells if the easing is currently playing
- */
- playing: false,
-
- /**
- * Constructor: OpenLayers.Tween
- * Creates a Tween.
- *
- * Parameters:
- * easing - {<OpenLayers.Easing>(Function)} easing function method to use
- */
- initialize: function(easing) {
- this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut;
- },
-
- /**
- * APIMethod: start
- * Plays the Tween, and calls the callback method on each step
- *
- * Parameters:
- * begin - {Object} values to start the animation with
- * finish - {Object} values to finish the animation with
- * duration - {int} duration of the tween (number of steps)
- * options - {Object} hash of options (for example callbacks (start, eachStep, done))
- */
- start: function(begin, finish, duration, options) {
- this.playing = true;
- this.begin = begin;
- this.finish = finish;
- this.duration = duration;
- this.callbacks = options.callbacks;
- this.time = 0;
- if (this.interval) {
- window.clearInterval(this.interval);
- this.interval = null;
+ // Opera and IE7 can't handle a node with position:aboslute if it inherits
+ // position:absolute from a parent.
+ var parentHasPositionAbsolute = false;
+ var parent = container.parentNode;
+ 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;
}
- if (this.callbacks && this.callbacks.start) {
- this.callbacks.start.call(this, this.begin);
- }
- this.interval = window.setInterval(
- OpenLayers.Function.bind(this.play, this), this.INTERVAL);
- },
+ parent = parent.parentNode;
+ }
+
+ if(!parentHasPositionAbsolute) {
+ container.style.position = "absolute";
+ }
- /**
- * APIMethod: stop
- * Stops the Tween, and calls the done callback
- * Doesn't do anything if animation is already finished
- */
- stop: function() {
- if (!this.playing) {
- return;
- }
-
- if (this.callbacks && this.callbacks.done) {
- this.callbacks.done.call(this, this.finish);
- }
- window.clearInterval(this.interval);
- this.interval = null;
- this.playing = false;
- },
+ // calculate scroll width of content and add corners and shadow width
+ if (!w) {
+ w = parseInt(content.scrollWidth);
- /**
- * Method: play
- * Calls the appropriate easing method
- */
- play: function() {
- var value = {};
- for (var i in this.begin) {
- var b = this.begin[i];
- var f = this.finish[i];
- if (b == null || f == null || isNaN(b) || isNaN(f)) {
- OpenLayers.Console.error('invalid value for Tween');
- }
-
- var c = f - b;
- value[i] = this.easing.apply(this, [this.time, b, c, this.duration]);
- }
- this.time++;
-
- if (this.callbacks && this.callbacks.eachStep) {
- this.callbacks.eachStep.call(this, value);
- }
-
- if (this.time > this.duration) {
- this.stop();
- }
- },
+ // update container width to allow height to adjust
+ container.style.width = w + "px";
+ }
+ // capture height and add shadow and corner image widths
+ if (!h) {
+ h = parseInt(content.scrollHeight);
+ }
+
+ // remove elements
+ container.removeChild(content);
+ containerElement.removeChild(container);
- /**
- * Create empty functions for all easing methods.
- */
- CLASS_NAME: "OpenLayers.Tween"
-});
+ return new OpenLayers.Size(w, h);
+};
/**
- * Namespace: OpenLayers.Easing
+ * APIFunction: getScrollbarWidth
+ * This function has been modified by the OpenLayers from the original version,
+ * written by Matthew Eernisse and released under the Apache 2
+ * license here:
*
- * Credits:
- * Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>
+ * http://www.fleegix.org/articles/2006/05/30/getting-the-scrollbar-width-in-pixels
+ *
+ * It has been modified simply to cache its value, since it is physically
+ * impossible that this code could ever run in more than one browser at
+ * once.
+ *
+ * Returns:
+ * {Integer}
*/
-OpenLayers.Easing = {
- /**
- * Create empty functions for all easing methods.
- */
- CLASS_NAME: "OpenLayers.Easing"
-};
-
-/**
- * Namespace: OpenLayers.Easing.Linear
- */
-OpenLayers.Easing.Linear = {
+OpenLayers.Util.getScrollbarWidth = function() {
- /**
- * Function: easeIn
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- */
- easeIn: function(t, b, c, d) {
- return c*t/d + b;
- },
+ var scrollbarWidth = OpenLayers.Util._scrollbarWidth;
- /**
- * Function: easeOut
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- */
- easeOut: function(t, b, c, d) {
- return c*t/d + b;
- },
+ if (scrollbarWidth == null) {
+ var scr = null;
+ var inn = null;
+ var wNoScroll = 0;
+ var wScroll = 0;
- /**
- * Function: easeInOut
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- */
- easeInOut: function(t, b, c, d) {
- return c*t/d + b;
- },
-
- CLASS_NAME: "OpenLayers.Easing.Linear"
-};
-
-/**
- * Namespace: OpenLayers.Easing.Expo
- */
-OpenLayers.Easing.Expo = {
+ // Outer scrolling div
+ scr = document.createElement('div');
+ scr.style.position = 'absolute';
+ scr.style.top = '-1000px';
+ scr.style.left = '-1000px';
+ scr.style.width = '100px';
+ scr.style.height = '50px';
+ // Start with no scrollbar
+ scr.style.overflow = 'hidden';
- /**
- * Function: easeIn
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- */
- easeIn: function(t, b, c, d) {
- return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
- },
+ // Inner content div
+ inn = document.createElement('div');
+ inn.style.width = '100%';
+ inn.style.height = '200px';
- /**
- * Function: easeOut
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- */
- easeOut: function(t, b, c, d) {
- return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
- },
+ // Put the inner div in the scrolling div
+ scr.appendChild(inn);
+ // Append the scrolling div to the doc
+ document.body.appendChild(scr);
- /**
- * Function: easeInOut
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- */
- easeInOut: function(t, b, c, d) {
- if (t==0) return b;
- if (t==d) return b+c;
- if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
- return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
- },
-
- CLASS_NAME: "OpenLayers.Easing.Expo"
-};
-
-/**
- * Namespace: OpenLayers.Easing.Quad
- */
-OpenLayers.Easing.Quad = {
+ // Width of the inner div sans scrollbar
+ wNoScroll = inn.offsetWidth;
- /**
- * Function: easeIn
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- */
- easeIn: function(t, b, c, d) {
- return c*(t/=d)*t + b;
- },
+ // Add the scrollbar
+ scr.style.overflow = 'scroll';
+ // Width of the inner div width scrollbar
+ wScroll = inn.offsetWidth;
- /**
- * Function: easeOut
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- */
- easeOut: function(t, b, c, d) {
- return -c *(t/=d)*(t-2) + b;
- },
+ // Remove the scrolling div from the doc
+ document.body.removeChild(document.body.lastChild);
- /**
- * Function: easeInOut
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- */
- easeInOut: function(t, b, c, d) {
- if ((t/=d/2) < 1) return c/2*t*t + b;
- return -c/2 * ((--t)*(t-2) - 1) + b;
- },
+ // Pixel width of the scroller
+ OpenLayers.Util._scrollbarWidth = (wNoScroll - wScroll);
+ scrollbarWidth = OpenLayers.Util._scrollbarWidth;
+ }
- CLASS_NAME: "OpenLayers.Easing.Quad"
+ return scrollbarWidth;
};
-/* ======================================================================
- OpenLayers/Control/ArgParser.js
- ====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-
/**
- * @requires OpenLayers/Control.js
- */
-
-/**
- * Class: OpenLayers.Control.ArgParser
- * The ArgParser control adds location bar querystring parsing functionality
- * to an OpenLayers Map.
- * When added to a Map control, on a page load/refresh, the Map will
- * automatically take the href string and parse it for lon, lat, zoom, and
- * layers information.
+ * APIFunction: getFormattedLonLat
+ * This function will return latitude or longitude value formatted as
*
- * Inherits from:
- * - <OpenLayers.Control>
+ * Parameters:
+ * coordinate - {Float} the coordinate value to be formatted
+ * axis - {String} value of either 'lat' or 'lon' to indicate which axis is to
+ * to be formatted (default = lat)
+ * dmsOption - {String} specify the precision of the output can be one of:
+ * 'dms' show degrees minutes and seconds
+ * 'dm' show only degrees and minutes
+ * 'd' show only degrees
+ *
+ * Returns:
+ * {String} the coordinate value formatted as a string
*/
-OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, {
+OpenLayers.Util.getFormattedLonLat = function(coordinate, axis, dmsOption) {
+ if (!dmsOption) {
+ dmsOption = 'dms'; //default to show degree, minutes, seconds
+ }
+ var abscoordinate = Math.abs(coordinate)
+ var coordinatedegrees = Math.floor(abscoordinate);
- /**
- * Parameter: center
- * {<OpenLayers.LonLat>}
- */
- center: null,
-
- /**
- * Parameter: zoom
- * {int}
- */
- zoom: null,
+ var coordinateminutes = (abscoordinate - coordinatedegrees)/(1/60);
+ var tempcoordinateminutes = coordinateminutes;
+ coordinateminutes = Math.floor(coordinateminutes);
+ var coordinateseconds = (tempcoordinateminutes - coordinateminutes)/(1/60);
+ coordinateseconds = Math.round(coordinateseconds*10);
+ coordinateseconds /= 10;
- /**
- * Parameter: layers
- * {Array(<OpenLayers.Layer>)}
- */
- layers: null,
-
- /**
- * APIProperty: displayProjection
- * {<OpenLayers.Projection>} Requires proj4js support.
- * Projection used when reading the coordinates from the URL. This will
- *
- * reproject the map coordinates from the URL into the map's
- * projection.
- *
- * If you are using this functionality, be aware that any permalink
- * which is added to the map will determine the coordinate type which
- * is read from the URL, which means you should not add permalinks with
- * different displayProjections to the same map.
- */
- displayProjection: null,
+ if( coordinatedegrees < 10 ) {
+ coordinatedegrees = "0" + coordinatedegrees;
+ }
+ var str = coordinatedegrees + "\u00B0";
- /**
- * Constructor: OpenLayers.Control.ArgParser
- *
- * Parameters:
- * options - {Object}
- */
- initialize: function(options) {
- OpenLayers.Control.prototype.initialize.apply(this, arguments);
- },
-
- /**
- * Method: setMap
- * Set the map property for the control.
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- setMap: function(map) {
- OpenLayers.Control.prototype.setMap.apply(this, arguments);
-
- //make sure we dont already have an arg parser attached
- for(var i=0, len=this.map.controls.length; i<len; i++) {
- var control = this.map.controls[i];
- if ( (control != this) &&
- (control.CLASS_NAME == "OpenLayers.Control.ArgParser") ) {
-
- // If a second argparser is added to the map, then we
- // override the displayProjection to be the one added to the
- // map.
- if (control.displayProjection != this.displayProjection) {
- this.displayProjection = control.displayProjection;
- }
-
- break;
- }
+ if (dmsOption.indexOf('dm') >= 0) {
+ if( coordinateminutes < 10 ) {
+ coordinateminutes = "0" + coordinateminutes;
}
- if (i == this.map.controls.length) {
-
- var args = OpenLayers.Util.getParameters();
- // Be careful to set layer first, to not trigger unnecessary layer loads
- if (args.layers) {
- this.layers = args.layers;
-
- // when we add a new layer, set its visibility
- this.map.events.register('addlayer', this,
- this.configureLayers);
- this.configureLayers();
+ str += coordinateminutes + "'";
+
+ if (dmsOption.indexOf('dms') >= 0) {
+ if( coordinateseconds < 10 ) {
+ coordinateseconds = "0" + coordinateseconds;
}
- if (args.lat && args.lon) {
- this.center = new OpenLayers.LonLat(parseFloat(args.lon),
- parseFloat(args.lat));
- if (args.zoom) {
- this.zoom = parseInt(args.zoom);
- }
-
- // when we add a new baselayer to see when we can set the center
- this.map.events.register('changebaselayer', this,
- this.setCenter);
- this.setCenter();
- }
+ str += coordinateseconds + '"';
}
- },
-
- /**
- * Method: setCenter
- * As soon as a baseLayer has been loaded, we center and zoom
- * ...and remove the handler.
- */
- setCenter: function() {
-
- if (this.map.baseLayer) {
- //dont need to listen for this one anymore
- this.map.events.unregister('changebaselayer', this,
- this.setCenter);
-
- if (this.displayProjection) {
- this.center.transform(this.displayProjection,
- this.map.getProjectionObject());
- }
-
- this.map.setCenter(this.center, this.zoom);
- }
- },
-
- /**
- * Method: configureLayers
- * As soon as all the layers are loaded, cycle through them and
- * hide or show them.
- */
- configureLayers: function() {
-
- if (this.layers.length == this.map.layers.length) {
- this.map.events.unregister('addlayer', this, this.configureLayers);
-
- for(var i=0, len=this.layers.length; i<len; i++) {
-
- var layer = this.map.layers[i];
- var c = this.layers.charAt(i);
-
- if (c == "B") {
- this.map.setBaseLayer(layer);
- } else if ( (c == "T") || (c == "F") ) {
- layer.setVisibility(c == "T");
- }
- }
- }
- },
-
- CLASS_NAME: "OpenLayers.Control.ArgParser"
-});
-/* ======================================================================
- OpenLayers/Control/PanZoom.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Control.js
- */
-
-/**
- * Class: OpenLayers.Control.PanZoom
- * The PanZoom is a visible control, composed of a
- * <OpenLayers.Control.PanPanel> and a <OpenLayers.Control.ZoomPanel>. By
- * default it is drawn in the upper left corner of the map.
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * APIProperty: slideFactor
- * {Integer} Number of pixels by which we'll pan the map in any direction
- * on clicking the arrow buttons. If you want to pan by some ratio
- * of the map dimensions, use <slideRatio> instead.
- */
- slideFactor: 50,
-
- /**
- * APIProperty: slideRatio
- * {Number} The fraction of map width/height by which we'll pan the map
- * on clicking the arrow buttons. Default is null. If set, will
- * override <slideFactor>. E.g. if slideRatio is .5, then the Pan Up
- * button will pan up half the map height.
- */
- slideRatio: null,
-
- /**
- * Property: buttons
- * {Array(DOMElement)} Array of Button Divs
- */
- buttons: null,
-
- /**
- * Property: position
- * {<OpenLayers.Pixel>}
- */
- position: null,
-
- /**
- * Constructor: OpenLayers.Control.PanZoom
- *
- * Parameters:
- * options - {Object}
- */
- initialize: function(options) {
- this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,
- OpenLayers.Control.PanZoom.Y);
- OpenLayers.Control.prototype.initialize.apply(this, arguments);
- },
-
- /**
- * APIMethod: destroy
- */
- destroy: function() {
- OpenLayers.Control.prototype.destroy.apply(this, arguments);
- this.removeButtons();
- this.buttons = null;
- this.position = null;
- },
-
- /**
- * Method: draw
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {DOMElement} A reference to the container div for the PanZoom control.
- */
- draw: function(px) {
- // initialize our internal div
- OpenLayers.Control.prototype.draw.apply(this, arguments);
- px = this.position;
-
- // place the controls
- this.buttons = [];
-
- var sz = new OpenLayers.Size(18,18);
- var centered = new OpenLayers.Pixel(px.x+sz.w/2, px.y);
-
- this._addButton("panup", "north-mini.png", centered, sz);
- px.y = centered.y+sz.h;
- this._addButton("panleft", "west-mini.png", px, sz);
- this._addButton("panright", "east-mini.png", px.add(sz.w, 0), sz);
- this._addButton("pandown", "south-mini.png",
- centered.add(0, sz.h*2), sz);
- this._addButton("zoomin", "zoom-plus-mini.png",
- centered.add(0, sz.h*3+5), sz);
- this._addButton("zoomworld", "zoom-world-mini.png",
- centered.add(0, sz.h*4+5), sz);
- this._addButton("zoomout", "zoom-minus-mini.png",
- centered.add(0, sz.h*5+5), sz);
- return this.div;
- },
+ }
- /**
- * Method: _addButton
- *
- * Parameters:
- * id - {String}
- * img - {String}
- * xy - {<OpenLayers.Pixel>}
- * sz - {<OpenLayers.Size>}
- *
- * Returns:
- * {DOMElement} A Div (an alphaImageDiv, to be precise) that contains the
- * image of the button, and has all the proper event handlers set.
- */
- _addButton:function(id, img, xy, sz) {
- var imgLocation = OpenLayers.Util.getImagesLocation() + img;
- var btn = OpenLayers.Util.createAlphaImageDiv(
- this.id + "_" + id,
- xy, sz, imgLocation, "absolute");
+ if (axis == "lon") {
+ str += coordinate < 0 ? OpenLayers.i18n("W") : OpenLayers.i18n("E");
+ } else {
+ str += coordinate < 0 ? OpenLayers.i18n("S") : OpenLayers.i18n("N");
+ }
+ return str;
+};
- //we want to add the outer div
- this.div.appendChild(btn);
-
- OpenLayers.Event.observe(btn, "mousedown",
- OpenLayers.Function.bindAsEventListener(this.buttonDown, btn));
- OpenLayers.Event.observe(btn, "dblclick",
- OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
- OpenLayers.Event.observe(btn, "click",
- OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
- btn.action = id;
- btn.map = this.map;
-
- if(!this.slideRatio){
- var slideFactorPixels = this.slideFactor;
- var getSlideFactor = function() {
- return slideFactorPixels;
- };
- } else {
- var slideRatio = this.slideRatio;
- var getSlideFactor = function(dim) {
- return this.map.getSize()[dim] * slideRatio;
- };
- }
-
- btn.getSlideFactor = getSlideFactor;
-
- //we want to remember/reference the outer div
- this.buttons.push(btn);
- return btn;
- },
-
- /**
- * Method: _removeButton
- *
- * Parameters:
- * btn - {Object}
- */
- _removeButton: function(btn) {
- OpenLayers.Event.stopObservingElement(btn);
- btn.map = null;
- btn.getSlideFactor = null;
- this.div.removeChild(btn);
- OpenLayers.Util.removeItem(this.buttons, btn);
- },
-
- /**
- * Method: removeButtons
- */
- removeButtons: function() {
- for(var i=this.buttons.length-1; i>=0; --i) {
- this._removeButton(this.buttons[i]);
- }
- },
-
- /**
- * Method: doubleClick
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean}
- */
- doubleClick: function (evt) {
- OpenLayers.Event.stop(evt);
- return false;
- },
-
- /**
- * Method: buttonDown
- *
- * Parameters:
- * evt - {Event}
- */
- buttonDown: function (evt) {
- if (!OpenLayers.Event.isLeftClick(evt)) {
- return;
- }
-
- switch (this.action) {
- case "panup":
- this.map.pan(0, -this.getSlideFactor("h"));
- break;
- case "pandown":
- this.map.pan(0, this.getSlideFactor("h"));
- break;
- case "panleft":
- this.map.pan(-this.getSlideFactor("w"), 0);
- break;
- case "panright":
- this.map.pan(this.getSlideFactor("w"), 0);
- break;
- case "zoomin":
- this.map.zoomIn();
- break;
- case "zoomout":
- this.map.zoomOut();
- break;
- case "zoomworld":
- this.map.zoomToMaxExtent();
- break;
- }
-
- OpenLayers.Event.stop(evt);
- },
-
- CLASS_NAME: "OpenLayers.Control.PanZoom"
-});
-
-/**
- * Constant: X
- * {Integer}
- */
-OpenLayers.Control.PanZoom.X = 4;
-
-/**
- * Constant: Y
- * {Integer}
- */
-OpenLayers.Control.PanZoom.Y = 4;
/* ======================================================================
- OpenLayers/Control/ScaleLine.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Control.js
- */
-
-/**
- * Class: OpenLayers.Control.ScaleLine
- * The ScaleLine displays a small line indicator representing the current
- * map scale on the map. By default it is drawn in the lower left corner of
- * the map.
- *
- * Inherits from:
- * - <OpenLayers.Control>
- *
- * Is a very close copy of:
- * - <OpenLayers.Control.Scale>
- */
-OpenLayers.Control.ScaleLine = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * Property: maxWidth
- * {Integer} Maximum width of the scale line in pixels. Default is 100.
- */
- maxWidth: 100,
-
- /**
- * Property: topOutUnits
- * {String} Units for zoomed out on top bar. Default is km.
- */
- topOutUnits: "km",
-
- /**
- * Property: topInUnits
- * {String} Units for zoomed in on top bar. Default is m.
- */
- topInUnits: "m",
-
- /**
- * Property: bottomOutUnits
- * {String} Units for zoomed out on bottom bar. Default is mi.
- */
- bottomOutUnits: "mi",
-
- /**
- * Property: bottomInUnits
- * {String} Units for zoomed in on bottom bar. Default is ft.
- */
- bottomInUnits: "ft",
-
- /**
- * Property: eTop
- * {DOMElement}
- */
- eTop: null,
-
- /**
- * Property: eBottom
- * {DOMElement}
- */
- eBottom:null,
-
- /**
- * APIProperty: geodesic
- * {Boolean} Use geodesic measurement. Default is false. The recommended
- * setting for maps in EPSG:4326 is false, and true EPSG:900913. If set to
- * true, the scale will be calculated based on the horizontal size of the
- * pixel in the center of the map viewport.
- */
- geodesic: false,
-
- /**
- * Constructor: OpenLayers.Control.ScaleLine
- * Create a new scale line control.
- *
- * Parameters:
- * options - {Object} An optional object whose properties will be used
- * to extend the control.
- */
- initialize: function(options) {
- OpenLayers.Control.prototype.initialize.apply(this, [options]);
- },
-
- /**
- * Method: draw
- *
- * Returns:
- * {DOMElement}
- */
- draw: function() {
- OpenLayers.Control.prototype.draw.apply(this, arguments);
- if (!this.eTop) {
- // stick in the top bar
- this.eTop = document.createElement("div");
- this.eTop.className = this.displayClass + "Top";
- var theLen = this.topInUnits.length;
- this.div.appendChild(this.eTop);
- if((this.topOutUnits == "") || (this.topInUnits == "")) {
- this.eTop.style.visibility = "hidden";
- } else {
- this.eTop.style.visibility = "visible";
- }
-
- // and the bottom bar
- this.eBottom = document.createElement("div");
- this.eBottom.className = this.displayClass + "Bottom";
- this.div.appendChild(this.eBottom);
- if((this.bottomOutUnits == "") || (this.bottomInUnits == "")) {
- this.eBottom.style.visibility = "hidden";
- } else {
- this.eBottom.style.visibility = "visible";
- }
- }
- this.map.events.register('moveend', this, this.update);
- this.update();
- return this.div;
- },
-
- /**
- * Method: getBarLen
- * Given a number, round it down to the nearest 1,2,5 times a power of 10.
- * That seems a fairly useful set of number groups to use.
- *
- * Parameters:
- * maxLen - {float} the number we're rounding down from
- *
- * Returns:
- * {Float} the rounded number (less than or equal to maxLen)
- */
- getBarLen: function(maxLen) {
- // nearest power of 10 lower than maxLen
- var digits = parseInt(Math.log(maxLen) / Math.log(10));
- var pow10 = Math.pow(10, digits);
-
- // ok, find first character
- var firstChar = parseInt(maxLen / pow10);
-
- // right, put it into the correct bracket
- var barLen;
- if(firstChar > 5) {
- barLen = 5;
- } else if(firstChar > 2) {
- barLen = 2;
- } else {
- barLen = 1;
- }
-
- // scale it up the correct power of 10
- return barLen * pow10;
- },
-
- /**
- * Method: update
- * Update the size of the bars, and the labels they contain.
- */
- update: function() {
- var res = this.map.getResolution();
- if (!res) {
- return;
- }
-
- var curMapUnits = this.map.getUnits();
- var inches = OpenLayers.INCHES_PER_UNIT;
-
- // convert maxWidth to map units
- var maxSizeData = this.maxWidth * res * inches[curMapUnits];
- var geodesicRatio = 1;
- if(this.geodesic === true) {
- var maxSizeGeodesic = (this.map.getGeodesicPixelSize().w ||
- 0.000001) * this.maxWidth;
- var maxSizeKilometers = maxSizeData / inches["km"];
- geodesicRatio = maxSizeGeodesic / maxSizeKilometers;
- maxSizeData *= geodesicRatio;
- }
-
- // decide whether to use large or small scale units
- var topUnits;
- var bottomUnits;
- if(maxSizeData > 100000) {
- topUnits = this.topOutUnits;
- bottomUnits = this.bottomOutUnits;
- } else {
- topUnits = this.topInUnits;
- bottomUnits = this.bottomInUnits;
- }
-
- // and to map units units
- var topMax = maxSizeData / inches[topUnits];
- var bottomMax = maxSizeData / inches[bottomUnits];
-
- // now trim this down to useful block length
- var topRounded = this.getBarLen(topMax);
- var bottomRounded = this.getBarLen(bottomMax);
-
- // and back to display units
- topMax = topRounded / inches[curMapUnits] * inches[topUnits];
- bottomMax = bottomRounded / inches[curMapUnits] * inches[bottomUnits];
-
- // and to pixel units
- var topPx = topMax / res / geodesicRatio;
- var bottomPx = bottomMax / res / geodesicRatio;
-
- // now set the pixel widths
- // and the values inside them
-
- if (this.eBottom.style.visibility == "visible"){
- this.eBottom.style.width = Math.round(bottomPx) + "px";
- this.eBottom.innerHTML = bottomRounded + " " + bottomUnits ;
- }
-
- if (this.eTop.style.visibility == "visible"){
- this.eTop.style.width = Math.round(topPx) + "px";
- this.eTop.innerHTML = topRounded + " " + topUnits;
- }
-
- },
-
- CLASS_NAME: "OpenLayers.Control.ScaleLine"
-});
-
-/* ======================================================================
OpenLayers/Events.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
@@ -10969,8 +5114,8 @@
* 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
+ * 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)} Array of custom application events
* fallThrough - {Boolean} Allow events to fall through after these have
* been handled?
@@ -11262,7 +5407,7 @@
// fast path
if(!listeners || listeners.length == 0) {
- return;
+ return undefined;
}
// prep evt object with object & div references
@@ -11278,7 +5423,8 @@
// execute all callbacks registered for specified type
// get a clone of the listeners array to
// allow for splicing during callbacks
- var listeners = listeners.slice(), continueChain;
+ listeners = listeners.slice();
+ var continueChain;
for (var i=0, len=listeners.length; i<len; i++) {
var callback = listeners[i];
// bind the context to callback.obj
@@ -11306,10 +5452,15 @@
* evt - {Event}
*/
handleBrowserEvent: function (evt) {
+ var type = evt.type, listeners = this.listeners[type];
+ if(!listeners || listeners.length == 0) {
+ // noone's listening, bail out
+ return;
+ }
if (this.includeXY) {
evt.xy = this.getMousePosition(evt);
}
- this.triggerEvent(evt.type, evt);
+ this.triggerEvent(type, evt);
},
/**
@@ -11343,11 +5494,10 @@
}
if (!this.element.scrolls) {
+ var viewportElement = OpenLayers.Util.getViewportElement();
this.element.scrolls = [
- (document.documentElement.scrollLeft
- || document.body.scrollLeft),
- (document.documentElement.scrollTop
- || document.body.scrollTop)
+ viewportElement.scrollLeft,
+ viewportElement.scrollTop
];
}
@@ -11360,8 +5510,6 @@
if (!this.element.offsets) {
this.element.offsets = OpenLayers.Util.pagePosition(this.element);
- this.element.offsets[0] += this.element.scrolls[0];
- this.element.offsets[1] += this.element.scrolls[1];
}
return new OpenLayers.Pixel(
(evt.clientX + this.element.scrolls[0]) - this.element.offsets[0]
@@ -11374,4117 +5522,344 @@
CLASS_NAME: "OpenLayers.Events"
});
/* ======================================================================
- OpenLayers/Format.js
+ OpenLayers/Tween.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
- * @requires OpenLayers/Util.js
+ * @requires OpenLayers/BaseTypes/Class.js
* @requires OpenLayers/Console.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.
+ * Namespace: OpenLayers.Tween
*/
-OpenLayers.Format = OpenLayers.Class({
+OpenLayers.Tween = OpenLayers.Class({
/**
- * Property: options
- * {Object} A reference to options passed to the constructor.
+ * Constant: INTERVAL
+ * {int} Interval in milliseconds between 2 steps
*/
- options: null,
+ INTERVAL: 10,
/**
- * APIProperty: externalProjection
- * {<OpenLayers.Projection>} 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
- * {<OpenLayers.Projection.addTransform>} for more information on
- * custom transformations.
+ * APIProperty: easing
+ * {<OpenLayers.Easing>(Function)} Easing equation used for the animation
+ * Defaultly set to OpenLayers.Easing.Expo.easeOut
*/
- externalProjection: null,
-
- /**
- * APIProperty: internalProjection
- * {<OpenLayers.Projection>} 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
- * {<OpenLayers.Projection.addTransform>} for more information on
- * custom transformations.
- */
- internalProjection: null,
-
- /**
- * APIProperty: data
- * {Object} When <keepData> is true, this is the parsed string sent to
- * <read>.
- */
- data: null,
-
- /**
- * APIProperty: keepData
- * {Object} Maintain a reference (<data>) 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 <read>, 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;
- },
+ easing: null,
/**
- * APIMethod: destroy
- * Clean up.
+ * APIProperty: begin
+ * {Object} Values to start the animation with
*/
- 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) {
- OpenLayers.Console.userError(OpenLayers.i18n("readNotImplemented"));
- },
+ begin: null,
/**
- * Method: write
- * Accept an object, and return a string.
- *
- * Parameters:
- * object - {Object} Object to be serialized
- *
- * Returns:
- * {String} A string representation of the object.
+ * APIProperty: finish
+ * {Object} Values to finish the animation with
*/
- write: function(object) {
- OpenLayers.Console.userError(OpenLayers.i18n("writeNotImplemented"));
- },
-
- CLASS_NAME: "OpenLayers.Format"
-});
-/* ======================================================================
- OpenLayers/Lang/en.js
- ====================================================================== */
-
-/**
- * @requires OpenLayers/Lang.js
- */
-
-/**
- * Namespace: OpenLayers.Lang["en"]
- * Dictionary for English. Keys for entries are used in calls to
- * <OpenLayers.Lang.translate>. Entry bodies are normal strings or
- * strings formatted for use with <OpenLayers.String.format> calls.
- */
-OpenLayers.Lang.en = {
-
- 'unhandledRequest': "Unhandled request return ${statusText}",
-
- 'permalink': "Permalink",
-
- 'overlays': "Overlays",
-
- 'baseLayer': "Base Layer",
-
- 'sameProjection':
- "The overview map only works when it is in the same projection as the main map",
-
- 'readNotImplemented': "Read not implemented.",
-
- 'writeNotImplemented': "Write not implemented.",
-
- 'noFID': "Can't update a feature for which there is no FID.",
-
- 'errorLoadingGML': "Error in loading GML file ${url}",
-
- 'browserNotSupported':
- "Your browser does not support vector rendering. Currently supported renderers are:\n${renderers}",
-
- 'componentShouldBe': "addFeatures : component should be an ${geomType}",
-
- // console message
- 'getFeatureError':
- "getFeatureFromEvent called on layer with no renderer. This usually means you " +
- "destroyed a layer, but not some handler which is associated with it.",
-
- // console message
- 'minZoomLevelError':
- "The minZoomLevel property is only intended for use " +
- "with the FixedZoomLevels-descendent layers. That this " +
- "wfs layer checks for minZoomLevel is a relic of the" +
- "past. We cannot, however, remove it without possibly " +
- "breaking OL based applications that may depend on it." +
- " Therefore we are deprecating it -- the minZoomLevel " +
- "check below will be removed at 3.0. Please instead " +
- "use min/max resolution setting as described here: " +
- "http://trac.openlayers.org/wiki/SettingZoomLevels",
-
- 'commitSuccess': "WFS Transaction: SUCCESS ${response}",
-
- 'commitFailed': "WFS Transaction: FAILED ${response}",
-
- 'googleWarning':
- "The Google Layer was unable to load correctly.<br><br>" +
- "To get rid of this message, select a new BaseLayer " +
- "in the layer switcher in the upper-right corner.<br><br>" +
- "Most likely, this is because the Google Maps library " +
- "script was either not included, or does not contain the " +
- "correct API key for your site.<br><br>" +
- "Developers: For help getting this working correctly, " +
- "<a href='http://trac.openlayers.org/wiki/Google' " +
- "target='_blank'>click here</a>",
-
- 'getLayerWarning':
- "The ${layerType} Layer was unable to load correctly.<br><br>" +
- "To get rid of this message, select a new BaseLayer " +
- "in the layer switcher in the upper-right corner.<br><br>" +
- "Most likely, this is because the ${layerLib} library " +
- "script was not correctly included.<br><br>" +
- "Developers: For help getting this working correctly, " +
- "<a href='http://trac.openlayers.org/wiki/${layerLib}' " +
- "target='_blank'>click here</a>",
-
- 'scale': "Scale = 1 : ${scaleDenom}",
+ finish: null,
- //labels for the graticule control
- 'W': 'W',
- 'E': 'E',
- 'N': 'N',
- 'S': 'S',
- 'graticule': 'Graticule',
-
- // console message
- 'layerAlreadyAdded':
- "You tried to add the layer: ${layerName} to the map, but it has already been added",
-
- // console message
- 'reprojectDeprecated':
- "You are using the 'reproject' option " +
- "on the ${layerName} layer. This option is deprecated: " +
- "its use was designed to support displaying data over commercial " +
- "basemaps, but that functionality should now be achieved by using " +
- "Spherical Mercator support. More information is available from " +
- "http://trac.openlayers.org/wiki/SphericalMercator.",
-
- // console message
- 'methodDeprecated':
- "This method has been deprecated and will be removed in 3.0. " +
- "Please use ${newMethod} instead.",
-
- // console message
- 'boundsAddError': "You must pass both x and y values to the add function.",
-
- // console message
- 'lonlatAddError': "You must pass both lon and lat values to the add function.",
-
- // console message
- 'pixelAddError': "You must pass both x and y values to the add function.",
-
- // console message
- 'unsupportedGeometryType': "Unsupported geometry type: ${geomType}",
-
- // console message
- 'pagePositionFailed':
- "OpenLayers.Util.pagePosition failed: element with id ${elemId} may be misplaced.",
-
- // console message
- 'filterEvaluateNotImplemented': "evaluate is not implemented for this filter type.",
-
- // **** end ****
- 'end': ''
-
-};
-/* ======================================================================
- OpenLayers/Popup/AnchoredBubble.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Popup/Anchored.js
- */
-
-/**
- * Class: OpenLayers.Popup.AnchoredBubble
- *
- * Inherits from:
- * - <OpenLayers.Popup.Anchored>
- */
-OpenLayers.Popup.AnchoredBubble =
- OpenLayers.Class(OpenLayers.Popup.Anchored, {
-
/**
- * Property: rounded
- * {Boolean} Has the popup been rounded yet?
+ * APIProperty: duration
+ * {int} duration of the tween (number of steps)
*/
- rounded: false,
+ duration: null,
- /**
- * Constructor: OpenLayers.Popup.AnchoredBubble
- *
- * Parameters:
- * id - {String}
- * lonlat - {<OpenLayers.LonLat>}
- * contentSize - {<OpenLayers.Size>}
- * contentHTML - {String}
- * anchor - {Object} Object to which we'll anchor the popup. Must expose
- * a 'size' (<OpenLayers.Size>) and 'offset' (<OpenLayers.Pixel>)
- * (Note that this is generally an <OpenLayers.Icon>).
- * closeBox - {Boolean}
- * closeBoxCallback - {Function} Function to be called on closeBox click.
- */
- initialize:function(id, lonlat, contentSize, contentHTML, anchor, closeBox,
- closeBoxCallback) {
-
- this.padding = new OpenLayers.Bounds(
- 0, OpenLayers.Popup.AnchoredBubble.CORNER_SIZE,
- 0, OpenLayers.Popup.AnchoredBubble.CORNER_SIZE
- );
- OpenLayers.Popup.Anchored.prototype.initialize.apply(this, arguments);
- },
-
- /**
- * Method: draw
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {DOMElement} Reference to a div that contains the drawn popup.
- */
- draw: function(px) {
-
- OpenLayers.Popup.Anchored.prototype.draw.apply(this, arguments);
-
- this.setContentHTML();
-
- //set the popup color and opacity
- this.setBackgroundColor();
- this.setOpacity();
-
- return this.div;
- },
-
/**
- * Method: updateRelativePosition
- * The popup has been moved to a new relative location, in which case
- * we will want to re-do the rico corners.
+ * APIProperty: callbacks
+ * {Object} An object with start, eachStep and done properties whose values
+ * are functions to be call during the animation. They are passed the
+ * current computed value as argument.
*/
- updateRelativePosition: function() {
- this.setRicoCorners();
- },
-
- /**
- * APIMethod: setSize
- *
- * Parameters:
- * contentSize - {<OpenLayers.Size>} the new size for the popup's
- * contents div (in pixels).
- */
- setSize:function(contentSize) {
- OpenLayers.Popup.Anchored.prototype.setSize.apply(this, arguments);
-
- this.setRicoCorners();
- },
-
- /**
- * APIMethod: setBackgroundColor
- *
- * Parameters:
- * color - {String}
- */
- setBackgroundColor:function(color) {
- if (color != undefined) {
- this.backgroundColor = color;
- }
-
- if (this.div != null) {
- if (this.contentDiv != null) {
- this.div.style.background = "transparent";
- OpenLayers.Rico.Corner.changeColor(this.groupDiv,
- this.backgroundColor);
- }
- }
- },
+ callbacks: null,
/**
- * APIMethod: setOpacity
- *
- * Parameters:
- * opacity - {float}
+ * Property: time
+ * {int} Step counter
*/
- setOpacity:function(opacity) {
- OpenLayers.Popup.Anchored.prototype.setOpacity.call(this, opacity);
-
- if (this.div != null) {
- if (this.groupDiv != null) {
- OpenLayers.Rico.Corner.changeOpacity(this.groupDiv,
- this.opacity);
- }
- }
- },
-
- /**
- * Method: setBorder
- * Always sets border to 0. Bubble Popups can not have a border.
- *
- * Parameters:
- * border - {Integer}
- */
- setBorder:function(border) {
- this.border = 0;
- },
-
- /**
- * Method: setRicoCorners
- * Update RICO corners according to the popup's current relative postion.
- */
- setRicoCorners:function() {
+ time: null,
- var corners = this.getCornersToRound(this.relativePosition);
- var options = {corners: corners,
- color: this.backgroundColor,
- bgColor: "transparent",
- blend: false};
-
- if (!this.rounded) {
- OpenLayers.Rico.Corner.round(this.div, options);
- this.rounded = true;
- } else {
- OpenLayers.Rico.Corner.reRound(this.groupDiv, options);
- //set the popup color and opacity
- this.setBackgroundColor();
- this.setOpacity();
- }
- },
-
- /**
- * Method: getCornersToRound
- *
- * Returns:
- * {String} The proper corners string ("tr tl bl br") for rico to round.
- */
- getCornersToRound:function() {
-
- var corners = ['tl', 'tr', 'bl', 'br'];
-
- //we want to round all the corners _except_ the opposite one.
- var corner = OpenLayers.Bounds.oppositeQuadrant(this.relativePosition);
- OpenLayers.Util.removeItem(corners, corner);
-
- return corners.join(" ");
- },
-
- CLASS_NAME: "OpenLayers.Popup.AnchoredBubble"
-});
-
-/**
- * Constant: CORNER_SIZE
- * {Integer} 5. Border space for the RICO corners.
- */
-OpenLayers.Popup.AnchoredBubble.CORNER_SIZE = 5;
-
-/* ======================================================================
- OpenLayers/Projection.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Util.js
- */
-
-/**
- * Class: OpenLayers.Projection
- * Class for coordinate transforms between coordinate systems.
- * Depends on the proj4js library. If proj4js is not available,
- * then this is just an empty stub.
- */
-OpenLayers.Projection = OpenLayers.Class({
-
/**
- * Property: proj
- * {Object} Proj4js.Proj instance.
+ * Property: interval
+ * {int} Interval id returned by window.setInterval
*/
- proj: null,
+ interval: null,
/**
- * Property: projCode
- * {String}
+ * Property: playing
+ * {Boolean} Tells if the easing is currently playing
*/
- projCode: null,
-
- /**
- * Constructor: OpenLayers.Projection
- * This class offers several methods for interacting with a wrapped
- * pro4js projection object.
- *
- * Parameters:
- * projCode - {String} A string identifying the Well Known Identifier for
- * the projection.
- * options - {Object} An optional object to set additional properties
- * on the layer.
- *
- * Returns:
- * {<OpenLayers.Projection>} A projection object.
- */
- initialize: function(projCode, options) {
- OpenLayers.Util.extend(this, options);
- this.projCode = projCode;
- if (window.Proj4js) {
- this.proj = new Proj4js.Proj(projCode);
- }
- },
+ playing: false,
- /**
- * APIMethod: getCode
- * Get the string SRS code.
- *
- * Returns:
- * {String} The SRS code.
- */
- getCode: function() {
- return this.proj ? this.proj.srsCode : this.projCode;
- },
-
- /**
- * APIMethod: getUnits
- * Get the units string for the projection -- returns null if
- * proj4js is not available.
- *
- * Returns:
- * {String} The units abbreviation.
- */
- getUnits: function() {
- return this.proj ? this.proj.units : null;
- },
-
- /**
- * Method: toString
- * Convert projection to string (getCode wrapper).
- *
- * Returns:
- * {String} The projection code.
- */
- toString: function() {
- return this.getCode();
- },
-
- /**
- * Method: equals
- * Test equality of two projection instances. Determines equality based
- * soley on the projection code.
- *
- * Returns:
- * {Boolean} The two projections are equivalent.
- */
- equals: function(projection) {
- if (projection && projection.getCode) {
- return this.getCode() == projection.getCode();
- } else {
- return false;
- }
- },
-
- /* Method: destroy
- * Destroy projection object.
- */
- destroy: function() {
- delete this.proj;
- delete this.projCode;
- },
-
- CLASS_NAME: "OpenLayers.Projection"
-});
-
-/**
- * Property: transforms
- * Transforms is an object, with from properties, each of which may
- * have a to property. This allows you to define projections without
- * requiring support for proj4js to be included.
- *
- * This object has keys which correspond to a 'source' projection object. The
- * keys should be strings, corresponding to the projection.getCode() value.
- * Each source projection object should have a set of destination projection
- * keys included in the object.
- *
- * Each value in the destination object should be a transformation function,
- * where the function is expected to be passed an object with a .x and a .y
- * property. The function should return the object, with the .x and .y
- * transformed according to the transformation function.
- *
- * Note - Properties on this object should not be set directly. To add a
- * transform method to this object, use the <addTransform> method. For an
- * example of usage, see the OpenLayers.Layer.SphericalMercator file.
- */
-OpenLayers.Projection.transforms = {};
-
-/**
- * APIMethod: addTransform
- * Set a custom transform method between two projections. Use this method in
- * cases where the proj4js lib is not available or where custom projections
- * need to be handled.
- *
- * Parameters:
- * from - {String} The code for the source projection
- * to - {String} the code for the destination projection
- * method - {Function} A function that takes a point as an argument and
- * transforms that point from the source to the destination projection
- * in place. The original point should be modified.
- */
-OpenLayers.Projection.addTransform = function(from, to, method) {
- if(!OpenLayers.Projection.transforms[from]) {
- OpenLayers.Projection.transforms[from] = {};
- }
- OpenLayers.Projection.transforms[from][to] = method;
-};
-
-/**
- * APIMethod: transform
- * Transform a point coordinate from one projection to another. Note that
- * the input point is transformed in place.
- *
- * Parameters:
- * point - {{OpenLayers.Geometry.Point> | Object} An object with x and y
- * properties representing coordinates in those dimensions.
- * sourceProj - {OpenLayers.Projection} Source map coordinate system
- * destProj - {OpenLayers.Projection} Destination map coordinate system
- *
- * Returns:
- * point - {object} A transformed coordinate. The original point is modified.
- */
-OpenLayers.Projection.transform = function(point, source, dest) {
- if (source.proj && dest.proj) {
- point = Proj4js.transform(source.proj, dest.proj, point);
- } else if (source && dest &&
- OpenLayers.Projection.transforms[source.getCode()] &&
- OpenLayers.Projection.transforms[source.getCode()][dest.getCode()]) {
- OpenLayers.Projection.transforms[source.getCode()][dest.getCode()](point);
- }
- return point;
-};
-/* ======================================================================
- OpenLayers/Renderer/SVG.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Renderer/Elements.js
- */
-
-/**
- * Class: OpenLayers.Renderer.SVG
- *
- * Inherits:
- * - <OpenLayers.Renderer.Elements>
- */
-OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
-
/**
- * Property: xmlns
- * {String}
- */
- xmlns: "http://www.w3.org/2000/svg",
-
- /**
- * Property: xlinkns
- * {String}
- */
- xlinkns: "http://www.w3.org/1999/xlink",
-
- /**
- * Constant: MAX_PIXEL
- * {Integer} Firefox has a limitation where values larger or smaller than
- * about 15000 in an SVG document lock the browser up. This
- * works around it.
- */
- MAX_PIXEL: 15000,
-
- /**
- * Property: translationParameters
- * {Object} Hash with "x" and "y" properties
- */
- translationParameters: null,
-
- /**
- * Property: symbolMetrics
- * {Object} Cache for symbol metrics according to their svg coordinate
- * space. This is an object keyed by the symbol's id, and values are
- * an array of [width, centerX, centerY].
- */
- symbolMetrics: null,
-
- /**
- * Property: isGecko
- * {Boolean}
- */
- isGecko: null,
-
- /**
- * Property: supportUse
- * {Boolean} true if defs/use is supported - known to not work as expected
- * at least in some applewebkit/5* builds.
- * See https://bugs.webkit.org/show_bug.cgi?id=33322
- */
- supportUse: null,
-
- /**
- * Constructor: OpenLayers.Renderer.SVG
- *
- * Parameters:
- * containerID - {String}
- */
- initialize: function(containerID) {
- if (!this.supported()) {
- return;
- }
- OpenLayers.Renderer.Elements.prototype.initialize.apply(this,
- arguments);
- this.translationParameters = {x: 0, y: 0};
- this.supportUse = (navigator.userAgent.toLowerCase().indexOf("applewebkit/5") == -1);
- this.isGecko = (navigator.userAgent.toLowerCase().indexOf("gecko/") != -1);
-
- this.symbolMetrics = {};
- },
-
- /**
- * APIMethod: destroy
- */
- destroy: function() {
- OpenLayers.Renderer.Elements.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * APIMethod: supported
- *
- * Returns:
- * {Boolean} Whether or not the browser supports the SVG renderer
- */
- supported: function() {
- var svgFeature = "http://www.w3.org/TR/SVG11/feature#";
- return (document.implementation &&
- (document.implementation.hasFeature("org.w3c.svg", "1.0") ||
- document.implementation.hasFeature(svgFeature + "SVG", "1.1") ||
- document.implementation.hasFeature(svgFeature + "BasicStructure", "1.1") ));
- },
-
- /**
- * Method: inValidRange
- * See #669 for more information
+ * Constructor: OpenLayers.Tween
+ * Creates a Tween.
*
* Parameters:
- * x - {Integer}
- * y - {Integer}
- * xyOnly - {Boolean} whether or not to just check for x and y, which means
- * to not take the current translation parameters into account if true.
- *
- * Returns:
- * {Boolean} Whether or not the 'x' and 'y' coordinates are in the
- * valid range.
+ * easing - {<OpenLayers.Easing>(Function)} easing function method to use
*/
- inValidRange: function(x, y, xyOnly) {
- var left = x + (xyOnly ? 0 : this.translationParameters.x);
- var top = y + (xyOnly ? 0 : this.translationParameters.y);
- return (left >= -this.MAX_PIXEL && left <= this.MAX_PIXEL &&
- top >= -this.MAX_PIXEL && top <= this.MAX_PIXEL);
+ initialize: function(easing) {
+ this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut;
},
-
- /**
- * Method: setExtent
- *
- * Parameters:
- * extent - {<OpenLayers.Bounds>}
- * resolutionChanged - {Boolean}
- *
- * Returns:
- * {Boolean} true to notify the layer that the new extent does not exceed
- * the coordinate range, and the features will not need to be redrawn.
- * False otherwise.
- */
- setExtent: function(extent, resolutionChanged) {
- OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,
- arguments);
-
- var resolution = this.getResolution();
- var left = -extent.left / resolution;
- var top = extent.top / resolution;
-
- // If the resolution has changed, start over changing the corner, because
- // the features will redraw.
- if (resolutionChanged) {
- this.left = left;
- this.top = top;
- // Set the viewbox
- var extentString = "0 0 " + this.size.w + " " + this.size.h;
-
- this.rendererRoot.setAttributeNS(null, "viewBox", extentString);
- this.translate(0, 0);
- return true;
- } else {
- var inRange = this.translate(left - this.left, top - this.top);
- if (!inRange) {
- // recenter the coordinate system
- this.setExtent(extent, true);
- }
- return inRange;
- }
- },
/**
- * Method: translate
- * Transforms the SVG coordinate system
+ * APIMethod: start
+ * Plays the Tween, and calls the callback method on each step
*
* Parameters:
- * x - {Float}
- * y - {Float}
- *
- * Returns:
- * {Boolean} true if the translation parameters are in the valid coordinates
- * range, false otherwise.
+ * begin - {Object} values to start the animation with
+ * finish - {Object} values to finish the animation with
+ * duration - {int} duration of the tween (number of steps)
+ * options - {Object} hash of options (for example callbacks (start, eachStep, done))
*/
- translate: function(x, y) {
- if (!this.inValidRange(x, y, true)) {
- return false;
- } else {
- var transformString = "";
- if (x || y) {
- transformString = "translate(" + x + "," + y + ")";
- }
- this.root.setAttributeNS(null, "transform", transformString);
- this.translationParameters = {x: x, y: y};
- return true;
+ start: function(begin, finish, duration, options) {
+ this.playing = true;
+ this.begin = begin;
+ this.finish = finish;
+ this.duration = duration;
+ this.callbacks = options.callbacks;
+ this.time = 0;
+ if (this.interval) {
+ window.clearInterval(this.interval);
+ this.interval = null;
}
- },
-
- /**
- * Method: setSize
- * Sets the size of the drawing surface.
- *
- * Parameters:
- * size - {<OpenLayers.Size>} The size of the drawing surface
- */
- setSize: function(size) {
- OpenLayers.Renderer.prototype.setSize.apply(this, arguments);
-
- this.rendererRoot.setAttributeNS(null, "width", this.size.w);
- this.rendererRoot.setAttributeNS(null, "height", this.size.h);
- },
-
- /**
- * Method: getNodeType
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- *
- * Returns:
- * {String} The corresponding node type for the specified geometry
- */
- getNodeType: function(geometry, style) {
- var nodeType = null;
- switch (geometry.CLASS_NAME) {
- case "OpenLayers.Geometry.Point":
- if (style.externalGraphic) {
- nodeType = "image";
- } else if (this.isComplexSymbol(style.graphicName)) {
- nodeType = this.supportUse === false ? "svg" : "use";
- } else {
- nodeType = "circle";
- }
- break;
- case "OpenLayers.Geometry.Rectangle":
- nodeType = "rect";
- break;
- case "OpenLayers.Geometry.LineString":
- nodeType = "polyline";
- break;
- case "OpenLayers.Geometry.LinearRing":
- nodeType = "polygon";
- break;
- case "OpenLayers.Geometry.Polygon":
- case "OpenLayers.Geometry.Curve":
- case "OpenLayers.Geometry.Surface":
- nodeType = "path";
- break;
- default:
- break;
+ if (this.callbacks && this.callbacks.start) {
+ this.callbacks.start.call(this, this.begin);
}
- return nodeType;
+ this.interval = window.setInterval(
+ OpenLayers.Function.bind(this.play, this), this.INTERVAL);
},
-
- /**
- * Method: setStyle
- * Use to set all the style attributes to a SVG node.
- *
- * Takes care to adjust stroke width and point radius to be
- * resolution-relative
- *
- * Parameters:
- * node - {SVGDomElement} An SVG element to decorate
- * style - {Object}
- * options - {Object} Currently supported options include
- * 'isFilled' {Boolean} and
- * 'isStroked' {Boolean}
- */
- setStyle: function(node, style, options) {
- style = style || node._style;
- options = options || node._options;
- var r = parseFloat(node.getAttributeNS(null, "r"));
- var widthFactor = 1;
- var pos;
- if (node._geometryClass == "OpenLayers.Geometry.Point" && r) {
- node.style.visibility = "";
- if (style.graphic === false) {
- node.style.visibility = "hidden";
- } else if (style.externalGraphic) {
- pos = this.getPosition(node);
-
- if (style.graphicTitle) {
- node.setAttributeNS(null, "title", style.graphicTitle);
- }
- if (style.graphicWidth && style.graphicHeight) {
- node.setAttributeNS(null, "preserveAspectRatio", "none");
- }
- var width = style.graphicWidth || style.graphicHeight;
- var height = style.graphicHeight || style.graphicWidth;
- width = width ? width : style.pointRadius*2;
- height = height ? height : style.pointRadius*2;
- var xOffset = (style.graphicXOffset != undefined) ?
- style.graphicXOffset : -(0.5 * width);
- var yOffset = (style.graphicYOffset != undefined) ?
- style.graphicYOffset : -(0.5 * height);
-
- var opacity = style.graphicOpacity || style.fillOpacity;
-
- node.setAttributeNS(null, "x", (pos.x + xOffset).toFixed());
- node.setAttributeNS(null, "y", (pos.y + yOffset).toFixed());
- node.setAttributeNS(null, "width", width);
- node.setAttributeNS(null, "height", height);
- node.setAttributeNS(this.xlinkns, "href", style.externalGraphic);
- node.setAttributeNS(null, "style", "opacity: "+opacity);
- } else if (this.isComplexSymbol(style.graphicName)) {
- // the symbol viewBox is three times as large as the symbol
- var offset = style.pointRadius * 3;
- var size = offset * 2;
- var id = this.importSymbol(style.graphicName);
- pos = this.getPosition(node);
- widthFactor = this.symbolMetrics[id][0] * 3 / size;
-
- // remove the node from the dom before we modify it. This
- // prevents various rendering issues in Safari and FF
- var parent = node.parentNode;
- var nextSibling = node.nextSibling;
- if(parent) {
- parent.removeChild(node);
- }
-
- if(this.supportUse === false) {
- // workaround for webkit versions that cannot do defs/use
- // (see https://bugs.webkit.org/show_bug.cgi?id=33322):
- // copy the symbol instead of referencing it
- var src = document.getElementById(id);
- node.firstChild && node.removeChild(node.firstChild);
- node.appendChild(src.firstChild.cloneNode(true));
- node.setAttributeNS(null, "viewBox", src.getAttributeNS(null, "viewBox"));
- } else {
- node.setAttributeNS(this.xlinkns, "href", "#" + id);
- }
- node.setAttributeNS(null, "width", size);
- node.setAttributeNS(null, "height", size);
- node.setAttributeNS(null, "x", pos.x - offset);
- node.setAttributeNS(null, "y", pos.y - offset);
-
- // now that the node has all its new properties, insert it
- // back into the dom where it was
- if(nextSibling) {
- parent.insertBefore(node, nextSibling);
- } else if(parent) {
- parent.appendChild(node);
- }
- } else {
- node.setAttributeNS(null, "r", style.pointRadius);
- }
-
- var rotation = style.rotation;
- if ((rotation !== undefined || node._rotation !== undefined) && pos) {
- node._rotation = rotation;
- rotation |= 0;
- if(node.nodeName !== "svg") {
- node.setAttributeNS(null, "transform",
- "rotate(" + rotation + " " + pos.x + " " +
- pos.y + ")");
- } else {
- var metrics = this.symbolMetrics[id];
- node.firstChild.setAttributeNS(null, "transform",
- "rotate(" + style.rotation + " " + metrics[1] +
- " " + metrics[2] + ")");
- }
- }
- }
-
- if (options.isFilled) {
- node.setAttributeNS(null, "fill", style.fillColor);
- node.setAttributeNS(null, "fill-opacity", style.fillOpacity);
- } else {
- node.setAttributeNS(null, "fill", "none");
- }
-
- if (options.isStroked) {
- node.setAttributeNS(null, "stroke", style.strokeColor);
- node.setAttributeNS(null, "stroke-opacity", style.strokeOpacity);
- node.setAttributeNS(null, "stroke-width", style.strokeWidth * widthFactor);
- node.setAttributeNS(null, "stroke-linecap", style.strokeLinecap || "round");
- // Hard-coded linejoin for now, to make it look the same as in VML.
- // There is no strokeLinejoin property yet for symbolizers.
- node.setAttributeNS(null, "stroke-linejoin", "round");
- style.strokeDashstyle && node.setAttributeNS(null,
- "stroke-dasharray", this.dashStyle(style, widthFactor));
- } else {
- node.setAttributeNS(null, "stroke", "none");
- }
-
- if (style.pointerEvents) {
- node.setAttributeNS(null, "pointer-events", style.pointerEvents);
- }
-
- if (style.cursor != null) {
- node.setAttributeNS(null, "cursor", style.cursor);
- }
-
- return node;
- },
-
- /**
- * Method: dashStyle
- *
- * Parameters:
- * style - {Object}
- * widthFactor - {Number}
- *
- * Returns:
- * {String} A SVG compliant 'stroke-dasharray' value
- */
- dashStyle: function(style, widthFactor) {
- var w = style.strokeWidth * widthFactor;
- var str = style.strokeDashstyle;
- switch (str) {
- case 'solid':
- return 'none';
- case 'dot':
- return [1, 4 * w].join();
- case 'dash':
- return [4 * w, 4 * w].join();
- case 'dashdot':
- return [4 * w, 4 * w, 1, 4 * w].join();
- case 'longdash':
- return [8 * w, 4 * w].join();
- case 'longdashdot':
- return [8 * w, 4 * w, 1, 4 * w].join();
- default:
- return OpenLayers.String.trim(str).replace(/\s+/g, ",");
- }
- },
- /**
- * Method: createNode
- *
- * Parameters:
- * type - {String} Kind of node to draw
- * id - {String} Id for node
- *
- * Returns:
- * {DOMElement} A new node of the given type and id
- */
- createNode: function(type, id) {
- var node = document.createElementNS(this.xmlns, type);
- if (id) {
- node.setAttributeNS(null, "id", id);
- }
- return node;
- },
-
- /**
- * Method: nodeTypeCompare
- *
- * Parameters:
- * node - {SVGDomElement} An SVG element
- * type - {String} Kind of node
- *
- * Returns:
- * {Boolean} Whether or not the specified node is of the specified type
- */
- nodeTypeCompare: function(node, type) {
- return (type == node.nodeName);
- },
-
/**
- * Method: createRenderRoot
- *
- * Returns:
- * {DOMElement} The specific render engine's root element
+ * APIMethod: stop
+ * Stops the Tween, and calls the done callback
+ * Doesn't do anything if animation is already finished
*/
- createRenderRoot: function() {
- return this.nodeFactory(this.container.id + "_svgRoot", "svg");
- },
-
- /**
- * Method: createRoot
- *
- * Parameter:
- * suffix - {String} suffix to append to the id
- *
- * Returns:
- * {DOMElement}
- */
- createRoot: function(suffix) {
- return this.nodeFactory(this.container.id + suffix, "g");
- },
-
- /**
- * Method: createDefs
- *
- * Returns:
- * {DOMElement} The element to which we'll add the symbol definitions
- */
- createDefs: function() {
- var defs = this.nodeFactory(this.container.id + "_defs", "defs");
- this.rendererRoot.appendChild(defs);
- return defs;
- },
-
- /**************************************
- * *
- * GEOMETRY DRAWING FUNCTIONS *
- * *
- **************************************/
-
- /**
- * Method: drawPoint
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or false if the renderer could not draw the point
- */
- drawPoint: function(node, geometry) {
- return this.drawCircle(node, geometry, 1);
- },
-
- /**
- * Method: drawCircle
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- * radius - {Float}
- *
- * Returns:
- * {DOMElement} or false if the renderer could not draw the circle
- */
- drawCircle: function(node, geometry, radius) {
- var resolution = this.getResolution();
- var x = (geometry.x / resolution + this.left);
- var y = (this.top - geometry.y / resolution);
-
- if (this.inValidRange(x, y)) {
- node.setAttributeNS(null, "cx", x);
- node.setAttributeNS(null, "cy", y);
- node.setAttributeNS(null, "r", radius);
- return node;
- } else {
- return false;
- }
-
- },
-
- /**
- * Method: drawLineString
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or null if the renderer could not draw all components of
- * the linestring, or false if nothing could be drawn
- */
- drawLineString: function(node, geometry) {
- var componentsResult = this.getComponentsString(geometry.components);
- if (componentsResult.path) {
- node.setAttributeNS(null, "points", componentsResult.path);
- return (componentsResult.complete ? node : null);
- } else {
- return false;
+ stop: function() {
+ if (!this.playing) {
+ return;
}
- },
-
- /**
- * Method: drawLinearRing
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or null if the renderer could not draw all components
- * of the linear ring, or false if nothing could be drawn
- */
- drawLinearRing: function(node, geometry) {
- var componentsResult = this.getComponentsString(geometry.components);
- if (componentsResult.path) {
- node.setAttributeNS(null, "points", componentsResult.path);
- return (componentsResult.complete ? node : null);
- } else {
- return false;
+
+ if (this.callbacks && this.callbacks.done) {
+ this.callbacks.done.call(this, this.finish);
}
+ window.clearInterval(this.interval);
+ this.interval = null;
+ this.playing = false;
},
/**
- * Method: drawPolygon
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or null if the renderer could not draw all components
- * of the polygon, or false if nothing could be drawn
- */
- drawPolygon: function(node, geometry) {
- var d = "";
- var draw = true;
- var complete = true;
- var linearRingResult, path;
- for (var j=0, len=geometry.components.length; j<len; j++) {
- d += " M";
- linearRingResult = this.getComponentsString(
- geometry.components[j].components, " ");
- path = linearRingResult.path;
- if (path) {
- d += " " + path;
- complete = linearRingResult.complete && complete;
- } else {
- draw = false;
- }
- }
- d += " z";
- if (draw) {
- node.setAttributeNS(null, "d", d);
- node.setAttributeNS(null, "fill-rule", "evenodd");
- return complete ? node : null;
- } else {
- return false;
- }
- },
-
- /**
- * Method: drawRectangle
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or false if the renderer could not draw the rectangle
- */
- drawRectangle: function(node, geometry) {
- var resolution = this.getResolution();
- var x = (geometry.x / resolution + this.left);
- var y = (this.top - geometry.y / resolution);
-
- if (this.inValidRange(x, y)) {
- node.setAttributeNS(null, "x", x);
- node.setAttributeNS(null, "y", y);
- node.setAttributeNS(null, "width", geometry.width / resolution);
- node.setAttributeNS(null, "height", geometry.height / resolution);
- return node;
- } else {
- return false;
- }
- },
-
- /**
- * Method: drawSurface
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or false if the renderer could not draw the surface
- */
- drawSurface: function(node, geometry) {
-
- // create the svg path string representation
- var d = null;
- var draw = true;
- for (var i=0, len=geometry.components.length; i<len; i++) {
- if ((i%3) == 0 && (i/3) == 0) {
- var component = this.getShortString(geometry.components[i]);
- if (!component) { draw = false; }
- d = "M " + component;
- } else if ((i%3) == 1) {
- var component = this.getShortString(geometry.components[i]);
- if (!component) { draw = false; }
- d += " C " + component;
- } else {
- var component = this.getShortString(geometry.components[i]);
- if (!component) { draw = false; }
- d += " " + component;
- }
- }
- d += " Z";
- if (draw) {
- node.setAttributeNS(null, "d", d);
- return node;
- } else {
- return false;
- }
- },
-
- /**
- * Method: drawText
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * featureId - {String}
- * style -
- * location - {<OpenLayers.Geometry.Point>}
+ * Method: play
+ * Calls the appropriate easing method
*/
- drawText: function(featureId, style, location) {
- var resolution = this.getResolution();
-
- var x = (location.x / resolution + this.left);
- var y = (location.y / resolution - this.top);
-
- var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "text");
- var tspan = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_tspan", "tspan");
-
- label.setAttributeNS(null, "x", x);
- label.setAttributeNS(null, "y", -y);
-
- if (style.fontColor) {
- label.setAttributeNS(null, "fill", style.fontColor);
- }
- if (style.fontOpacity) {
- label.setAttributeNS(null, "opacity", style.fontOpacity);
- }
- if (style.fontFamily) {
- label.setAttributeNS(null, "font-family", style.fontFamily);
- }
- if (style.fontSize) {
- label.setAttributeNS(null, "font-size", style.fontSize);
- }
- if (style.fontWeight) {
- label.setAttributeNS(null, "font-weight", style.fontWeight);
- }
- if(style.labelSelect === true) {
- label.setAttributeNS(null, "pointer-events", "visible");
- label._featureId = featureId;
- tspan._featureId = featureId;
- tspan._geometry = location;
- tspan._geometryClass = location.CLASS_NAME;
- } else {
- label.setAttributeNS(null, "pointer-events", "none");
- }
- var align = style.labelAlign || "cm";
- label.setAttributeNS(null, "text-anchor",
- OpenLayers.Renderer.SVG.LABEL_ALIGN[align[0]] || "middle");
-
- if (this.isGecko) {
- label.setAttributeNS(null, "dominant-baseline",
- OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]] || "central");
- } else {
- tspan.setAttributeNS(null, "baseline-shift",
- OpenLayers.Renderer.SVG.LABEL_VSHIFT[align[1]] || "-35%");
- }
-
- tspan.textContent = style.label;
-
- if(!label.parentNode) {
- label.appendChild(tspan);
- this.textRoot.appendChild(label);
- }
- },
-
- /**
- * Method: getComponentString
- *
- * Parameters:
- * components - {Array(<OpenLayers.Geometry.Point>)} Array of points
- * separator - {String} character between coordinate pairs. Defaults to ","
- *
- * Returns:
- * {Object} hash with properties "path" (the string created from the
- * components and "complete" (false if the renderer was unable to
- * draw all components)
- */
- getComponentsString: function(components, separator) {
- var renderCmp = [];
- var complete = true;
- var len = components.length;
- var strings = [];
- var str, component;
- for(var i=0; i<len; i++) {
- component = components[i];
- renderCmp.push(component);
- str = this.getShortString(component);
- if (str) {
- strings.push(str);
- } else {
- // The current component is outside the valid range. Let's
- // see if the previous or next component is inside the range.
- // If so, add the coordinate of the intersection with the
- // valid range bounds.
- if (i > 0) {
- if (this.getShortString(components[i - 1])) {
- strings.push(this.clipLine(components[i],
- components[i-1]));
- }
- }
- if (i < len - 1) {
- if (this.getShortString(components[i + 1])) {
- strings.push(this.clipLine(components[i],
- components[i+1]));
- }
- }
- complete = false;
+ play: function() {
+ var value = {};
+ for (var i in this.begin) {
+ var b = this.begin[i];
+ var f = this.finish[i];
+ if (b == null || f == null || isNaN(b) || isNaN(f)) {
+ OpenLayers.Console.error('invalid value for Tween');
}
+
+ var c = f - b;
+ value[i] = this.easing.apply(this, [this.time, b, c, this.duration]);
}
-
- return {
- path: strings.join(separator || ","),
- complete: complete
- };
- },
-
- /**
- * Method: clipLine
- * Given two points (one inside the valid range, and one outside),
- * clips the line betweeen the two points so that the new points are both
- * inside the valid range.
- *
- * Parameters:
- * badComponent - {<OpenLayers.Geometry.Point>)} original geometry of the
- * invalid point
- * goodComponent - {<OpenLayers.Geometry.Point>)} original geometry of the
- * valid point
- * Returns
- * {String} the SVG coordinate pair of the clipped point (like
- * getShortString), or an empty string if both passed componets are at
- * the same point.
- */
- clipLine: function(badComponent, goodComponent) {
- if (goodComponent.equals(badComponent)) {
- return "";
- }
- var resolution = this.getResolution();
- var maxX = this.MAX_PIXEL - this.translationParameters.x;
- var maxY = this.MAX_PIXEL - this.translationParameters.y;
- var x1 = goodComponent.x / resolution + this.left;
- var y1 = this.top - goodComponent.y / resolution;
- var x2 = badComponent.x / resolution + this.left;
- var y2 = this.top - badComponent.y / resolution;
- var k;
- if (x2 < -maxX || x2 > maxX) {
- k = (y2 - y1) / (x2 - x1);
- x2 = x2 < 0 ? -maxX : maxX;
- y2 = y1 + (x2 - x1) * k;
- }
- if (y2 < -maxY || y2 > maxY) {
- k = (x2 - x1) / (y2 - y1);
- y2 = y2 < 0 ? -maxY : maxY;
- x2 = x1 + (y2 - y1) * k;
- }
- return x2 + "," + y2;
- },
-
- /**
- * Method: getShortString
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point>}
- *
- * Returns:
- * {String} or false if point is outside the valid range
- */
- getShortString: function(point) {
- var resolution = this.getResolution();
- var x = (point.x / resolution + this.left);
- var y = (this.top - point.y / resolution);
-
- if (this.inValidRange(x, y)) {
- return x + "," + y;
- } else {
- return false;
- }
- },
-
- /**
- * Method: getPosition
- * Finds the position of an svg node.
- *
- * Parameters:
- * node - {DOMElement}
- *
- * Returns:
- * {Object} hash with x and y properties, representing the coordinates
- * within the svg coordinate system
- */
- getPosition: function(node) {
- return({
- x: parseFloat(node.getAttributeNS(null, "cx")),
- y: parseFloat(node.getAttributeNS(null, "cy"))
- });
- },
-
- /**
- * Method: importSymbol
- * add a new symbol definition from the rendererer's symbol hash
- *
- * Parameters:
- * graphicName - {String} name of the symbol to import
- *
- * Returns:
- * {String} - id of the imported symbol
- */
- importSymbol: function (graphicName) {
- if (!this.defs) {
- // create svg defs tag
- this.defs = this.createDefs();
- }
- var id = this.container.id + "-" + graphicName;
+ this.time++;
- // check if symbol already exists in the defs
- if (document.getElementById(id) != null) {
- return id;
+ if (this.callbacks && this.callbacks.eachStep) {
+ this.callbacks.eachStep.call(this, value);
}
- var symbol = OpenLayers.Renderer.symbol[graphicName];
- if (!symbol) {
- throw new Error(graphicName + ' is not a valid symbol name');
+ if (this.time > this.duration) {
+ this.stop();
}
-
- var symbolNode = this.nodeFactory(id, "symbol");
- var node = this.nodeFactory(null, "polygon");
- symbolNode.appendChild(node);
- var symbolExtent = new OpenLayers.Bounds(
- Number.MAX_VALUE, Number.MAX_VALUE, 0, 0);
-
- var points = [];
- var x,y;
- for (var i=0; i<symbol.length; i=i+2) {
- x = symbol[i];
- y = symbol[i+1];
- symbolExtent.left = Math.min(symbolExtent.left, x);
- symbolExtent.bottom = Math.min(symbolExtent.bottom, y);
- symbolExtent.right = Math.max(symbolExtent.right, x);
- symbolExtent.top = Math.max(symbolExtent.top, y);
- points.push(x, ",", y);
- }
-
- node.setAttributeNS(null, "points", points.join(" "));
-
- var width = symbolExtent.getWidth();
- var height = symbolExtent.getHeight();
- // create a viewBox three times as large as the symbol itself,
- // to allow for strokeWidth being displayed correctly at the corners.
- var viewBox = [symbolExtent.left - width,
- symbolExtent.bottom - height, width * 3, height * 3];
- symbolNode.setAttributeNS(null, "viewBox", viewBox.join(" "));
- this.symbolMetrics[id] = [
- Math.max(width, height),
- symbolExtent.getCenterLonLat().lon,
- symbolExtent.getCenterLonLat().lat
- ];
-
- this.defs.appendChild(symbolNode);
- return symbolNode.id;
},
/**
- * Method: getFeatureIdFromEvent
- *
- * Parameters:
- * evt - {Object} An <OpenLayers.Event> object
- *
- * Returns:
- * {<OpenLayers.Geometry>} A geometry from an event that
- * happened on a layer.
+ * Create empty functions for all easing methods.
*/
- getFeatureIdFromEvent: function(evt) {
- var featureId = OpenLayers.Renderer.Elements.prototype.getFeatureIdFromEvent.apply(this, arguments);
- if(this.supportUse === false && !featureId) {
- var target = evt.target;
- featureId = target.parentNode && target != this.rendererRoot &&
- target.parentNode._featureId;
- }
- return featureId;
- },
-
- CLASS_NAME: "OpenLayers.Renderer.SVG"
+ CLASS_NAME: "OpenLayers.Tween"
});
/**
- * Constant: OpenLayers.Renderer.SVG.LABEL_ALIGN
- * {Object}
+ * Namespace: OpenLayers.Easing
+ *
+ * Credits:
+ * Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>
*/
-OpenLayers.Renderer.SVG.LABEL_ALIGN = {
- "l": "start",
- "r": "end",
- "b": "bottom",
- "t": "hanging"
+OpenLayers.Easing = {
+ /**
+ * Create empty functions for all easing methods.
+ */
+ CLASS_NAME: "OpenLayers.Easing"
};
/**
- * Constant: OpenLayers.Renderer.SVG.LABEL_VSHIFT
- * {Object}
+ * Namespace: OpenLayers.Easing.Linear
*/
-OpenLayers.Renderer.SVG.LABEL_VSHIFT = {
- // according to
- // http://www.w3.org/Graphics/SVG/Test/20061213/htmlObjectHarness/full-text-align-02-b.html
- // a baseline-shift of -70% shifts the text exactly from the
- // bottom to the top of the baseline, so -35% moves the text to
- // the center of the baseline.
- "t": "-70%",
- "b": "0"
-};
-/* ======================================================================
- OpenLayers/Renderer/VML.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Renderer/Elements.js
- */
-
-/**
- * Class: OpenLayers.Renderer.VML
- * Render vector features in browsers with VML capability. Construct a new
- * VML renderer with the <OpenLayers.Renderer.VML> constructor.
- *
- * Note that for all calculations in this class, we use (num | 0) to truncate a
- * float value to an integer. This is done because it seems that VML doesn't
- * support float values.
- *
- * Inherits from:
- * - <OpenLayers.Renderer.Elements>
- */
-OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
-
- /**
- * Property: xmlns
- * {String} XML Namespace URN
- */
- xmlns: "urn:schemas-microsoft-com:vml",
+OpenLayers.Easing.Linear = {
/**
- * Property: symbolCache
- * {DOMElement} node holding symbols. This hash is keyed by symbol name,
- * and each value is a hash with a "path" and an "extent" property.
- */
- symbolCache: {},
-
- /**
- * Property: offset
- * {Object} Hash with "x" and "y" properties
- */
- offset: null,
-
- /**
- * Constructor: OpenLayers.Renderer.VML
- * Create a new VML renderer.
- *
- * Parameters:
- * containerID - {String} The id for the element that contains the renderer
- */
- initialize: function(containerID) {
- if (!this.supported()) {
- return;
- }
- if (!document.namespaces.olv) {
- document.namespaces.add("olv", this.xmlns);
- var style = document.createStyleSheet();
- var shapes = ['shape','rect', 'oval', 'fill', 'stroke', 'imagedata', 'group','textbox'];
- for (var i = 0, len = shapes.length; i < len; i++) {
-
- style.addRule('olv\\:' + shapes[i], "behavior: url(#default#VML); " +
- "position: absolute; display: inline-block;");
- }
- }
-
- OpenLayers.Renderer.Elements.prototype.initialize.apply(this,
- arguments);
- },
-
- /**
- * APIMethod: destroy
- * Deconstruct the renderer.
- */
- destroy: function() {
- OpenLayers.Renderer.Elements.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * APIMethod: supported
- * Determine whether a browser supports this renderer.
- *
- * Returns:
- * {Boolean} The browser supports the VML renderer
- */
- supported: function() {
- return !!(document.namespaces);
- },
-
- /**
- * Method: setExtent
- * Set the renderer's extent
- *
- * Parameters:
- * extent - {<OpenLayers.Bounds>}
- * resolutionChanged - {Boolean}
+ * Function: easeIn
*
- * Returns:
- * {Boolean} true to notify the layer that the new extent does not exceed
- * the coordinate range, and the features will not need to be redrawn.
- */
- setExtent: function(extent, resolutionChanged) {
- OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,
- arguments);
- var resolution = this.getResolution();
-
- var left = (extent.left/resolution) | 0;
- var top = (extent.top/resolution - this.size.h) | 0;
- if (resolutionChanged || !this.offset) {
- this.offset = {x: left, y: top};
- left = 0;
- top = 0;
- } else {
- left = left - this.offset.x;
- top = top - this.offset.y;
- }
-
-
- var org = left + " " + top;
- this.root.coordorigin = org;
- var roots = [this.root, this.vectorRoot, this.textRoot];
- var root;
- for(var i=0, len=roots.length; i<len; ++i) {
- root = roots[i];
-
- var size = this.size.w + " " + this.size.h;
- root.coordsize = size;
-
- }
- // flip the VML display Y axis upside down so it
- // matches the display Y axis of the map
- this.root.style.flip = "y";
-
- return true;
- },
-
-
- /**
- * Method: setSize
- * Set the size of the drawing surface
- *
* Parameters:
- * size - {<OpenLayers.Size>} the size of the drawing surface
+ * t - {Float} time
+ * b - {Float} beginning position
+ * c - {Float} total change
+ * d - {Float} duration of the transition
*/
- setSize: function(size) {
- OpenLayers.Renderer.prototype.setSize.apply(this, arguments);
-
- // setting width and height on all roots to avoid flicker which we
- // would get with 100% width and height on child roots
- var roots = [
- this.rendererRoot,
- this.root,
- this.vectorRoot,
- this.textRoot
- ];
- var w = this.size.w + "px";
- var h = this.size.h + "px";
- var root;
- for(var i=0, len=roots.length; i<len; ++i) {
- root = roots[i];
- root.style.width = w;
- root.style.height = h;
- }
+ easeIn: function(t, b, c, d) {
+ return c*t/d + b;
},
-
- /**
- * Method: getNodeType
- * Get the node type for a geometry and style
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- *
- * Returns:
- * {String} The corresponding node type for the specified geometry
- */
- getNodeType: function(geometry, style) {
- var nodeType = null;
- switch (geometry.CLASS_NAME) {
- case "OpenLayers.Geometry.Point":
- if (style.externalGraphic) {
- nodeType = "olv:rect";
- } else if (this.isComplexSymbol(style.graphicName)) {
- nodeType = "olv:shape";
- } else {
- nodeType = "olv:oval";
- }
- break;
- case "OpenLayers.Geometry.Rectangle":
- nodeType = "olv:rect";
- break;
- case "OpenLayers.Geometry.LineString":
- case "OpenLayers.Geometry.LinearRing":
- case "OpenLayers.Geometry.Polygon":
- case "OpenLayers.Geometry.Curve":
- case "OpenLayers.Geometry.Surface":
- nodeType = "olv:shape";
- break;
- default:
- break;
- }
- return nodeType;
- },
-
- /**
- * Method: setStyle
- * Use to set all the style attributes to a VML node.
- *
- * Parameters:
- * node - {DOMElement} An VML element to decorate
- * style - {Object}
- * options - {Object} Currently supported options include
- * 'isFilled' {Boolean} and
- * 'isStroked' {Boolean}
- * geometry - {<OpenLayers.Geometry>}
- */
- setStyle: function(node, style, options, geometry) {
- style = style || node._style;
- options = options || node._options;
- var fillColor = style.fillColor;
-
- if (node._geometryClass === "OpenLayers.Geometry.Point") {
- if (style.externalGraphic) {
- if (style.graphicTitle) {
- node.title=style.graphicTitle;
- }
- var width = style.graphicWidth || style.graphicHeight;
- var height = style.graphicHeight || style.graphicWidth;
- width = width ? width : style.pointRadius*2;
- height = height ? height : style.pointRadius*2;
-
- var resolution = this.getResolution();
- var xOffset = (style.graphicXOffset != undefined) ?
- style.graphicXOffset : -(0.5 * width);
- var yOffset = (style.graphicYOffset != undefined) ?
- style.graphicYOffset : -(0.5 * height);
-
- node.style.left = (((geometry.x/resolution - this.offset.x)+xOffset) | 0) + "px";
- node.style.top = (((geometry.y/resolution - this.offset.y)-(yOffset+height)) | 0) + "px";
- node.style.width = width + "px";
- node.style.height = height + "px";
- node.style.flip = "y";
-
- // modify fillColor and options for stroke styling below
- fillColor = "none";
- options.isStroked = false;
- } else if (this.isComplexSymbol(style.graphicName)) {
- var cache = this.importSymbol(style.graphicName);
- node.path = cache.path;
- node.coordorigin = cache.left + "," + cache.bottom;
- var size = cache.size;
- node.coordsize = size + "," + size;
- this.drawCircle(node, geometry, style.pointRadius);
- node.style.flip = "y";
- } else {
- this.drawCircle(node, geometry, style.pointRadius);
- }
- }
-
- // fill
- if (options.isFilled) {
- node.fillcolor = fillColor;
- } else {
- node.filled = "false";
- }
- var fills = node.getElementsByTagName("fill");
- var fill = (fills.length == 0) ? null : fills[0];
- if (!options.isFilled) {
- if (fill) {
- node.removeChild(fill);
- }
- } else {
- if (!fill) {
- fill = this.createNode('olv:fill', node.id + "_fill");
- }
- fill.opacity = style.fillOpacity;
-
- if (node._geometryClass === "OpenLayers.Geometry.Point" &&
- style.externalGraphic) {
-
- // override fillOpacity
- if (style.graphicOpacity) {
- fill.opacity = style.graphicOpacity;
- }
-
- fill.src = style.externalGraphic;
- fill.type = "frame";
-
- if (!(style.graphicWidth && style.graphicHeight)) {
- fill.aspect = "atmost";
- }
- }
- if (fill.parentNode != node) {
- node.appendChild(fill);
- }
- }
-
- // additional rendering for rotated graphics or symbols
- var rotation = style.rotation;
- if ((rotation !== undefined || node._rotation !== undefined)) {
- node._rotation = rotation;
- if (style.externalGraphic) {
- this.graphicRotate(node, xOffset, yOffset, style);
- // make the fill fully transparent, because we now have
- // the graphic as imagedata element. We cannot just remove
- // the fill, because this is part of the hack described
- // in graphicRotate
- fill.opacity = 0;
- } else if(node._geometryClass === "OpenLayers.Geometry.Point") {
- node.style.rotation = rotation || 0;
- }
- }
-
- // stroke
- var strokes = node.getElementsByTagName("stroke");
- var stroke = (strokes.length == 0) ? null : strokes[0];
- if (!options.isStroked) {
- node.stroked = false;
- if (stroke) {
- stroke.on = false;
- }
- } else {
- if (!stroke) {
- stroke = this.createNode('olv:stroke', node.id + "_stroke");
- node.appendChild(stroke);
- }
- stroke.on = true;
- stroke.color = style.strokeColor;
- stroke.weight = style.strokeWidth + "px";
- stroke.opacity = style.strokeOpacity;
- stroke.endcap = style.strokeLinecap == 'butt' ? 'flat' :
- (style.strokeLinecap || 'round');
- if (style.strokeDashstyle) {
- stroke.dashstyle = this.dashStyle(style);
- }
- }
-
- if (style.cursor != "inherit" && style.cursor != null) {
- node.style.cursor = style.cursor;
- }
- return node;
- },
-
- /**
- * Method: graphicRotate
- * If a point is to be styled with externalGraphic and rotation, VML fills
- * cannot be used to display the graphic, because rotation of graphic
- * fills is not supported by the VML implementation of Internet Explorer.
- * This method creates a olv:imagedata element inside the VML node,
- * DXImageTransform.Matrix and BasicImage filters for rotation and
- * opacity, and a 3-step hack to remove rendering artefacts from the
- * graphic and preserve the ability of graphics to trigger events.
- * Finally, OpenLayers methods are used to determine the correct
- * insertion point of the rotated image, because DXImageTransform.Matrix
- * does the rotation without the ability to specify a rotation center
- * point.
- *
- * Parameters:
- * node - {DOMElement}
- * xOffset - {Number} rotation center relative to image, x coordinate
- * yOffset - {Number} rotation center relative to image, y coordinate
- * style - {Object}
- */
- graphicRotate: function(node, xOffset, yOffset, style) {
- var style = style || node._style;
- var rotation = style.rotation || 0;
-
- var aspectRatio, size;
- if (!(style.graphicWidth && style.graphicHeight)) {
- // load the image to determine its size
- var img = new Image();
- img.onreadystatechange = OpenLayers.Function.bind(function() {
- if(img.readyState == "complete" ||
- img.readyState == "interactive") {
- aspectRatio = img.width / img.height;
- size = Math.max(style.pointRadius * 2,
- style.graphicWidth || 0,
- style.graphicHeight || 0);
- xOffset = xOffset * aspectRatio;
- style.graphicWidth = size * aspectRatio;
- style.graphicHeight = size;
- this.graphicRotate(node, xOffset, yOffset, style);
- }
- }, this);
- img.src = style.externalGraphic;
-
- // will be called again by the onreadystate handler
- return;
- } else {
- size = Math.max(style.graphicWidth, style.graphicHeight);
- aspectRatio = style.graphicWidth / style.graphicHeight;
- }
-
- var width = Math.round(style.graphicWidth || size * aspectRatio);
- var height = Math.round(style.graphicHeight || size);
- node.style.width = width + "px";
- node.style.height = height + "px";
-
- // Three steps are required to remove artefacts for images with
- // transparent backgrounds (resulting from using DXImageTransform
- // filters on svg objects), while preserving awareness for browser
- // events on images:
- // - Use the fill as usual (like for unrotated images) to handle
- // events
- // - specify an imagedata element with the same src as the fill
- // - style the imagedata element with an AlphaImageLoader filter
- // with empty src
- var image = document.getElementById(node.id + "_image");
- if (!image) {
- image = this.createNode("olv:imagedata", node.id + "_image");
- node.appendChild(image);
- }
- image.style.width = width + "px";
- image.style.height = height + "px";
- image.src = style.externalGraphic;
- image.style.filter =
- "progid:DXImageTransform.Microsoft.AlphaImageLoader(" +
- "src='', sizingMethod='scale')";
-
- var rot = rotation * Math.PI / 180;
- var sintheta = Math.sin(rot);
- var costheta = Math.cos(rot);
-
- // do the rotation on the image
- var filter =
- "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta +
- ",M12=" + (-sintheta) + ",M21=" + sintheta + ",M22=" + costheta +
- ",SizingMethod='auto expand')\n";
-
- // set the opacity (needed for the imagedata)
- var opacity = style.graphicOpacity || style.fillOpacity;
- if (opacity && opacity != 1) {
- filter +=
- "progid:DXImageTransform.Microsoft.BasicImage(opacity=" +
- opacity+")\n";
- }
- node.style.filter = filter;
-
- // do the rotation again on a box, so we know the insertion point
- var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset);
- var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry();
- imgBox.rotate(style.rotation, centerPoint);
- var imgBounds = imgBox.getBounds();
-
- node.style.left = Math.round(
- parseInt(node.style.left) + imgBounds.left) + "px";
- node.style.top = Math.round(
- parseInt(node.style.top) - imgBounds.bottom) + "px";
- },
-
- /**
- * Method: postDraw
- * Does some node postprocessing to work around browser issues:
- * - Some versions of Internet Explorer seem to be unable to set fillcolor
- * and strokecolor to "none" correctly before the fill node is appended
- * to a visible vml node. This method takes care of that and sets
- * fillcolor and strokecolor again if needed.
- * - In some cases, a node won't become visible after being drawn. Setting
- * style.visibility to "visible" works around that.
- *
- * Parameters:
- * node - {DOMElement}
- */
- postDraw: function(node) {
- node.style.visibility = "visible";
- var fillColor = node._style.fillColor;
- var strokeColor = node._style.strokeColor;
- if (fillColor == "none" &&
- node.fillcolor != fillColor) {
- node.fillcolor = fillColor;
- }
- if (strokeColor == "none" &&
- node.strokecolor != strokeColor) {
- node.strokecolor = strokeColor;
- }
- },
-
-
- /**
- * Method: setNodeDimension
- * Get the geometry's bounds, convert it to our vml coordinate system,
- * then set the node's position, size, and local coordinate system.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- */
- setNodeDimension: function(node, geometry) {
-
- var bbox = geometry.getBounds();
- if(bbox) {
- var resolution = this.getResolution();
-
- var scaledBox =
- new OpenLayers.Bounds((bbox.left/resolution - this.offset.x) | 0,
- (bbox.bottom/resolution - this.offset.y) | 0,
- (bbox.right/resolution - this.offset.x) | 0,
- (bbox.top/resolution - this.offset.y) | 0);
-
- // Set the internal coordinate system to draw the path
- node.style.left = scaledBox.left + "px";
- node.style.top = scaledBox.top + "px";
- node.style.width = scaledBox.getWidth() + "px";
- node.style.height = scaledBox.getHeight() + "px";
- node.coordorigin = scaledBox.left + " " + scaledBox.top;
- node.coordsize = scaledBox.getWidth()+ " " + scaledBox.getHeight();
- }
- },
-
- /**
- * Method: dashStyle
- *
- * Parameters:
- * style - {Object}
- *
- * Returns:
- * {String} A VML compliant 'stroke-dasharray' value
- */
- dashStyle: function(style) {
- var dash = style.strokeDashstyle;
- switch (dash) {
- case 'solid':
- case 'dot':
- case 'dash':
- case 'dashdot':
- case 'longdash':
- case 'longdashdot':
- return dash;
- default:
- // very basic guessing of dash style patterns
- var parts = dash.split(/[ ,]/);
- if (parts.length == 2) {
- if (1*parts[0] >= 2*parts[1]) {
- return "longdash";
- }
- return (parts[0] == 1 || parts[1] == 1) ? "dot" : "dash";
- } else if (parts.length == 4) {
- return (1*parts[0] >= 2*parts[1]) ? "longdashdot" :
- "dashdot";
- }
- return "solid";
- }
- },
-
/**
- * Method: createNode
- * Create a new node
- *
- * Parameters:
- * type - {String} Kind of node to draw
- * id - {String} Id for node
- *
- * Returns:
- * {DOMElement} A new node of the given type and id
- */
- createNode: function(type, id) {
- var node = document.createElement(type);
- if (id) {
- node.id = id;
- }
-
- // IE hack to make elements unselectable, to prevent 'blue flash'
- // while dragging vectors; #1410
- node.unselectable = 'on';
- node.onselectstart = OpenLayers.Function.False;
-
- return node;
- },
-
- /**
- * Method: nodeTypeCompare
- * Determine whether a node is of a given type
- *
- * Parameters:
- * node - {DOMElement} An VML element
- * type - {String} Kind of node
- *
- * Returns:
- * {Boolean} Whether or not the specified node is of the specified type
- */
- nodeTypeCompare: function(node, type) {
-
- //split type
- var subType = type;
- var splitIndex = subType.indexOf(":");
- if (splitIndex != -1) {
- subType = subType.substr(splitIndex+1);
- }
-
- //split nodeName
- var nodeName = node.nodeName;
- splitIndex = nodeName.indexOf(":");
- if (splitIndex != -1) {
- nodeName = nodeName.substr(splitIndex+1);
- }
-
- return (subType == nodeName);
- },
-
- /**
- * Method: createRenderRoot
- * Create the renderer root
- *
- * Returns:
- * {DOMElement} The specific render engine's root element
- */
- createRenderRoot: function() {
- return this.nodeFactory(this.container.id + "_vmlRoot", "div");
- },
-
- /**
- * Method: createRoot
- * Create the main root element
+ * Function: easeOut
*
* Parameters:
- * suffix - {String} suffix to append to the id
- *
- * Returns:
- * {DOMElement}
+ * t - {Float} time
+ * b - {Float} beginning position
+ * c - {Float} total change
+ * d - {Float} duration of the transition
*/
- createRoot: function(suffix) {
- return this.nodeFactory(this.container.id + suffix, "olv:group");
+ easeOut: function(t, b, c, d) {
+ return c*t/d + b;
},
- /**************************************
- * *
- * GEOMETRY DRAWING FUNCTIONS *
- * *
- **************************************/
-
/**
- * Method: drawPoint
- * Render a point
+ * Function: easeInOut
*
* Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or false if the point could not be drawn
+ * t - {Float} time
+ * b - {Float} beginning position
+ * c - {Float} total change
+ * d - {Float} duration of the transition
*/
- drawPoint: function(node, geometry) {
- return this.drawCircle(node, geometry, 1);
+ easeInOut: function(t, b, c, d) {
+ return c*t/d + b;
},
- /**
- * Method: drawCircle
- * Render a circle.
- * Size and Center a circle given geometry (x,y center) and radius
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- * radius - {float}
- *
- * Returns:
- * {DOMElement} or false if the circle could not ne drawn
- */
- drawCircle: function(node, geometry, radius) {
- if(!isNaN(geometry.x)&& !isNaN(geometry.y)) {
- var resolution = this.getResolution();
+ CLASS_NAME: "OpenLayers.Easing.Linear"
+};
- node.style.left = (((geometry.x /resolution - this.offset.x) | 0) - radius) + "px";
- node.style.top = (((geometry.y /resolution - this.offset.y) | 0) - radius) + "px";
+/**
+ * Namespace: OpenLayers.Easing.Expo
+ */
+OpenLayers.Easing.Expo = {
- var diameter = radius * 2;
-
- node.style.width = diameter + "px";
- node.style.height = diameter + "px";
- return node;
- }
- return false;
- },
-
-
/**
- * Method: drawLineString
- * Render a linestring.
+ * Function: easeIn
*
* Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement}
+ * t - {Float} time
+ * b - {Float} beginning position
+ * c - {Float} total change
+ * d - {Float} duration of the transition
*/
- drawLineString: function(node, geometry) {
- return this.drawLine(node, geometry, false);
+ easeIn: function(t, b, c, d) {
+ return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
},
-
- /**
- * Method: drawLinearRing
- * Render a linearring
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement}
- */
- drawLinearRing: function(node, geometry) {
- return this.drawLine(node, geometry, true);
- },
-
- /**
- * Method: DrawLine
- * Render a line.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- * closeLine - {Boolean} Close the line? (make it a ring?)
- *
- * Returns:
- * {DOMElement}
- */
- drawLine: function(node, geometry, closeLine) {
-
- this.setNodeDimension(node, geometry);
-
- var resolution = this.getResolution();
- var numComponents = geometry.components.length;
- var parts = new Array(numComponents);
-
- var comp, x, y;
- for (var i = 0; i < numComponents; i++) {
- comp = geometry.components[i];
- x = (comp.x/resolution - this.offset.x) | 0;
- y = (comp.y/resolution - this.offset.y) | 0;
- parts[i] = " " + x + "," + y + " l ";
- }
- var end = (closeLine) ? " x e" : " e";
- node.path = "m" + parts.join("") + end;
- return node;
- },
-
- /**
- * Method: drawPolygon
- * Render a polygon
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement}
- */
- drawPolygon: function(node, geometry) {
- this.setNodeDimension(node, geometry);
-
- var resolution = this.getResolution();
- var path = [];
- var linearRing, i, j, len, ilen, comp, x, y;
- for (j = 0, len=geometry.components.length; j<len; j++) {
- linearRing = geometry.components[j];
-
- path.push("m");
- for (i=0, ilen=linearRing.components.length; i<ilen; i++) {
- comp = linearRing.components[i];
- x = (comp.x / resolution - this.offset.x) | 0;
- y = (comp.y / resolution - this.offset.y) | 0;
- path.push(" " + x + "," + y);
- if (i==0) {
- path.push(" l");
- }
- }
- path.push(" x ");
- }
- path.push("e");
- node.path = path.join("");
- return node;
- },
-
/**
- * Method: drawRectangle
- * Render a rectangle
+ * Function: easeOut
*
* Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement}
+ * t - {Float} time
+ * b - {Float} beginning position
+ * c - {Float} total change
+ * d - {Float} duration of the transition
*/
- drawRectangle: function(node, geometry) {
- var resolution = this.getResolution();
-
- node.style.left = ((geometry.x/resolution - this.offset.x) | 0) + "px";
- node.style.top = ((geometry.y/resolution - this.offset.y) | 0) + "px";
- node.style.width = ((geometry.width/resolution) | 0) + "px";
- node.style.height = ((geometry.height/resolution) | 0) + "px";
-
- return node;
+ easeOut: function(t, b, c, d) {
+ return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
},
/**
- * Method: drawText
- * This method is only called by the renderer itself.
+ * Function: easeInOut
*
- * Parameters:
- * featureId - {String}
- * style -
- * location - {<OpenLayers.Geometry.Point>}
- */
- drawText: function(featureId, style, location) {
- var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "olv:rect");
- var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox");
-
- var resolution = this.getResolution();
- label.style.left = ((location.x/resolution - this.offset.x) | 0) + "px";
- label.style.top = ((location.y/resolution - this.offset.y) | 0) + "px";
- label.style.flip = "y";
-
- textbox.innerText = style.label;
-
- if (style.fontColor) {
- textbox.style.color = style.fontColor;
- }
- if (style.fontOpacity) {
- textbox.style.filter = 'alpha(opacity=' + (style.fontOpacity * 100) + ')';
- }
- if (style.fontFamily) {
- textbox.style.fontFamily = style.fontFamily;
- }
- if (style.fontSize) {
- textbox.style.fontSize = style.fontSize;
- }
- if (style.fontWeight) {
- textbox.style.fontWeight = style.fontWeight;
- }
- if(style.labelSelect === true) {
- label._featureId = featureId;
- textbox._featureId = featureId;
- textbox._geometry = location;
- textbox._geometryClass = location.CLASS_NAME;
- }
- textbox.style.whiteSpace = "nowrap";
- // fun with IE: IE7 in standards compliant mode does not display any
- // text with a left inset of 0. So we set this to 1px and subtract one
- // pixel later when we set label.style.left
- textbox.inset = "1px,0px,0px,0px";
-
- if(!label.parentNode) {
- label.appendChild(textbox);
- this.textRoot.appendChild(label);
- }
-
- var align = style.labelAlign || "cm";
- if (align.length == 1) {
- align += "m";
- }
- var xshift = textbox.clientWidth *
- (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0,1)]);
- var yshift = textbox.clientHeight *
- (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1,1)]);
- label.style.left = parseInt(label.style.left)-xshift-1+"px";
- label.style.top = parseInt(label.style.top)+yshift+"px";
-
- },
-
- /**
- * Method: drawSurface
- *
* Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement}
+ * t - {Float} time
+ * b - {Float} beginning position
+ * c - {Float} total change
+ * d - {Float} duration of the transition
*/
- drawSurface: function(node, geometry) {
-
- this.setNodeDimension(node, geometry);
-
- var resolution = this.getResolution();
-
- var path = [];
- var comp, x, y;
- for (var i=0, len=geometry.components.length; i<len; i++) {
- comp = geometry.components[i];
- x = (comp.x / resolution - this.offset.x) | 0;
- y = (comp.y / resolution - this.offset.y) | 0;
- if ((i%3)==0 && (i/3)==0) {
- path.push("m");
- } else if ((i%3)==1) {
- path.push(" c");
- }
- path.push(" " + x + "," + y);
- }
- path.push(" x e");
-
- node.path = path.join("");
- return node;
+ easeInOut: function(t, b, c, d) {
+ if (t==0) return b;
+ if (t==d) return b+c;
+ if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
+ return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
},
-
- /**
- * Method: moveRoot
- * moves this renderer's root to a different renderer.
- *
- * Parameters:
- * renderer - {<OpenLayers.Renderer>} target renderer for the moved root
- * root - {DOMElement} optional root node. To be used when this renderer
- * holds roots from multiple layers to tell this method which one to
- * detach
- *
- * Returns:
- * {Boolean} true if successful, false otherwise
- */
- moveRoot: function(renderer) {
- var layer = this.map.getLayer(renderer.container.id);
- if(layer instanceof OpenLayers.Layer.Vector.RootContainer) {
- layer = this.map.getLayer(this.container.id);
- }
- layer && layer.renderer.clear();
- OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments);
- layer && layer.redraw();
- },
-
- /**
- * Method: importSymbol
- * add a new symbol definition from the rendererer's symbol hash
- *
- * Parameters:
- * graphicName - {String} name of the symbol to import
- *
- * Returns:
- * {Object} - hash of {DOMElement} "symbol" and {Number} "size"
- */
- importSymbol: function (graphicName) {
- var id = this.container.id + "-" + graphicName;
-
- // check if symbol already exists in the cache
- var cache = this.symbolCache[id];
- if (cache) {
- return cache;
- }
-
- var symbol = OpenLayers.Renderer.symbol[graphicName];
- if (!symbol) {
- throw new Error(graphicName + ' is not a valid symbol name');
- }
- var symbolExtent = new OpenLayers.Bounds(
- Number.MAX_VALUE, Number.MAX_VALUE, 0, 0);
-
- var pathitems = ["m"];
- for (var i=0; i<symbol.length; i=i+2) {
- var x = symbol[i];
- var y = symbol[i+1];
- symbolExtent.left = Math.min(symbolExtent.left, x);
- symbolExtent.bottom = Math.min(symbolExtent.bottom, y);
- symbolExtent.right = Math.max(symbolExtent.right, x);
- symbolExtent.top = Math.max(symbolExtent.top, y);
-
- pathitems.push(x);
- pathitems.push(y);
- if (i == 0) {
- pathitems.push("l");
- }
- }
- pathitems.push("x e");
- var path = pathitems.join(" ");
-
- var diff = (symbolExtent.getWidth() - symbolExtent.getHeight()) / 2;
- if(diff > 0) {
- symbolExtent.bottom = symbolExtent.bottom - diff;
- symbolExtent.top = symbolExtent.top + diff;
- } else {
- symbolExtent.left = symbolExtent.left + diff;
- symbolExtent.right = symbolExtent.right - diff;
- }
-
- cache = {
- path: path,
- size: symbolExtent.getWidth(), // equals getHeight() now
- left: symbolExtent.left,
- bottom: symbolExtent.bottom
- };
- this.symbolCache[id] = cache;
-
- return cache;
- },
-
- CLASS_NAME: "OpenLayers.Renderer.VML"
-});
-
-/**
- * Constant: OpenLayers.Renderer.VML.LABEL_SHIFT
- * {Object}
- */
-OpenLayers.Renderer.VML.LABEL_SHIFT = {
- "l": 0,
- "c": .5,
- "r": 1,
- "t": 0,
- "m": .5,
- "b": 1
+ CLASS_NAME: "OpenLayers.Easing.Expo"
};
-/* ======================================================================
- OpenLayers/Tile.js
- ====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-
-/*
- * @requires OpenLayers/Util.js
- * @requires OpenLayers/Console.js
- */
-
-/*
- * Class: OpenLayers.Tile
- * This is a class designed to designate a single tile, however
- * it is explicitly designed to do relatively little. Tiles store
- * information about themselves -- such as the URL that they are related
- * to, and their size - but do not add themselves to the layer div
- * automatically, for example. Create a new tile with the
- * <OpenLayers.Tile> constructor, or a subclass.
- *
- * TBD 3.0 - remove reference to url in above paragraph
- *
- */
-OpenLayers.Tile = OpenLayers.Class({
-
- /**
- * Constant: EVENT_TYPES
- * {Array(String)} Supported application event types
- */
- EVENT_TYPES: [ "loadstart", "loadend", "reload", "unload"],
-
- /**
- * APIProperty: events
- * {<OpenLayers.Events>} An events object that handles all
- * events on the tile.
- */
- events: null,
-
- /**
- * Property: id
- * {String} null
- */
- id: null,
-
- /**
- * Property: layer
- * {<OpenLayers.Layer>} layer the tile is attached to
- */
- layer: null,
-
- /**
- * Property: url
- * {String} url of the request.
- *
- * TBD 3.0
- * Deprecated. The base tile class does not need an url. This should be
- * handled in subclasses. Does not belong here.
- */
- url: null,
-
- /**
- * APIProperty: bounds
- * {<OpenLayers.Bounds>} null
- */
- bounds: null,
-
- /**
- * Property: size
- * {<OpenLayers.Size>} null
- */
- size: null,
-
- /**
- * Property: position
- * {<OpenLayers.Pixel>} Top Left pixel of the tile
- */
- position: null,
-
- /**
- * Property: isLoading
- * {Boolean} Is the tile loading?
- */
- isLoading: false,
-
- /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor.
- * there is no need for the base tile class to have a url.
- *
- * Constructor: OpenLayers.Tile
- * Constructor for a new <OpenLayers.Tile> instance.
- *
- * Parameters:
- * layer - {<OpenLayers.Layer>} layer that the tile will go in.
- * position - {<OpenLayers.Pixel>}
- * bounds - {<OpenLayers.Bounds>}
- * url - {<String>}
- * size - {<OpenLayers.Size>}
- */
- initialize: function(layer, position, bounds, url, size) {
- this.layer = layer;
- this.position = position.clone();
- this.bounds = bounds.clone();
- this.url = url;
- this.size = size.clone();
-
- //give the tile a unique id based on its BBOX.
- this.id = OpenLayers.Util.createUniqueID("Tile_");
-
- this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
- },
-
- /**
- * Method: unload
- * Call immediately before destroying if you are listening to tile
- * events, so that counters are properly handled if tile is still
- * loading at destroy-time. Will only fire an event if the tile is
- * still loading.
- */
- unload: function() {
- if (this.isLoading) {
- this.isLoading = false;
- this.events.triggerEvent("unload");
- }
- },
-
- /**
- * APIMethod: destroy
- * Nullify references to prevent circular references and memory leaks.
- */
- destroy:function() {
- this.layer = null;
- this.bounds = null;
- this.size = null;
- this.position = null;
-
- this.events.destroy();
- this.events = null;
- },
-
- /**
- * Method: clone
- *
- * Parameters:
- * obj - {<OpenLayers.Tile>} The tile to be cloned
- *
- * Returns:
- * {<OpenLayers.Tile>} An exact clone of this <OpenLayers.Tile>
- */
- clone: function (obj) {
- if (obj == null) {
- obj = new OpenLayers.Tile(this.layer,
- this.position,
- this.bounds,
- this.url,
- this.size);
- }
-
- // catch any randomly tagged-on properties
- OpenLayers.Util.applyDefaults(obj, this);
-
- return obj;
- },
-
- /**
- * Method: draw
- * Clear whatever is currently in the tile, then return whether or not
- * it should actually be re-drawn.
- *
- * Returns:
- * {Boolean} Whether or not the tile should actually be drawn. Note that
- * this is not really the best way of doing things, but such is
- * the way the code has been developed. Subclasses call this and
- * depend on the return to know if they should draw or not.
- */
- draw: function() {
- var maxExtent = this.layer.maxExtent;
- var withinMaxExtent = (maxExtent &&
- this.bounds.intersectsBounds(maxExtent, false));
-
- // The only case where we *wouldn't* want to draw the tile is if the
- // tile is outside its layer's maxExtent.
- this.shouldDraw = (withinMaxExtent || this.layer.displayOutsideMaxExtent);
-
- //clear tile's contents and mark as not drawn
- this.clear();
-
- return this.shouldDraw;
- },
-
- /**
- * Method: moveTo
- * Reposition the tile.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * position - {<OpenLayers.Pixel>}
- * redraw - {Boolean} Call draw method on tile after moving.
- * Default is true
- */
- moveTo: function (bounds, position, redraw) {
- if (redraw == null) {
- redraw = true;
- }
-
- this.bounds = bounds.clone();
- this.position = position.clone();
- if (redraw) {
- this.draw();
- }
- },
-
- /**
- * Method: clear
- * Clear the tile of any bounds/position-related data so that it can
- * be reused in a new location. To be implemented by subclasses.
- */
- clear: function() {
- // to be implemented by subclasses
- },
-
- /**
- * Method: getBoundsFromBaseLayer
- * Take the pixel locations of the corner of the tile, and pass them to
- * the base layer and ask for the location of those pixels, so that
- * displaying tiles over Google works fine.
- *
- * Parameters:
- * position - {<OpenLayers.Pixel>}
- *
- * Returns:
- * bounds - {<OpenLayers.Bounds>}
- */
- getBoundsFromBaseLayer: function(position) {
- var msg = OpenLayers.i18n('reprojectDeprecated',
- {'layerName':this.layer.name});
- OpenLayers.Console.warn(msg);
- var topLeft = this.layer.map.getLonLatFromLayerPx(position);
- var bottomRightPx = position.clone();
- bottomRightPx.x += this.size.w;
- bottomRightPx.y += this.size.h;
- var bottomRight = this.layer.map.getLonLatFromLayerPx(bottomRightPx);
- // Handle the case where the base layer wraps around the date line.
- // Google does this, and it breaks WMS servers to request bounds in
- // that fashion.
- if (topLeft.lon > bottomRight.lon) {
- if (topLeft.lon < 0) {
- topLeft.lon = -180 - (topLeft.lon+180);
- } else {
- bottomRight.lon = 180+bottomRight.lon+180;
- }
- }
- var bounds = new OpenLayers.Bounds(topLeft.lon,
- bottomRight.lat,
- bottomRight.lon,
- topLeft.lat);
- return bounds;
- },
-
- /**
- * Method: showTile
- * Show the tile only if it should be drawn.
- */
- showTile: function() {
- if (this.shouldDraw) {
- this.show();
- }
- },
-
- /**
- * Method: show
- * Show the tile. To be implemented by subclasses.
- */
- show: function() { },
-
- /**
- * Method: hide
- * Hide the tile. To be implemented by subclasses.
- */
- hide: function() { },
-
- CLASS_NAME: "OpenLayers.Tile"
-});
-/* ======================================================================
- OpenLayers/Format/XML.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
/**
- * @requires OpenLayers/Format.js
+ * Namespace: OpenLayers.Easing.Quad
*/
-
-/**
- * Class: OpenLayers.Format.XML
- * Read and write XML. For cross-browser XML generation, use methods on an
- * instance of the XML format class instead of on <code>document<end>.
- * The DOM creation and traversing methods exposed here all mimic the
- * W3C XML DOM methods. Create a new parser with the
- * <OpenLayers.Format.XML> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Format>
- */
-OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
+OpenLayers.Easing.Quad = {
/**
- * Property: namespaces
- * {Object} Mapping of namespace aliases to namespace URIs. Properties
- * of this object should not be set individually. Read-only. All
- * XML subclasses should have their own namespaces object. Use
- * <setNamespace> to add or set a namespace alias after construction.
- */
- namespaces: null,
-
- /**
- * Property: namespaceAlias
- * {Object} Mapping of namespace URI to namespace alias. This object
- * is read-only. Use <setNamespace> to add or set a namespace alias.
- */
- namespaceAlias: null,
-
- /**
- * Property: defaultPrefix
- * {String} The default namespace alias for creating element nodes.
- */
- defaultPrefix: null,
-
- /**
- * Property: readers
- * Contains public functions, grouped by namespace prefix, that will
- * be applied when a namespaced node is found matching the function
- * name. The function will be applied in the scope of this parser
- * with two arguments: the node being read and a context object passed
- * from the parent.
- */
- readers: {},
-
- /**
- * Property: writers
- * As a compliment to the <readers> property, this structure contains public
- * writing functions grouped by namespace alias and named like the
- * node names they produce.
- */
- writers: {},
-
- /**
- * Property: xmldom
- * {XMLDom} If this browser uses ActiveX, this will be set to a XMLDOM
- * object. It is not intended to be a browser sniffing property.
- * Instead, the xmldom property is used instead of <code>document<end>
- * where namespaced node creation methods are not supported. In all
- * other browsers, this remains null.
- */
- xmldom: null,
-
- /**
- * Constructor: OpenLayers.Format.XML
- * Construct an XML parser. The parser is used to read and write XML.
- * Reading XML from a string returns a DOM element. Writing XML from
- * a DOM element returns a string.
- *
- * Parameters:
- * options - {Object} Optional object whose properties will be set on
- * the object.
- */
- initialize: function(options) {
- if(window.ActiveXObject) {
- this.xmldom = new ActiveXObject("Microsoft.XMLDOM");
- }
- OpenLayers.Format.prototype.initialize.apply(this, [options]);
- // clone the namespace object and set all namespace aliases
- this.namespaces = OpenLayers.Util.extend({}, this.namespaces);
- this.namespaceAlias = {};
- for(var alias in this.namespaces) {
- this.namespaceAlias[this.namespaces[alias]] = alias;
- }
- },
-
- /**
- * APIMethod: destroy
- * Clean up.
- */
- destroy: function() {
- this.xmldom = null;
- OpenLayers.Format.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: setNamespace
- * Set a namespace alias and URI for the format.
- *
- * Parameters:
- * alias - {String} The namespace alias (prefix).
- * uri - {String} The namespace URI.
- */
- setNamespace: function(alias, uri) {
- this.namespaces[alias] = uri;
- this.namespaceAlias[uri] = alias;
- },
-
- /**
- * APIMethod: read
- * Deserialize a XML string and return a DOM node.
- *
- * Parameters:
- * text - {String} A XML string
-
- * Returns:
- * {DOMElement} A DOM node
- */
- read: function(text) {
- var index = text.indexOf('<');
- if(index > 0) {
- text = text.substring(index);
- }
- var node = OpenLayers.Util.Try(
- OpenLayers.Function.bind((
- function() {
- var xmldom;
- /**
- * Since we want to be able to call this method on the prototype
- * itself, this.xmldom may not exist even if in IE.
- */
- if(window.ActiveXObject && !this.xmldom) {
- xmldom = new ActiveXObject("Microsoft.XMLDOM");
- } else {
- xmldom = this.xmldom;
-
- }
- xmldom.loadXML(text);
- return xmldom;
- }
- ), this),
- function() {
- return new DOMParser().parseFromString(text, 'text/xml');
- },
- function() {
- var req = new XMLHttpRequest();
- req.open("GET", "data:" + "text/xml" +
- ";charset=utf-8," + encodeURIComponent(text), false);
- if(req.overrideMimeType) {
- req.overrideMimeType("text/xml");
- }
- req.send(null);
- return req.responseXML;
- }
- );
-
- if(this.keepData) {
- this.data = node;
- }
-
- return node;
- },
-
- /**
- * APIMethod: write
- * Serialize a DOM node into a XML string.
+ * Function: easeIn
*
* Parameters:
- * node - {DOMElement} A DOM node.
- *
- * Returns:
- * {String} The XML string representation of the input node.
+ * t - {Float} time
+ * b - {Float} beginning position
+ * c - {Float} total change
+ * d - {Float} duration of the transition
*/
- write: function(node) {
- var data;
- if(this.xmldom) {
- data = node.xml;
- } else {
- var serializer = new XMLSerializer();
- if (node.nodeType == 1) {
- // Add nodes to a document before serializing. Everything else
- // is serialized as is. This may need more work. See #1218 .
- var doc = document.implementation.createDocument("", "", null);
- if (doc.importNode) {
- node = doc.importNode(node, true);
- }
- doc.appendChild(node);
- data = serializer.serializeToString(doc);
- } else {
- data = serializer.serializeToString(node);
- }
- }
- return data;
+ easeIn: function(t, b, c, d) {
+ return c*(t/=d)*t + b;
},
-
- /**
- * APIMethod: createElementNS
- * Create a new element with namespace. This node can be appended to
- * another node with the standard node.appendChild method. For
- * cross-browser support, this method must be used instead of
- * document.createElementNS.
- *
- * Parameters:
- * uri - {String} Namespace URI for the element.
- * name - {String} The qualified name of the element (prefix:localname).
- *
- * Returns:
- * {Element} A DOM element with namespace.
- */
- createElementNS: function(uri, name) {
- var element;
- if(this.xmldom) {
- if(typeof uri == "string") {
- element = this.xmldom.createNode(1, name, uri);
- } else {
- element = this.xmldom.createNode(1, name, "");
- }
- } else {
- element = document.createElementNS(uri, name);
- }
- return element;
- },
-
- /**
- * APIMethod: createTextNode
- * Create a text node. This node can be appended to another node with
- * the standard node.appendChild method. For cross-browser support,
- * this method must be used instead of document.createTextNode.
- *
- * Parameters:
- * text - {String} The text of the node.
- *
- * Returns:
- * {DOMElement} A DOM text node.
- */
- createTextNode: function(text) {
- var node;
- if (typeof text !== "string") {
- text = String(text);
- }
- if(this.xmldom) {
- node = this.xmldom.createTextNode(text);
- } else {
- node = document.createTextNode(text);
- }
- return node;
- },
-
- /**
- * APIMethod: getElementsByTagNameNS
- * Get a list of elements on a node given the namespace URI and local name.
- * To return all nodes in a given namespace, use '*' for the name
- * argument. To return all nodes of a given (local) name, regardless
- * of namespace, use '*' for the uri argument.
- *
- * Parameters:
- * node - {Element} Node on which to search for other nodes.
- * uri - {String} Namespace URI.
- * name - {String} Local name of the tag (without the prefix).
- *
- * Returns:
- * {NodeList} A node list or array of elements.
- */
- getElementsByTagNameNS: function(node, uri, name) {
- var elements = [];
- if(node.getElementsByTagNameNS) {
- elements = node.getElementsByTagNameNS(uri, name);
- } else {
- // brute force method
- var allNodes = node.getElementsByTagName("*");
- var potentialNode, fullName;
- for(var i=0, len=allNodes.length; i<len; ++i) {
- potentialNode = allNodes[i];
- fullName = (potentialNode.prefix) ?
- (potentialNode.prefix + ":" + name) : name;
- if((name == "*") || (fullName == potentialNode.nodeName)) {
- if((uri == "*") || (uri == potentialNode.namespaceURI)) {
- elements.push(potentialNode);
- }
- }
- }
- }
- return elements;
- },
-
- /**
- * APIMethod: getAttributeNodeNS
- * Get an attribute node given the namespace URI and local name.
- *
- * Parameters:
- * node - {Element} Node on which to search for attribute nodes.
- * uri - {String} Namespace URI.
- * name - {String} Local name of the attribute (without the prefix).
- *
- * Returns:
- * {DOMElement} An attribute node or null if none found.
- */
- getAttributeNodeNS: function(node, uri, name) {
- var attributeNode = null;
- if(node.getAttributeNodeNS) {
- attributeNode = node.getAttributeNodeNS(uri, name);
- } else {
- var attributes = node.attributes;
- var potentialNode, fullName;
- for(var i=0, len=attributes.length; i<len; ++i) {
- potentialNode = attributes[i];
- if(potentialNode.namespaceURI == uri) {
- fullName = (potentialNode.prefix) ?
- (potentialNode.prefix + ":" + name) : name;
- if(fullName == potentialNode.nodeName) {
- attributeNode = potentialNode;
- break;
- }
- }
- }
- }
- return attributeNode;
- },
-
- /**
- * APIMethod: getAttributeNS
- * Get an attribute value given the namespace URI and local name.
- *
- * Parameters:
- * node - {Element} Node on which to search for an attribute.
- * uri - {String} Namespace URI.
- * name - {String} Local name of the attribute (without the prefix).
- *
- * Returns:
- * {String} An attribute value or and empty string if none found.
- */
- getAttributeNS: function(node, uri, name) {
- var attributeValue = "";
- if(node.getAttributeNS) {
- attributeValue = node.getAttributeNS(uri, name) || "";
- } else {
- var attributeNode = this.getAttributeNodeNS(node, uri, name);
- if(attributeNode) {
- attributeValue = attributeNode.nodeValue;
- }
- }
- return attributeValue;
- },
/**
- * APIMethod: getChildValue
- * Get the textual value of the node if it exists, or return an
- * optional default string. Returns an empty string if no first child
- * exists and no default value is supplied.
- *
- * Parameters:
- * node - {DOMElement} The element used to look for a first child value.
- * def - {String} Optional string to return in the event that no
- * first child value exists.
- *
- * Returns:
- * {String} The value of the first child of the given node.
- */
- getChildValue: function(node, def) {
- var value = def || "";
- if(node) {
- for(var child=node.firstChild; child; child=child.nextSibling) {
- switch(child.nodeType) {
- case 3: // text node
- case 4: // cdata section
- value += child.nodeValue;
- }
- }
- }
- return value;
- },
-
- /**
- * APIMethod: concatChildValues
- * *Deprecated*. Use <getChildValue> instead.
- *
- * Concatenate the value of all child nodes if any exist, or return an
- * optional default string. Returns an empty string if no children
- * exist and no default value is supplied. Not optimized for large
- * numbers of child nodes.
- *
- * Parameters:
- * node - {DOMElement} The element used to look for child values.
- * def - {String} Optional string to return in the event that no
- * child exist.
- *
- * Returns:
- * {String} The concatenated value of all child nodes of the given node.
- */
- concatChildValues: function(node, def) {
- var value = "";
- var child = node.firstChild;
- var childValue;
- while(child) {
- childValue = child.nodeValue;
- if(childValue) {
- value += childValue;
- }
- child = child.nextSibling;
- }
- if(value == "" && def != undefined) {
- value = def;
- }
- return value;
- },
-
- /**
- * APIMethod: isSimpleContent
- * Test if the given node has only simple content (i.e. no child element
- * nodes).
- *
- * Parameters:
- * node - {DOMElement} An element node.
- *
- * Returns:
- * {Boolean} The node has no child element nodes (nodes of type 1).
- */
- isSimpleContent: function(node) {
- var simple = true;
- for(var child=node.firstChild; child; child=child.nextSibling) {
- if(child.nodeType === 1) {
- simple = false;
- break;
- }
- }
- return simple;
- },
-
- /**
- * APIMethod: contentType
- * Determine the content type for a given node.
- *
- * Parameters:
- * node - {DOMElement}
- *
- * Returns:
- * {Integer} One of OpenLayers.Format.XML.CONTENT_TYPE.{EMPTY,SIMPLE,COMPLEX,MIXED}
- * if the node has no, simple, complex, or mixed content.
- */
- contentType: function(node) {
- var simple = false,
- complex = false;
-
- var type = OpenLayers.Format.XML.CONTENT_TYPE.EMPTY;
-
- for(var child=node.firstChild; child; child=child.nextSibling) {
- switch(child.nodeType) {
- case 1: // element
- complex = true;
- break;
- case 8: // comment
- break;
- default:
- simple = true;
- }
- if(complex && simple) {
- break;
- }
- }
-
- if(complex && simple) {
- type = OpenLayers.Format.XML.CONTENT_TYPE.MIXED;
- } else if(complex) {
- return OpenLayers.Format.XML.CONTENT_TYPE.COMPLEX;
- } else if(simple) {
- return OpenLayers.Format.XML.CONTENT_TYPE.SIMPLE;
- }
- return type;
- },
-
- /**
- * APIMethod: hasAttributeNS
- * Determine whether a node has a particular attribute matching the given
- * name and namespace.
+ * Function: easeOut
*
* Parameters:
- * node - {Element} Node on which to search for an attribute.
- * uri - {String} Namespace URI.
- * name - {String} Local name of the attribute (without the prefix).
- *
- * Returns:
- * {Boolean} The node has an attribute matching the name and namespace.
+ * t - {Float} time
+ * b - {Float} beginning position
+ * c - {Float} total change
+ * d - {Float} duration of the transition
*/
- hasAttributeNS: function(node, uri, name) {
- var found = false;
- if(node.hasAttributeNS) {
- found = node.hasAttributeNS(uri, name);
- } else {
- found = !!this.getAttributeNodeNS(node, uri, name);
- }
- return found;
+ easeOut: function(t, b, c, d) {
+ return -c *(t/=d)*(t-2) + b;
},
/**
- * APIMethod: setAttributeNS
- * Adds a new attribute or changes the value of an attribute with the given
- * namespace and name.
- *
- * Parameters:
- * node - {Element} Element node on which to set the attribute.
- * uri - {String} Namespace URI for the attribute.
- * name - {String} Qualified name (prefix:localname) for the attribute.
- * value - {String} Attribute value.
- */
- setAttributeNS: function(node, uri, name, value) {
- if(node.setAttributeNS) {
- node.setAttributeNS(uri, name, value);
- } else {
- if(this.xmldom) {
- if(uri) {
- var attribute = node.ownerDocument.createNode(
- 2, name, uri
- );
- attribute.nodeValue = value;
- node.setAttributeNode(attribute);
- } else {
- node.setAttribute(name, value);
- }
- } else {
- throw "setAttributeNS not implemented";
- }
- }
- },
-
- /**
- * Method: createElementNSPlus
- * Shorthand for creating namespaced elements with optional attributes and
- * child text nodes.
- *
- * Parameters:
- * name - {String} The qualified node name.
- * options - {Object} Optional object for node configuration.
- *
- * Valid options:
- * uri - {String} Optional namespace uri for the element - supply a prefix
- * instead if the namespace uri is a property of the format's namespace
- * object.
- * attributes - {Object} Optional attributes to be set using the
- * <setAttributes> method.
- * value - {String} Optional text to be appended as a text node.
- *
- * Returns:
- * {Element} An element node.
- */
- createElementNSPlus: function(name, options) {
- options = options || {};
- // order of prefix preference
- // 1. in the uri option
- // 2. in the prefix option
- // 3. in the qualified name
- // 4. from the defaultPrefix
- var uri = options.uri || this.namespaces[options.prefix];
- if(!uri) {
- var loc = name.indexOf(":");
- uri = this.namespaces[name.substring(0, loc)];
- }
- if(!uri) {
- uri = this.namespaces[this.defaultPrefix];
- }
- var node = this.createElementNS(uri, name);
- if(options.attributes) {
- this.setAttributes(node, options.attributes);
- }
- var value = options.value;
- if(value != null) {
- node.appendChild(this.createTextNode(value));
- }
- return node;
- },
-
- /**
- * Method: setAttributes
- * Set multiple attributes given key value pairs from an object.
- *
- * Parameters:
- * node - {Element} An element node.
- * obj - {Object || Array} An object whose properties represent attribute
- * names and values represent attribute values. If an attribute name
- * is a qualified name ("prefix:local"), the prefix will be looked up
- * in the parsers {namespaces} object. If the prefix is found,
- * setAttributeNS will be used instead of setAttribute.
- */
- setAttributes: function(node, obj) {
- var value, uri;
- for(var name in obj) {
- if(obj[name] != null && obj[name].toString) {
- value = obj[name].toString();
- // check for qualified attribute name ("prefix:local")
- uri = this.namespaces[name.substring(0, name.indexOf(":"))] || null;
- this.setAttributeNS(node, uri, name, value);
- }
- }
- },
-
- /**
- * Method: readNode
- * Shorthand for applying one of the named readers given the node
- * namespace and local name. Readers take two args (node, obj) and
- * generally extend or modify the second.
- *
- * Parameters:
- * node - {DOMElement} The node to be read (required).
- * obj - {Object} The object to be modified (optional).
- *
- * Returns:
- * {Object} The input object, modified (or a new one if none was provided).
- */
- readNode: function(node, obj) {
- if(!obj) {
- obj = {};
- }
- var group = this.readers[node.namespaceURI ? this.namespaceAlias[node.namespaceURI]: this.defaultPrefix];
- if(group) {
- var local = node.localName || node.nodeName.split(":").pop();
- var reader = group[local] || group["*"];
- if(reader) {
- reader.apply(this, [node, obj]);
- }
- }
- return obj;
- },
-
- /**
- * Method: readChildNodes
- * Shorthand for applying the named readers to all children of a node.
- * For each child of type 1 (element), <readSelf> is called.
- *
- * Parameters:
- * node - {DOMElement} The node to be read (required).
- * obj - {Object} The object to be modified (optional).
- *
- * Returns:
- * {Object} The input object, modified.
- */
- readChildNodes: function(node, obj) {
- if(!obj) {
- obj = {};
- }
- var children = node.childNodes;
- var child;
- for(var i=0, len=children.length; i<len; ++i) {
- child = children[i];
- if(child.nodeType == 1) {
- this.readNode(child, obj);
- }
- }
- return obj;
- },
-
- /**
- * Method: writeNode
- * Shorthand for applying one of the named writers and appending the
- * results to a node. If a qualified name is not provided for the
- * second argument (and a local name is used instead), the namespace
- * of the parent node will be assumed.
- *
- * Parameters:
- * name - {String} The name of a node to generate. If a qualified name
- * (e.g. "pre:Name") is used, the namespace prefix is assumed to be
- * in the <writers> group. If a local name is used (e.g. "Name") then
- * the namespace of the parent is assumed. If a local name is used
- * and no parent is supplied, then the default namespace is assumed.
- * obj - {Object} Structure containing data for the writer.
- * parent - {DOMElement} Result will be appended to this node. If no parent
- * is supplied, the node will not be appended to anything.
- *
- * Returns:
- * {DOMElement} The child node.
- */
- writeNode: function(name, obj, parent) {
- var prefix, local;
- var split = name.indexOf(":");
- if(split > 0) {
- prefix = name.substring(0, split);
- local = name.substring(split + 1);
- } else {
- if(parent) {
- prefix = this.namespaceAlias[parent.namespaceURI];
- } else {
- prefix = this.defaultPrefix;
- }
- local = name;
- }
- var child = this.writers[prefix][local].apply(this, [obj]);
- if(parent) {
- parent.appendChild(child);
- }
- return child;
- },
-
- /**
- * APIMethod: getChildEl
- * Get the first child element. Optionally only return the first child
- * if it matches the given name and namespace URI.
- *
- * Parameters:
- * node - {DOMElement} The parent node.
- * name - {String} Optional node name (local) to search for.
- * uri - {String} Optional namespace URI to search for.
- *
- * Returns:
- * {DOMElement} The first child. Returns null if no element is found, if
- * something significant besides an element is found, or if the element
- * found does not match the optional name and uri.
- */
- getChildEl: function(node, name, uri) {
- return node && this.getThisOrNextEl(node.firstChild, name, uri);
- },
-
- /**
- * APIMethod: getNextEl
- * Get the next sibling element. Optionally get the first sibling only
- * if it matches the given local name and namespace URI.
- *
- * Parameters:
- * node - {DOMElement} The node.
- * name - {String} Optional local name of the sibling to search for.
- * uri - {String} Optional namespace URI of the sibling to search for.
- *
- * Returns:
- * {DOMElement} The next sibling element. Returns null if no element is
- * found, something significant besides an element is found, or the
- * found element does not match the optional name and uri.
- */
- getNextEl: function(node, name, uri) {
- return node && this.getThisOrNextEl(node.nextSibling, name, uri);
- },
-
- /**
- * Method: getThisOrNextEl
- * Return this node or the next element node. Optionally get the first
- * sibling with the given local name or namespace URI.
- *
- * Parameters:
- * node - {DOMElement} The node.
- * name - {String} Optional local name of the sibling to search for.
- * uri - {String} Optional namespace URI of the sibling to search for.
- *
- * Returns:
- * {DOMElement} The next sibling element. Returns null if no element is
- * found, something significant besides an element is found, or the
- * found element does not match the query.
- */
- getThisOrNextEl: function(node, name, uri) {
- outer: for(var sibling=node; sibling; sibling=sibling.nextSibling) {
- switch(sibling.nodeType) {
- case 1: // Element
- if((!name || name === (sibling.localName || sibling.nodeName.split(":").pop())) &&
- (!uri || uri === sibling.namespaceURI)) {
- // matches
- break outer;
- }
- sibling = null;
- break outer;
- case 3: // Text
- if(/^\s*$/.test(sibling.nodeValue)) {
- break;
- }
- case 4: // CDATA
- case 6: // ENTITY_NODE
- case 12: // NOTATION_NODE
- case 10: // DOCUMENT_TYPE_NODE
- case 11: // DOCUMENT_FRAGMENT_NODE
- sibling = null;
- break outer;
- } // ignore comments and processing instructions
- }
- return sibling || null;
- },
-
- /**
- * APIMethod: lookupNamespaceURI
- * Takes a prefix and returns the namespace URI associated with it on the given
- * node if found (and null if not). Supplying null for the prefix will
- * return the default namespace.
- *
- * For browsers that support it, this calls the native lookupNamesapceURI
- * function. In other browsers, this is an implementation of
- * http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI.
- *
- * For browsers that don't support the attribute.ownerElement property, this
- * method cannot be called on attribute nodes.
- *
- * Parameters:
- * node - {DOMElement} The node from which to start looking.
- * prefix - {String} The prefix to lookup or null to lookup the default namespace.
+ * Function: easeInOut
*
- * Returns:
- * {String} The namespace URI for the given prefix. Returns null if the prefix
- * cannot be found or the node is the wrong type.
- */
- lookupNamespaceURI: function(node, prefix) {
- var uri = null;
- if(node) {
- if(node.lookupNamespaceURI) {
- uri = node.lookupNamespaceURI(prefix);
- } else {
- outer: switch(node.nodeType) {
- case 1: // ELEMENT_NODE
- if(node.namespaceURI !== null && node.prefix === prefix) {
- uri = node.namespaceURI;
- break outer;
- }
- var len = node.attributes.length;
- if(len) {
- var attr;
- for(var i=0; i<len; ++i) {
- attr = node.attributes[i];
- if(attr.prefix === "xmlns" && attr.name === "xmlns:" + prefix) {
- uri = attr.value || null;
- break outer;
- } else if(attr.name === "xmlns" && prefix === null) {
- uri = attr.value || null;
- break outer;
- }
- }
- }
- uri = this.lookupNamespaceURI(node.parentNode, prefix);
- break outer;
- case 2: // ATTRIBUTE_NODE
- uri = this.lookupNamespaceURI(node.ownerElement, prefix);
- break outer;
- case 9: // DOCUMENT_NODE
- uri = this.lookupNamespaceURI(node.documentElement, prefix);
- break outer;
- case 6: // ENTITY_NODE
- case 12: // NOTATION_NODE
- case 10: // DOCUMENT_TYPE_NODE
- case 11: // DOCUMENT_FRAGMENT_NODE
- break outer;
- default:
- // TEXT_NODE (3), CDATA_SECTION_NODE (4), ENTITY_REFERENCE_NODE (5),
- // PROCESSING_INSTRUCTION_NODE (7), COMMENT_NODE (8)
- uri = this.lookupNamespaceURI(node.parentNode, prefix);
- break outer;
- }
- }
- }
- return uri;
- },
-
- CLASS_NAME: "OpenLayers.Format.XML"
-
-});
-
-OpenLayers.Format.XML.CONTENT_TYPE = {EMPTY: 0, SIMPLE: 1, COMPLEX: 2, MIXED: 3};
-
-/**
- * APIFunction: OpenLayers.Format.XML.lookupNamespaceURI
- * Takes a prefix and returns the namespace URI associated with it on the given
- * node if found (and null if not). Supplying null for the prefix will
- * return the default namespace.
- *
- * For browsers that support it, this calls the native lookupNamesapceURI
- * function. In other browsers, this is an implementation of
- * http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI.
- *
- * For browsers that don't support the attribute.ownerElement property, this
- * method cannot be called on attribute nodes.
- *
- * Parameters:
- * node - {DOMElement} The node from which to start looking.
- * prefix - {String} The prefix to lookup or null to lookup the default namespace.
- *
- * Returns:
- * {String} The namespace URI for the given prefix. Returns null if the prefix
- * cannot be found or the node is the wrong type.
- */
-OpenLayers.Format.XML.lookupNamespaceURI = OpenLayers.Function.bind(
- OpenLayers.Format.XML.prototype.lookupNamespaceURI,
- OpenLayers.Format.XML.prototype
-);
-/* ======================================================================
- OpenLayers/Handler.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Events.js
- */
-
-/**
- * Class: OpenLayers.Handler
- * Base class to construct a higher-level handler for event sequences. All
- * handlers have activate and deactivate methods. In addition, they have
- * methods named like browser events. When a handler is activated, any
- * additional methods named like a browser event is registered as a
- * listener for the corresponding event. When a handler is deactivated,
- * those same methods are unregistered as event listeners.
- *
- * Handlers also typically have a callbacks object with keys named like
- * the abstracted events or event sequences that they are in charge of
- * handling. The controls that wrap handlers define the methods that
- * correspond to these abstract events - so instead of listening for
- * individual browser events, they only listen for the abstract events
- * defined by the handler.
- *
- * Handlers are created by controls, which ultimately have the responsibility
- * of making changes to the the state of the application. Handlers
- * themselves may make temporary changes, but in general are expected to
- * return the application in the same state that they found it.
- */
-OpenLayers.Handler = OpenLayers.Class({
-
- /**
- * Property: id
- * {String}
- */
- id: null,
-
- /**
- * APIProperty: control
- * {<OpenLayers.Control>}. The control that initialized this handler. The
- * control is assumed to have a valid map property - that map is used
- * in the handler's own setMap method.
- */
- control: null,
-
- /**
- * Property: map
- * {<OpenLayers.Map>}
- */
- map: null,
-
- /**
- * APIProperty: keyMask
- * {Integer} Use bitwise operators and one or more of the OpenLayers.Handler
- * constants to construct a keyMask. The keyMask is used by
- * <checkModifiers>. If the keyMask matches the combination of keys
- * down on an event, checkModifiers returns true.
- *
- * Example:
- * (code)
- * // handler only responds if the Shift key is down
- * handler.keyMask = OpenLayers.Handler.MOD_SHIFT;
- *
- * // handler only responds if Ctrl-Shift is down
- * handler.keyMask = OpenLayers.Handler.MOD_SHIFT |
- * OpenLayers.Handler.MOD_CTRL;
- * (end)
- */
- keyMask: null,
-
- /**
- * Property: active
- * {Boolean}
- */
- active: false,
-
- /**
- * Property: evt
- * {Event} This property references the last event handled by the handler.
- * Note that this property is not part of the stable API. Use of the
- * evt property should be restricted to controls in the library
- * or other applications that are willing to update with changes to
- * the OpenLayers code.
- */
- evt: null,
-
- /**
- * Constructor: OpenLayers.Handler
- * Construct a handler.
- *
* Parameters:
- * control - {<OpenLayers.Control>} The control that initialized this
- * handler. The control is assumed to have a valid map property; that
- * map is used in the handler's own setMap method. If a map property
- * is present in the options argument it will be used instead.
- * callbacks - {Object} An object whose properties correspond to abstracted
- * events or sequences of browser events. The values for these
- * properties are functions defined by the control that get called by
- * the handler.
- * options - {Object} An optional object whose properties will be set on
- * the handler.
+ * t - {Float} time
+ * b - {Float} beginning position
+ * c - {Float} total change
+ * d - {Float} duration of the transition
*/
- initialize: function(control, callbacks, options) {
- OpenLayers.Util.extend(this, options);
- this.control = control;
- this.callbacks = callbacks;
-
- var map = this.map || control.map;
- if (map) {
- this.setMap(map);
- }
-
- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+ easeInOut: function(t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t + b;
+ return -c/2 * ((--t)*(t-2) - 1) + b;
},
-
- /**
- * Method: setMap
- */
- setMap: function (map) {
- this.map = map;
- },
- /**
- * Method: checkModifiers
- * Check the keyMask on the handler. If no <keyMask> is set, this always
- * returns true. If a <keyMask> is set and it matches the combination
- * of keys down on an event, this returns true.
- *
- * Returns:
- * {Boolean} The keyMask matches the keys down on an event.
- */
- checkModifiers: function (evt) {
- if(this.keyMask == null) {
- return true;
- }
- /* calculate the keyboard modifier mask for this event */
- var keyModifiers =
- (evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) |
- (evt.ctrlKey ? OpenLayers.Handler.MOD_CTRL : 0) |
- (evt.altKey ? OpenLayers.Handler.MOD_ALT : 0);
-
- /* if it differs from the handler object's key mask,
- bail out of the event handler */
- return (keyModifiers == this.keyMask);
- },
-
- /**
- * APIMethod: activate
- * Turn on the handler. Returns false if the handler was already active.
- *
- * Returns:
- * {Boolean} The handler was activated.
- */
- activate: function() {
- if(this.active) {
- return false;
- }
- // register for event handlers defined on this class.
- var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
- for (var i=0, len=events.length; i<len; i++) {
- if (this[events[i]]) {
- this.register(events[i], this[events[i]]);
- }
- }
- this.active = true;
- return true;
- },
-
- /**
- * APIMethod: deactivate
- * Turn off the handler. Returns false if the handler was already inactive.
- *
- * Returns:
- * {Boolean} The handler was deactivated.
- */
- deactivate: function() {
- if(!this.active) {
- return false;
- }
- // unregister event handlers defined on this class.
- var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
- for (var i=0, len=events.length; i<len; i++) {
- if (this[events[i]]) {
- this.unregister(events[i], this[events[i]]);
- }
- }
- this.active = false;
- return true;
- },
-
- /**
- * Method: callback
- * Trigger the control's named callback with the given arguments
- *
- * Parameters:
- * name - {String} The key for the callback that is one of the properties
- * of the handler's callbacks object.
- * args - {Array(*)} An array of arguments (any type) with which to call
- * the callback (defined by the control).
- */
- callback: function (name, args) {
- if (name && this.callbacks[name]) {
- this.callbacks[name].apply(this.control, args);
- }
- },
-
- /**
- * Method: register
- * register an event on the map
- */
- register: function (name, method) {
- // TODO: deal with registerPriority in 3.0
- this.map.events.registerPriority(name, this, method);
- this.map.events.registerPriority(name, this, this.setEvent);
- },
-
- /**
- * Method: unregister
- * unregister an event from the map
- */
- unregister: function (name, method) {
- this.map.events.unregister(name, this, method);
- this.map.events.unregister(name, this, this.setEvent);
- },
-
- /**
- * Method: setEvent
- * With each registered browser event, the handler sets its own evt
- * property. This property can be accessed by controls if needed
- * to get more information about the event that the handler is
- * processing.
- *
- * This allows modifier keys on the event to be checked (alt, shift,
- * and ctrl cannot be checked with the keyboard handler). For a
- * control to determine which modifier keys are associated with the
- * event that a handler is currently processing, it should access
- * (code)handler.evt.altKey || handler.evt.shiftKey ||
- * handler.evt.ctrlKey(end).
- *
- * Parameters:
- * evt - {Event} The browser event.
- */
- setEvent: function(evt) {
- this.evt = evt;
- return true;
- },
-
- /**
- * Method: destroy
- * Deconstruct the handler.
- */
- destroy: function () {
- // unregister event listeners
- this.deactivate();
- // eliminate circular references
- this.control = this.map = null;
- },
-
- CLASS_NAME: "OpenLayers.Handler"
-});
-
-/**
- * Constant: OpenLayers.Handler.MOD_NONE
- * If set as the <keyMask>, <checkModifiers> returns false if any key is down.
- */
-OpenLayers.Handler.MOD_NONE = 0;
-
-/**
- * Constant: OpenLayers.Handler.MOD_SHIFT
- * If set as the <keyMask>, <checkModifiers> returns false if Shift is down.
- */
-OpenLayers.Handler.MOD_SHIFT = 1;
-
-/**
- * Constant: OpenLayers.Handler.MOD_CTRL
- * If set as the <keyMask>, <checkModifiers> returns false if Ctrl is down.
- */
-OpenLayers.Handler.MOD_CTRL = 2;
-
-/**
- * Constant: OpenLayers.Handler.MOD_ALT
- * If set as the <keyMask>, <checkModifiers> returns false if Alt is down.
- */
-OpenLayers.Handler.MOD_ALT = 4;
-
-
+ CLASS_NAME: "OpenLayers.Easing.Quad"
+};
/* ======================================================================
OpenLayers/Map.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
+ * @requires OpenLayers/BaseTypes/Class.js
* @requires OpenLayers/Util.js
* @requires OpenLayers/Events.js
* @requires OpenLayers/Tween.js
* @requires OpenLayers/Console.js
+ * @requires OpenLayers/Lang.js
*/
/**
@@ -15990,7 +6365,7 @@
this.viewPortDiv.appendChild(this.layerContainerDiv);
this.events = new OpenLayers.Events(this,
- this.div,
+ this.viewPortDiv,
this.EVENT_TYPES,
this.fallThrough,
{includeXY: true});
@@ -16087,7 +6462,6 @@
render: function(div) {
this.div = OpenLayers.Util.getElement(div);
OpenLayers.Element.addClass(this.div, 'olMap');
- this.events.attachToElement(this.div);
this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);
this.div.appendChild(this.viewPortDiv);
this.updateSize();
@@ -17893,3780 +8267,235 @@
*/
OpenLayers.Map.TILE_HEIGHT = 256;
/* ======================================================================
- OpenLayers/Marker.js
+ OpenLayers/Projection.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
-
/**
- * @requires OpenLayers/Events.js
- * @requires OpenLayers/Icon.js
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/Util.js
*/
/**
- * Class: OpenLayers.Marker
- * Instances of OpenLayers.Marker are a combination of a
- * <OpenLayers.LonLat> and an <OpenLayers.Icon>.
- *
- * Markers are generally added to a special layer called
- * <OpenLayers.Layer.Markers>.
- *
- * Example:
- * (code)
- * var markers = new OpenLayers.Layer.Markers( "Markers" );
- * map.addLayer(markers);
- *
- * var size = new OpenLayers.Size(21,25);
- * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
- * var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset);
- * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon));
- * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone()));
- *
- * (end)
- *
- * Note that if you pass an icon into the Marker constructor, it will take
- * that icon and use it. This means that you should not share icons between
- * markers -- you use them once, but you should clone() for any additional
- * markers using that same icon.
+ * Class: OpenLayers.Projection
+ * Class for coordinate transforms between coordinate systems.
+ * Depends on the proj4js library. If proj4js is not available,
+ * then this is just an empty stub.
*/
-OpenLayers.Marker = OpenLayers.Class({
-
- /**
- * Property: icon
- * {<OpenLayers.Icon>} The icon used by this marker.
- */
- icon: null,
+OpenLayers.Projection = OpenLayers.Class({
- /**
- * Property: lonlat
- * {<OpenLayers.LonLat>} location of object
- */
- lonlat: null,
-
- /**
- * Property: events
- * {<OpenLayers.Events>} the event handler.
- */
- events: null,
-
- /**
- * Property: map
- * {<OpenLayers.Map>} the map this marker is attached to
- */
- map: null,
-
- /**
- * Constructor: OpenLayers.Marker
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>} the position of this marker
- * icon - {<OpenLayers.Icon>} the icon for this marker
- */
- initialize: function(lonlat, icon) {
- this.lonlat = lonlat;
-
- var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon();
- if (this.icon == null) {
- this.icon = newIcon;
- } else {
- this.icon.url = newIcon.url;
- this.icon.size = newIcon.size;
- this.icon.offset = newIcon.offset;
- this.icon.calculateOffset = newIcon.calculateOffset;
- }
- this.events = new OpenLayers.Events(this, this.icon.imageDiv, null);
- },
-
/**
- * APIMethod: destroy
- * Destroy the marker. You must first remove the marker from any
- * layer which it has been added to, or you will get buggy behavior.
- * (This can not be done within the marker since the marker does not
- * know which layer it is attached to.)
+ * Property: proj
+ * {Object} Proj4js.Proj instance.
*/
- destroy: function() {
- // erase any drawn features
- this.erase();
-
- this.map = null;
-
- this.events.destroy();
- this.events = null;
-
- if (this.icon != null) {
- this.icon.destroy();
- this.icon = null;
- }
- },
+ proj: null,
- /**
- * Method: draw
- * Calls draw on the icon, and returns that output.
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {DOMElement} A new DOM Image with this marker's icon set at the
- * location passed-in
- */
- draw: function(px) {
- return this.icon.draw(px);
- },
-
- /**
- * Method: erase
- * Erases any drawn elements for this marker.
- */
- erase: function() {
- if (this.icon != null) {
- this.icon.erase();
- }
- },
-
/**
- * Method: moveTo
- * Move the marker to the new location.
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>} the pixel position to move to
- */
- moveTo: function (px) {
- if ((px != null) && (this.icon != null)) {
- this.icon.moveTo(px);
- }
- this.lonlat = this.map.getLonLatFromLayerPx(px);
- },
-
- /**
- * APIMethod: isDrawn
- *
- * Returns:
- * {Boolean} Whether or not the marker is drawn.
+ * Property: projCode
+ * {String}
*/
- isDrawn: function() {
- var isDrawn = (this.icon && this.icon.isDrawn());
- return isDrawn;
- },
-
- /**
- * Method: onScreen
- *
- * Returns:
- * {Boolean} Whether or not the marker is currently visible on screen.
- */
- onScreen:function() {
-
- var onScreen = false;
- if (this.map) {
- var screenBounds = this.map.getExtent();
- onScreen = screenBounds.containsLonLat(this.lonlat);
- }
- return onScreen;
- },
+ projCode: null,
/**
- * Method: inflate
- * Englarges the markers icon by the specified ratio.
- *
- * Parameters:
- * inflate - {float} the ratio to enlarge the marker by (passing 2
- * will double the size).
+ * Property: titleRegEx
+ * {RegEx} regular expression to strip the title from a proj4js definition
*/
- inflate: function(inflate) {
- if (this.icon) {
- var newSize = new OpenLayers.Size(this.icon.size.w * inflate,
- this.icon.size.h * inflate);
- this.icon.setSize(newSize);
- }
- },
-
- /**
- * Method: setOpacity
- * Change the opacity of the marker by changin the opacity of
- * its icon
- *
- * Parameters:
- * opacity - {float} Specified as fraction (0.4, etc)
- */
- setOpacity: function(opacity) {
- this.icon.setOpacity(opacity);
- },
+ titleRegEx: /\+title=[^\+]*/,
/**
- * Method: setUrl
- * Change URL of the Icon Image.
- *
- * url - {String}
- */
- setUrl: function(url) {
- this.icon.setUrl(url);
- },
-
- /**
- * Method: display
- * Hide or show the icon
- *
- * display - {Boolean}
- */
- display: function(display) {
- this.icon.display(display);
- },
-
- CLASS_NAME: "OpenLayers.Marker"
-});
-
-
-/**
- * Function: defaultIcon
- * Creates a default <OpenLayers.Icon>.
- *
- * Returns:
- * {<OpenLayers.Icon>} A default OpenLayers.Icon to use for a marker
- */
-OpenLayers.Marker.defaultIcon = function() {
- var url = OpenLayers.Util.getImagesLocation() + "marker.png";
- var size = new OpenLayers.Size(21, 25);
- var calculateOffset = function(size) {
- return new OpenLayers.Pixel(-(size.w/2), -size.h);
- };
-
- return new OpenLayers.Icon(url, size, null, calculateOffset);
-};
-
-
-/* ======================================================================
- OpenLayers/Request.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Events.js
- */
-
-/**
- * Namespace: OpenLayers.Request
- * The OpenLayers.Request namespace contains convenience methods for working
- * with XMLHttpRequests. These methods work with a cross-browser
- * W3C compliant <OpenLayers.Request.XMLHttpRequest> class.
- */
-OpenLayers.Request = {
-
- /**
- * Constant: DEFAULT_CONFIG
- * {Object} Default configuration for all requests.
- */
- DEFAULT_CONFIG: {
- method: "GET",
- url: window.location.href,
- async: true,
- user: undefined,
- password: undefined,
- params: null,
- proxy: OpenLayers.ProxyHost,
- headers: {},
- data: null,
- callback: function() {},
- success: null,
- failure: null,
- scope: null
- },
-
- /**
- * APIProperty: events
- * {<OpenLayers.Events>} An events object that handles all
- * events on the {<OpenLayers.Request>} object.
+ * Constructor: OpenLayers.Projection
+ * This class offers several methods for interacting with a wrapped
+ * pro4js projection object.
*
- * All event listeners will receive an event object with three properties:
- * request - {<OpenLayers.Request.XMLHttpRequest>} The request object.
- * config - {Object} The config object sent to the specific request method.
- * requestUrl - {String} The request url.
- *
- * Supported event types:
- * complete - Triggered when we have a response from the request, if a
- * listener returns false, no further response processing will take
- * place.
- * success - Triggered when the HTTP response has a success code (200-299).
- * failure - Triggered when the HTTP response does not have a success code.
- */
- events: new OpenLayers.Events(this, null, ["complete", "success", "failure"]),
-
- /**
- * APIMethod: issue
- * Create a new XMLHttpRequest object, open it, set any headers, bind
- * a callback to done state, and send any data. It is recommended that
- * you use one <GET>, <POST>, <PUT>, <DELETE>, <OPTIONS>, or <HEAD>.
- * This method is only documented to provide detail on the configuration
- * options available to all request methods.
- *
* Parameters:
- * config - {Object} Object containing properties for configuring the
- * request. Allowed configuration properties are described below.
- * This object is modified and should not be reused.
+ * projCode - {String} A string identifying the Well Known Identifier for
+ * the projection.
+ * options - {Object} An optional object to set additional properties
+ * on the layer.
*
- * Allowed config properties:
- * method - {String} One of GET, POST, PUT, DELETE, HEAD, or
- * OPTIONS. Default is GET.
- * url - {String} URL for the request.
- * async - {Boolean} Open an asynchronous request. Default is true.
- * user - {String} User for relevant authentication scheme. Set
- * to null to clear current user.
- * password - {String} Password for relevant authentication scheme.
- * Set to null to clear current password.
- * proxy - {String} Optional proxy. Defaults to
- * <OpenLayers.ProxyHost>.
- * params - {Object} Any key:value pairs to be appended to the
- * url as a query string. Assumes url doesn't already include a query
- * string or hash. Typically, this is only appropriate for <GET>
- * requests where the query string will be appended to the url.
- * Parameter values that are arrays will be
- * concatenated with a comma (note that this goes against form-encoding)
- * as is done with <OpenLayers.Util.getParameterString>.
- * headers - {Object} Object with header:value pairs to be set on
- * the request.
- * data - {String | Document} Optional data to send with the request.
- * Typically, this is only used with <POST> and <PUT> requests.
- * Make sure to provide the appropriate "Content-Type" header for your
- * data. For <POST> and <PUT> requests, the content type defaults to
- * "application-xml". If your data is a different content type, or
- * if you are using a different HTTP method, set the "Content-Type"
- * header to match your data type.
- * callback - {Function} Function to call when request is done.
- * To determine if the request failed, check request.status (200
- * indicates success).
- * success - {Function} Optional function to call if request status is in
- * the 200s. This will be called in addition to callback above and
- * would typically only be used as an alternative.
- * failure - {Function} Optional function to call if request status is not
- * in the 200s. This will be called in addition to callback above and
- * would typically only be used as an alternative.
- * scope - {Object} If callback is a public method on some object,
- * set the scope to that object.
- *
* Returns:
- * {XMLHttpRequest} Request object. To abort the request before a response
- * is received, call abort() on the request object.
+ * {<OpenLayers.Projection>} A projection object.
*/
- issue: function(config) {
- // apply default config - proxy host may have changed
- var defaultConfig = OpenLayers.Util.extend(
- this.DEFAULT_CONFIG,
- {proxy: OpenLayers.ProxyHost}
- );
- config = OpenLayers.Util.applyDefaults(config, defaultConfig);
-
- // create request, open, and set headers
- var request = new OpenLayers.Request.XMLHttpRequest();
- var url = config.url;
- if(config.params) {
- var paramString = OpenLayers.Util.getParameterString(config.params);
- if(paramString.length > 0) {
- var separator = (url.indexOf('?') > -1) ? '&' : '?';
- url += separator + paramString;
- }
+ initialize: function(projCode, options) {
+ OpenLayers.Util.extend(this, options);
+ this.projCode = projCode;
+ if (window.Proj4js) {
+ this.proj = new Proj4js.Proj(projCode);
}
- if(config.proxy && (url.indexOf("http") == 0)) {
- if(typeof config.proxy == "function") {
- url = config.proxy(url);
- } else {
- url = config.proxy + encodeURIComponent(url);
- }
- }
- request.open(
- config.method, url, config.async, config.user, config.password
- );
- for(var header in config.headers) {
- request.setRequestHeader(header, config.headers[header]);
- }
-
- var events = this.events;
-
- // we want to execute runCallbacks with "this" as the
- // execution scope
- var self = this;
-
- request.onreadystatechange = function() {
- if(request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {
- var proceed = events.triggerEvent(
- "complete",
- {request: request, config: config, requestUrl: url}
- );
- if(proceed !== false) {
- self.runCallbacks(
- {request: request, config: config, requestUrl: url}
- );
- }
- }
- };
-
- // send request (optionally with data) and return
- // call in a timeout for asynchronous requests so the return is
- // available before readyState == 4 for cached docs
- if(config.async === false) {
- request.send(config.data);
- } else {
- window.setTimeout(function(){
- if (request._aborted !== true) {
- request.send(config.data);
- }
- }, 0);
- }
- return request;
},
/**
- * Method: runCallbacks
- * Calls the complete, success and failure callbacks. Application
- * can listen to the "complete" event, have the listener
- * display a confirm window and always return false, and
- * execute OpenLayers.Request.runCallbacks if the user
- * hits "yes" in the confirm window.
+ * APIMethod: getCode
+ * Get the string SRS code.
*
- * Parameters:
- * options - {Object} Hash containing request, config and requestUrl keys
- */
- runCallbacks: function(options) {
- var request = options.request;
- var config = options.config;
-
- // bind callbacks to readyState 4 (done)
- var complete = (config.scope) ?
- OpenLayers.Function.bind(config.callback, config.scope) :
- config.callback;
-
- // optional success callback
- var success;
- if(config.success) {
- success = (config.scope) ?
- OpenLayers.Function.bind(config.success, config.scope) :
- config.success;
- }
-
- // optional failure callback
- var failure;
- if(config.failure) {
- failure = (config.scope) ?
- OpenLayers.Function.bind(config.failure, config.scope) :
- config.failure;
- }
-
- complete(request);
-
- if (!request.status || (request.status >= 200 && request.status < 300)) {
- this.events.triggerEvent("success", options);
- if(success) {
- success(request);
- }
- }
- if(request.status && (request.status < 200 || request.status >= 300)) {
- this.events.triggerEvent("failure", options);
- if(failure) {
- failure(request);
- }
- }
- },
-
- /**
- * APIMethod: GET
- * Send an HTTP GET request. Additional configuration properties are
- * documented in the <issue> method, with the method property set
- * to GET.
- *
- * Parameters:
- * config - {Object} Object with properties for configuring the request.
- * See the <issue> method for documentation of allowed properties.
- * This object is modified and should not be reused.
- *
* Returns:
- * {XMLHttpRequest} Request object.
+ * {String} The SRS code.
*/
- GET: function(config) {
- config = OpenLayers.Util.extend(config, {method: "GET"});
- return OpenLayers.Request.issue(config);
+ getCode: function() {
+ return this.proj ? this.proj.srsCode : this.projCode;
},
-
+
/**
- * APIMethod: POST
- * Send a POST request. Additional configuration properties are
- * documented in the <issue> method, with the method property set
- * to POST and "Content-Type" header set to "application/xml".
+ * APIMethod: getUnits
+ * Get the units string for the projection -- returns null if
+ * proj4js is not available.
*
- * Parameters:
- * config - {Object} Object with properties for configuring the request.
- * See the <issue> method for documentation of allowed properties. The
- * default "Content-Type" header will be set to "application-xml" if
- * none is provided. This object is modified and should not be reused.
- *
* Returns:
- * {XMLHttpRequest} Request object.
+ * {String} The units abbreviation.
*/
- POST: function(config) {
- config = OpenLayers.Util.extend(config, {method: "POST"});
- // set content type to application/xml if it isn't already set
- config.headers = config.headers ? config.headers : {};
- if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
- config.headers["Content-Type"] = "application/xml";
- }
- return OpenLayers.Request.issue(config);
+ getUnits: function() {
+ return this.proj ? this.proj.units : null;
},
-
+
/**
- * APIMethod: PUT
- * Send an HTTP PUT request. Additional configuration properties are
- * documented in the <issue> method, with the method property set
- * to PUT and "Content-Type" header set to "application/xml".
+ * Method: toString
+ * Convert projection to string (getCode wrapper).
*
- * Parameters:
- * config - {Object} Object with properties for configuring the request.
- * See the <issue> method for documentation of allowed properties. The
- * default "Content-Type" header will be set to "application-xml" if
- * none is provided. This object is modified and should not be reused.
- *
* Returns:
- * {XMLHttpRequest} Request object.
+ * {String} The projection code.
*/
- PUT: function(config) {
- config = OpenLayers.Util.extend(config, {method: "PUT"});
- // set content type to application/xml if it isn't already set
- config.headers = config.headers ? config.headers : {};
- if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
- config.headers["Content-Type"] = "application/xml";
- }
- return OpenLayers.Request.issue(config);
+ toString: function() {
+ return this.getCode();
},
-
- /**
- * APIMethod: DELETE
- * Send an HTTP DELETE request. Additional configuration properties are
- * documented in the <issue> method, with the method property set
- * to DELETE.
- *
- * Parameters:
- * config - {Object} Object with properties for configuring the request.
- * See the <issue> method for documentation of allowed properties.
- * This object is modified and should not be reused.
- *
- * Returns:
- * {XMLHttpRequest} Request object.
- */
- DELETE: function(config) {
- config = OpenLayers.Util.extend(config, {method: "DELETE"});
- return OpenLayers.Request.issue(config);
- },
-
- /**
- * APIMethod: HEAD
- * Send an HTTP HEAD request. Additional configuration properties are
- * documented in the <issue> method, with the method property set
- * to HEAD.
- *
- * Parameters:
- * config - {Object} Object with properties for configuring the request.
- * See the <issue> method for documentation of allowed properties.
- * This object is modified and should not be reused.
- *
- * Returns:
- * {XMLHttpRequest} Request object.
- */
- HEAD: function(config) {
- config = OpenLayers.Util.extend(config, {method: "HEAD"});
- return OpenLayers.Request.issue(config);
- },
-
- /**
- * APIMethod: OPTIONS
- * Send an HTTP OPTIONS request. Additional configuration properties are
- * documented in the <issue> method, with the method property set
- * to OPTIONS.
- *
- * Parameters:
- * config - {Object} Object with properties for configuring the request.
- * See the <issue> method for documentation of allowed properties.
- * This object is modified and should not be reused.
- *
- * Returns:
- * {XMLHttpRequest} Request object.
- */
- OPTIONS: function(config) {
- config = OpenLayers.Util.extend(config, {method: "OPTIONS"});
- return OpenLayers.Request.issue(config);
- }
-};
-/* ======================================================================
- OpenLayers/Tile/Image.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Tile.js
- */
-
-/**
- * Class: OpenLayers.Tile.Image
- * Instances of OpenLayers.Tile.Image are used to manage the image tiles
- * used by various layers. Create a new image tile with the
- * <OpenLayers.Tile.Image> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Tile>
- */
-OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
-
- /**
- * Property: url
- * {String} The URL of the image being requested. No default. Filled in by
- * layer.getURL() function.
- */
- url: null,
-
- /**
- * Property: imgDiv
- * {DOMElement} The div element which wraps the image.
- */
- imgDiv: null,
-
/**
- * Property: frame
- * {DOMElement} The image element is appended to the frame. Any gutter on
- * the image will be hidden behind the frame.
- */
- frame: null,
-
- /**
- * Property: layerAlphaHack
- * {Boolean} True if the png alpha hack needs to be applied on the layer's div.
- */
- layerAlphaHack: null,
-
- /**
- * Property: isBackBuffer
- * {Boolean} Is this tile a back buffer tile?
- */
- isBackBuffer: false,
-
- /**
- * Property: lastRatio
- * {Float} Used in transition code only. This is the previous ratio
- * of the back buffer tile resolution to the map resolution. Compared
- * with the current ratio to determine if zooming occurred.
- */
- lastRatio: 1,
-
- /**
- * Property: isFirstDraw
- * {Boolean} Is this the first time the tile is being drawn?
- * This is used to force resetBackBuffer to synchronize
- * the backBufferTile with the foreground tile the first time
- * the foreground tile loads so that if the user zooms
- * before the layer has fully loaded, the backBufferTile for
- * tiles that have been loaded can be used.
- */
- isFirstDraw: true,
-
- /**
- * Property: backBufferTile
- * {<OpenLayers.Tile>} A clone of the tile used to create transition
- * effects when the tile is moved or changes resolution.
- */
- backBufferTile: null,
-
- /** TBD 3.0 - reorder the parameters to the init function to remove
- * URL. the getUrl() function on the layer gets called on
- * each draw(), so no need to specify it here.
- *
- * Constructor: OpenLayers.Tile.Image
- * Constructor for a new <OpenLayers.Tile.Image> instance.
- *
- * Parameters:
- * layer - {<OpenLayers.Layer>} layer that the tile will go in.
- * position - {<OpenLayers.Pixel>}
- * bounds - {<OpenLayers.Bounds>}
- * url - {<String>} Deprecated. Remove me in 3.0.
- * size - {<OpenLayers.Size>}
- */
- initialize: function(layer, position, bounds, url, size) {
- OpenLayers.Tile.prototype.initialize.apply(this, arguments);
-
- this.url = url; //deprecated remove me
-
- this.frame = document.createElement('div');
- this.frame.style.overflow = 'hidden';
- this.frame.style.position = 'absolute';
-
- this.layerAlphaHack = this.layer.alpha && OpenLayers.Util.alphaHack();
- },
-
- /**
- * APIMethod: destroy
- * nullify references to prevent circular references and memory leaks
- */
- destroy: function() {
- if (this.imgDiv != null) {
- if (this.layerAlphaHack) {
- // unregister the "load" handler
- OpenLayers.Event.stopObservingElement(this.imgDiv.childNodes[0]);
- }
-
- // unregister the "load" and "error" handlers. Only the "error" handler if
- // this.layerAlphaHack is true.
- OpenLayers.Event.stopObservingElement(this.imgDiv);
-
- if (this.imgDiv.parentNode == this.frame) {
- this.frame.removeChild(this.imgDiv);
- this.imgDiv.map = null;
- }
- this.imgDiv.urls = null;
- // abort any currently loading image
- this.imgDiv.src = OpenLayers.Util.getImagesLocation() + "blank.gif";
- }
- this.imgDiv = null;
- if ((this.frame != null) && (this.frame.parentNode == this.layer.div)) {
- this.layer.div.removeChild(this.frame);
- }
- this.frame = null;
-
- /* clean up the backBufferTile if it exists */
- if (this.backBufferTile) {
- this.backBufferTile.destroy();
- this.backBufferTile = null;
- }
-
- this.layer.events.unregister("loadend", this, this.resetBackBuffer);
-
- OpenLayers.Tile.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: clone
+ * Method: equals
+ * Test equality of two projection instances. Determines equality based
+ * soley on the projection code.
*
- * Parameters:
- * obj - {<OpenLayers.Tile.Image>} The tile to be cloned
- *
* Returns:
- * {<OpenLayers.Tile.Image>} An exact clone of this <OpenLayers.Tile.Image>
+ * {Boolean} The two projections are equivalent.
*/
- clone: function (obj) {
- if (obj == null) {
- obj = new OpenLayers.Tile.Image(this.layer,
- this.position,
- this.bounds,
- this.url,
- this.size);
- }
-
- //pick up properties from superclass
- obj = OpenLayers.Tile.prototype.clone.apply(this, [obj]);
-
- //dont want to directly copy the image div
- obj.imgDiv = null;
-
-
- return obj;
- },
-
- /**
- * Method: draw
- * Check that a tile should be drawn, and draw it.
- *
- * Returns:
- * {Boolean} Always returns true.
- */
- draw: function() {
- if (this.layer != this.layer.map.baseLayer && this.layer.reproject) {
- this.bounds = this.getBoundsFromBaseLayer(this.position);
- }
- var drawTile = OpenLayers.Tile.prototype.draw.apply(this, arguments);
-
- if ((OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS, this.layer.transitionEffect) != -1) ||
- this.layer.singleTile) {
- if (drawTile) {
- //we use a clone of this tile to create a double buffer for visual
- //continuity. The backBufferTile is used to create transition
- //effects while the tile in the grid is repositioned and redrawn
- if (!this.backBufferTile) {
- this.backBufferTile = this.clone();
- this.backBufferTile.hide();
- // this is important. It allows the backBuffer to place itself
- // appropriately in the DOM. The Image subclass needs to put
- // the backBufferTile behind the main tile so the tiles can
- // load over top and display as soon as they are loaded.
- this.backBufferTile.isBackBuffer = true;
-
- // potentially end any transition effects when the tile loads
- this.events.register('loadend', this, this.resetBackBuffer);
-
- // clear transition back buffer tile only after all tiles in
- // this layer have loaded to avoid visual glitches
- this.layer.events.register("loadend", this, this.resetBackBuffer);
- }
- // run any transition effects
- this.startTransition();
- } else {
- // if we aren't going to draw the tile, then the backBuffer should
- // be hidden too!
- if (this.backBufferTile) {
- this.backBufferTile.clear();
- }
+ equals: function(projection) {
+ var p = projection, equals = false;
+ if (p) {
+ if (window.Proj4js && this.proj.defData && p.proj.defData) {
+ equals = this.proj.defData.replace(this.titleRegEx, "") ==
+ p.proj.defData.replace(this.titleRegEx, "");
+ } else if (p.getCode) {
+ var source = this.getCode(), target = p.getCode();
+ equals = source == target ||
+ !!OpenLayers.Projection.transforms[source] &&
+ OpenLayers.Projection.transforms[source][target] ===
+ OpenLayers.Projection.nullTransform;
}
- } else {
- if (drawTile && this.isFirstDraw) {
- this.events.register('loadend', this, this.showTile);
- this.isFirstDraw = false;
- }
- }
-
- if (!drawTile) {
- return false;
}
-
- if (this.isLoading) {
- //if we're already loading, send 'reload' instead of 'loadstart'.
- this.events.triggerEvent("reload");
- } else {
- this.isLoading = true;
- this.events.triggerEvent("loadstart");
- }
-
- return this.renderTile();
+ return equals;
},
-
- /**
- * Method: resetBackBuffer
- * Triggered by two different events, layer loadend, and tile loadend.
- * In any of these cases, we check to see if we can hide the
- * backBufferTile yet and update its parameters to match the
- * foreground tile.
- *
- * Basic logic:
- * - If the backBufferTile hasn't been drawn yet, reset it
- * - If layer is still loading, show foreground tile but don't hide
- * the backBufferTile yet
- * - If layer is done loading, reset backBuffer tile and show
- * foreground tile
- */
- resetBackBuffer: function() {
- this.showTile();
- if (this.backBufferTile &&
- (this.isFirstDraw || !this.layer.numLoadingTiles)) {
- this.isFirstDraw = false;
- // check to see if the backBufferTile is within the max extents
- // before rendering it
- var maxExtent = this.layer.maxExtent;
- var withinMaxExtent = (maxExtent &&
- this.bounds.intersectsBounds(maxExtent, false));
- if (withinMaxExtent) {
- this.backBufferTile.position = this.position;
- this.backBufferTile.bounds = this.bounds;
- this.backBufferTile.size = this.size;
- this.backBufferTile.imageSize = this.layer.getImageSize(this.bounds) || this.size;
- this.backBufferTile.imageOffset = this.layer.imageOffset;
- this.backBufferTile.resolution = this.layer.getResolution();
- this.backBufferTile.renderTile();
- }
- this.backBufferTile.hide();
- }
- },
-
- /**
- * Method: renderTile
- * Internal function to actually initialize the image tile,
- * position it correctly, and set its url.
+ /* Method: destroy
+ * Destroy projection object.
*/
- renderTile: function() {
- if (this.imgDiv == null) {
- this.initImgDiv();
- }
-
- this.imgDiv.viewRequestID = this.layer.map.viewRequestID;
-
- if (this.layer.async) {
- // Asyncronous image requests call the asynchronous getURL method
- // on the layer to fetch an image that covers 'this.bounds', in the scope of
- // 'this', setting the 'url' property of the layer itself, and running
- // the callback 'positionFrame' when the image request returns.
- this.layer.getURLasync(this.bounds, this, "url", this.positionImage);
- } else {
- // syncronous image requests get the url and position the frame immediately,
- // and don't wait for an image request to come back.
-
- // needed for changing to a different server for onload error
- if (this.layer.url instanceof Array) {
- this.imgDiv.urls = this.layer.url.slice();
- }
-
- this.url = this.layer.getURL(this.bounds);
-
- // position the frame immediately
- this.positionImage();
- }
- return true;
+ destroy: function() {
+ delete this.proj;
+ delete this.projCode;
},
-
- /**
- * Method: positionImage
- * Using the properties currenty set on the layer, position the tile correctly.
- * This method is used both by the async and non-async versions of the Tile.Image
- * code.
- */
- positionImage: function() {
- // if the this layer doesn't exist at the point the image is
- // returned, do not attempt to use it for size computation
- if (this.layer === null) {
- return;
- }
- // position the frame
- OpenLayers.Util.modifyDOMElement(this.frame,
- null, this.position, this.size);
-
- var imageSize = this.layer.getImageSize(this.bounds);
- if (this.layerAlphaHack) {
- OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,
- null, null, imageSize, this.url);
- } else {
- OpenLayers.Util.modifyDOMElement(this.imgDiv,
- null, null, imageSize) ;
- this.imgDiv.src = this.url;
- }
- },
-
- /**
- * Method: clear
- * Clear the tile of any bounds/position-related data so that it can
- * be reused in a new location.
- */
- clear: function() {
- if(this.imgDiv) {
- this.hide();
- if (OpenLayers.Tile.Image.useBlankTile) {
- this.imgDiv.src = OpenLayers.Util.getImagesLocation() + "blank.gif";
- }
- }
- },
-
- /**
- * Method: initImgDiv
- * Creates the imgDiv property on the tile.
- */
- initImgDiv: function() {
-
- var offset = this.layer.imageOffset;
- var size = this.layer.getImageSize(this.bounds);
-
- if (this.layerAlphaHack) {
- this.imgDiv = OpenLayers.Util.createAlphaImageDiv(null,
- offset,
- size,
- null,
- "relative",
- null,
- null,
- null,
- true);
- } else {
- this.imgDiv = OpenLayers.Util.createImage(null,
- offset,
- size,
- null,
- "relative",
- null,
- null,
- true);
- }
-
- this.imgDiv.className = 'olTileImage';
-
- /* checkImgURL used to be used to called as a work around, but it
- ended up hiding problems instead of solving them and broke things
- like relative URLs. See discussion on the dev list:
- http://openlayers.org/pipermail/dev/2007-January/000205.html
-
- OpenLayers.Event.observe( this.imgDiv, "load",
- OpenLayers.Function.bind(this.checkImgURL, this) );
- */
- this.frame.style.zIndex = this.isBackBuffer ? 0 : 1;
- this.frame.appendChild(this.imgDiv);
- this.layer.div.appendChild(this.frame);
-
- if(this.layer.opacity != null) {
-
- OpenLayers.Util.modifyDOMElement(this.imgDiv, null, null, null,
- null, null, null,
- this.layer.opacity);
- }
-
- // we need this reference to check back the viewRequestID
- this.imgDiv.map = this.layer.map;
-
- //bind a listener to the onload of the image div so that we
- // can register when a tile has finished loading.
- var onload = function() {
-
- //normally isLoading should always be true here but there are some
- // right funky conditions where loading and then reloading a tile
- // with the same url *really*fast*. this check prevents sending
- // a 'loadend' if the msg has already been sent
- //
- if (this.isLoading) {
- this.isLoading = false;
- this.events.triggerEvent("loadend");
- }
- };
-
- if (this.layerAlphaHack) {
- OpenLayers.Event.observe(this.imgDiv.childNodes[0], 'load',
- OpenLayers.Function.bind(onload, this));
- } else {
- OpenLayers.Event.observe(this.imgDiv, 'load',
- OpenLayers.Function.bind(onload, this));
- }
-
-
- // Bind a listener to the onerror of the image div so that we
- // can registere when a tile has finished loading with errors.
- var onerror = function() {
-
- // If we have gone through all image reload attempts, it is time
- // to realize that we are done with this image. Since
- // OpenLayers.Util.onImageLoadError already has taken care about
- // the error, we can continue as if the image was loaded
- // successfully.
- if (this.imgDiv._attempts > OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
- onload.call(this);
- }
- };
- OpenLayers.Event.observe(this.imgDiv, "error",
- OpenLayers.Function.bind(onerror, this));
- },
-
- /**
- * Method: checkImgURL
- * Make sure that the image that just loaded is the one this tile is meant
- * to display, since panning/zooming might have changed the tile's URL in
- * the meantime. If the tile URL did change before the image loaded, set
- * the imgDiv display to 'none', as either (a) it will be reset to visible
- * when the new URL loads in the image, or (b) we don't want to display
- * this tile after all because its new bounds are outside our maxExtent.
- *
- * This function should no longer be neccesary with the improvements to
- * Grid.js in OpenLayers 2.3. The lack of a good isEquivilantURL function
- * caused problems in 2.2, but it's possible that with the improved
- * isEquivilant URL function, this might be neccesary at some point.
- *
- * See discussion in the thread at
- * http://openlayers.org/pipermail/dev/2007-January/000205.html
- */
- checkImgURL: function () {
- // Sometimes our image will load after it has already been removed
- // from the map, in which case this check is not needed.
- if (this.layer) {
- var loaded = this.layerAlphaHack ? this.imgDiv.firstChild.src : this.imgDiv.src;
- if (!OpenLayers.Util.isEquivalentUrl(loaded, this.url)) {
- this.hide();
- }
- }
- },
- /**
- * Method: startTransition
- * This method is invoked on tiles that are backBuffers for tiles in the
- * grid. The grid tile is about to be cleared and a new tile source
- * loaded. This is where the transition effect needs to be started
- * to provide visual continuity.
- */
- startTransition: function() {
- // backBufferTile has to be valid and ready to use
- if (!this.backBufferTile || !this.backBufferTile.imgDiv) {
- return;
- }
+ CLASS_NAME: "OpenLayers.Projection"
+});
- // calculate the ratio of change between the current resolution of the
- // backBufferTile and the layer. If several animations happen in a
- // row, then the backBufferTile will scale itself appropriately for
- // each request.
- var ratio = 1;
- if (this.backBufferTile.resolution) {
- ratio = this.backBufferTile.resolution / this.layer.getResolution();
- }
-
- // if the ratio is not the same as it was last time (i.e. we are
- // zooming), then we need to adjust the backBuffer tile
- if (ratio != this.lastRatio) {
- if (this.layer.transitionEffect == 'resize') {
- // In this case, we can just immediately resize the
- // backBufferTile.
- var upperLeft = new OpenLayers.LonLat(
- this.backBufferTile.bounds.left,
- this.backBufferTile.bounds.top
- );
- var size = new OpenLayers.Size(
- this.backBufferTile.size.w * ratio,
- this.backBufferTile.size.h * ratio
- );
-
- var px = this.layer.map.getLayerPxFromLonLat(upperLeft);
- OpenLayers.Util.modifyDOMElement(this.backBufferTile.frame,
- null, px, size);
- var imageSize = this.backBufferTile.imageSize;
- imageSize = new OpenLayers.Size(imageSize.w * ratio,
- imageSize.h * ratio);
- var imageOffset = this.backBufferTile.imageOffset;
- if(imageOffset) {
- imageOffset = new OpenLayers.Pixel(
- imageOffset.x * ratio, imageOffset.y * ratio
- );
- }
-
- OpenLayers.Util.modifyDOMElement(
- this.backBufferTile.imgDiv, null, imageOffset, imageSize
- ) ;
-
- this.backBufferTile.show();
- }
- } else {
- // default effect is just to leave the existing tile
- // until the new one loads if this is a singleTile and
- // there was no change in resolution. Otherwise we
- // don't bother to show the backBufferTile at all
- if (this.layer.singleTile) {
- this.backBufferTile.show();
- } else {
- this.backBufferTile.hide();
- }
- }
- this.lastRatio = ratio;
-
- },
-
- /**
- * Method: show
- * Show the tile by showing its frame.
- */
- show: function() {
- this.frame.style.display = '';
- // Force a reflow on gecko based browsers to actually show the element
- // before continuing execution.
- if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS,
- this.layer.transitionEffect) != -1) {
- if (navigator.userAgent.toLowerCase().indexOf("gecko") != -1) {
- this.frame.scrollLeft = this.frame.scrollLeft;
- }
- }
- },
-
- /**
- * Method: hide
- * Hide the tile by hiding its frame.
- */
- hide: function() {
- this.frame.style.display = 'none';
- },
-
- CLASS_NAME: "OpenLayers.Tile.Image"
- }
-);
-
-OpenLayers.Tile.Image.useBlankTile = (
- OpenLayers.Util.getBrowserName() == "safari" ||
- OpenLayers.Util.getBrowserName() == "opera");
-/* ======================================================================
- OpenLayers/Control/OverviewMap.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/BaseTypes.js
- * @requires OpenLayers/Events.js
- */
-
/**
- * Class: OpenLayers.Control.OverviewMap
- * The OverMap control creates a small overview map, useful to display the
- * extent of a zoomed map and your main map and provide additional
- * navigation options to the User. By default the overview map is drawn in
- * the lower right corner of the main map. Create a new overview map with the
- * <OpenLayers.Control.OverviewMap> constructor.
+ * Property: transforms
+ * Transforms is an object, with from properties, each of which may
+ * have a to property. This allows you to define projections without
+ * requiring support for proj4js to be included.
*
- * Inerits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * Property: element
- * {DOMElement} The DOM element that contains the overview map
- */
- element: null,
-
- /**
- * APIProperty: ovmap
- * {<OpenLayers.Map>} A reference to the overview map itself.
- */
- ovmap: null,
-
- /**
- * APIProperty: size
- * {<OpenLayers.Size>} The overvew map size in pixels. Note that this is
- * the size of the map itself - the element that contains the map (default
- * class name olControlOverviewMapElement) may have padding or other style
- * attributes added via CSS.
- */
- size: new OpenLayers.Size(180, 90),
-
- /**
- * APIProperty: layers
- * {Array(<OpenLayers.Layer>)} Ordered list of layers in the overview map.
- * If none are sent at construction, the base layer for the main map is used.
- */
- layers: null,
-
- /**
- * APIProperty: minRectSize
- * {Integer} The minimum width or height (in pixels) of the extent
- * rectangle on the overview map. When the extent rectangle reaches
- * this size, it will be replaced depending on the value of the
- * <minRectDisplayClass> property. Default is 15 pixels.
- */
- minRectSize: 15,
-
- /**
- * APIProperty: minRectDisplayClass
- * {String} Replacement style class name for the extent rectangle when
- * <minRectSize> is reached. This string will be suffixed on to the
- * displayClass. Default is "RectReplacement".
- *
- * Example CSS declaration:
- * (code)
- * .olControlOverviewMapRectReplacement {
- * overflow: hidden;
- * cursor: move;
- * background-image: url("img/overview_replacement.gif");
- * background-repeat: no-repeat;
- * background-position: center;
- * }
- * (end)
- */
- minRectDisplayClass: "RectReplacement",
-
- /**
- * APIProperty: minRatio
- * {Float} The ratio of the overview map resolution to the main map
- * resolution at which to zoom farther out on the overview map.
- */
- minRatio: 8,
-
- /**
- * APIProperty: maxRatio
- * {Float} The ratio of the overview map resolution to the main map
- * resolution at which to zoom farther in on the overview map.
- */
- maxRatio: 32,
-
- /**
- * APIProperty: mapOptions
- * {Object} An object containing any non-default properties to be sent to
- * the overview map's map constructor. These should include any
- * non-default options that the main map was constructed with.
- */
- mapOptions: null,
-
- /**
- * APIProperty: autoPan
- * {Boolean} Always pan the overview map, so the extent marker remains in
- * the center. Default is false. If true, when you drag the extent
- * marker, the overview map will update itself so the marker returns
- * to the center.
- */
- autoPan: false,
-
- /**
- * Property: handlers
- * {Object}
- */
- handlers: null,
-
- /**
- * Property: resolutionFactor
- * {Object}
- */
- resolutionFactor: 1,
-
- /**
- * APIProperty: maximized
- * {Boolean} Start as maximized (visible). Defaults to false.
- */
- maximized: false,
-
- /**
- * Constructor: OpenLayers.Control.OverviewMap
- * Create a new overview map
- *
- * Parameters:
- * object - {Object} Properties of this object will be set on the overview
- * map object. Note, to set options on the map object contained in this
- * control, set <mapOptions> as one of the options properties.
- */
- initialize: function(options) {
- this.layers = [];
- this.handlers = {};
- OpenLayers.Control.prototype.initialize.apply(this, [options]);
- },
-
- /**
- * APIMethod: destroy
- * Deconstruct the control
- */
- destroy: function() {
- if (!this.mapDiv) { // we've already been destroyed
- return;
- }
- if (this.handlers.click) {
- this.handlers.click.destroy();
- }
- if (this.handlers.drag) {
- this.handlers.drag.destroy();
- }
-
- this.mapDiv.removeChild(this.extentRectangle);
- this.extentRectangle = null;
-
- if (this.rectEvents) {
- this.rectEvents.destroy();
- this.rectEvents = null;
- }
-
- if (this.ovmap) {
- this.ovmap.destroy();
- this.ovmap = null;
- }
-
- this.element.removeChild(this.mapDiv);
- this.mapDiv = null;
-
- this.div.removeChild(this.element);
- this.element = null;
-
- if (this.maximizeDiv) {
- OpenLayers.Event.stopObservingElement(this.maximizeDiv);
- this.div.removeChild(this.maximizeDiv);
- this.maximizeDiv = null;
- }
-
- if (this.minimizeDiv) {
- OpenLayers.Event.stopObservingElement(this.minimizeDiv);
- this.div.removeChild(this.minimizeDiv);
- this.minimizeDiv = null;
- }
-
- this.map.events.un({
- "moveend": this.update,
- "changebaselayer": this.baseLayerDraw,
- scope: this
- });
-
- OpenLayers.Control.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: draw
- * Render the control in the browser.
- */
- draw: function() {
- OpenLayers.Control.prototype.draw.apply(this, arguments);
- if(!(this.layers.length > 0)) {
- if (this.map.baseLayer) {
- var layer = this.map.baseLayer.clone();
- this.layers = [layer];
- } else {
- this.map.events.register("changebaselayer", this, this.baseLayerDraw);
- return this.div;
- }
- }
-
- // create overview map DOM elements
- this.element = document.createElement('div');
- this.element.className = this.displayClass + 'Element';
- this.element.style.display = 'none';
-
- this.mapDiv = document.createElement('div');
- this.mapDiv.style.width = this.size.w + 'px';
- this.mapDiv.style.height = this.size.h + 'px';
- this.mapDiv.style.position = 'relative';
- this.mapDiv.style.overflow = 'hidden';
- this.mapDiv.id = OpenLayers.Util.createUniqueID('overviewMap');
-
- this.extentRectangle = document.createElement('div');
- this.extentRectangle.style.position = 'absolute';
- this.extentRectangle.style.zIndex = 1000; //HACK
- this.extentRectangle.className = this.displayClass+'ExtentRectangle';
- this.mapDiv.appendChild(this.extentRectangle);
-
- this.element.appendChild(this.mapDiv);
-
- this.div.appendChild(this.element);
-
- // Optionally add min/max buttons if the control will go in the
- // map viewport.
- if(!this.outsideViewport) {
- this.div.className += " " + this.displayClass + 'Container';
- var imgLocation = OpenLayers.Util.getImagesLocation();
- // maximize button div
- var img = imgLocation + 'layer-switcher-maximize.png';
- this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
- this.displayClass + 'MaximizeButton',
- null,
- new OpenLayers.Size(18,18),
- img,
- 'absolute');
- this.maximizeDiv.style.display = 'none';
- this.maximizeDiv.className = this.displayClass + 'MaximizeButton';
- OpenLayers.Event.observe(this.maximizeDiv, 'click',
- OpenLayers.Function.bindAsEventListener(this.maximizeControl,
- this)
- );
- this.div.appendChild(this.maximizeDiv);
-
- // minimize button div
- var img = imgLocation + 'layer-switcher-minimize.png';
- this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
- 'OpenLayers_Control_minimizeDiv',
- null,
- new OpenLayers.Size(18,18),
- img,
- 'absolute');
- this.minimizeDiv.style.display = 'none';
- this.minimizeDiv.className = this.displayClass + 'MinimizeButton';
- OpenLayers.Event.observe(this.minimizeDiv, 'click',
- OpenLayers.Function.bindAsEventListener(this.minimizeControl,
- this)
- );
- this.div.appendChild(this.minimizeDiv);
-
- var eventsToStop = ['dblclick','mousedown'];
-
- for (var i=0, len=eventsToStop.length; i<len; i++) {
-
- OpenLayers.Event.observe(this.maximizeDiv,
- eventsToStop[i],
- OpenLayers.Event.stop);
-
- OpenLayers.Event.observe(this.minimizeDiv,
- eventsToStop[i],
- OpenLayers.Event.stop);
- }
-
- this.minimizeControl();
- } else {
- // show the overview map
- this.element.style.display = '';
- }
- if(this.map.getExtent()) {
- this.update();
- }
-
- this.map.events.register('moveend', this, this.update);
-
- if (this.maximized) {
- this.maximizeControl();
- }
- return this.div;
- },
-
- /**
- * Method: baseLayerDraw
- * Draw the base layer - called if unable to complete in the initial draw
- */
- baseLayerDraw: function() {
- this.draw();
- this.map.events.unregister("changebaselayer", this, this.baseLayerDraw);
- },
-
- /**
- * Method: rectDrag
- * Handle extent rectangle drag
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>} The pixel location of the drag.
- */
- rectDrag: function(px) {
- var deltaX = this.handlers.drag.last.x - px.x;
- var deltaY = this.handlers.drag.last.y - px.y;
- if(deltaX != 0 || deltaY != 0) {
- var rectTop = this.rectPxBounds.top;
- var rectLeft = this.rectPxBounds.left;
- var rectHeight = Math.abs(this.rectPxBounds.getHeight());
- var rectWidth = this.rectPxBounds.getWidth();
- // don't allow dragging off of parent element
- var newTop = Math.max(0, (rectTop - deltaY));
- newTop = Math.min(newTop,
- this.ovmap.size.h - this.hComp - rectHeight);
- var newLeft = Math.max(0, (rectLeft - deltaX));
- newLeft = Math.min(newLeft,
- this.ovmap.size.w - this.wComp - rectWidth);
- this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
- newTop + rectHeight,
- newLeft + rectWidth,
- newTop));
- }
- },
-
- /**
- * Method: mapDivClick
- * Handle browser events
- *
- * Parameters:
- * evt - {<OpenLayers.Event>} evt
- */
- mapDivClick: function(evt) {
- var pxCenter = this.rectPxBounds.getCenterPixel();
- var deltaX = evt.xy.x - pxCenter.x;
- var deltaY = evt.xy.y - pxCenter.y;
- var top = this.rectPxBounds.top;
- var left = this.rectPxBounds.left;
- var height = Math.abs(this.rectPxBounds.getHeight());
- var width = this.rectPxBounds.getWidth();
- var newTop = Math.max(0, (top + deltaY));
- newTop = Math.min(newTop, this.ovmap.size.h - height);
- var newLeft = Math.max(0, (left + deltaX));
- newLeft = Math.min(newLeft, this.ovmap.size.w - width);
- this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
- newTop + height,
- newLeft + width,
- newTop));
- this.updateMapToRect();
- },
-
- /**
- * Method: maximizeControl
- * Unhide the control. Called when the control is in the map viewport.
- *
- * Parameters:
- * e - {<OpenLayers.Event>}
- */
- maximizeControl: function(e) {
- this.element.style.display = '';
- this.showToggle(false);
- if (e != null) {
- OpenLayers.Event.stop(e);
- }
- },
-
- /**
- * Method: minimizeControl
- * Hide all the contents of the control, shrink the size,
- * add the maximize icon
- *
- * Parameters:
- * e - {<OpenLayers.Event>}
- */
- minimizeControl: function(e) {
- this.element.style.display = 'none';
- this.showToggle(true);
- if (e != null) {
- OpenLayers.Event.stop(e);
- }
- },
-
- /**
- * Method: showToggle
- * Hide/Show the toggle depending on whether the control is minimized
- *
- * Parameters:
- * minimize - {Boolean}
- */
- showToggle: function(minimize) {
- this.maximizeDiv.style.display = minimize ? '' : 'none';
- this.minimizeDiv.style.display = minimize ? 'none' : '';
- },
-
- /**
- * Method: update
- * Update the overview map after layers move.
- */
- update: function() {
- if(this.ovmap == null) {
- this.createMap();
- }
-
- if(this.autoPan || !this.isSuitableOverview()) {
- this.updateOverview();
- }
-
- // update extent rectangle
- this.updateRectToMap();
- },
-
- /**
- * Method: isSuitableOverview
- * Determines if the overview map is suitable given the extent and
- * resolution of the main map.
- */
- isSuitableOverview: function() {
- var mapExtent = this.map.getExtent();
- var maxExtent = this.map.maxExtent;
- var testExtent = new OpenLayers.Bounds(
- Math.max(mapExtent.left, maxExtent.left),
- Math.max(mapExtent.bottom, maxExtent.bottom),
- Math.min(mapExtent.right, maxExtent.right),
- Math.min(mapExtent.top, maxExtent.top));
-
- if (this.ovmap.getProjection() != this.map.getProjection()) {
- testExtent = testExtent.transform(
- this.map.getProjectionObject(),
- this.ovmap.getProjectionObject() );
- }
-
- var resRatio = this.ovmap.getResolution() / this.map.getResolution();
- return ((resRatio > this.minRatio) &&
- (resRatio <= this.maxRatio) &&
- (this.ovmap.getExtent().containsBounds(testExtent)));
- },
-
- /**
- * Method updateOverview
- * Called by <update> if <isSuitableOverview> returns true
- */
- updateOverview: function() {
- var mapRes = this.map.getResolution();
- var targetRes = this.ovmap.getResolution();
- var resRatio = targetRes / mapRes;
- if(resRatio > this.maxRatio) {
- // zoom in overview map
- targetRes = this.minRatio * mapRes;
- } else if(resRatio <= this.minRatio) {
- // zoom out overview map
- targetRes = this.maxRatio * mapRes;
- }
- var center;
- if (this.ovmap.getProjection() != this.map.getProjection()) {
- center = this.map.center.clone();
- center.transform(this.map.getProjectionObject(),
- this.ovmap.getProjectionObject() );
- } else {
- center = this.map.center;
- }
- this.ovmap.setCenter(center, this.ovmap.getZoomForResolution(
- targetRes * this.resolutionFactor));
- this.updateRectToMap();
- },
-
- /**
- * Method: createMap
- * Construct the map that this control contains
- */
- createMap: function() {
- // create the overview map
- var options = OpenLayers.Util.extend(
- {controls: [], maxResolution: 'auto',
- fallThrough: false}, this.mapOptions);
- this.ovmap = new OpenLayers.Map(this.mapDiv, options);
-
- // prevent ovmap from being destroyed when the page unloads, because
- // the OverviewMap control has to do this (and does it).
- OpenLayers.Event.stopObserving(window, 'unload', this.ovmap.unloadDestroy);
-
- this.ovmap.addLayers(this.layers);
- this.ovmap.zoomToMaxExtent();
- // check extent rectangle border width
- this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
- 'border-left-width')) +
- parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
- 'border-right-width'));
- this.wComp = (this.wComp) ? this.wComp : 2;
- this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
- 'border-top-width')) +
- parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
- 'border-bottom-width'));
- this.hComp = (this.hComp) ? this.hComp : 2;
-
- this.handlers.drag = new OpenLayers.Handler.Drag(
- this, {move: this.rectDrag, done: this.updateMapToRect},
- {map: this.ovmap}
- );
- this.handlers.click = new OpenLayers.Handler.Click(
- this, {
- "click": this.mapDivClick
- },{
- "single": true, "double": false,
- "stopSingle": true, "stopDouble": true,
- "pixelTolerance": 1,
- map: this.ovmap
- }
- );
- this.handlers.click.activate();
-
- this.rectEvents = new OpenLayers.Events(this, this.extentRectangle,
- null, true);
- this.rectEvents.register("mouseover", this, function(e) {
- if(!this.handlers.drag.active && !this.map.dragging) {
- this.handlers.drag.activate();
- }
- });
- this.rectEvents.register("mouseout", this, function(e) {
- if(!this.handlers.drag.dragging) {
- this.handlers.drag.deactivate();
- }
- });
-
- if (this.ovmap.getProjection() != this.map.getProjection()) {
- var sourceUnits = this.map.getProjectionObject().getUnits() ||
- this.map.units || this.map.baseLayer.units;
- var targetUnits = this.ovmap.getProjectionObject().getUnits() ||
- this.ovmap.units || this.ovmap.baseLayer.units;
- this.resolutionFactor = sourceUnits && targetUnits ?
- OpenLayers.INCHES_PER_UNIT[sourceUnits] /
- OpenLayers.INCHES_PER_UNIT[targetUnits] : 1;
- }
- },
-
- /**
- * Method: updateRectToMap
- * Updates the extent rectangle position and size to match the map extent
- */
- updateRectToMap: function() {
- // If the projections differ we need to reproject
- var bounds;
- if (this.ovmap.getProjection() != this.map.getProjection()) {
- bounds = this.map.getExtent().transform(
- this.map.getProjectionObject(),
- this.ovmap.getProjectionObject() );
- } else {
- bounds = this.map.getExtent();
- }
- var pxBounds = this.getRectBoundsFromMapBounds(bounds);
- if (pxBounds) {
- this.setRectPxBounds(pxBounds);
- }
- },
-
- /**
- * Method: updateMapToRect
- * Updates the map extent to match the extent rectangle position and size
- */
- updateMapToRect: function() {
- var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds);
- if (this.ovmap.getProjection() != this.map.getProjection()) {
- lonLatBounds = lonLatBounds.transform(
- this.ovmap.getProjectionObject(),
- this.map.getProjectionObject() );
- }
- this.map.panTo(lonLatBounds.getCenterLonLat());
- },
-
- /**
- * Method: setRectPxBounds
- * Set extent rectangle pixel bounds.
- *
- * Parameters:
- * pxBounds - {<OpenLayers.Bounds>}
- */
- setRectPxBounds: function(pxBounds) {
- var top = Math.max(pxBounds.top, 0);
- var left = Math.max(pxBounds.left, 0);
- var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()),
- this.ovmap.size.h - this.hComp);
- var right = Math.min(pxBounds.left + pxBounds.getWidth(),
- this.ovmap.size.w - this.wComp);
- var width = Math.max(right - left, 0);
- var height = Math.max(bottom - top, 0);
- if(width < this.minRectSize || height < this.minRectSize) {
- this.extentRectangle.className = this.displayClass +
- this.minRectDisplayClass;
- var rLeft = left + (width / 2) - (this.minRectSize / 2);
- var rTop = top + (height / 2) - (this.minRectSize / 2);
- this.extentRectangle.style.top = Math.round(rTop) + 'px';
- this.extentRectangle.style.left = Math.round(rLeft) + 'px';
- this.extentRectangle.style.height = this.minRectSize + 'px';
- this.extentRectangle.style.width = this.minRectSize + 'px';
- } else {
- this.extentRectangle.className = this.displayClass +
- 'ExtentRectangle';
- this.extentRectangle.style.top = Math.round(top) + 'px';
- this.extentRectangle.style.left = Math.round(left) + 'px';
- this.extentRectangle.style.height = Math.round(height) + 'px';
- this.extentRectangle.style.width = Math.round(width) + 'px';
- }
- this.rectPxBounds = new OpenLayers.Bounds(
- Math.round(left), Math.round(bottom),
- Math.round(right), Math.round(top)
- );
- },
-
- /**
- * Method: getRectBoundsFromMapBounds
- * Get the rect bounds from the map bounds.
- *
- * Parameters:
- * lonLatBounds - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {<OpenLayers.Bounds>}A bounds which is the passed-in map lon/lat extent
- * translated into pixel bounds for the overview map
- */
- getRectBoundsFromMapBounds: function(lonLatBounds) {
- var leftBottomLonLat = new OpenLayers.LonLat(lonLatBounds.left,
- lonLatBounds.bottom);
- var rightTopLonLat = new OpenLayers.LonLat(lonLatBounds.right,
- lonLatBounds.top);
- var leftBottomPx = this.getOverviewPxFromLonLat(leftBottomLonLat);
- var rightTopPx = this.getOverviewPxFromLonLat(rightTopLonLat);
- var bounds = null;
- if (leftBottomPx && rightTopPx) {
- bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y,
- rightTopPx.x, rightTopPx.y);
- }
- return bounds;
- },
-
- /**
- * Method: getMapBoundsFromRectBounds
- * Get the map bounds from the rect bounds.
- *
- * Parameters:
- * pxBounds - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {<OpenLayers.Bounds>} Bounds which is the passed-in overview rect bounds
- * translated into lon/lat bounds for the overview map
- */
- getMapBoundsFromRectBounds: function(pxBounds) {
- var leftBottomPx = new OpenLayers.Pixel(pxBounds.left,
- pxBounds.bottom);
- var rightTopPx = new OpenLayers.Pixel(pxBounds.right,
- pxBounds.top);
- var leftBottomLonLat = this.getLonLatFromOverviewPx(leftBottomPx);
- var rightTopLonLat = this.getLonLatFromOverviewPx(rightTopPx);
- return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat,
- rightTopLonLat.lon, rightTopLonLat.lat);
- },
-
- /**
- * Method: getLonLatFromOverviewPx
- * Get a map location from a pixel location
- *
- * Parameters:
- * overviewMapPx - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.LonLat>} Location which is the passed-in overview map
- * OpenLayers.Pixel, translated into lon/lat by the overview map
- */
- getLonLatFromOverviewPx: function(overviewMapPx) {
- var size = this.ovmap.size;
- var res = this.ovmap.getResolution();
- var center = this.ovmap.getExtent().getCenterLonLat();
-
- var delta_x = overviewMapPx.x - (size.w / 2);
- var delta_y = overviewMapPx.y - (size.h / 2);
-
- return new OpenLayers.LonLat(center.lon + delta_x * res ,
- center.lat - delta_y * res);
- },
-
- /**
- * Method: getOverviewPxFromLonLat
- * Get a pixel location from a map location
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>}
- *
- * Returns:
- * {<OpenLayers.Pixel>} Location which is the passed-in OpenLayers.LonLat,
- * translated into overview map pixels
- */
- getOverviewPxFromLonLat: function(lonlat) {
- var res = this.ovmap.getResolution();
- var extent = this.ovmap.getExtent();
- var px = null;
- if (extent) {
- px = new OpenLayers.Pixel(
- Math.round(1/res * (lonlat.lon - extent.left)),
- Math.round(1/res * (extent.top - lonlat.lat)));
- }
- return px;
- },
-
- CLASS_NAME: 'OpenLayers.Control.OverviewMap'
-});
-/* ======================================================================
- OpenLayers/Feature.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Util.js
- * @requires OpenLayers/Marker.js
- * @requires OpenLayers/Popup/AnchoredBubble.js
- */
-
-/**
- * Class: OpenLayers.Feature
- * Features are combinations of geography and attributes. The OpenLayers.Feature
- * class specifically combines a marker and a lonlat.
- */
-OpenLayers.Feature = OpenLayers.Class({
-
- /**
- * Property: layer
- * {<OpenLayers.Layer>}
- */
- layer: null,
-
- /**
- * Property: id
- * {String}
- */
- id: null,
-
- /**
- * Property: lonlat
- * {<OpenLayers.LonLat>}
- */
- lonlat: null,
-
- /**
- * Property: data
- * {Object}
- */
- data: null,
-
- /**
- * Property: marker
- * {<OpenLayers.Marker>}
- */
- marker: null,
-
- /**
- * APIProperty: popupClass
- * {<OpenLayers.Class>} The class which will be used to instantiate
- * a new Popup. Default is <OpenLayers.Popup.AnchoredBubble>.
- */
- popupClass: OpenLayers.Popup.AnchoredBubble,
-
- /**
- * Property: popup
- * {<OpenLayers.Popup>}
- */
- popup: null,
-
- /**
- * Constructor: OpenLayers.Feature
- * Constructor for features.
- *
- * Parameters:
- * layer - {<OpenLayers.Layer>}
- * lonlat - {<OpenLayers.LonLat>}
- * data - {Object}
- *
- * Returns:
- * {<OpenLayers.Feature>}
- */
- initialize: function(layer, lonlat, data) {
- this.layer = layer;
- this.lonlat = lonlat;
- this.data = (data != null) ? data : {};
- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
- },
-
- /**
- * Method: destroy
- * nullify references to prevent circular references and memory leaks
- */
- destroy: function() {
-
- //remove the popup from the map
- if ((this.layer != null) && (this.layer.map != null)) {
- if (this.popup != null) {
- this.layer.map.removePopup(this.popup);
- }
- }
- // remove the marker from the layer
- if (this.layer != null && this.marker != null) {
- this.layer.removeMarker(this.marker);
- }
-
- this.layer = null;
- this.id = null;
- this.lonlat = null;
- this.data = null;
- if (this.marker != null) {
- this.destroyMarker(this.marker);
- this.marker = null;
- }
- if (this.popup != null) {
- this.destroyPopup(this.popup);
- this.popup = null;
- }
- },
-
- /**
- * Method: onScreen
- *
- * Returns:
- * {Boolean} Whether or not the feature is currently visible on screen
- * (based on its 'lonlat' property)
- */
- onScreen:function() {
-
- var onScreen = false;
- if ((this.layer != null) && (this.layer.map != null)) {
- var screenBounds = this.layer.map.getExtent();
- onScreen = screenBounds.containsLonLat(this.lonlat);
- }
- return onScreen;
- },
-
-
- /**
- * Method: createMarker
- * Based on the data associated with the Feature, create and return a marker object.
- *
- * Returns:
- * {<OpenLayers.Marker>} A Marker Object created from the 'lonlat' and 'icon' properties
- * set in this.data. If no 'lonlat' is set, returns null. If no
- * 'icon' is set, OpenLayers.Marker() will load the default image.
- *
- * Note - this.marker is set to return value
- *
- */
- createMarker: function() {
-
- if (this.lonlat != null) {
- this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon);
- }
- return this.marker;
- },
-
- /**
- * Method: destroyMarker
- * Destroys marker.
- * If user overrides the createMarker() function, s/he should be able
- * to also specify an alternative function for destroying it
- */
- destroyMarker: function() {
- this.marker.destroy();
- },
-
- /**
- * Method: createPopup
- * Creates a popup object created from the 'lonlat', 'popupSize',
- * and 'popupContentHTML' properties set in this.data. It uses
- * this.marker.icon as default anchor.
- *
- * If no 'lonlat' is set, returns null.
- * If no this.marker has been created, no anchor is sent.
- *
- * Note - the returned popup object is 'owned' by the feature, so you
- * cannot use the popup's destroy method to discard the popup.
- * Instead, you must use the feature's destroyPopup
- *
- * Note - this.popup is set to return value
- *
- * Parameters:
- * closeBox - {Boolean} create popup with closebox or not
- *
- * Returns:
- * {<OpenLayers.Popup>} Returns the created popup, which is also set
- * as 'popup' property of this feature. Will be of whatever type
- * specified by this feature's 'popupClass' property, but must be
- * of type <OpenLayers.Popup>.
- *
- */
- createPopup: function(closeBox) {
-
- if (this.lonlat != null) {
-
- var id = this.id + "_popup";
- var anchor = (this.marker) ? this.marker.icon : null;
-
- if (!this.popup) {
- this.popup = new this.popupClass(id,
- 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/Handler/Click.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Handler.js
- */
-
-/**
- * Class: OpenLayers.Handler.Click
- * A handler for mouse clicks. The intention of this handler is to give
- * controls more flexibility with handling clicks. Browsers trigger
- * click events twice for a double-click. In addition, the mousedown,
- * mousemove, mouseup sequence fires a click event. With this handler,
- * controls can decide whether to ignore clicks associated with a double
- * click. By setting a <pixelTolerance>, controls can also ignore clicks
- * that include a drag. Create a new instance with the
- * <OpenLayers.Handler.Click> constructor.
+ * This object has keys which correspond to a 'source' projection object. The
+ * keys should be strings, corresponding to the projection.getCode() value.
+ * Each source projection object should have a set of destination projection
+ * keys included in the object.
*
- * Inherits from:
- * - <OpenLayers.Handler>
- */
-OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
-
- /**
- * APIProperty: delay
- * {Number} Number of milliseconds between clicks before the event is
- * considered a double-click.
- */
- delay: 300,
-
- /**
- * APIProperty: single
- * {Boolean} Handle single clicks. Default is true. If false, clicks
- * will not be reported. If true, single-clicks will be reported.
- */
- single: true,
-
- /**
- * APIProperty: double
- * {Boolean} Handle double-clicks. Default is false.
- */
- 'double': false,
-
- /**
- * APIProperty: pixelTolerance
- * {Number} Maximum number of pixels between mouseup and mousedown for an
- * event to be considered a click. Default is 0. If set to an
- * integer value, clicks with a drag greater than the value will be
- * ignored. This property can only be set when the handler is
- * constructed.
- */
- pixelTolerance: 0,
-
- /**
- * APIProperty: stopSingle
- * {Boolean} Stop other listeners from being notified of clicks. Default
- * is false. If true, any click listeners registered before this one
- * will not be notified of *any* click event (associated with double
- * or single clicks).
- */
- stopSingle: false,
-
- /**
- * APIProperty: stopDouble
- * {Boolean} Stop other listeners from being notified of double-clicks.
- * Default is false. If true, any click listeners registered before
- * this one will not be notified of *any* double-click events.
- *
- * The one caveat with stopDouble is that given a map with two click
- * handlers, one with stopDouble true and the other with stopSingle
- * true, the stopSingle handler should be activated last to get
- * uniform cross-browser performance. Since IE triggers one click
- * with a dblclick and FF triggers two, if a stopSingle handler is
- * activated first, all it gets in IE is a single click when the
- * second handler stops propagation on the dblclick.
- */
- stopDouble: false,
-
- /**
- * Property: timerId
- * {Number} The id of the timeout waiting to clear the <delayedCall>.
- */
- timerId: null,
-
- /**
- * Property: down
- * {<OpenLayers.Pixel>} The pixel location of the last mousedown.
- */
- down: null,
-
- /**
- * Property: rightclickTimerId
- * {Number} The id of the right mouse timeout waiting to clear the
- * <delayedEvent>.
- */
- rightclickTimerId: null,
-
- /**
- * Constructor: OpenLayers.Handler.Click
- * Create a new click handler.
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that is making use of
- * this handler. If a handler is being used without a control, the
- * handler's setMap method must be overridden to deal properly with
- * the map.
- * callbacks - {Object} An object with keys corresponding to callbacks
- * that will be called by the handler. The callbacks should
- * expect to recieve a single argument, the click event.
- * Callbacks for 'click' and 'dblclick' are supported.
- * options - {Object} Optional object whose properties will be set on the
- * handler.
- */
- initialize: function(control, callbacks, options) {
- OpenLayers.Handler.prototype.initialize.apply(this, arguments);
- // optionally register for mouseup and mousedown
- if(this.pixelTolerance != null) {
- this.mousedown = function(evt) {
- this.down = evt.xy;
- return true;
- };
- }
- },
-
- /**
- * Method: mousedown
- * Handle mousedown. Only registered as a listener if pixelTolerance is
- * a non-zero value at construction.
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- mousedown: null,
-
- /**
- * Method: mouseup
- * Handle mouseup. Installed to support collection of right mouse events.
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- mouseup: function (evt) {
- var propagate = true;
-
- // Collect right mouse clicks from the mouseup
- // IE - ignores the second right click in mousedown so using
- // mouseup instead
- if (this.checkModifiers(evt) &&
- this.control.handleRightClicks &&
- OpenLayers.Event.isRightClick(evt)) {
- propagate = this.rightclick(evt);
- }
-
- return propagate;
- },
-
- /**
- * Method: rightclick
- * Handle rightclick. For a dblrightclick, we get two clicks so we need
- * to always register for dblrightclick to properly handle single
- * clicks.
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- rightclick: function(evt) {
- if(this.passesTolerance(evt)) {
- if(this.rightclickTimerId != null) {
- //Second click received before timeout this must be
- // a double click
- this.clearTimer();
- this.callback('dblrightclick', [evt]);
- return !this.stopDouble;
- } else {
- //Set the rightclickTimerId, send evt only if double is
- // true else trigger single
- var clickEvent = this['double'] ?
- OpenLayers.Util.extend({}, evt) :
- this.callback('rightclick', [evt]);
-
- var delayedRightCall = OpenLayers.Function.bind(
- this.delayedRightCall,
- this,
- clickEvent
- );
- this.rightclickTimerId = window.setTimeout(
- delayedRightCall, this.delay
- );
- }
- }
- return !this.stopSingle;
- },
-
- /**
- * Method: delayedRightCall
- * Sets <rightclickTimerId> to null. And optionally triggers the
- * rightclick callback if evt is set.
- */
- delayedRightCall: function(evt) {
- this.rightclickTimerId = null;
- if (evt) {
- this.callback('rightclick', [evt]);
- }
- return !this.stopSingle;
- },
-
- /**
- * Method: dblclick
- * Handle dblclick. For a dblclick, we get two clicks in some browsers
- * (FF) and one in others (IE). So we need to always register for
- * dblclick to properly handle single clicks.
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- dblclick: function(evt) {
- if(this.passesTolerance(evt)) {
- if(this["double"]) {
- this.callback('dblclick', [evt]);
- }
- this.clearTimer();
- }
- return !this.stopDouble;
- },
-
- /**
- * Method: click
- * Handle click.
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- click: function(evt) {
- if(this.passesTolerance(evt)) {
- if(this.timerId != null) {
- // already received a click
- this.clearTimer();
- } else {
- // set the timer, send evt only if single is true
- //use a clone of the event object because it will no longer
- //be a valid event object in IE in the timer callback
- var clickEvent = this.single ?
- OpenLayers.Util.extend({}, evt) : null;
- this.timerId = window.setTimeout(
- OpenLayers.Function.bind(this.delayedCall, this, clickEvent),
- this.delay
- );
- }
- }
- return !this.stopSingle;
- },
-
- /**
- * Method: passesTolerance
- * Determine whether the event is within the optional pixel tolerance. Note
- * that the pixel tolerance check only works if mousedown events get to
- * the listeners registered here. If they are stopped by other elements,
- * the <pixelTolerance> will have no effect here (this method will always
- * return true).
- *
- * Returns:
- * {Boolean} The click is within the pixel tolerance (if specified).
- */
- passesTolerance: function(evt) {
- var passes = true;
- if(this.pixelTolerance != null && this.down) {
- var dpx = Math.sqrt(
- Math.pow(this.down.x - evt.xy.x, 2) +
- Math.pow(this.down.y - evt.xy.y, 2)
- );
- if(dpx > this.pixelTolerance) {
- passes = false;
- }
- }
- return passes;
- },
-
- /**
- * Method: clearTimer
- * Clear the timer and set <timerId> to null.
- */
- clearTimer: function() {
- if(this.timerId != null) {
- window.clearTimeout(this.timerId);
- this.timerId = null;
- }
- if(this.rightclickTimerId != null) {
- window.clearTimeout(this.rightclickTimerId);
- this.rightclickTimerId = null;
- }
- },
-
- /**
- * Method: delayedCall
- * Sets <timerId> to null. And optionally triggers the click callback if
- * evt is set.
- */
- delayedCall: function(evt) {
- this.timerId = null;
- if(evt) {
- this.callback('click', [evt]);
- }
- },
-
- /**
- * APIMethod: deactivate
- * Deactivate the handler.
- *
- * Returns:
- * {Boolean} The handler was successfully deactivated.
- */
- deactivate: function() {
- var deactivated = false;
- if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
- this.clearTimer();
- this.down = null;
- deactivated = true;
- }
- return deactivated;
- },
-
- CLASS_NAME: "OpenLayers.Handler.Click"
-});
-/* ======================================================================
- OpenLayers/Handler/Drag.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Handler.js
- */
-
-/**
- * Class: OpenLayers.Handler.Drag
- * The drag handler is used to deal with sequences of browser events related
- * to dragging. The handler is used by controls that want to know when
- * a drag sequence begins, when a drag is happening, and when it has
- * finished.
+ * Each value in the destination object should be a transformation function,
+ * where the function is expected to be passed an object with a .x and a .y
+ * property. The function should return the object, with the .x and .y
+ * transformed according to the transformation function.
*
- * Controls that use the drag handler typically construct it with callbacks
- * for 'down', 'move', and 'done'. Callbacks for these keys are called
- * when the drag begins, with each move, and when the drag is done. In
- * addition, controls can have callbacks keyed to 'up' and 'out' if they
- * care to differentiate between the types of events that correspond with
- * the end of a drag sequence. If no drag actually occurs (no mouse move)
- * the 'down' and 'up' callbacks will be called, but not the 'done'
- * callback.
- *
- * Create a new drag handler with the <OpenLayers.Handler.Drag> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Handler>
+ * Note - Properties on this object should not be set directly. To add a
+ * transform method to this object, use the <addTransform> method. For an
+ * example of usage, see the OpenLayers.Layer.SphericalMercator file.
*/
-OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, {
-
- /**
- * Property: started
- * {Boolean} When a mousedown event is received, we want to record it, but
- * not set 'dragging' until the mouse moves after starting.
- */
- started: false,
-
- /**
- * Property: stopDown
- * {Boolean} Stop propagation of mousedown events from getting to listeners
- * on the same element. Default is true.
- */
- stopDown: true,
+OpenLayers.Projection.transforms = {};
- /**
- * Property: dragging
- * {Boolean}
- */
- dragging: false,
-
- /**
- * Property: last
- * {<OpenLayers.Pixel>} The last pixel location of the drag.
- */
- last: null,
-
- /**
- * Property: start
- * {<OpenLayers.Pixel>} The first pixel location of the drag.
- */
- start: null,
-
- /**
- * Property: oldOnselectstart
- * {Function}
- */
- oldOnselectstart: null,
-
- /**
- * Property: interval
- * {Integer} In order to increase performance, an interval (in
- * milliseconds) can be set to reduce the number of drag events
- * called. If set, a new drag event will not be set until the
- * interval has passed.
- * Defaults to 0, meaning no interval.
- */
- interval: 0,
-
- /**
- * Property: timeoutId
- * {String} The id of the timeout used for the mousedown interval.
- * This is "private", and should be left alone.
- */
- timeoutId: null,
-
- /**
- * APIProperty: documentDrag
- * {Boolean} If set to true, the handler will also handle mouse moves when
- * the cursor has moved out of the map viewport. Default is false.
- */
- documentDrag: false,
-
- /**
- * Property: documentEvents
- * {<OpenLayers.Events>} Event instance for observing document events. Will
- * be set on mouseout if documentDrag is set to true.
- */
- documentEvents: null,
-
- /**
- * Constructor: OpenLayers.Handler.Drag
- * Returns OpenLayers.Handler.Drag
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that is making use of
- * this handler. If a handler is being used without a control, the
- * handlers setMap method must be overridden to deal properly with
- * the map.
- * callbacks - {Object} An object containing a single function to be
- * called when the drag operation is finished. The callback should
- * expect to recieve a single argument, the pixel location of the event.
- * Callbacks for 'move' and 'done' are supported. You can also speficy
- * callbacks for 'down', 'up', and 'out' to respond to those events.
- * options - {Object}
- */
- initialize: function(control, callbacks, options) {
- OpenLayers.Handler.prototype.initialize.apply(this, arguments);
- },
-
- /**
- * The four methods below (down, move, up, and out) are used by subclasses
- * to do their own processing related to these mouse events.
- */
-
- /**
- * Method: down
- * This method is called during the handling of the mouse down event.
- * Subclasses can do their own processing here.
- *
- * Parameters:
- * evt - {Event} The mouse down event
- */
- down: function(evt) {
- },
-
- /**
- * Method: move
- * This method is called during the handling of the mouse move event.
- * Subclasses can do their own processing here.
- *
- * Parameters:
- * evt - {Event} The mouse move event
- *
- */
- move: function(evt) {
- },
-
- /**
- * Method: up
- * This method is called during the handling of the mouse up event.
- * Subclasses can do their own processing here.
- *
- * Parameters:
- * evt - {Event} The mouse up event
- */
- up: function(evt) {
- },
-
- /**
- * Method: out
- * This method is called during the handling of the mouse out event.
- * Subclasses can do their own processing here.
- *
- * Parameters:
- * evt - {Event} The mouse out event
- */
- out: function(evt) {
- },
-
- /**
- * The methods below are part of the magic of event handling. Because
- * they are named like browser events, they are registered as listeners
- * for the events they represent.
- */
-
- /**
- * Method: mousedown
- * Handle mousedown events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- mousedown: function (evt) {
- var propagate = true;
- this.dragging = false;
- if (this.checkModifiers(evt) && OpenLayers.Event.isLeftClick(evt)) {
- this.started = true;
- this.start = evt.xy;
- this.last = evt.xy;
- OpenLayers.Element.addClass(
- this.map.viewPortDiv, "olDragDown"
- );
- this.down(evt);
- this.callback("down", [evt.xy]);
- OpenLayers.Event.stop(evt);
-
- if(!this.oldOnselectstart) {
- this.oldOnselectstart = (document.onselectstart) ? document.onselectstart : OpenLayers.Function.True;
- }
- document.onselectstart = OpenLayers.Function.False;
-
- propagate = !this.stopDown;
- } else {
- this.started = false;
- this.start = null;
- this.last = null;
- }
- return propagate;
- },
-
- /**
- * Method: mousemove
- * Handle mousemove events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- mousemove: function (evt) {
- if (this.started && !this.timeoutId && (evt.xy.x != this.last.x || evt.xy.y != this.last.y)) {
- if(this.documentDrag === true && this.documentEvents) {
- if(evt.element === document) {
- this.adjustXY(evt);
- // do setEvent manually because the documentEvents are not
- // registered with the map
- this.setEvent(evt);
- } else {
- this.destroyDocumentEvents();
- }
- }
- if (this.interval > 0) {
- this.timeoutId = setTimeout(OpenLayers.Function.bind(this.removeTimeout, this), this.interval);
- }
- this.dragging = true;
- this.move(evt);
- this.callback("move", [evt.xy]);
- if(!this.oldOnselectstart) {
- this.oldOnselectstart = document.onselectstart;
- document.onselectstart = OpenLayers.Function.False;
- }
- this.last = this.evt.xy;
- }
- return true;
- },
-
- /**
- * Method: removeTimeout
- * Private. Called by mousemove() to remove the drag timeout.
- */
- removeTimeout: function() {
- this.timeoutId = null;
- },
-
- /**
- * Method: mouseup
- * Handle mouseup events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- mouseup: function (evt) {
- if (this.started) {
- if(this.documentDrag === true && this.documentEvents) {
- this.adjustXY(evt);
- this.destroyDocumentEvents();
- }
- var dragged = (this.start != this.last);
- this.started = false;
- this.dragging = false;
- OpenLayers.Element.removeClass(
- this.map.viewPortDiv, "olDragDown"
- );
- this.up(evt);
- this.callback("up", [evt.xy]);
- if(dragged) {
- this.callback("done", [evt.xy]);
- }
- document.onselectstart = this.oldOnselectstart;
- }
- return true;
- },
-
- /**
- * Method: mouseout
- * Handle mouseout events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- mouseout: function (evt) {
- if (this.started && OpenLayers.Util.mouseLeft(evt, this.map.div)) {
- if(this.documentDrag === true) {
- this.documentEvents = new OpenLayers.Events(this, document,
- null, null, {includeXY: true});
- this.documentEvents.on({
- mousemove: this.mousemove,
- mouseup: this.mouseup
- });
- OpenLayers.Element.addClass(
- document.body, "olDragDown"
- );
- } else {
- var dragged = (this.start != this.last);
- this.started = false;
- this.dragging = false;
- OpenLayers.Element.removeClass(
- this.map.viewPortDiv, "olDragDown"
- );
- this.out(evt);
- this.callback("out", []);
- if(dragged) {
- this.callback("done", [evt.xy]);
- }
- if(document.onselectstart) {
- document.onselectstart = this.oldOnselectstart;
- }
- }
- }
- return true;
- },
-
- /**
- * Method: click
- * The drag handler captures the click event. If something else registers
- * for clicks on the same element, its listener will not be called
- * after a drag.
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- click: function (evt) {
- // let the click event propagate only if the mouse moved
- return (this.start == this.last);
- },
-
- /**
- * Method: activate
- * Activate the handler.
- *
- * Returns:
- * {Boolean} The handler was successfully activated.
- */
- activate: function() {
- var activated = false;
- if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
- this.dragging = false;
- activated = true;
- }
- return activated;
- },
-
- /**
- * Method: deactivate
- * Deactivate the handler.
- *
- * Returns:
- * {Boolean} The handler was successfully deactivated.
- */
- deactivate: function() {
- var deactivated = false;
- if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
- this.started = false;
- this.dragging = false;
- this.start = null;
- this.last = null;
- deactivated = true;
- OpenLayers.Element.removeClass(
- this.map.viewPortDiv, "olDragDown"
- );
- }
- return deactivated;
- },
-
- /**
- * Method: adjustXY
- * Converts event coordinates that are relative to the document body to
- * ones that are relative to the map viewport. The latter is the default in
- * OpenLayers.
- *
- * Parameters:
- * evt - {Object}
- */
- adjustXY: function(evt) {
- var pos = OpenLayers.Util.pagePosition(this.map.div);
- evt.xy.x -= pos[0];
- evt.xy.y -= pos[1];
- },
-
- /**
- * Method: destroyDocumentEvents
- * Destroys the events instance that gets added to the document body when
- * documentDrag is true and the mouse cursor leaves the map viewport while
- * dragging.
- */
- destroyDocumentEvents: function() {
- OpenLayers.Element.removeClass(
- document.body, "olDragDown"
- );
- this.documentEvents.destroy();
- this.documentEvents = null;
- },
-
- CLASS_NAME: "OpenLayers.Handler.Drag"
-});
-/* ======================================================================
- OpenLayers/Handler/Feature.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-
/**
- * @requires OpenLayers/Handler.js
- */
-
-/**
- * Class: OpenLayers.Handler.Feature
- * Handler to respond to mouse events related to a drawn feature. Callbacks
- * with the following keys will be notified of the following events
- * associated with features: click, clickout, over, out, and dblclick.
+ * APIMethod: addTransform
+ * Set a custom transform method between two projections. Use this method in
+ * cases where the proj4js lib is not available or where custom projections
+ * need to be handled.
*
- * This handler stops event propagation for mousedown and mouseup if those
- * browser events target features that can be selected.
+ * Parameters:
+ * from - {String} The code for the source projection
+ * to - {String} the code for the destination projection
+ * method - {Function} A function that takes a point as an argument and
+ * transforms that point from the source to the destination projection
+ * in place. The original point should be modified.
*/
-OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, {
+OpenLayers.Projection.addTransform = function(from, to, method) {
+ if(!OpenLayers.Projection.transforms[from]) {
+ OpenLayers.Projection.transforms[from] = {};
+ }
+ OpenLayers.Projection.transforms[from][to] = method;
+};
- /**
- * Property: EVENTMAP
- * {Object} A object mapping the browser events to objects with callback
- * keys for in and out.
- */
- EVENTMAP: {
- 'click': {'in': 'click', 'out': 'clickout'},
- 'mousemove': {'in': 'over', 'out': 'out'},
- 'dblclick': {'in': 'dblclick', 'out': null},
- 'mousedown': {'in': null, 'out': null},
- 'mouseup': {'in': null, 'out': null}
- },
-
- /**
- * Property: feature
- * {<OpenLayers.Feature.Vector>} The last feature that was hovered.
- */
- feature: null,
-
- /**
- * Property: lastFeature
- * {<OpenLayers.Feature.Vector>} The last feature that was handled.
- */
- lastFeature: null,
-
- /**
- * Property: down
- * {<OpenLayers.Pixel>} The location of the last mousedown.
- */
- down: null,
-
- /**
- * Property: up
- * {<OpenLayers.Pixel>} The location of the last mouseup.
- */
- up: null,
-
- /**
- * Property: clickTolerance
- * {Number} The number of pixels the mouse can move between mousedown
- * and mouseup for the event to still be considered a click.
- * Dragging the map should not trigger the click and clickout callbacks
- * unless the map is moved by less than this tolerance. Defaults to 4.
- */
- clickTolerance: 4,
-
- /**
- * Property: geometryTypes
- * To restrict dragging to a limited set of geometry types, send a list
- * of strings corresponding to the geometry class names.
- *
- * @type Array(String)
- */
- geometryTypes: null,
-
- /**
- * Property: stopClick
- * {Boolean} If stopClick is set to true, handled clicks do not
- * propagate to other click listeners. Otherwise, handled clicks
- * do propagate. Unhandled clicks always propagate, whatever the
- * value of stopClick. Defaults to true.
- */
- stopClick: true,
-
- /**
- * Property: stopDown
- * {Boolean} If stopDown is set to true, handled mousedowns do not
- * propagate to other mousedown listeners. Otherwise, handled
- * mousedowns do propagate. Unhandled mousedowns always propagate,
- * whatever the value of stopDown. Defaults to true.
- */
- stopDown: true,
-
- /**
- * Property: stopUp
- * {Boolean} If stopUp is set to true, handled mouseups do not
- * propagate to other mouseup listeners. Otherwise, handled mouseups
- * do propagate. Unhandled mouseups always propagate, whatever the
- * value of stopUp. Defaults to false.
- */
- stopUp: false,
-
- /**
- * Constructor: OpenLayers.Handler.Feature
- *
- * Parameters:
- * control - {<OpenLayers.Control>}
- * layer - {<OpenLayers.Layer.Vector>}
- * callbacks - {Object} An object with a 'over' property whos value is
- * a function to be called when the mouse is over a feature. The
- * callback should expect to recieve a single argument, the feature.
- * options - {Object}
- */
- initialize: function(control, layer, callbacks, options) {
- OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]);
- this.layer = layer;
- },
-
-
- /**
- * Method: mousedown
- * Handle mouse down. Stop propagation if a feature is targeted by this
- * event (stops map dragging during feature selection).
- *
- * Parameters:
- * evt - {Event}
- */
- mousedown: function(evt) {
- this.down = evt.xy;
- return this.handle(evt) ? !this.stopDown : true;
- },
-
- /**
- * Method: mouseup
- * Handle mouse up. Stop propagation if a feature is targeted by this
- * event.
- *
- * Parameters:
- * evt - {Event}
- */
- mouseup: function(evt) {
- this.up = evt.xy;
- return this.handle(evt) ? !this.stopUp : true;
- },
-
- /**
- * Method: click
- * Handle click. Call the "click" callback if click on a feature,
- * or the "clickout" callback if click outside any feature.
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean}
- */
- click: function(evt) {
- return this.handle(evt) ? !this.stopClick : true;
- },
-
- /**
- * Method: mousemove
- * Handle mouse moves. Call the "over" callback if moving in to a feature,
- * or the "out" callback if moving out of a feature.
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean}
- */
- mousemove: function(evt) {
- if (!this.callbacks['over'] && !this.callbacks['out']) {
- return true;
- }
- this.handle(evt);
- return true;
- },
-
- /**
- * Method: dblclick
- * Handle dblclick. Call the "dblclick" callback if dblclick on a feature.
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean}
- */
- dblclick: function(evt) {
- return !this.handle(evt);
- },
-
- /**
- * Method: geometryTypeMatches
- * Return true if the geometry type of the passed feature matches
- * one of the geometry types in the geometryTypes array.
- *
- * Parameters:
- * feature - {<OpenLayers.Vector.Feature>}
- *
- * Returns:
- * {Boolean}
- */
- geometryTypeMatches: function(feature) {
- return this.geometryTypes == null ||
- OpenLayers.Util.indexOf(this.geometryTypes,
- feature.geometry.CLASS_NAME) > -1;
- },
-
- /**
- * Method: handle
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} The event occurred over a relevant feature.
- */
- handle: function(evt) {
- if(this.feature && !this.feature.layer) {
- // feature has been destroyed
- this.feature = null;
- }
- var type = evt.type;
- var handled = false;
- var previouslyIn = !!(this.feature); // previously in a feature
- var click = (type == "click" || type == "dblclick");
- this.feature = this.layer.getFeatureFromEvent(evt);
- if(this.feature && !this.feature.layer) {
- // feature has been destroyed
- this.feature = null;
- }
- if(this.lastFeature && !this.lastFeature.layer) {
- // last feature has been destroyed
- this.lastFeature = null;
- }
- if(this.feature) {
- var inNew = (this.feature != this.lastFeature);
- if(this.geometryTypeMatches(this.feature)) {
- // in to a feature
- if(previouslyIn && inNew) {
- // out of last feature and in to another
- if(this.lastFeature) {
- this.triggerCallback(type, 'out', [this.lastFeature]);
- }
- this.triggerCallback(type, 'in', [this.feature]);
- } else if(!previouslyIn || click) {
- // in feature for the first time
- this.triggerCallback(type, 'in', [this.feature]);
- }
- this.lastFeature = this.feature;
- handled = true;
- } else {
- // not in to a feature
- if(this.lastFeature && (previouslyIn && inNew || click)) {
- // out of last feature for the first time
- this.triggerCallback(type, 'out', [this.lastFeature]);
- }
- // next time the mouse goes in a feature whose geometry type
- // doesn't match we don't want to call the 'out' callback
- // again, so let's set this.feature to null so that
- // previouslyIn will evaluate to false the next time
- // we enter handle. Yes, a bit hackish...
- this.feature = null;
- }
- } else {
- if(this.lastFeature && (previouslyIn || click)) {
- this.triggerCallback(type, 'out', [this.lastFeature]);
- }
- }
- return handled;
- },
-
- /**
- * Method: triggerCallback
- * Call the callback keyed in the event map with the supplied arguments.
- * For click and clickout, the <clickTolerance> is checked first.
- *
- * Parameters:
- * type - {String}
- */
- triggerCallback: function(type, mode, args) {
- var key = this.EVENTMAP[type][mode];
- if(key) {
- if(type == 'click' && this.up && this.down) {
- // for click/clickout, only trigger callback if tolerance is met
- var dpx = Math.sqrt(
- Math.pow(this.up.x - this.down.x, 2) +
- Math.pow(this.up.y - this.down.y, 2)
- );
- if(dpx <= this.clickTolerance) {
- this.callback(key, args);
- }
- } else {
- this.callback(key, args);
- }
- }
- },
-
- /**
- * Method: activate
- * Turn on the handler. Returns false if the handler was already active.
- *
- * Returns:
- * {Boolean}
- */
- activate: function() {
- var activated = false;
- if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
- this.moveLayerToTop();
- this.map.events.on({
- "removelayer": this.handleMapEvents,
- "changelayer": this.handleMapEvents,
- scope: this
- });
- activated = true;
- }
- return activated;
- },
-
- /**
- * Method: deactivate
- * Turn off the handler. Returns false if the handler was already active.
- *
- * Returns:
- * {Boolean}
- */
- deactivate: function() {
- var deactivated = false;
- if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
- this.moveLayerBack();
- this.feature = null;
- this.lastFeature = null;
- this.down = null;
- this.up = null;
- this.map.events.un({
- "removelayer": this.handleMapEvents,
- "changelayer": this.handleMapEvents,
- scope: this
- });
- deactivated = true;
- }
- return deactivated;
- },
-
- /**
- * Method handleMapEvents
- *
- * Parameters:
- * evt - {Object}
- */
- handleMapEvents: function(evt) {
- if (!evt.property || evt.property == "order") {
- this.moveLayerToTop();
- }
- },
-
- /**
- * Method: moveLayerToTop
- * Moves the layer for this handler to the top, so mouse events can reach
- * it.
- */
- moveLayerToTop: function() {
- var index = Math.max(this.map.Z_INDEX_BASE['Feature'] - 1,
- this.layer.getZIndex()) + 1;
- this.layer.setZIndex(index);
-
- },
-
- /**
- * Method: moveLayerBack
- * Moves the layer back to the position determined by the map's layers
- * array.
- */
- moveLayerBack: function() {
- var index = this.layer.getZIndex() - 1;
- if (index >= this.map.Z_INDEX_BASE['Feature']) {
- this.layer.setZIndex(index);
- } else {
- this.map.setLayerZIndex(this.layer,
- this.map.getLayerIndex(this.layer));
- }
- },
-
- CLASS_NAME: "OpenLayers.Handler.Feature"
-});
-/* ======================================================================
- OpenLayers/Handler/Hover.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
/**
- * @requires OpenLayers/Handler.js
- */
-
-/**
- * Class: OpenLayers.Handler.Hover
- * The hover handler is to be used to emulate mouseovers on objects
- * on the map that aren't DOM elements. For example one can use
- * this handler to send WMS/GetFeatureInfo requests as the user
- * moves the mouve over the map.
+ * APIMethod: transform
+ * Transform a point coordinate from one projection to another. Note that
+ * the input point is transformed in place.
*
- * Inherits from:
- * - <OpenLayers.Handler>
+ * Parameters:
+ * point - {{OpenLayers.Geometry.Point> | Object} An object with x and y
+ * properties representing coordinates in those dimensions.
+ * sourceProj - {OpenLayers.Projection} Source map coordinate system
+ * destProj - {OpenLayers.Projection} Destination map coordinate system
+ *
+ * Returns:
+ * point - {object} A transformed coordinate. The original point is modified.
*/
-OpenLayers.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, {
+OpenLayers.Projection.transform = function(point, source, dest) {
+ if (source.proj && dest.proj) {
+ point = Proj4js.transform(source.proj, dest.proj, point);
+ } else if (source && dest &&
+ OpenLayers.Projection.transforms[source.getCode()] &&
+ OpenLayers.Projection.transforms[source.getCode()][dest.getCode()]) {
+ OpenLayers.Projection.transforms[source.getCode()][dest.getCode()](point);
+ }
+ return point;
+};
- /**
- * APIProperty: delay
- * {Integer} - Number of milliseconds between mousemoves before
- * the event is considered a hover. Default is 500.
- */
- delay: 500,
-
- /**
- * APIProperty: pixelTolerance
- * {Integer} - Maximum number of pixels between mousemoves for
- * an event to be considered a hover. Default is null.
- */
- pixelTolerance: null,
-
- /**
- * APIProperty: stopMove
- * {Boolean} - Stop other listeners from being notified on mousemoves.
- * Default is false.
- */
- stopMove: false,
-
- /**
- * Property: px
- * {<OpenLayers.Pixel>} - The location of the last mousemove, expressed
- * in pixels.
- */
- px: null,
-
- /**
- * Property: timerId
- * {Number} - The id of the timer.
- */
- timerId: null,
-
- /**
- * Constructor: OpenLayers.Handler.Hover
- * Construct a hover handler.
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that initialized this
- * handler. The control is assumed to have a valid map property; that
- * map is used in the handler's own setMap method.
- * callbacks - {Object} An object with keys corresponding to callbacks
- * that will be called by the handler. The callbacks should
- * expect to receive a single argument, the event. Callbacks for
- * 'move', the mouse is moving, and 'pause', the mouse is pausing,
- * are supported.
- * options - {Object} An optional object whose properties will be set on
- * the handler.
- */
- initialize: function(control, callbacks, options) {
- OpenLayers.Handler.prototype.initialize.apply(this, arguments);
- },
-
- /**
- * Method: mousemove
- * Called when the mouse moves on the map.
- *
- * Parameters:
- * evt - {<OpenLayers.Event>}
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- mousemove: function(evt) {
- if(this.passesTolerance(evt.xy)) {
- this.clearTimer();
- this.callback('move', [evt]);
- this.px = evt.xy;
- // clone the evt so original properties can be accessed even
- // if the browser deletes them during the delay
- evt = OpenLayers.Util.extend({}, evt);
- this.timerId = window.setTimeout(
- OpenLayers.Function.bind(this.delayedCall, this, evt),
- this.delay
- );
- }
- return !this.stopMove;
- },
-
- /**
- * Method: mouseout
- * Called when the mouse goes out of the map.
- *
- * Parameters:
- * evt - {<OpenLayers.Event>}
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- mouseout: function(evt) {
- if (OpenLayers.Util.mouseLeft(evt, this.map.div)) {
- this.clearTimer();
- this.callback('move', [evt]);
- }
- return true;
- },
-
- /**
- * Method: passesTolerance
- * Determine whether the mouse move is within the optional pixel tolerance.
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {Boolean} The mouse move is within the pixel tolerance.
- */
- passesTolerance: function(px) {
- var passes = true;
- if(this.pixelTolerance && this.px) {
- var dpx = Math.sqrt(
- Math.pow(this.px.x - px.x, 2) +
- Math.pow(this.px.y - px.y, 2)
- );
- if(dpx < this.pixelTolerance) {
- passes = false;
- }
- }
- return passes;
- },
-
- /**
- * Method: clearTimer
- * Clear the timer and set <timerId> to null.
- */
- clearTimer: function() {
- if(this.timerId != null) {
- window.clearTimeout(this.timerId);
- this.timerId = null;
- }
- },
-
- /**
- * Method: delayedCall
- * Triggers pause callback.
- *
- * Parameters:
- * evt - {<OpenLayers.Event>}
- */
- delayedCall: function(evt) {
- this.callback('pause', [evt]);
- },
-
- /**
- * APIMethod: deactivate
- * Deactivate the handler.
- *
- * Returns:
- * {Boolean} The handler was successfully deactivated.
- */
- deactivate: function() {
- var deactivated = false;
- if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
- this.clearTimer();
- deactivated = true;
- }
- return deactivated;
- },
-
- CLASS_NAME: "OpenLayers.Handler.Hover"
-});
-/* ======================================================================
- OpenLayers/Handler/MouseWheel.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
/**
- * @requires OpenLayers/Handler.js
+ * APIFunction: nullTransform
+ * A null transformation - useful for defining projection aliases when
+ * proj4js is not available:
+ *
+ * (code)
+ * OpenLayers.Projection.addTransform("EPSG:4326", "EPSG:3857",
+ * OpenLayers.Layer.SphericalMercator.projectForward);
+ * OpenLayers.Projection.addTransform("EPSG:3857", "EPSG:3857",
+ * OpenLayers.Layer.SphericalMercator.projectInverse);
+ * OpenLayers.Projection.addTransform("EPSG:3857", "EPSG:900913",
+ * OpenLayers.Projection.nullTransform);
+ * OpenLayers.Projection.addTransform("EPSG:900913", "EPSG:3857",
+ * OpenLayers.Projection.nullTransform);
+ * (end)
*/
-
-/**
- * Class: OpenLayers.Handler.MouseWheel
- * Handler for wheel up/down events.
- *
- * Inherits from:
- * - <OpenLayers.Handler>
- */
-OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, {
- /**
- * Property: wheelListener
- * {function}
- */
- wheelListener: null,
-
- /**
- * Property: mousePosition
- * {<OpenLayers.Pixel>} mousePosition is necessary because
- * evt.clientX/Y is buggy in Moz on wheel events, so we cache and use the
- * value from the last mousemove.
- */
- mousePosition: null,
-
- /**
- * Property: interval
- * {Integer} In order to increase server performance, an interval (in
- * milliseconds) can be set to reduce the number of up/down events
- * called. If set, a new up/down event will not be set until the
- * interval has passed.
- * Defaults to 0, meaning no interval.
- */
- interval: 0,
-
- /**
- * Property: delta
- * {Integer} When interval is set, delta collects the mousewheel z-deltas
- * of the events that occur within the interval.
- * See also the cumulative option
- */
- delta: 0,
-
- /**
- * Property: cumulative
- * {Boolean} When interval is set: true to collect all the mousewheel
- * z-deltas, false to only record the delta direction (positive or
- * negative)
- */
- cumulative: true,
-
- /**
- * Constructor: OpenLayers.Handler.MouseWheel
- *
- * Parameters:
- * control - {<OpenLayers.Control>}
- * callbacks - {Object} An object containing a single function to be
- * called when the drag operation is finished.
- * The callback should expect to recieve a single
- * argument, the point geometry.
- * options - {Object}
- */
- initialize: function(control, callbacks, options) {
- OpenLayers.Handler.prototype.initialize.apply(this, arguments);
- this.wheelListener = OpenLayers.Function.bindAsEventListener(
- this.onWheelEvent, this
- );
- },
-
- /**
- * Method: destroy
- */
- destroy: function() {
- OpenLayers.Handler.prototype.destroy.apply(this, arguments);
- this.wheelListener = null;
- },
-
- /**
- * Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/
- */
-
- /**
- * Method: onWheelEvent
- * Catch the wheel event and handle it xbrowserly
- *
- * Parameters:
- * e - {Event}
- */
- onWheelEvent: function(e){
-
- // make sure we have a map and check keyboard modifiers
- if (!this.map || !this.checkModifiers(e)) {
- return;
- }
-
- // Ride up the element's DOM hierarchy to determine if it or any of
- // its ancestors was:
- // * specifically marked as scrollable
- // * one of our layer divs
- // * the map div
- //
- var overScrollableDiv = false;
- var overLayerDiv = false;
- var overMapDiv = false;
-
- var elem = OpenLayers.Event.element(e);
- while((elem != null) && !overMapDiv && !overScrollableDiv) {
-
- if (!overScrollableDiv) {
- try {
- if (elem.currentStyle) {
- overflow = elem.currentStyle["overflow"];
- } else {
- var style =
- document.defaultView.getComputedStyle(elem, null);
- var overflow = style.getPropertyValue("overflow");
- }
- overScrollableDiv = ( overflow &&
- (overflow == "auto") || (overflow == "scroll") );
- } catch(err) {
- //sometimes when scrolling in a popup, this causes
- // obscure browser error
- }
- }
-
- if (!overLayerDiv) {
- for(var i=0, len=this.map.layers.length; i<len; i++) {
- // Are we in the layer div? Note that we have two cases
- // here: one is to catch EventPane layers, which have a
- // pane above the layer (layer.pane)
- if (elem == this.map.layers[i].div
- || elem == this.map.layers[i].pane) {
- overLayerDiv = true;
- break;
- }
- }
- }
- overMapDiv = (elem == this.map.div);
-
- elem = elem.parentNode;
- }
-
- // Logic below is the following:
- //
- // If we are over a scrollable div or not over the map div:
- // * do nothing (let the browser handle scrolling)
- //
- // otherwise
- //
- // If we are over the layer div:
- // * zoom/in out
- // then
- // * kill event (so as not to also scroll the page after zooming)
- //
- // otherwise
- //
- // Kill the event (dont scroll the page if we wheel over the
- // layerswitcher or the pan/zoom control)
- //
- if (!overScrollableDiv && overMapDiv) {
- if (overLayerDiv) {
- var delta = 0;
- if (!e) {
- e = window.event;
- }
- if (e.wheelDelta) {
- delta = e.wheelDelta/120;
- if (window.opera && window.opera.version() < 9.2) {
- delta = -delta;
- }
- } else if (e.detail) {
- delta = -e.detail / 3;
- }
- this.delta = this.delta + delta;
-
- if(this.interval) {
- window.clearTimeout(this._timeoutId);
- this._timeoutId = window.setTimeout(
- OpenLayers.Function.bind(function(){
- this.wheelZoom(e);
- }, this),
- this.interval
- );
- } else {
- this.wheelZoom(e);
- }
- }
- OpenLayers.Event.stop(e);
- }
- },
-
- /**
- * Method: wheelZoom
- * Given the wheel event, we carry out the appropriate zooming in or out,
- * based on the 'wheelDelta' or 'detail' property of the event.
- *
- * Parameters:
- * e - {Event}
- */
- wheelZoom: function(e) {
- var delta = this.delta;
- this.delta = 0;
-
- if (delta) {
- // add the mouse position to the event because mozilla has
- // a bug with clientX and clientY (see
- // https://bugzilla.mozilla.org/show_bug.cgi?id=352179)
- // getLonLatFromViewPortPx(e) returns wrong values
- if (this.mousePosition) {
- e.xy = this.mousePosition;
- }
- if (!e.xy) {
- // If the mouse hasn't moved over the map yet, then
- // we don't have a mouse position (in FF), so we just
- // act as if the mouse was at the center of the map.
- // Note that we can tell we are in the map -- and
- // this.map is ensured to be true above.
- e.xy = this.map.getPixelFromLonLat(
- this.map.getCenter()
- );
- }
- if (delta < 0) {
- this.callback("down", [e, this.cumulative ? delta : -1]);
- } else {
- this.callback("up", [e, this.cumulative ? delta : 1]);
- }
- }
- },
-
- /**
- * Method: mousemove
- * Update the stored mousePosition on every move.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- mousemove: function (evt) {
- this.mousePosition = evt.xy;
- },
-
- /**
- * Method: activate
- */
- activate: function (evt) {
- if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
- //register mousewheel events specifically on the window and document
- var wheelListener = this.wheelListener;
- OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener);
- OpenLayers.Event.observe(window, "mousewheel", wheelListener);
- OpenLayers.Event.observe(document, "mousewheel", wheelListener);
- return true;
- } else {
- return false;
- }
- },
-
- /**
- * Method: deactivate
- */
- deactivate: function (evt) {
- if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
- // unregister mousewheel events specifically on the window and document
- var wheelListener = this.wheelListener;
- OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener);
- OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener);
- OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener);
- return true;
- } else {
- return false;
- }
- },
-
- CLASS_NAME: "OpenLayers.Handler.MouseWheel"
-});
+OpenLayers.Projection.nullTransform = function(point) {
+ return point;
+};
/* ======================================================================
OpenLayers/Layer.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
+ * @requires OpenLayers/BaseTypes/Class.js
* @requires OpenLayers/Map.js
* @requires OpenLayers/Projection.js
*/
@@ -22366,7 +9195,9 @@
/**
* APIMethod: display
- * Hide or show the Layer
+ * Hide or show the Layer. This is designed to be used internally, and
+ * is not generally the way to enable or disable the layer. For that,
+ * use the setVisibility function instead..
*
* Parameters:
* display - {Boolean}
@@ -22965,2410 +9796,231 @@
CLASS_NAME: "OpenLayers.Layer"
});
/* ======================================================================
- OpenLayers/Marker/Box.js
+ OpenLayers/Layer/SphericalMercator.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
-
/**
- * @requires OpenLayers/Marker.js
+ * @requires OpenLayers/Layer.js
+ * @requires OpenLayers/Projection.js
*/
/**
- * Class: OpenLayers.Marker.Box
+ * Class: OpenLayers.Layer.SphericalMercator
+ * A mixin for layers that wraps up the pieces neccesary to have a coordinate
+ * conversion for working with commercial APIs which use a spherical
+ * mercator projection. Using this layer as a base layer, additional
+ * layers can be used as overlays if they are in the same projection.
*
- * Inherits from:
- * - <OpenLayers.Marker>
- */
-OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, {
-
- /**
- * Property: bounds
- * {<OpenLayers.Bounds>}
- */
- bounds: null,
-
- /**
- * Property: div
- * {DOMElement}
- */
- div: null,
-
- /**
- * Constructor: OpenLayers.Marker.Box
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * borderColor - {String}
- * borderWidth - {int}
- */
- initialize: function(bounds, borderColor, borderWidth) {
- this.bounds = bounds;
- this.div = OpenLayers.Util.createDiv();
- this.div.style.overflow = 'hidden';
- this.events = new OpenLayers.Events(this, this.div, null);
- this.setBorder(borderColor, borderWidth);
- },
-
- /**
- * Method: destroy
- */
- destroy: function() {
-
- this.bounds = null;
- this.div = null;
-
- OpenLayers.Marker.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: setBorder
- * Allow the user to change the box's color and border width
- *
- * Parameters:
- * color - {String} Default is "red"
- * width - {int} Default is 2
- */
- setBorder: function (color, width) {
- if (!color) {
- color = "red";
- }
- if (!width) {
- width = 2;
- }
- this.div.style.border = width + "px solid " + color;
- },
-
- /**
- * Method: draw
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- * sz - {<OpenLayers.Size>}
- *
- * Returns:
- * {DOMElement} A new DOM Image with this marker´s icon set at the
- * location passed-in
- */
- draw: function(px, sz) {
- OpenLayers.Util.modifyDOMElement(this.div, null, px, sz);
- return this.div;
- },
-
- /**
- * Method: onScreen
- *
- * Rreturn:
- * {Boolean} Whether or not the marker is currently visible on screen.
- */
- onScreen:function() {
- var onScreen = false;
- if (this.map) {
- var screenBounds = this.map.getExtent();
- onScreen = screenBounds.containsBounds(this.bounds, true, true);
- }
- return onScreen;
- },
-
- /**
- * Method: display
- * Hide or show the icon
- *
- * Parameters:
- * display - {Boolean}
- */
- display: function(display) {
- this.div.style.display = (display) ? "" : "none";
- },
-
- CLASS_NAME: "OpenLayers.Marker.Box"
-});
-
-/* ======================================================================
- OpenLayers/Request/XMLHttpRequest.js
- ====================================================================== */
-
-// XMLHttpRequest.js Copyright (C) 2010 Sergey Ilinsky (http://www.ilinsky.com)
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-/**
- * @requires OpenLayers/Request.js
- */
-
-(function () {
-
- // Save reference to earlier defined object implementation (if any)
- var oXMLHttpRequest = window.XMLHttpRequest;
-
- // Define on browser type
- var bGecko = !!window.controllers,
- bIE = window.document.all && !window.opera,
- bIE7 = bIE && window.navigator.userAgent.match(/MSIE ([\.0-9]+)/) && RegExp.$1 == 7;
-
- // Constructor
- function cXMLHttpRequest() {
- this._object = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP");
- this._listeners = [];
- };
-
- // BUGFIX: Firefox with Firebug installed would break pages if not executed
- if (bGecko && oXMLHttpRequest.wrapped)
- cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped;
-
- // Constants
- cXMLHttpRequest.UNSENT = 0;
- cXMLHttpRequest.OPENED = 1;
- cXMLHttpRequest.HEADERS_RECEIVED = 2;
- cXMLHttpRequest.LOADING = 3;
- cXMLHttpRequest.DONE = 4;
-
- // Public Properties
- cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT;
- cXMLHttpRequest.prototype.responseText = '';
- cXMLHttpRequest.prototype.responseXML = null;
- cXMLHttpRequest.prototype.status = 0;
- cXMLHttpRequest.prototype.statusText = '';
-
- // Instance-level Events Handlers
- cXMLHttpRequest.prototype.onreadystatechange = null;
-
- // Class-level Events Handlers
- cXMLHttpRequest.onreadystatechange = null;
- cXMLHttpRequest.onopen = null;
- cXMLHttpRequest.onsend = null;
- cXMLHttpRequest.onabort = null;
-
- // Public Methods
- cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) {
- // Delete headers, required when object is reused
- delete this._headers;
-
- // When bAsync parameter value is omitted, use true as default
- if (arguments.length < 3)
- bAsync = true;
-
- // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests
- this._async = bAsync;
-
- // Set the onreadystatechange handler
- var oRequest = this,
- nState = this.readyState,
- fOnUnload;
-
- // BUGFIX: IE - memory leak on page unload (inter-page leak)
- if (bIE && bAsync) {
- fOnUnload = function() {
- if (nState != cXMLHttpRequest.DONE) {
- fCleanTransport(oRequest);
- // Safe to abort here since onreadystatechange handler removed
- oRequest.abort();
- }
- };
- window.attachEvent("onunload", fOnUnload);
- }
-
- // Add method sniffer
- if (cXMLHttpRequest.onopen)
- cXMLHttpRequest.onopen.apply(this, arguments);
-
- if (arguments.length > 4)
- this._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
- else
- if (arguments.length > 3)
- this._object.open(sMethod, sUrl, bAsync, sUser);
- else
- this._object.open(sMethod, sUrl, bAsync);
-
- if (!bGecko && !bIE) {
- this.readyState = cXMLHttpRequest.OPENED;
- fReadyStateChange(this);
- }
-
- this._object.onreadystatechange = function() {
- if (bGecko && !bAsync)
- return;
-
- // Synchronize state
- oRequest.readyState = oRequest._object.readyState;
-
- //
- fSynchronizeValues(oRequest);
-
- // BUGFIX: Firefox fires unnecessary DONE when aborting
- if (oRequest._aborted) {
- // Reset readyState to UNSENT
- oRequest.readyState = cXMLHttpRequest.UNSENT;
-
- // Return now
- return;
- }
-
- if (oRequest.readyState == cXMLHttpRequest.DONE) {
- //
- fCleanTransport(oRequest);
-// Uncomment this block if you need a fix for IE cache
-/*
- // BUGFIX: IE - cache issue
- if (!oRequest._object.getResponseHeader("Date")) {
- // Save object to cache
- oRequest._cached = oRequest._object;
-
- // Instantiate a new transport object
- cXMLHttpRequest.call(oRequest);
-
- // Re-send request
- if (sUser) {
- if (sPassword)
- oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
- else
- oRequest._object.open(sMethod, sUrl, bAsync, sUser);
- }
- else
- oRequest._object.open(sMethod, sUrl, bAsync);
- oRequest._object.setRequestHeader("If-Modified-Since", oRequest._cached.getResponseHeader("Last-Modified") || new window.Date(0));
- // Copy headers set
- if (oRequest._headers)
- for (var sHeader in oRequest._headers)
- if (typeof oRequest._headers[sHeader] == "string") // Some frameworks prototype objects with functions
- oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]);
-
- oRequest._object.onreadystatechange = function() {
- // Synchronize state
- oRequest.readyState = oRequest._object.readyState;
-
- if (oRequest._aborted) {
- //
- oRequest.readyState = cXMLHttpRequest.UNSENT;
-
- // Return
- return;
- }
-
- if (oRequest.readyState == cXMLHttpRequest.DONE) {
- // Clean Object
- fCleanTransport(oRequest);
-
- // get cached request
- if (oRequest.status == 304)
- oRequest._object = oRequest._cached;
-
- //
- delete oRequest._cached;
-
- //
- fSynchronizeValues(oRequest);
-
- //
- fReadyStateChange(oRequest);
-
- // BUGFIX: IE - memory leak in interrupted
- if (bIE && bAsync)
- window.detachEvent("onunload", fOnUnload);
- }
- };
- oRequest._object.send(null);
-
- // Return now - wait until re-sent request is finished
- return;
- };
-*/
- // BUGFIX: IE - memory leak in interrupted
- if (bIE && bAsync)
- window.detachEvent("onunload", fOnUnload);
- }
-
- // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice
- if (nState != oRequest.readyState)
- fReadyStateChange(oRequest);
-
- nState = oRequest.readyState;
- }
- };
- cXMLHttpRequest.prototype.send = function(vData) {
- // Add method sniffer
- if (cXMLHttpRequest.onsend)
- cXMLHttpRequest.onsend.apply(this, arguments);
-
- // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required
- // BUGFIX: IE - rewrites any custom mime-type to "text/xml" in case an XMLNode is sent
- // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard)
- if (vData && vData.nodeType) {
- vData = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml;
- if (!this._headers["Content-Type"])
- this._object.setRequestHeader("Content-Type", "application/xml");
- }
-
- this._object.send(vData);
-
- // BUGFIX: Gecko - missing readystatechange calls in synchronous requests
- if (bGecko && !this._async) {
- this.readyState = cXMLHttpRequest.OPENED;
-
- // Synchronize state
- fSynchronizeValues(this);
-
- // Simulate missing states
- while (this.readyState < cXMLHttpRequest.DONE) {
- this.readyState++;
- fReadyStateChange(this);
- // Check if we are aborted
- if (this._aborted)
- return;
- }
- }
- };
- cXMLHttpRequest.prototype.abort = function() {
- // Add method sniffer
- if (cXMLHttpRequest.onabort)
- cXMLHttpRequest.onabort.apply(this, arguments);
-
- // BUGFIX: Gecko - unnecessary DONE when aborting
- if (this.readyState > cXMLHttpRequest.UNSENT)
- this._aborted = true;
-
- this._object.abort();
-
- // BUGFIX: IE - memory leak
- fCleanTransport(this);
- };
- cXMLHttpRequest.prototype.getAllResponseHeaders = function() {
- return this._object.getAllResponseHeaders();
- };
- cXMLHttpRequest.prototype.getResponseHeader = function(sName) {
- return this._object.getResponseHeader(sName);
- };
- cXMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) {
- // BUGFIX: IE - cache issue
- if (!this._headers)
- this._headers = {};
- this._headers[sName] = sValue;
-
- return this._object.setRequestHeader(sName, sValue);
- };
-
- // EventTarget interface implementation
- cXMLHttpRequest.prototype.addEventListener = function(sName, fHandler, bUseCapture) {
- for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)
- if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)
- return;
- // Add listener
- this._listeners.push([sName, fHandler, bUseCapture]);
- };
-
- cXMLHttpRequest.prototype.removeEventListener = function(sName, fHandler, bUseCapture) {
- for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)
- if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)
- break;
- // Remove listener
- if (oListener)
- this._listeners.splice(nIndex, 1);
- };
-
- cXMLHttpRequest.prototype.dispatchEvent = function(oEvent) {
- var oEventPseudo = {
- 'type': oEvent.type,
- 'target': this,
- 'currentTarget':this,
- 'eventPhase': 2,
- 'bubbles': oEvent.bubbles,
- 'cancelable': oEvent.cancelable,
- 'timeStamp': oEvent.timeStamp,
- 'stopPropagation': function() {}, // There is no flow
- 'preventDefault': function() {}, // There is no default action
- 'initEvent': function() {} // Original event object should be initialized
- };
-
- // Execute onreadystatechange
- if (oEventPseudo.type == "readystatechange" && this.onreadystatechange)
- (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]);
-
- // Execute listeners
- for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)
- if (oListener[0] == oEventPseudo.type && !oListener[2])
- (oListener[1].handleEvent || oListener[1]).apply(this, [oEventPseudo]);
- };
-
- //
- cXMLHttpRequest.prototype.toString = function() {
- return '[' + "object" + ' ' + "XMLHttpRequest" + ']';
- };
-
- cXMLHttpRequest.toString = function() {
- return '[' + "XMLHttpRequest" + ']';
- };
-
- // Helper function
- function fReadyStateChange(oRequest) {
- // Sniffing code
- if (cXMLHttpRequest.onreadystatechange)
- cXMLHttpRequest.onreadystatechange.apply(oRequest);
-
- // Fake event
- oRequest.dispatchEvent({
- 'type': "readystatechange",
- 'bubbles': false,
- 'cancelable': false,
- 'timeStamp': new Date + 0
- });
- };
-
- function fGetDocument(oRequest) {
- var oDocument = oRequest.responseXML,
- sResponse = oRequest.responseText;
- // Try parsing responseText
- if (bIE && sResponse && oDocument && !oDocument.documentElement && oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)) {
- oDocument = new window.ActiveXObject("Microsoft.XMLDOM");
- oDocument.async = false;
- oDocument.validateOnParse = false;
- oDocument.loadXML(sResponse);
- }
- // Check if there is no error in document
- if (oDocument)
- if ((bIE && oDocument.parseError != 0) || !oDocument.documentElement || (oDocument.documentElement && oDocument.documentElement.tagName == "parsererror"))
- return null;
- return oDocument;
- };
-
- function fSynchronizeValues(oRequest) {
- try { oRequest.responseText = oRequest._object.responseText; } catch (e) {}
- try { oRequest.responseXML = fGetDocument(oRequest._object); } catch (e) {}
- try { oRequest.status = oRequest._object.status; } catch (e) {}
- try { oRequest.statusText = oRequest._object.statusText; } catch (e) {}
- };
-
- function fCleanTransport(oRequest) {
- // BUGFIX: IE - memory leak (on-page leak)
- oRequest._object.onreadystatechange = new window.Function;
- };
-
- // Internet Explorer 5.0 (missing apply)
- if (!window.Function.prototype.apply) {
- window.Function.prototype.apply = function(oRequest, oArguments) {
- if (!oArguments)
- oArguments = [];
- oRequest.__func = this;
- oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]);
- delete oRequest.__func;
- };
- };
-
- // Register new object with window
- /**
- * Class: OpenLayers.Request.XMLHttpRequest
- * Standard-compliant (W3C) cross-browser implementation of the
- * XMLHttpRequest object. From
- * http://code.google.com/p/xmlhttprequest/.
- */
- OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest;
-})();
-/* ======================================================================
- OpenLayers/Ajax.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Request/XMLHttpRequest.js
- * @requires OpenLayers/Console.js
- */
-
-OpenLayers.ProxyHost = "";
-//OpenLayers.ProxyHost = "examples/proxy.cgi?url=";
-
-/**
- * Ajax reader for OpenLayers
+ * A layer is given properties of this object by setting the sphericalMercator
+ * property to true.
*
- * @uri url to do remote XML http get
- * @param {String} 'get' format params (x=y&a=b...)
- * @who object to handle callbacks for this request
- * @complete the function to be called on success
- * @failure the function to be called on failure
- *
- * example usage from a caller:
- *
- * caps: function(request) {
- * -blah-
- * },
- *
- * OpenLayers.loadURL(url,params,this,caps);
+ * More projection information:
+ * - http://spatialreference.org/ref/user/google-projection/
*
- * Notice the above example does not provide an error handler; a default empty
- * handler is provided which merely logs the error if a failure handler is not
- * supplied
+ * Proj4 Text:
+ * +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0
+ * +k=1.0 +units=m +nadgrids=@null +no_defs
*
+ * WKT:
+ * 900913=PROJCS["WGS84 / Simple Mercator", GEOGCS["WGS 84",
+ * DATUM["WGS_1984", SPHEROID["WGS_1984", 6378137.0, 298.257223563]],
+ * PRIMEM["Greenwich", 0.0], UNIT["degree", 0.017453292519943295],
+ * AXIS["Longitude", EAST], AXIS["Latitude", NORTH]],
+ * PROJECTION["Mercator_1SP_Google"],
+ * PARAMETER["latitude_of_origin", 0.0], PARAMETER["central_meridian", 0.0],
+ * PARAMETER["scale_factor", 1.0], PARAMETER["false_easting", 0.0],
+ * PARAMETER["false_northing", 0.0], UNIT["m", 1.0], AXIS["x", EAST],
+ * AXIS["y", NORTH], AUTHORITY["EPSG","900913"]]
*/
+OpenLayers.Layer.SphericalMercator = {
-
-/**
- * Function: OpenLayers.nullHandler
- * @param {} request
- */
-OpenLayers.nullHandler = function(request) {
- OpenLayers.Console.userError(OpenLayers.i18n("unhandledRequest", {'statusText':request.statusText}));
-};
-
-/**
- * APIFunction: OpenLayers.loadURL
- * Background load a document. For more flexibility in using XMLHttpRequest,
- * see the <OpenLayers.Request> methods.
- *
- * Parameters:
- * uri - {String} URI of source doc
- * params - {String} or {Object} GET params. Either a string in the form
- * "?hello=world&foo=bar" (do not forget the leading question mark)
- * or an object in the form {'hello': 'world', 'foo': 'bar}
- * caller - {Object} object which gets callbacks
- * onComplete - {Function} Optional callback for success. The callback
- * will be called with this set to caller and will receive the request
- * object as an argument. Note that if you do not specify an onComplete
- * function, <OpenLayers.nullHandler> will be called (which pops up a
- * user friendly error message dialog).
- * onFailure - {Function} Optional callback for failure. In the event of
- * a failure, the callback will be called with this set to caller and will
- * receive the request object as an argument. Note that if you do not
- * specify an onComplete function, <OpenLayers.nullHandler> will be called
- * (which pops up a user friendly error message dialog).
- *
- * Returns:
- * {<OpenLayers.Request.XMLHttpRequest>} The request object. To abort loading,
- * call request.abort().
- */
-OpenLayers.loadURL = function(uri, params, caller,
- onComplete, onFailure) {
-
- if(typeof params == 'string') {
- params = OpenLayers.Util.getParameters(params);
- }
- var success = (onComplete) ? onComplete : OpenLayers.nullHandler;
- var failure = (onFailure) ? onFailure : OpenLayers.nullHandler;
-
- return OpenLayers.Request.GET({
- url: uri, params: params,
- success: success, failure: failure, scope: caller
- });
-};
-
-/**
- * Function: OpenLayers.parseXMLString
- * Parse XML into a doc structure
- *
- * Parameters:
- * text - {String}
- *
- * Returns:
- * {?} Parsed AJAX Responsev
- */
-OpenLayers.parseXMLString = function(text) {
-
- //MS sucks, if the server is bad it dies
- var index = text.indexOf('<');
- if (index > 0) {
- text = text.substring(index);
- }
-
- var ajaxResponse = OpenLayers.Util.Try(
- function() {
- var xmldom = new ActiveXObject('Microsoft.XMLDOM');
- xmldom.loadXML(text);
- return xmldom;
- },
- function() {
- return new DOMParser().parseFromString(text, 'text/xml');
- },
- function() {
- var req = new XMLHttpRequest();
- req.open("GET", "data:" + "text/xml" +
- ";charset=utf-8," + encodeURIComponent(text), false);
- if (req.overrideMimeType) {
- req.overrideMimeType("text/xml");
- }
- req.send(null);
- return req.responseXML;
- }
- );
-
- return ajaxResponse;
-};
-
-
-/**
- * Namespace: OpenLayers.Ajax
- */
-OpenLayers.Ajax = {
-
/**
- * Method: emptyFunction
- */
- emptyFunction: function () {},
-
- /**
- * Method: getTransport
- *
- * Returns:
- * {Object} Transport mechanism for whichever browser we're in, or false if
- * none available.
- */
- getTransport: function() {
- return OpenLayers.Util.Try(
- function() {return new XMLHttpRequest();},
- function() {return new ActiveXObject('Msxml2.XMLHTTP');},
- function() {return new ActiveXObject('Microsoft.XMLHTTP');}
- ) || false;
- },
-
- /**
- * Property: activeRequestCount
- * {Integer}
- */
- activeRequestCount: 0
-};
-
-/**
- * Namespace: OpenLayers.Ajax.Responders
- * {Object}
- */
-OpenLayers.Ajax.Responders = {
-
- /**
- * Property: responders
- * {Array}
- */
- responders: [],
-
- /**
- * Method: register
- *
- * Parameters:
- * responderToAdd - {?}
- */
- register: function(responderToAdd) {
- for (var i = 0; i < this.responders.length; i++){
- if (responderToAdd == this.responders[i]){
- return;
- }
- }
- this.responders.push(responderToAdd);
- },
-
- /**
- * Method: unregister
- *
- * Parameters:
- * responderToRemove - {?}
- */
- unregister: function(responderToRemove) {
- OpenLayers.Util.removeItem(this.reponders, responderToRemove);
- },
-
- /**
- * Method: dispatch
- *
- * Parameters:
- * callback - {?}
- * request - {?}
- * transport - {?}
- */
- dispatch: function(callback, request, transport) {
- var responder;
- for (var i = 0; i < this.responders.length; i++) {
- responder = this.responders[i];
-
- if (responder[callback] &&
- typeof responder[callback] == 'function') {
- try {
- responder[callback].apply(responder,
- [request, transport]);
- } catch (e) {}
- }
- }
- }
-};
-
-OpenLayers.Ajax.Responders.register({
- /**
- * Function: onCreate
- */
- onCreate: function() {
- OpenLayers.Ajax.activeRequestCount++;
- },
-
- /**
- * Function: onComplete
- */
- onComplete: function() {
- OpenLayers.Ajax.activeRequestCount--;
- }
-});
-
-/**
- * Class: OpenLayers.Ajax.Base
- */
-OpenLayers.Ajax.Base = OpenLayers.Class({
-
- /**
- * Constructor: OpenLayers.Ajax.Base
- *
- * Parameters:
- * options - {Object}
- */
- initialize: function(options) {
- this.options = {
- method: 'post',
- asynchronous: true,
- contentType: 'application/xml',
- parameters: ''
- };
- OpenLayers.Util.extend(this.options, options || {});
-
- this.options.method = this.options.method.toLowerCase();
-
- if (typeof this.options.parameters == 'string') {
- this.options.parameters =
- OpenLayers.Util.getParameters(this.options.parameters);
- }
- }
-});
-
-/**
- * Class: OpenLayers.Ajax.Request
- * *Deprecated*. Use <OpenLayers.Request> method instead.
- *
- * Inherit:
- * - <OpenLayers.Ajax.Base>
- */
-OpenLayers.Ajax.Request = OpenLayers.Class(OpenLayers.Ajax.Base, {
-
- /**
- * Property: _complete
+ * Method: getExtent
+ * Get the map's extent.
*
- * {Boolean}
+ * Returns:
+ * {<OpenLayers.Bounds>} The map extent.
*/
- _complete: false,
-
- /**
- * Constructor: OpenLayers.Ajax.Request
- *
- * Parameters:
- * url - {String}
- * options - {Object}
- */
- initialize: function(url, options) {
- OpenLayers.Ajax.Base.prototype.initialize.apply(this, [options]);
-
- if (OpenLayers.ProxyHost && OpenLayers.String.startsWith(url, "http")) {
- url = OpenLayers.ProxyHost + encodeURIComponent(url);
+ getExtent: function() {
+ var extent = null;
+ if (this.sphericalMercator) {
+ extent = this.map.calculateBounds();
+ } else {
+ extent = OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this);
}
-
- this.transport = OpenLayers.Ajax.getTransport();
- this.request(url);
+ return extent;
},
/**
- * Method: request
+ * Method: getLonLatFromViewPortPx
+ * Get a map location from a pixel location
*
* Parameters:
- * url - {String}
- */
- request: function(url) {
- this.url = url;
- this.method = this.options.method;
- var params = OpenLayers.Util.extend({}, this.options.parameters);
-
- if (this.method != 'get' && this.method != 'post') {
- // simulate other verbs over post
- params['_method'] = this.method;
- this.method = 'post';
- }
-
- this.parameters = params;
-
- if (params = OpenLayers.Util.getParameterString(params)) {
- // when GET, append parameters to URL
- if (this.method == 'get') {
- this.url += ((this.url.indexOf('?') > -1) ? '&' : '?') + params;
- } else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
- params += '&_=';
- }
- }
- try {
- var response = new OpenLayers.Ajax.Response(this);
- if (this.options.onCreate) {
- this.options.onCreate(response);
- }
-
- OpenLayers.Ajax.Responders.dispatch('onCreate',
- this,
- response);
-
- this.transport.open(this.method.toUpperCase(),
- this.url,
- this.options.asynchronous);
-
- if (this.options.asynchronous) {
- window.setTimeout(
- OpenLayers.Function.bind(this.respondToReadyState, this, 1),
- 10);
- }
-
- this.transport.onreadystatechange =
- OpenLayers.Function.bind(this.onStateChange, this);
- this.setRequestHeaders();
-
- this.body = this.method == 'post' ?
- (this.options.postBody || params) : null;
- this.transport.send(this.body);
-
- // Force Firefox to handle ready state 4 for synchronous requests
- if (!this.options.asynchronous &&
- this.transport.overrideMimeType) {
- this.onStateChange();
- }
- } catch (e) {
- this.dispatchException(e);
- }
- },
-
- /**
- * Method: onStateChange
- */
- onStateChange: function() {
- var readyState = this.transport.readyState;
- if (readyState > 1 && !((readyState == 4) && this._complete)) {
- this.respondToReadyState(this.transport.readyState);
- }
- },
-
- /**
- * Method: setRequestHeaders
- */
- setRequestHeaders: function() {
- var headers = {
- 'X-Requested-With': 'XMLHttpRequest',
- 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*',
- 'OpenLayers': true
- };
-
- if (this.method == 'post') {
- headers['Content-type'] = this.options.contentType +
- (this.options.encoding ? '; charset=' + this.options.encoding : '');
-
- /* Force "Connection: close" for older Mozilla browsers to work
- * around a bug where XMLHttpRequest sends an incorrect
- * Content-length header. See Mozilla Bugzilla #246651.
- */
- if (this.transport.overrideMimeType &&
- (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) {
- headers['Connection'] = 'close';
- }
- }
- // user-defined headers
- if (typeof this.options.requestHeaders == 'object') {
- var extras = this.options.requestHeaders;
-
- if (typeof extras.push == 'function') {
- for (var i = 0, length = extras.length; i < length; i += 2) {
- headers[extras[i]] = extras[i+1];
- }
- } else {
- for (var i in extras) {
- headers[i] = extras[i];
- }
- }
- }
-
- for (var name in headers) {
- this.transport.setRequestHeader(name, headers[name]);
- }
- },
-
- /**
- * Method: success
+ * viewPortPx - {<OpenLayers.Pixel>}
*
* Returns:
- * {Boolean} -
+ * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view
+ * port OpenLayers.Pixel, translated into lon/lat by map lib
+ * If the map lib is not loaded or not centered, returns null
*/
- success: function() {
- var status = this.getStatus();
- return !status || (status >=200 && status < 300);
+ getLonLatFromViewPortPx: function (viewPortPx) {
+ return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this, arguments);
},
/**
- * Method: getStatus
+ * Method: getViewPortPxFromLonLat
+ * Get a pixel location from a map location
*
- * Returns:
- * {Integer} - Status
- */
- getStatus: function() {
- try {
- return this.transport.status || 0;
- } catch (e) {
- return 0;
- }
- },
-
- /**
- * Method: respondToReadyState
- *
* Parameters:
- * readyState - {?}
- */
- respondToReadyState: function(readyState) {
- var state = OpenLayers.Ajax.Request.Events[readyState];
- var response = new OpenLayers.Ajax.Response(this);
-
- if (state == 'Complete') {
- try {
- this._complete = true;
- (this.options['on' + response.status] ||
- this.options['on' + (this.success() ? 'Success' : 'Failure')] ||
- OpenLayers.Ajax.emptyFunction)(response);
- } catch (e) {
- this.dispatchException(e);
- }
-
- var contentType = response.getHeader('Content-type');
- }
-
- try {
- (this.options['on' + state] ||
- OpenLayers.Ajax.emptyFunction)(response);
- OpenLayers.Ajax.Responders.dispatch('on' + state,
- this,
- response);
- } catch (e) {
- this.dispatchException(e);
- }
-
- if (state == 'Complete') {
- // avoid memory leak in MSIE: clean up
- this.transport.onreadystatechange = OpenLayers.Ajax.emptyFunction;
- }
- },
-
- /**
- * Method: getHeader
- *
- * Parameters:
- * name - {String} Header name
+ * lonlat - {<OpenLayers.LonLat>}
*
* Returns:
- * {?} - response header for the given name
+ * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
+ * OpenLayers.LonLat, translated into view port pixels by map lib
+ * If map lib is not loaded or not centered, returns null
*/
- getHeader: function(name) {
- try {
- return this.transport.getResponseHeader(name);
- } catch (e) {
- return null;
- }
+ getViewPortPxFromLonLat: function (lonlat) {
+ return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this, arguments);
},
- /**
- * Method: dispatchException
- * If the optional onException function is set, execute it
- * and then dispatch the call to any other listener registered
- * for onException.
- *
- * If no optional onException function is set, we suspect that
- * the user may have also not used
- * OpenLayers.Ajax.Responders.register to register a listener
- * for the onException call. To make sure that something
- * gets done with this exception, only dispatch the call if there
- * are listeners.
- *
- * If you explicitly want to swallow exceptions, set
- * request.options.onException to an empty function (function(){})
- * or register an empty function with <OpenLayers.Ajax.Responders>
- * for onException.
- *
- * Parameters:
- * exception - {?}
+ /**
+ * Method: initMercatorParameters
+ * Set up the mercator parameters on the layer: resolutions,
+ * projection, units.
*/
- dispatchException: function(exception) {
- var handler = this.options.onException;
- if(handler) {
- // call options.onException and alert any other listeners
- handler(this, exception);
- OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
- } else {
- // check if there are any other listeners
- var listener = false;
- var responders = OpenLayers.Ajax.Responders.responders;
- for (var i = 0; i < responders.length; i++) {
- if(responders[i].onException) {
- listener = true;
- break;
- }
- }
- if(listener) {
- // call all listeners
- OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
- } else {
- // let the exception through
- throw exception;
- }
+ initMercatorParameters: function() {
+ // set up properties for Mercator - assume EPSG:900913
+ this.RESOLUTIONS = [];
+ var maxResolution = 156543.0339;
+ for(var zoom=0; zoom<=this.MAX_ZOOM_LEVEL; ++zoom) {
+ this.RESOLUTIONS[zoom] = maxResolution / Math.pow(2, zoom);
}
- }
-});
-
-/**
- * Property: Events
- * {Array(String)}
- */
-OpenLayers.Ajax.Request.Events =
- ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
-
-/**
- * Class: OpenLayers.Ajax.Response
- */
-OpenLayers.Ajax.Response = OpenLayers.Class({
-
- /**
- * Property: status
- *
- * {Integer}
- */
- status: 0,
-
-
- /**
- * Property: statusText
- *
- * {String}
- */
- statusText: '',
-
- /**
- * Constructor: OpenLayers.Ajax.Response
- *
- * Parameters:
- * request - {Object}
- */
- initialize: function(request) {
- this.request = request;
- var transport = this.transport = request.transport,
- readyState = this.readyState = transport.readyState;
-
- if ((readyState > 2 &&
- !(!!(window.attachEvent && !window.opera))) ||
- readyState == 4) {
- this.status = this.getStatus();
- this.statusText = this.getStatusText();
- this.responseText = transport.responseText == null ?
- '' : String(transport.responseText);
- }
-
- if(readyState == 4) {
- var xml = transport.responseXML;
- this.responseXML = xml === undefined ? null : xml;
- }
+ this.units = "m";
+ this.projection = this.projection || "EPSG:900913";
},
-
- /**
- * Method: getStatus
- */
- getStatus: OpenLayers.Ajax.Request.prototype.getStatus,
-
- /**
- * Method: getStatustext
- *
- * Returns:
- * {String} - statusText
- */
- getStatusText: function() {
- try {
- return this.transport.statusText || '';
- } catch (e) {
- return '';
- }
- },
-
- /**
- * Method: getHeader
- */
- getHeader: OpenLayers.Ajax.Request.prototype.getHeader,
-
- /**
- * Method: getResponseHeader
- *
- * Returns:
- * {?} - response header for given name
- */
- getResponseHeader: function(name) {
- return this.transport.getResponseHeader(name);
- }
-});
-
-/**
- * Function: getElementsByTagNameNS
- *
- * Parameters:
- * parentnode - {?}
- * nsuri - {?}
- * nsprefix - {?}
- * tagname - {?}
- *
- * Returns:
- * {?}
- */
-OpenLayers.Ajax.getElementsByTagNameNS = function(parentnode, nsuri,
- nsprefix, tagname) {
- var elem = null;
- if (parentnode.getElementsByTagNameNS) {
- elem = parentnode.getElementsByTagNameNS(nsuri, tagname);
- } else {
- elem = parentnode.getElementsByTagName(nsprefix + ':' + tagname);
- }
- return elem;
-};
-
-
-/**
- * Function: serializeXMLToString
- * Wrapper function around XMLSerializer, which doesn't exist/work in
- * IE/Safari. We need to come up with a way to serialize in those browser:
- * for now, these browsers will just fail. #535, #536
- *
- * Parameters:
- * xmldom {XMLNode} xml dom to serialize
- *
- * Returns:
- * {?}
- */
-OpenLayers.Ajax.serializeXMLToString = function(xmldom) {
- var serializer = new XMLSerializer();
- var data = serializer.serializeToString(xmldom);
- return data;
-};
-/* ======================================================================
- OpenLayers/Control/DragPan.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/Handler/Drag.js
- */
-
-/**
- * Class: OpenLayers.Control.DragPan
- * The DragPan control pans the map with a drag of the mouse.
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * Property: type
- * {OpenLayers.Control.TYPES}
- */
- type: OpenLayers.Control.TYPE_TOOL,
-
/**
- * Property: panned
- * {Boolean} The map moved.
- */
- panned: false,
-
- /**
- * Property: interval
- * {Integer} The number of milliseconds that should ellapse before
- * panning the map again. Set this to increase dragging performance.
- * Defaults to 25 milliseconds.
- */
- interval: 25,
-
- /**
- * APIProperty: documentDrag
- * {Boolean} If set to true, mouse dragging will continue even if the
- * mouse cursor leaves the map viewport. Default is false.
- */
- documentDrag: false,
-
- /**
- * Method: draw
- * Creates a Drag handler, using <panMap> and
- * <panMapDone> as callbacks.
- */
- draw: function() {
- this.handler = new OpenLayers.Handler.Drag(this, {
- "move": this.panMap,
- "done": this.panMapDone
- }, {
- interval: this.interval,
- documentDrag: this.documentDrag
- }
- );
- },
-
- /**
- * Method: panMap
- *
- * Parameters:
- * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
- */
- panMap: function(xy) {
- this.panned = true;
- this.map.pan(
- this.handler.last.x - xy.x,
- this.handler.last.y - xy.y,
- {dragging: this.handler.dragging, animate: false}
- );
- },
-
- /**
- * Method: panMapDone
- * Finish the panning operation. Only call setCenter (through <panMap>)
- * if the map has actually been moved.
+ * APIMethod: forwardMercator
+ * Given a lon,lat in EPSG:4326, return a point in Spherical Mercator.
*
* Parameters:
- * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
- */
- panMapDone: function(xy) {
- if(this.panned) {
- this.panMap(xy);
- this.panned = false;
- }
- },
-
- CLASS_NAME: "OpenLayers.Control.DragPan"
-});
-/* ======================================================================
- OpenLayers/Feature/Vector.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-// TRASH THIS
-OpenLayers.State = {
- /** states */
- UNKNOWN: 'Unknown',
- INSERT: 'Insert',
- UPDATE: 'Update',
- DELETE: 'Delete'
-};
-
-/**
- * @requires OpenLayers/Feature.js
- * @requires OpenLayers/Util.js
- */
-
-/**
- * Class: OpenLayers.Feature.Vector
- * Vector features use the OpenLayers.Geometry classes as geometry description.
- * They have an 'attributes' property, which is the data object, and a 'style'
- * property, the default values of which are defined in the
- * <OpenLayers.Feature.Vector.style> objects.
- *
- * Inherits from:
- * - <OpenLayers.Feature>
- */
-OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, {
-
- /**
- * Property: fid
- * {String}
- */
- fid: null,
-
- /**
- * APIProperty: geometry
- * {<OpenLayers.Geometry>}
- */
- geometry: null,
-
- /**
- * APIProperty: attributes
- * {Object} This object holds arbitrary, serializable properties that
- * describe the feature.
- */
- attributes: null,
-
- /**
- * Property: bounds
- * {<OpenLayers.Bounds>} The box bounding that feature's geometry, that
- * property can be set by an <OpenLayers.Format> object when
- * deserializing the feature, so in most cases it represents an
- * information set by the server.
- */
- bounds: null,
-
- /**
- * Property: state
- * {String}
- */
- state: null,
-
- /**
- * APIProperty: style
- * {Object}
- */
- style: null,
-
- /**
- * APIProperty: url
- * {String} If this property is set it will be taken into account by
- * {<OpenLayers.HTTP>} when upadting or deleting the feature.
- */
- url: null,
-
- /**
- * Property: renderIntent
- * {String} rendering intent currently being used
- */
- renderIntent: "default",
-
- /**
- * Constructor: OpenLayers.Feature.Vector
- * Create a vector feature.
+ * lon - {float}
+ * lat - {float}
*
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} The geometry that this feature
- * represents.
- * attributes - {Object} An optional object that will be mapped to the
- * <attributes> property.
- * style - {Object} An optional style object.
- */
- initialize: function(geometry, attributes, style) {
- OpenLayers.Feature.prototype.initialize.apply(this,
- [null, null, attributes]);
- this.lonlat = null;
- this.geometry = geometry ? geometry : null;
- this.state = null;
- this.attributes = {};
- if (attributes) {
- this.attributes = OpenLayers.Util.extend(this.attributes,
- attributes);
- }
- this.style = style ? style : null;
- },
-
- /**
- * Method: destroy
- * nullify references to prevent circular references and memory leaks
- */
- destroy: function() {
- if (this.layer) {
- this.layer.removeFeatures(this);
- this.layer = null;
- }
-
- this.geometry = null;
- OpenLayers.Feature.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: clone
- * Create a clone of this vector feature. Does not set any non-standard
- * properties.
- *
* Returns:
- * {<OpenLayers.Feature.Vector>} An exact clone of this vector feature.
+ * {<OpenLayers.LonLat>} The coordinates transformed to Mercator.
*/
- clone: function () {
- return new OpenLayers.Feature.Vector(
- this.geometry ? this.geometry.clone() : null,
- this.attributes,
- this.style);
+ forwardMercator: function(lon, lat) {
+ var x = lon * 20037508.34 / 180;
+ var y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
+
+ y = y * 20037508.34 / 180;
+
+ return new OpenLayers.LonLat(x, y);
},
/**
- * 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.
+ * APIMethod: inverseMercator
+ * Given a x,y in Spherical Mercator, return a point in EPSG:4326.
*
* 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.
+ * x - {float} A map x in Spherical Mercator.
+ * y - {float} A map y in Spherical Mercator.
*
* Returns:
- * {Boolean} The feature is currently visible on screen (optionally
- * based on its bounds if boundsOnly is true).
+ * {<OpenLayers.LonLat>} The coordinates transformed to EPSG:4326.
*/
- 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;
- },
+ inverseMercator: function(x, y) {
- /**
- * Method: getVisibility
- * Determine whether the feature is displayed or not. It may not displayed
- * because:
- * - its style display property is set to 'none',
- * - it doesn't belong to any layer,
- * - the styleMap creates a symbolizer with display property set to 'none'
- * for it,
- * - the layer which it belongs to is not visible.
- *
- * Returns:
- * {Boolean} The feature is currently displayed.
- */
- getVisibility: function() {
- return !(this.style && this.style.display == 'none' ||
- !this.layer ||
- this.layer && this.layer.styleMap &&
- this.layer.styleMap.createSymbolizer(this, this.renderIntent).display == 'none' ||
- this.layer && !this.layer.getVisibility());
- },
-
- /**
- * Method: createMarker
- * HACK - we need to decide if all vector features should be able to
- * create markers
- *
- * Returns:
- * {<OpenLayers.Marker>} For now just returns null
- */
- createMarker: function() {
- return null;
- },
+ var lon = (x / 20037508.34) * 180;
+ var lat = (y / 20037508.34) * 180;
- /**
- * 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
+ lat = 180/Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);
+
+ return new OpenLayers.LonLat(lon, lat);
},
/**
- * Method: createPopup
- * HACK - we need to decide if all vector features should be able to
- * create popups
+ * Method: projectForward
+ * Given an object with x and y properties in EPSG:4326, modify the x,y
+ * properties on the object to be the Spherical Mercator projected
+ * coordinates.
+ *
+ * Parameters:
+ * point - {Object} An object with x and y properties.
*
* Returns:
- * {<OpenLayers.Popup>} For now just returns null
+ * {Object} The point, with the x and y properties transformed to spherical
+ * mercator.
*/
- createPopup: function() {
- return null;
+ projectForward: function(point) {
+ var lonlat = OpenLayers.Layer.SphericalMercator.forwardMercator(point.x, point.y);
+ point.x = lonlat.lon;
+ point.y = lonlat.lat;
+ return point;
},
-
- /**
- * Method: atPoint
- * Determins whether the feature intersects with the specified location.
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>}
- * 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:
- * state - {OpenLayers.LonLat or OpenLayers.Pixel} the
- * location to which to move the feature.
- */
- move: function(location) {
-
- if(!this.layer || !this.geometry.move){
- //do nothing if no layer or immoveable geometry
- return;
- }
-
- 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
+ * Method: projectInverse
+ * Given an object with x and y properties in Spherical Mercator, modify
+ * the x,y properties on the object to be the unprojected coordinates.
*
* 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 for an external graphic. Only supported in Firefox and Internet Explorer.
- * 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". The canvas renderer does not
- * support vertical alignment, it will always use "b".
- * labelXOffset - {Number} Pixel offset along the positive x axis for displacing the label.
- * labelYOffset - {Number} Pixel offset along the positive y axis for displacing the label.
- * labelSelect - {Boolean} If set to true, labels will be selectable using SelectFeature or similar controls.
- * Default is false.
- * 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.
- * 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"
- },
- '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"
- },
- '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"
- },
- 'delete': {
- display: "none"
- }
-};
-/* ======================================================================
- OpenLayers/Handler/Box.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Handler.js
- * @requires OpenLayers/Handler/Drag.js
- */
-
-/**
- * Class: OpenLayers.Handler.Box
- * Handler for dragging a rectangle across the map. Box is displayed
- * on mouse down, moves on mouse move, and is finished on mouse up.
- *
- * Inherits from:
- * - <OpenLayers.Handler>
- */
-OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, {
-
- /**
- * Property: dragHandler
- * {<OpenLayers.Handler.Drag>}
- */
- dragHandler: null,
-
- /**
- * APIProperty: boxDivClassName
- * {String} The CSS class to use for drawing the box. Default is
- * olHandlerBoxZoomBox
- */
- boxDivClassName: 'olHandlerBoxZoomBox',
-
- /**
- * Property: boxCharacteristics
- * {Object} Caches some box characteristics from css. This is used
- * by the getBoxCharacteristics method.
- */
- boxCharacteristics: null,
-
- /**
- * Constructor: OpenLayers.Handler.Box
- *
- * Parameters:
- * control - {<OpenLayers.Control>}
- * callbacks - {Object} An object containing a single function to be
- * called when the drag operation is finished.
- * The callback should expect to recieve a single
- * argument, the point geometry.
- * options - {Object}
- */
- initialize: function(control, callbacks, options) {
- OpenLayers.Handler.prototype.initialize.apply(this, arguments);
- var callbacks = {
- "down": this.startBox,
- "move": this.moveBox,
- "out": this.removeBox,
- "up": this.endBox
- };
- this.dragHandler = new OpenLayers.Handler.Drag(
- this, callbacks, {keyMask: this.keyMask});
- },
-
- /**
- * Method: destroy
- */
- destroy: function() {
- if (this.dragHandler) {
- this.dragHandler.destroy();
- this.dragHandler = null;
- }
- OpenLayers.Handler.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: setMap
- */
- setMap: function (map) {
- OpenLayers.Handler.prototype.setMap.apply(this, arguments);
- if (this.dragHandler) {
- this.dragHandler.setMap(map);
- }
- },
-
- /**
- * Method: startBox
- *
- * Parameters:
- * evt - {Event}
- */
- startBox: function (xy) {
- this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
- this.dragHandler.start);
- this.zoomBox.className = this.boxDivClassName;
- this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
- this.map.viewPortDiv.appendChild(this.zoomBox);
-
- OpenLayers.Element.addClass(
- this.map.viewPortDiv, "olDrawBox"
- );
- },
-
- /**
- * Method: moveBox
- */
- moveBox: function (xy) {
- var startX = this.dragHandler.start.x;
- var startY = this.dragHandler.start.y;
- var deltaX = Math.abs(startX - xy.x);
- var deltaY = Math.abs(startY - xy.y);
- this.zoomBox.style.width = Math.max(1, deltaX) + "px";
- this.zoomBox.style.height = Math.max(1, deltaY) + "px";
- this.zoomBox.style.left = xy.x < startX ? xy.x+"px" : startX+"px";
- this.zoomBox.style.top = xy.y < startY ? xy.y+"px" : startY+"px";
-
- // depending on the box model, modify width and height to take borders
- // of the box into account
- var box = this.getBoxCharacteristics();
- if (box.newBoxModel) {
- if (xy.x > startX) {
- this.zoomBox.style.width =
- Math.max(1, deltaX - box.xOffset) + "px";
- }
- if (xy.y > startY) {
- this.zoomBox.style.height =
- Math.max(1, deltaY - box.yOffset) + "px";
- }
- }
- },
-
- /**
- * Method: endBox
- */
- endBox: function(end) {
- var result;
- if (Math.abs(this.dragHandler.start.x - end.x) > 5 ||
- Math.abs(this.dragHandler.start.y - end.y) > 5) {
- var start = this.dragHandler.start;
- var top = Math.min(start.y, end.y);
- var bottom = Math.max(start.y, end.y);
- var left = Math.min(start.x, end.x);
- var right = Math.max(start.x, end.x);
- result = new OpenLayers.Bounds(left, bottom, right, top);
- } else {
- result = this.dragHandler.start.clone(); // i.e. OL.Pixel
- }
- this.removeBox();
-
- this.callback("done", [result]);
- },
-
- /**
- * Method: removeBox
- * Remove the zoombox from the screen and nullify our reference to it.
- */
- removeBox: function() {
- this.map.viewPortDiv.removeChild(this.zoomBox);
- this.zoomBox = null;
- this.boxCharacteristics = null;
- OpenLayers.Element.removeClass(
- this.map.viewPortDiv, "olDrawBox"
- );
-
- },
-
- /**
- * Method: activate
- */
- activate: function () {
- if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
- this.dragHandler.activate();
- return true;
- } else {
- return false;
- }
- },
-
- /**
- * Method: deactivate
- */
- deactivate: function () {
- if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
- this.dragHandler.deactivate();
- return true;
- } else {
- return false;
- }
- },
-
- /**
- * Method: getCharacteristics
- * Determines offset and box model for a box.
+ * point - {Object} An object with x and y properties.
*
* Returns:
- * {Object} a hash with the following properties:
- * - xOffset - Corner offset in x-direction
- * - yOffset - Corner offset in y-direction
- * - newBoxModel - true for all browsers except IE in quirks mode
+ * {Object} The point, with the x and y properties transformed from
+ * spherical mercator to unprojected coordinates..
*/
- getBoxCharacteristics: function() {
- if (!this.boxCharacteristics) {
- var xOffset = parseInt(OpenLayers.Element.getStyle(this.zoomBox,
- "border-left-width")) + parseInt(OpenLayers.Element.getStyle(
- this.zoomBox, "border-right-width")) + 1;
- var yOffset = parseInt(OpenLayers.Element.getStyle(this.zoomBox,
- "border-top-width")) + parseInt(OpenLayers.Element.getStyle(
- this.zoomBox, "border-bottom-width")) + 1;
- // all browsers use the new box model, except IE in quirks mode
- var newBoxModel = OpenLayers.Util.getBrowserName() == "msie" ?
- document.compatMode != "BackCompat" : true;
- this.boxCharacteristics = {
- xOffset: xOffset,
- yOffset: yOffset,
- newBoxModel: newBoxModel
- };
- }
- return this.boxCharacteristics;
- },
+ projectInverse: function(point) {
+ var lonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(point.x, point.y);
+ point.x = lonlat.lon;
+ point.y = lonlat.lat;
+ return point;
+ }
- CLASS_NAME: "OpenLayers.Handler.Box"
-});
-/* ======================================================================
- OpenLayers/Handler/RegularPolygon.js
- ====================================================================== */
+};
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-
/**
- * @requires OpenLayers/Handler/Drag.js
+ * Note: Transforms for web mercator <-> EPSG:4326
+ * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113 and EPSG:102100.
+ * OpenLayers originally started referring to EPSG:900913 as web mercator.
+ * The EPSG has declared EPSG:3857 to be web mercator.
+ * ArcGIS 10 recognizes the EPSG:3857, EPSG:102113, and EPSG:102100 as
+ * equivalent. See http://blogs.esri.com/Dev/blogs/arcgisserver/archive/2009/11/20/ArcGIS-Online-moving-to-Google-_2F00_-Bing-tiling-scheme_3A00_-What-does-this-mean-for-you_3F00_.aspx#12084
*/
-
-/**
- * Class: OpenLayers.Handler.RegularPolygon
- * Handler to draw a regular polygon on the map. Polygon is displayed on mouse
- * down, moves or is modified on mouse move, and is finished on mouse up.
- * The handler triggers callbacks for 'done' and 'cancel'. Create a new
- * instance with the <OpenLayers.Handler.RegularPolygon> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Handler>
- */
-OpenLayers.Handler.RegularPolygon = OpenLayers.Class(OpenLayers.Handler.Drag, {
+(function() {
- /**
- * APIProperty: sides
- * {Integer} Number of sides for the regular polygon. Needs to be greater
- * than 2. Defaults to 4.
- */
- sides: 4,
-
- /**
- * APIProperty: radius
- * {Float} Optional radius in map units of the regular polygon. If this is
- * set to some non-zero value, a polygon with a fixed radius will be
- * drawn and dragged with mose movements. If this property is not
- * set, dragging changes the radius of the polygon. Set to null by
- * default.
- */
- radius: null,
+ // list of equivalent codes for web mercator
+ var codes = ["EPSG:900913", "EPSG:3857", "EPSG:102113", "EPSG:102100"];
- /**
- * APIProperty: snapAngle
- * {Float} If set to a non-zero value, the handler will snap the polygon
- * rotation to multiples of the snapAngle. Value is an angle measured
- * in degrees counterclockwise from the positive x-axis.
- */
- snapAngle: null,
+ var add = OpenLayers.Projection.addTransform;
+ var merc = OpenLayers.Layer.SphericalMercator;
+ var same = OpenLayers.Projection.nullTransform;
- /**
- * APIProperty: snapToggle
- * {String} If set, snapToggle is checked on mouse events and will set
- * the snap mode to the opposite of what it currently is. To disallow
- * toggling between snap and non-snap mode, set freehandToggle to
- * null. Acceptable toggle values are 'shiftKey', 'ctrlKey', and
- * 'altKey'. Snap mode is only possible if this.snapAngle is set to a
- * non-zero value.
- */
- snapToggle: 'shiftKey',
-
- /**
- * Property: layerOptions
- * {Object} Any optional properties to be set on the sketch layer.
- */
- layerOptions: null,
-
- /**
- * APIProperty: persist
- * {Boolean} Leave the feature rendered until clear is called. Default
- * is false. If set to true, the feature remains rendered until
- * clear is called, typically by deactivating the handler or starting
- * another drawing.
- */
- persist: false,
-
- /**
- * APIProperty: irregular
- * {Boolean} Draw an irregular polygon instead of a regular polygon.
- * Default is false. If true, the initial mouse down will represent
- * one corner of the polygon bounds and with each mouse movement, the
- * polygon will be stretched so the opposite corner of its bounds
- * follows the mouse position. This property takes precedence over
- * the radius property. If set to true, the radius property will
- * be ignored.
- */
- irregular: false,
-
- /**
- * Property: angle
- * {Float} The angle from the origin (mouse down) to the current mouse
- * position, in radians. This is measured counterclockwise from the
- * positive x-axis.
- */
- angle: null,
-
- /**
- * Property: fixedRadius
- * {Boolean} The polygon has a fixed radius. True if a radius is set before
- * drawing begins. False otherwise.
- */
- fixedRadius: false,
-
- /**
- * Property: feature
- * {<OpenLayers.Feature.Vector>} The currently drawn polygon feature
- */
- feature: null,
-
- /**
- * Property: layer
- * {<OpenLayers.Layer.Vector>} The temporary drawing layer
- */
- layer: null,
-
- /**
- * Property: origin
- * {<OpenLayers.Geometry.Point>} Location of the first mouse down
- */
- origin: null,
-
- /**
- * Constructor: OpenLayers.Handler.RegularPolygon
- * Create a new regular polygon handler.
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that owns this handler
- * callbacks - {Object} An object with a properties whose values are
- * functions. Various callbacks described below.
- * options - {Object} An object with properties to be set on the handler.
- * If the options.sides property is not specified, the number of sides
- * will default to 4.
- *
- * Named callbacks:
- * create - Called when a sketch is first created. Callback called with
- * the creation point geometry and sketch feature.
- * done - Called when the sketch drawing is finished. The callback will
- * recieve a single argument, the sketch geometry.
- * cancel - Called when the handler is deactivated while drawing. The
- * cancel callback will receive a geometry.
- */
- initialize: function(control, callbacks, options) {
- if(!(options && options.layerOptions && options.layerOptions.styleMap)) {
- this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {});
+ var i, len, code, other, j;
+ for (i=0, len=codes.length; i<len; ++i) {
+ code = codes[i];
+ add("EPSG:4326", code, merc.projectForward);
+ add(code, "EPSG:4326", merc.projectInverse);
+ for (j=i+1; j<len; ++j) {
+ other = codes[j];
+ add(code, other, same);
+ add(other, code, same);
}
-
- OpenLayers.Handler.prototype.initialize.apply(this,
- [control, callbacks, options]);
- this.options = (options) ? options : {};
- },
+ }
- /**
- * APIMethod: setOptions
- *
- * Parameters:
- * newOptions - {Object}
- */
- setOptions: function (newOptions) {
- OpenLayers.Util.extend(this.options, newOptions);
- OpenLayers.Util.extend(this, newOptions);
- },
-
- /**
- * APIMethod: activate
- * Turn on the handler.
- *
- * Return:
- * {Boolean} The handler was successfully activated
- */
- activate: function() {
- var activated = false;
- if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
- // create temporary vector layer for rendering geometry sketch
- var options = OpenLayers.Util.extend({
- displayInLayerSwitcher: false,
- // indicate that the temp vector layer will never be out of range
- // without this, resolution properties must be specified at the
- // map-level for this temporary layer to init its resolutions
- // correctly
- calculateInRange: OpenLayers.Function.True
- }, this.layerOptions);
- this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options);
- this.map.addLayer(this.layer);
- activated = true;
- }
- return activated;
- },
-
- /**
- * APIMethod: deactivate
- * Turn off the handler.
- *
- * Return:
- * {Boolean} The handler was successfully deactivated
- */
- deactivate: function() {
- var deactivated = false;
- if(OpenLayers.Handler.Drag.prototype.deactivate.apply(this, arguments)) {
- // call the cancel callback if mid-drawing
- if(this.dragging) {
- this.cancel();
- }
- // If a layer's map property is set to null, it means that that
- // layer isn't added to the map. Since we ourself added the layer
- // to the map in activate(), we can assume that if this.layer.map
- // is null it means that the layer has been destroyed (as a result
- // of map.destroy() for example.
- if (this.layer.map != null) {
- this.layer.destroy(false);
- if (this.feature) {
- this.feature.destroy();
- }
- }
- this.layer = null;
- this.feature = null;
- deactivated = true;
- }
- return deactivated;
- },
-
- /**
- * Method: down
- * Start drawing a new feature
- *
- * Parameters:
- * evt - {Event} The drag start event
- */
- down: function(evt) {
- this.fixedRadius = !!(this.radius);
- var maploc = this.map.getLonLatFromPixel(evt.xy);
- this.origin = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat);
- // create the new polygon
- if(!this.fixedRadius || this.irregular) {
- // smallest radius should not be less one pixel in map units
- // VML doesn't behave well with smaller
- this.radius = this.map.getResolution();
- }
- if(this.persist) {
- this.clear();
- }
- this.feature = new OpenLayers.Feature.Vector();
- this.createGeometry();
- this.callback("create", [this.origin, this.feature]);
- this.layer.addFeatures([this.feature], {silent: true});
- this.layer.drawFeature(this.feature, this.style);
- },
-
- /**
- * Method: move
- * Respond to drag move events
- *
- * Parameters:
- * evt - {Evt} The move event
- */
- move: function(evt) {
- var maploc = this.map.getLonLatFromPixel(evt.xy);
- var point = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat);
- if(this.irregular) {
- var ry = Math.sqrt(2) * Math.abs(point.y - this.origin.y) / 2;
- this.radius = Math.max(this.map.getResolution() / 2, ry);
- } else if(this.fixedRadius) {
- this.origin = point;
- } else {
- this.calculateAngle(point, evt);
- this.radius = Math.max(this.map.getResolution() / 2,
- point.distanceTo(this.origin));
- }
- this.modifyGeometry();
- if(this.irregular) {
- var dx = point.x - this.origin.x;
- var dy = point.y - this.origin.y;
- var ratio;
- if(dy == 0) {
- ratio = dx / (this.radius * Math.sqrt(2));
- } else {
- ratio = dx / dy;
- }
- this.feature.geometry.resize(1, this.origin, ratio);
- this.feature.geometry.move(dx / 2, dy / 2);
- }
- this.layer.drawFeature(this.feature, this.style);
- },
-
- /**
- * Method: up
- * Finish drawing the feature
- *
- * Parameters:
- * evt - {Event} The mouse up event
- */
- up: function(evt) {
- this.finalize();
- // the mouseup method of superclass doesn't call the
- // "done" callback if there's been no move between
- // down and up
- if (this.start == this.last) {
- this.callback("done", [evt.xy]);
- }
- },
-
- /**
- * Method: out
- * Finish drawing the feature.
- *
- * Parameters:
- * evt - {Event} The mouse out event
- */
- out: function(evt) {
- this.finalize();
- },
-
- /**
- * Method: createGeometry
- * Create the new polygon geometry. This is called at the start of the
- * drag and at any point during the drag if the number of sides
- * changes.
- */
- createGeometry: function() {
- this.angle = Math.PI * ((1/this.sides) - (1/2));
- if(this.snapAngle) {
- this.angle += this.snapAngle * (Math.PI / 180);
- }
- this.feature.geometry = OpenLayers.Geometry.Polygon.createRegularPolygon(
- this.origin, this.radius, this.sides, this.snapAngle
- );
- },
-
- /**
- * Method: modifyGeometry
- * Modify the polygon geometry in place.
- */
- modifyGeometry: function() {
- var angle, point;
- var ring = this.feature.geometry.components[0];
- // if the number of sides ever changes, create a new geometry
- if(ring.components.length != (this.sides + 1)) {
- this.createGeometry();
- ring = this.feature.geometry.components[0];
- }
- for(var i=0; i<this.sides; ++i) {
- point = ring.components[i];
- angle = this.angle + (i * 2 * Math.PI / this.sides);
- point.x = this.origin.x + (this.radius * Math.cos(angle));
- point.y = this.origin.y + (this.radius * Math.sin(angle));
- point.clearBounds();
- }
- },
-
- /**
- * Method: calculateAngle
- * Calculate the angle based on settings.
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point>}
- * evt - {Event}
- */
- calculateAngle: function(point, evt) {
- var alpha = Math.atan2(point.y - this.origin.y,
- point.x - this.origin.x);
- if(this.snapAngle && (this.snapToggle && !evt[this.snapToggle])) {
- var snapAngleRad = (Math.PI / 180) * this.snapAngle;
- this.angle = Math.round(alpha / snapAngleRad) * snapAngleRad;
- } else {
- this.angle = alpha;
- }
- },
-
- /**
- * APIMethod: cancel
- * Finish the geometry and call the "cancel" callback.
- */
- cancel: function() {
- // the polygon geometry gets cloned in the callback method
- this.callback("cancel", null);
- this.finalize();
- },
-
- /**
- * Method: finalize
- * Finish the geometry and call the "done" callback.
- */
- finalize: function() {
- this.origin = null;
- this.radius = this.options.radius;
- },
-
- /**
- * APIMethod: clear
- * Clear any rendered features on the temporary layer. This is called
- * when the handler is deactivated, canceled, or done (unless persist
- * is true).
- */
- clear: function() {
- if (this.layer) {
- this.layer.renderer.clear();
- this.layer.destroyFeatures();
- }
- },
-
- /**
- * Method: callback
- * Trigger the control's named callback with the given arguments
- *
- * Parameters:
- * name - {String} The key for the callback that is one of the properties
- * of the handler's callbacks object.
- * args - {Array} An array of arguments with which to call the callback
- * (defined by the control).
- */
- callback: function (name, args) {
- // override the callback method to always send the polygon geometry
- if (this.callbacks[name]) {
- this.callbacks[name].apply(this.control,
- [this.feature.geometry.clone()]);
- }
- // since sketch features are added to the temporary layer
- // they must be cleared here if done or cancel
- if(!this.persist && (name == "done" || name == "cancel")) {
- this.clear();
- }
- },
-
- CLASS_NAME: "OpenLayers.Handler.RegularPolygon"
-});
+})();
/* ======================================================================
OpenLayers/Layer/EventPane.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
@@ -25472,7 +10124,7 @@
this.pane.style.display = this.div.style.display;
this.pane.style.width="100%";
this.pane.style.height="100%";
- if (OpenLayers.Util.getBrowserName() == "msie") {
+ if (OpenLayers.BROWSER_NAME == "msie") {
this.pane.style.background =
"url(" + OpenLayers.Util.getImagesLocation() + "blank.gif)";
}
@@ -25790,7 +10442,7 @@
OpenLayers/Layer/FixedZoomLevels.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
@@ -26106,1551 +10758,383 @@
});
/* ======================================================================
- OpenLayers/Layer/HTTPRequest.js
+ OpenLayers/Layer/VirtualEarth.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
- * @requires OpenLayers/Layer.js
+ * @requires OpenLayers/Layer/SphericalMercator.js
+ * @requires OpenLayers/Layer/EventPane.js
+ * @requires OpenLayers/Layer/FixedZoomLevels.js
+ * @requires OpenLayers/Lang.js
*/
/**
- * Class: OpenLayers.Layer.HTTPRequest
+ * Class: OpenLayers.Layer.VirtualEarth
*
- * Inherits from:
- * - <OpenLayers.Layer>
+ * Inherits from:
+ * - <OpenLayers.Layer.EventPane>
+ * - <OpenLayers.Layer.FixedZoomLevels>
*/
-OpenLayers.Layer.HTTPRequest = OpenLayers.Class(OpenLayers.Layer, {
-
+OpenLayers.Layer.VirtualEarth = OpenLayers.Class(
+ OpenLayers.Layer.EventPane,
+ OpenLayers.Layer.FixedZoomLevels, {
+
/**
- * Constant: URL_HASH_FACTOR
- * {Float} Used to hash URL param strings for multi-WMS server selection.
- * Set to the Golden Ratio per Knuth's recommendation.
+ * Constant: MIN_ZOOM_LEVEL
+ * {Integer} 1
*/
- URL_HASH_FACTOR: (Math.sqrt(5) - 1) / 2,
-
+ MIN_ZOOM_LEVEL: 1,
+
/**
- * Property: url
- * {Array(String) or String} This is either an array of url strings or
- * a single url string.
+ * Constant: MAX_ZOOM_LEVEL
+ * {Integer} 19
*/
- url: null,
+ MAX_ZOOM_LEVEL: 19,
/**
- * Property: params
- * {Object} Hashtable of key/value parameters
+ * Constant: RESOLUTIONS
+ * {Array(Float)} Hardcode these resolutions so that they are more closely
+ * tied with the standard wms projection
*/
- params: null,
-
- /**
- * APIProperty: reproject
- * *Deprecated*. See http://trac.openlayers.org/wiki/SpatialMercator
- * for information on the replacement for this functionality.
- * {Boolean} Whether layer should reproject itself based on base layer
- * locations. This allows reprojection onto commercial layers.
- * Default is false: Most layers can't reproject, but layers
- * which can create non-square geographic pixels can, like WMS.
- *
- */
- reproject: false,
+ RESOLUTIONS: [
+ 1.40625,
+ 0.703125,
+ 0.3515625,
+ 0.17578125,
+ 0.087890625,
+ 0.0439453125,
+ 0.02197265625,
+ 0.010986328125,
+ 0.0054931640625,
+ 0.00274658203125,
+ 0.001373291015625,
+ 0.0006866455078125,
+ 0.00034332275390625,
+ 0.000171661376953125,
+ 0.0000858306884765625,
+ 0.00004291534423828125,
+ 0.00002145767211914062,
+ 0.00001072883605957031,
+ 0.00000536441802978515
+ ],
/**
- * Constructor: OpenLayers.Layer.HTTPRequest
- *
- * Parameters:
- * name - {String}
- * url - {Array(String) or String}
- * params - {Object}
- * options - {Object} Hashtable of extra options to tag onto the layer
+ * APIProperty: type
+ * {VEMapType}
*/
- initialize: function(name, url, params, options) {
- var newArguments = arguments;
- newArguments = [name, options];
- OpenLayers.Layer.prototype.initialize.apply(this, newArguments);
- this.url = url;
- this.params = OpenLayers.Util.extend( {}, params);
- },
+ type: null,
/**
- * APIMethod: destroy
+ * APIProperty: wrapDateLine
+ * {Boolean} Allow user to pan forever east/west. Default is true.
+ * Setting this to false only restricts panning if
+ * <sphericalMercator> is true.
*/
- destroy: function() {
- this.url = null;
- this.params = null;
- OpenLayers.Layer.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * APIMethod: clone
- *
- * Parameters:
- * obj - {Object}
- *
- * Returns:
- * {<OpenLayers.Layer.HTTPRequest>} An exact clone of this
- * <OpenLayers.Layer.HTTPRequest>
- */
- clone: function (obj) {
-
- if (obj == null) {
- obj = new OpenLayers.Layer.HTTPRequest(this.name,
- this.url,
- this.params,
- this.getOptions());
- }
-
- //get all additions from superclasses
- obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]);
+ wrapDateLine: true,
- // copy/set any non-init, non-simple values here
-
- return obj;
- },
-
- /**
- * APIMethod: setUrl
- *
- * Parameters:
- * newUrl - {String}
- */
- setUrl: function(newUrl) {
- this.url = newUrl;
- },
-
/**
- * APIMethod: mergeNewParams
- *
- * Parameters:
- * newParams - {Object}
- *
- * Returns:
- * redrawn: {Boolean} whether the layer was actually redrawn.
+ * APIProperty: sphericalMercator
+ * {Boolean} Should the map act as a mercator-projected map? This will
+ * cause all interactions with the map to be in the actual map
+ * projection, which allows support for vector drawing, overlaying
+ * other maps, etc.
*/
- mergeNewParams:function(newParams) {
- this.params = OpenLayers.Util.extend(this.params, newParams);
- var ret = this.redraw();
- if(this.map != null) {
- this.map.events.triggerEvent("changelayer", {
- layer: this,
- property: "params"
- });
- }
- return ret;
- },
-
- /**
- * APIMethod: redraw
- * Redraws the layer. Returns true if the layer was redrawn, false if not.
- *
- * Parameters:
- * force - {Boolean} Force redraw by adding random parameter.
- *
- * Returns:
- * {Boolean} The layer was redrawn.
- */
- redraw: function(force) {
- if (force) {
- return this.mergeNewParams({"_olSalt": Math.random()});
- } else {
- return OpenLayers.Layer.prototype.redraw.apply(this, []);
- }
- },
+ sphericalMercator: false,
/**
- * Method: selectUrl
- * selectUrl() implements the standard floating-point multiplicative
- * hash function described by Knuth, and hashes the contents of the
- * given param string into a float between 0 and 1. This float is then
- * scaled to the size of the provided urls array, and used to select
- * a URL.
- *
- * Parameters:
- * paramString - {String}
- * urls - {Array(String)}
- *
- * Returns:
- * {String} An entry from the urls array, deterministically selected based
- * on the paramString.
+ * APIProperty: animationEnabled
+ * {Boolean} If set to true, the transition between zoom levels will be
+ * animated. Set to false to match the zooming experience of other
+ * layer types. Default is true.
*/
- selectUrl: function(paramString, urls) {
- var product = 1;
- for (var i=0, len=paramString.length; i<len; i++) {
- product *= paramString.charCodeAt(i) * this.URL_HASH_FACTOR;
- product -= Math.floor(product);
- }
- return urls[Math.floor(product * urls.length)];
- },
+ animationEnabled: true,
/**
- * Method: getFullRequestString
- * Combine url with layer's params and these newParams.
- *
- * does checking on the serverPath variable, allowing for cases when it
- * is supplied with trailing ? or &, as well as cases where not.
- *
- * return in formatted string like this:
- * "server?key1=value1&key2=value2&key3=value3"
+ * Constructor: OpenLayers.Layer.VirtualEarth
*
- * WARNING: The altUrl parameter is deprecated and will be removed in 3.0.
- *
* Parameters:
- * newParams - {Object}
- * altUrl - {String} Use this as the url instead of the layer's url
- *
- * Returns:
- * {String}
+ * name - {String}
+ * options - {Object}
*/
- getFullRequestString:function(newParams, altUrl) {
-
- // if not altUrl passed in, use layer's url
- var url = altUrl || this.url;
-
- // create a new params hashtable with all the layer params and the
- // new params together. then convert to string
- var allParams = OpenLayers.Util.extend({}, this.params);
- allParams = OpenLayers.Util.extend(allParams, newParams);
- var paramsString = OpenLayers.Util.getParameterString(allParams);
-
- // if url is not a string, it should be an array of strings,
- // in which case we will deterministically select one of them in
- // order to evenly distribute requests to different urls.
- //
- if (url instanceof Array) {
- url = this.selectUrl(paramsString, url);
- }
-
- // ignore parameters that are already in the url search string
- var urlParams =
- OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));
- for(var key in allParams) {
- if(key.toUpperCase() in urlParams) {
- delete allParams[key];
- }
+ initialize: function(name, options) {
+ OpenLayers.Layer.EventPane.prototype.initialize.apply(this, arguments);
+ OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,
+ arguments);
+ if(this.sphericalMercator) {
+ OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
+ this.initMercatorParameters();
}
- paramsString = OpenLayers.Util.getParameterString(allParams);
-
- return OpenLayers.Util.urlAppend(url, paramsString);
},
-
- CLASS_NAME: "OpenLayers.Layer.HTTPRequest"
-});
-/* ======================================================================
- OpenLayers/Layer/Markers.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Layer.js
- */
-
-/**
- * Class: OpenLayers.Layer.Markers
- *
- * Inherits from:
- * - <OpenLayers.Layer>
- */
-OpenLayers.Layer.Markers = OpenLayers.Class(OpenLayers.Layer, {
- /**
- * APIProperty: isBaseLayer
- * {Boolean} Markers layer is never a base layer.
+ /**
+ * Method: loadMapObject
*/
- isBaseLayer: false,
-
- /**
- * APIProperty: markers
- * {Array(<OpenLayers.Marker>)} internal marker list
- */
- markers: null,
+ loadMapObject:function() {
+ // create div and set to same size as map
+ var veDiv = OpenLayers.Util.createDiv(this.name);
+ var sz = this.map.getSize();
+ veDiv.style.width = sz.w + "px";
+ veDiv.style.height = sz.h + "px";
+ this.div.appendChild(veDiv);
- /**
- * Property: drawn
- * {Boolean} internal state of drawing. This is a workaround for the fact
- * that the map does not call moveTo with a zoomChanged when the map is
- * first starting up. This lets us catch the case where we have *never*
- * drawn the layer, and draw it even if the zoom hasn't changed.
- */
- drawn: false,
-
- /**
- * Constructor: OpenLayers.Layer.Markers
- * Create a Markers layer.
- *
- * Parameters:
- * name - {String}
- * options - {Object} Hashtable of extra options to tag onto the layer
- */
- initialize: function(name, options) {
- OpenLayers.Layer.prototype.initialize.apply(this, arguments);
- this.markers = [];
- },
-
- /**
- * APIMethod: destroy
- */
- destroy: function() {
- this.clearMarkers();
- this.markers = null;
- OpenLayers.Layer.prototype.destroy.apply(this, arguments);
- },
+ try { // crash prevention
+ this.mapObject = new VEMap(this.name);
+ } catch (e) { }
- /**
- * APIMethod: setOpacity
- * Sets the opacity for all the markers.
- *
- * Parameter:
- * opacity - {Float}
- */
- setOpacity: function(opacity) {
- if (opacity != this.opacity) {
- this.opacity = opacity;
- for (var i=0, len=this.markers.length; i<len; i++) {
- this.markers[i].setOpacity(this.opacity);
- }
- }
- },
+ if (this.mapObject != null) {
+ try { // this is to catch a Mozilla bug without falling apart
- /**
- * Method: moveTo
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * zoomChanged - {Boolean}
- * dragging - {Boolean}
- */
- moveTo:function(bounds, zoomChanged, dragging) {
- OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
+ // The fourth argument is whether the map is 'fixed' -- not
+ // draggable. See:
+ // http://blogs.msdn.com/virtualearth/archive/2007/09/28/locking-a-virtual-earth-map.aspx
+ //
+ this.mapObject.LoadMap(null, null, this.type, true);
+ this.mapObject.AttachEvent("onmousedown", OpenLayers.Function.True);
- if (zoomChanged || !this.drawn) {
- for(var i=0, len=this.markers.length; i<len; i++) {
- this.drawMarker(this.markers[i]);
+ } catch (e) { }
+ this.mapObject.HideDashboard();
+ if(typeof this.mapObject.SetAnimationEnabled == "function") {
+ this.mapObject.SetAnimationEnabled(this.animationEnabled);
}
- this.drawn = true;
}
- },
- /**
- * APIMethod: addMarker
- *
- * Parameters:
- * marker - {<OpenLayers.Marker>}
- */
- addMarker: function(marker) {
- this.markers.push(marker);
+ //can we do smooth panning? this is an unpublished method, so we need
+ // to be careful
+ if ( !this.mapObject ||
+ !this.mapObject.vemapcontrol ||
+ !this.mapObject.vemapcontrol.PanMap ||
+ (typeof this.mapObject.vemapcontrol.PanMap != "function")) {
- if (this.opacity != null) {
- marker.setOpacity(this.opacity);
+ this.dragPanMapObject = null;
}
- if (this.map && this.map.getExtent()) {
- marker.map = this.map;
- this.drawMarker(marker);
- }
},
/**
- * APIMethod: removeMarker
- *
- * Parameters:
- * marker - {<OpenLayers.Marker>}
+ * Method: onMapResize
*/
- removeMarker: function(marker) {
- if (this.markers && this.markers.length) {
- OpenLayers.Util.removeItem(this.markers, marker);
- marker.erase();
- }
+ onMapResize: function() {
+ this.mapObject.Resize(this.map.size.w, this.map.size.h);
},
- /**
- * Method: clearMarkers
- * This method removes all markers from a layer. The markers are not
- * destroyed by this function, but are removed from the list of markers.
- */
- clearMarkers: function() {
- if (this.markers != null) {
- while(this.markers.length > 0) {
- this.removeMarker(this.markers[0]);
- }
- }
- },
-
/**
- * Method: drawMarker
- * Calculate the pixel location for the marker, create it, and
- * add it to the layer's div
- *
- * Parameters:
- * marker - {<OpenLayers.Marker>}
- */
- drawMarker: function(marker) {
- var px = this.map.getLayerPxFromLonLat(marker.lonlat);
- if (px == null) {
- marker.display(false);
- } else {
- if (!marker.isDrawn()) {
- var markerImg = marker.draw(px);
- this.div.appendChild(markerImg);
- } else if(marker.icon) {
- marker.icon.moveTo(px);
- }
- }
- },
-
- /**
- * APIMethod: getDataExtent
- * Calculates the max extent which includes all of the markers.
+ * APIMethod: getWarningHTML
*
- * Returns:
- * {<OpenLayers.Bounds>}
+ * Returns:
+ * {String} String with information on why layer is broken, how to get
+ * it working.
*/
- getDataExtent: function () {
- var maxExtent = null;
-
- if ( this.markers && (this.markers.length > 0)) {
- var maxExtent = new OpenLayers.Bounds();
- for(var i=0, len=this.markers.length; i<len; i++) {
- var marker = this.markers[i];
- maxExtent.extend(marker.lonlat);
- }
- }
-
- return maxExtent;
+ getWarningHTML:function() {
+ return OpenLayers.i18n(
+ "getLayerWarning", {'layerType':'VE', 'layerLib':'VirtualEarth'}
+ );
},
- CLASS_NAME: "OpenLayers.Layer.Markers"
-});
-/* ======================================================================
- OpenLayers/Layer/SphericalMercator.js
- ====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-/**
- * @requires OpenLayers/Layer.js
- * @requires OpenLayers/Projection.js
- */
+ /************************************
+ * *
+ * MapObject Interface Controls *
+ * *
+ ************************************/
-/**
- * Class: OpenLayers.Layer.SphericalMercator
- * A mixin for layers that wraps up the pieces neccesary to have a coordinate
- * conversion for working with commercial APIs which use a spherical
- * mercator projection. Using this layer as a base layer, additional
- * layers can be used as overlays if they are in the same projection.
- *
- * A layer is given properties of this object by setting the sphericalMercator
- * property to true.
- *
- * More projection information:
- * - http://spatialreference.org/ref/user/google-projection/
- *
- * Proj4 Text:
- * +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0
- * +k=1.0 +units=m +nadgrids=@null +no_defs
- *
- * WKT:
- * 900913=PROJCS["WGS84 / Simple Mercator", GEOGCS["WGS 84",
- * DATUM["WGS_1984", SPHEROID["WGS_1984", 6378137.0, 298.257223563]],
- * PRIMEM["Greenwich", 0.0], UNIT["degree", 0.017453292519943295],
- * AXIS["Longitude", EAST], AXIS["Latitude", NORTH]],
- * PROJECTION["Mercator_1SP_Google"],
- * PARAMETER["latitude_of_origin", 0.0], PARAMETER["central_meridian", 0.0],
- * PARAMETER["scale_factor", 1.0], PARAMETER["false_easting", 0.0],
- * PARAMETER["false_northing", 0.0], UNIT["m", 1.0], AXIS["x", EAST],
- * AXIS["y", NORTH], AUTHORITY["EPSG","900913"]]
- */
-OpenLayers.Layer.SphericalMercator = {
- /**
- * Method: getExtent
- * Get the map's extent.
- *
- * Returns:
- * {<OpenLayers.Bounds>} The map extent.
+ // Get&Set Center, Zoom
+
+ /**
+ * APIMethod: setMapObjectCenter
+ * Set the mapObject to the specified center and zoom
+ *
+ * Parameters:
+ * center - {Object} MapObject LonLat format
+ * zoom - {int} MapObject zoom format
*/
- getExtent: function() {
- var extent = null;
- if (this.sphericalMercator) {
- extent = this.map.calculateBounds();
- } else {
- extent = OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this);
- }
- return extent;
+ setMapObjectCenter: function(center, zoom) {
+ this.mapObject.SetCenterAndZoom(center, zoom);
},
-
+
/**
- * Method: getLonLatFromViewPortPx
- * Get a map location from a pixel location
+ * APIMethod: getMapObjectCenter
*
- * Parameters:
- * viewPortPx - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view
- * port OpenLayers.Pixel, translated into lon/lat by map lib
- * If the map lib is not loaded or not centered, returns null
+ * Returns:
+ * {Object} The mapObject's current center in Map Object format
*/
- getLonLatFromViewPortPx: function (viewPortPx) {
- return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this, arguments);
+ getMapObjectCenter: function() {
+ return this.mapObject.GetCenter();
},
-
+
/**
- * Method: getViewPortPxFromLonLat
- * Get a pixel location from a map location
- *
+ * APIMethod: dragPanMapObject
+ *
* Parameters:
- * lonlat - {<OpenLayers.LonLat>}
- *
- * Returns:
- * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
- * OpenLayers.LonLat, translated into view port pixels by map lib
- * If map lib is not loaded or not centered, returns null
+ * dX - {Integer}
+ * dY - {Integer}
*/
- getViewPortPxFromLonLat: function (lonlat) {
- return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this, arguments);
+ dragPanMapObject: function(dX, dY) {
+ this.mapObject.vemapcontrol.PanMap(dX, -dY);
},
/**
- * Method: initMercatorParameters
- * Set up the mercator parameters on the layer: resolutions,
- * projection, units.
- */
- initMercatorParameters: function() {
- // set up properties for Mercator - assume EPSG:900913
- this.RESOLUTIONS = [];
- var maxResolution = 156543.0339;
- for(var zoom=0; zoom<=this.MAX_ZOOM_LEVEL; ++zoom) {
- this.RESOLUTIONS[zoom] = maxResolution / Math.pow(2, zoom);
- }
- this.units = "m";
- this.projection = this.projection || "EPSG:900913";
- },
-
- /**
- * APIMethod: forwardMercator
- * Given a lon,lat in EPSG:4326, return a point in Spherical Mercator.
- *
- * Parameters:
- * lon - {float}
- * lat - {float}
+ * APIMethod: getMapObjectZoom
*
* Returns:
- * {<OpenLayers.LonLat>} The coordinates transformed to Mercator.
+ * {Integer} The mapObject's current zoom, in Map Object format
*/
- forwardMercator: function(lon, lat) {
- var x = lon * 20037508.34 / 180;
- var y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
-
- y = y * 20037508.34 / 180;
-
- return new OpenLayers.LonLat(x, y);
+ getMapObjectZoom: function() {
+ return this.mapObject.GetZoomLevel();
},
+
+ // LonLat - Pixel Translation
+
/**
- * APIMethod: inverseMercator
- * Given a x,y in Spherical Mercator, return a point in EPSG:4326.
- *
+ * APIMethod: getMapObjectLonLatFromMapObjectPixel
+ *
* Parameters:
- * x - {float} A map x in Spherical Mercator.
- * y - {float} A map y in Spherical Mercator.
+ * moPixel - {Object} MapObject Pixel format
*
* Returns:
- * {<OpenLayers.LonLat>} The coordinates transformed to EPSG:4326.
+ * {Object} MapObject LonLat translated from MapObject Pixel
*/
- inverseMercator: function(x, y) {
-
- var lon = (x / 20037508.34) * 180;
- var lat = (y / 20037508.34) * 180;
-
- lat = 180/Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);
-
- return new OpenLayers.LonLat(lon, lat);
+ getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
+ //the conditional here is to test if we are running the v6 of VE
+ return (typeof VEPixel != 'undefined')
+ ? this.mapObject.PixelToLatLong(moPixel)
+ : this.mapObject.PixelToLatLong(moPixel.x, moPixel.y);
},
/**
- * Method: projectForward
- * Given an object with x and y properties in EPSG:4326, modify the x,y
- * properties on the object to be the Spherical Mercator projected
- * coordinates.
- *
+ * APIMethod: getMapObjectPixelFromMapObjectLonLat
+ *
* Parameters:
- * point - {Object} An object with x and y properties.
+ * moLonLat - {Object} MapObject LonLat format
*
* Returns:
- * {Object} The point, with the x and y properties transformed to spherical
- * mercator.
+ * {Object} MapObject Pixel transtlated from MapObject LonLat
*/
- projectForward: function(point) {
- var lonlat = OpenLayers.Layer.SphericalMercator.forwardMercator(point.x, point.y);
- point.x = lonlat.lon;
- point.y = lonlat.lat;
- return point;
+ getMapObjectPixelFromMapObjectLonLat: function(moLonLat) {
+ return this.mapObject.LatLongToPixel(moLonLat);
},
-
- /**
- * Method: projectInverse
- * Given an object with x and y properties in Spherical Mercator, modify
- * the x,y properties on the object to be the unprojected coordinates.
- *
- * Parameters:
- * point - {Object} An object with x and y properties.
- *
- * Returns:
- * {Object} The point, with the x and y properties transformed from
- * spherical mercator to unprojected coordinates..
- */
- projectInverse: function(point) {
- var lonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(point.x, point.y);
- point.x = lonlat.lon;
- point.y = lonlat.lat;
- return point;
- }
-};
-/**
- * Note: Two transforms declared
- * Transforms from EPSG:4326 to EPSG:900913 and from EPSG:900913 to EPSG:4326
- * are set by this class.
- */
-OpenLayers.Projection.addTransform("EPSG:4326", "EPSG:900913",
- OpenLayers.Layer.SphericalMercator.projectForward);
-OpenLayers.Projection.addTransform("EPSG:900913", "EPSG:4326",
- OpenLayers.Layer.SphericalMercator.projectInverse);
-/* ======================================================================
- OpenLayers/Control/DrawFeature.js
- ====================================================================== */
+ /************************************
+ * *
+ * MapObject Primitives *
+ * *
+ ************************************/
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/Feature/Vector.js
- */
-
-/**
- * Class: OpenLayers.Control.DrawFeature
- * The DrawFeature control draws point, line or polygon features on a vector
- * layer when active.
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.DrawFeature = OpenLayers.Class(OpenLayers.Control, {
+ // LonLat
/**
- * Property: layer
- * {<OpenLayers.Layer.Vector>}
- */
- layer: null,
-
- /**
- * Property: callbacks
- * {Object} The functions that are sent to the handler for callback
- */
- callbacks: null,
-
- /**
- * Constant: EVENT_TYPES
- *
- * Supported event types:
- * featureadded - Triggered when a feature is added
- */
- EVENT_TYPES: ["featureadded"],
-
- /**
- * APIProperty: multi
- * {Boolean} Cast features to multi-part geometries before passing to the
- * layer. Default is false.
- */
- multi: false,
-
- /**
- * APIProperty: featureAdded
- * {Function} Called after each feature is added
- */
- featureAdded: function() {},
-
- /**
- * APIProperty: handlerOptions
- * {Object} Used to set non-default properties on the control's handler
- */
- handlerOptions: null,
-
- /**
- * Constructor: OpenLayers.Control.DrawFeature
+ * APIMethod: getLongitudeFromMapObjectLonLat
*
* Parameters:
- * layer - {<OpenLayers.Layer.Vector>}
- * handler - {<OpenLayers.Handler>}
- * options - {Object}
+ * moLonLat - {Object} MapObject LonLat format
+ *
+ * Returns:
+ * {Float} Longitude of the given MapObject LonLat
*/
- initialize: function(layer, handler, options) {
-
- // concatenate events specific to vector with those from the base
- this.EVENT_TYPES =
- OpenLayers.Control.DrawFeature.prototype.EVENT_TYPES.concat(
- OpenLayers.Control.prototype.EVENT_TYPES
- );
-
- OpenLayers.Control.prototype.initialize.apply(this, [options]);
- this.callbacks = OpenLayers.Util.extend(
- {
- done: this.drawFeature,
- modify: function(vertex, feature) {
- this.layer.events.triggerEvent(
- "sketchmodified", {vertex: vertex, feature: feature}
- );
- },
- create: function(vertex, feature) {
- this.layer.events.triggerEvent(
- "sketchstarted", {vertex: vertex, feature: feature}
- );
- }
- },
- this.callbacks
- );
- this.layer = layer;
- this.handlerOptions = this.handlerOptions || {};
- if (!("multi" in this.handlerOptions)) {
- this.handlerOptions.multi = this.multi;
- }
- var sketchStyle = this.layer.styleMap && this.layer.styleMap.styles.temporary;
- if(sketchStyle) {
- this.handlerOptions.layerOptions = OpenLayers.Util.applyDefaults(
- this.handlerOptions.layerOptions,
- {styleMap: new OpenLayers.StyleMap({"default": sketchStyle})}
- );
- }
- this.handler = new handler(this, this.callbacks, this.handlerOptions);
+ getLongitudeFromMapObjectLonLat: function(moLonLat) {
+ return this.sphericalMercator ?
+ this.forwardMercator(moLonLat.Longitude, moLonLat.Latitude).lon :
+ moLonLat.Longitude;
},
/**
- * Method: drawFeature
- */
- drawFeature: function(geometry) {
- var feature = new OpenLayers.Feature.Vector(geometry);
- var proceed = this.layer.events.triggerEvent(
- "sketchcomplete", {feature: feature}
- );
- if(proceed !== false) {
- feature.state = OpenLayers.State.INSERT;
- this.layer.addFeatures([feature]);
- this.featureAdded(feature);
- this.events.triggerEvent("featureadded",{feature : feature});
- }
- },
-
- CLASS_NAME: "OpenLayers.Control.DrawFeature"
-});
-/* ======================================================================
- OpenLayers/Control/Measure.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/Feature/Vector.js
- */
-
-/**
- * Class: OpenLayers.Control.Measure
- * Allows for drawing of features for measurements.
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * Constant: EVENT_TYPES
- * {Array(String)} Supported application event types. Register a listener
- * for a particular event with the following syntax:
- * (code)
- * control.events.register(type, obj, listener);
- * (end)
- *
- * Listeners will be called with a reference to an event object. The
- * properties of this event depends on exactly what happened.
- *
- * Supported control event types (in addition to those from <OpenLayers.Control>):
- * measure - Triggered when a measurement sketch is complete. Listeners
- * will receive an event with measure, units, order, and geometry
- * properties.
- * measurepartial - Triggered when a new point is added to the
- * measurement sketch. Listeners receive an event with measure,
- * units, order, and geometry.
- */
- EVENT_TYPES: ['measure', 'measurepartial'],
-
- /**
- * APIProperty: handlerOptions
- * {Object} Used to set non-default properties on the control's handler
- */
- handlerOptions: null,
-
- /**
- * Property: callbacks
- * {Object} The functions that are sent to the handler for callback
- */
- callbacks: null,
-
- /**
- * Property: displaySystem
- * {String} Display system for output measurements. Supported values
- * are 'english', 'metric', and 'geographic'. Default is 'metric'.
- */
- displaySystem: 'metric',
-
- /**
- * Property: geodesic
- * {Boolean} Calculate geodesic metrics instead of planar metrics. This
- * requires that geometries can be transformed into Geographic/WGS84
- * (if that is not already the map projection). Default is false.
- */
- geodesic: false,
-
- /**
- * Property: displaySystemUnits
- * {Object} Units for various measurement systems. Values are arrays
- * of unit abbreviations (from OpenLayers.INCHES_PER_UNIT) in decreasing
- * order of length.
- */
- displaySystemUnits: {
- geographic: ['dd'],
- english: ['mi', 'ft', 'in'],
- metric: ['km', 'm']
- },
-
- /**
- * Property: delay
- * {Number} Number of milliseconds between clicks before the event is
- * considered a double-click. The "measurepartial" event will not
- * be triggered if the sketch is completed within this time. This
- * is required for IE where creating a browser reflow (if a listener
- * is modifying the DOM by displaying the measurement values) messes
- * with the dblclick listener in the sketch handler.
- */
- partialDelay: 300,
-
- /**
- * Property: delayedTrigger
- * {Number} Timeout id of trigger for measurepartial.
- */
- delayedTrigger: null,
-
- /**
- * APIProperty: persist
- * {Boolean} Keep the temporary measurement sketch drawn after the
- * measurement is complete. The geometry will persist until a new
- * measurement is started, the control is deactivated, or <cancel> is
- * called.
- */
- persist: false,
-
- /**
- * Constructor: OpenLayers.Control.Measure
+ * APIMethod: getLatitudeFromMapObjectLonLat
*
* Parameters:
- * handler - {<OpenLayers.Handler>}
- * options - {Object}
- */
- initialize: function(handler, options) {
- // concatenate events specific to measure with those from the base
- this.EVENT_TYPES =
- OpenLayers.Control.Measure.prototype.EVENT_TYPES.concat(
- OpenLayers.Control.prototype.EVENT_TYPES
- );
- OpenLayers.Control.prototype.initialize.apply(this, [options]);
- this.callbacks = OpenLayers.Util.extend(
- {done: this.measureComplete, point: this.measurePartial},
- this.callbacks
- );
-
- // let the handler options override, so old code that passes 'persist'
- // directly to the handler does not need an update
- this.handlerOptions = OpenLayers.Util.extend(
- {persist: this.persist}, this.handlerOptions
- );
- this.handler = new handler(this, this.callbacks, this.handlerOptions);
- },
-
- /**
- * APIMethod: cancel
- * Stop the control from measuring. If <persist> is true, the temporary
- * sketch will be erased.
- */
- cancel: function() {
- this.handler.cancel();
- },
-
- /**
- * Method: updateHandler
- *
- * Parameters:
- * handler - {Function} One of the sketch handler constructors.
- * options - {Object} Options for the handler.
- */
- updateHandler: function(handler, options) {
- var active = this.active;
- if(active) {
- this.deactivate();
- }
- this.handler = new handler(this, this.callbacks, options);
- if(active) {
- this.activate();
- }
- },
-
- /**
- * Method: measureComplete
- * Called when the measurement sketch is done.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- */
- measureComplete: function(geometry) {
- if(this.delayedTrigger) {
- window.clearTimeout(this.delayedTrigger);
- }
- this.measure(geometry, "measure");
- },
-
- /**
- * Method: measurePartial
- * Called each time a new point is added to the measurement sketch.
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point>} The last point added.
- * geometry - {<OpenLayers.Geometry>} The sketch geometry.
- */
- measurePartial: function(point, geometry) {
- if (geometry.getLength() > 0) {
- geometry = geometry.clone();
- this.delayedTrigger = window.setTimeout(
- OpenLayers.Function.bind(function() {
- this.measure(geometry, "measurepartial");
- }, this),
- this.partialDelay
- );
- }
- },
-
- /**
- * Method: measure
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * eventType - {String}
- */
- measure: function(geometry, eventType) {
- var stat, order;
- if(geometry.CLASS_NAME.indexOf('LineString') > -1) {
- stat = this.getBestLength(geometry);
- order = 1;
- } else {
- stat = this.getBestArea(geometry);
- order = 2;
- }
- this.events.triggerEvent(eventType, {
- measure: stat[0],
- units: stat[1],
- order: order,
- geometry: geometry
- });
- },
-
- /**
- * Method: getBestArea
- * Based on the <displaySystem> returns the area of a geometry.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- *
+ * moLonLat - {Object} MapObject LonLat format
+ *
* Returns:
- * {Array([Float, String])} Returns a two item array containing the
- * area and the units abbreviation.
+ * {Float} Latitude of the given MapObject LonLat
*/
- getBestArea: function(geometry) {
- var units = this.displaySystemUnits[this.displaySystem];
- var unit, area;
- for(var i=0, len=units.length; i<len; ++i) {
- unit = units[i];
- area = this.getArea(geometry, unit);
- if(area > 1) {
- break;
- }
- }
- return [area, unit];
+ getLatitudeFromMapObjectLonLat: function(moLonLat) {
+ return this.sphericalMercator ?
+ this.forwardMercator(moLonLat.Longitude, moLonLat.Latitude).lat :
+ moLonLat.Latitude;
},
-
- /**
- * Method: getArea
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * units - {String} Unit abbreviation
- *
- * Returns:
- * {Float} The geometry area in the given units.
- */
- getArea: function(geometry, units) {
- var area, geomUnits;
- if(this.geodesic) {
- area = geometry.getGeodesicArea(this.map.getProjectionObject());
- geomUnits = "m";
- } else {
- area = geometry.getArea();
- geomUnits = this.map.getUnits();
- }
- var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units];
- if(inPerDisplayUnit) {
- var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits];
- area *= Math.pow((inPerMapUnit / inPerDisplayUnit), 2);
- }
- return area;
- },
-
- /**
- * Method: getBestLength
- * Based on the <displaySystem> returns the length of a geometry.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {Array([Float, String])} Returns a two item array containing the
- * length and the units abbreviation.
- */
- getBestLength: function(geometry) {
- var units = this.displaySystemUnits[this.displaySystem];
- var unit, length;
- for(var i=0, len=units.length; i<len; ++i) {
- unit = units[i];
- length = this.getLength(geometry, unit);
- if(length > 1) {
- break;
- }
- }
- return [length, unit];
- },
/**
- * Method: getLength
- *
+ * APIMethod: getMapObjectLonLatFromLonLat
+ *
* Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * units - {String} Unit abbreviation
- *
+ * lon - {Float}
+ * lat - {Float}
+ *
* Returns:
- * {Float} The geometry length in the given units.
+ * {Object} MapObject LonLat built from lon and lat params
*/
- getLength: function(geometry, units) {
- var length, geomUnits;
- if(this.geodesic) {
- length = geometry.getGeodesicLength(this.map.getProjectionObject());
- geomUnits = "m";
+ getMapObjectLonLatFromLonLat: function(lon, lat) {
+ var veLatLong;
+ if(this.sphericalMercator) {
+ var lonlat = this.inverseMercator(lon, lat);
+ veLatLong = new VELatLong(lonlat.lat, lonlat.lon);
} else {
- length = geometry.getLength();
- geomUnits = this.map.getUnits();
+ veLatLong = new VELatLong(lat, lon);
}
- var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units];
- if(inPerDisplayUnit) {
- var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits];
- length *= (inPerMapUnit / inPerDisplayUnit);
- }
- return length;
+ return veLatLong;
},
- CLASS_NAME: "OpenLayers.Control.Measure"
-});
-/* ======================================================================
- OpenLayers/Control/ZoomBox.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/Handler/Box.js
- */
-
-/**
- * Class: OpenLayers.Control.ZoomBox
- * The ZoomBox control enables zooming directly to a given extent, by drawing
- * a box on the map. The box is drawn by holding down shift, whilst dragging
- * the mouse.
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, {
- /**
- * Property: type
- * {OpenLayers.Control.TYPE}
- */
- type: OpenLayers.Control.TYPE_TOOL,
-
- /**
- * Property: out
- * {Boolean} Should the control be used for zooming out?
- */
- out: false,
-
- /**
- * Property: alwaysZoom
- * {Boolean} Always zoom in/out, when box drawed
- */
- alwaysZoom: false,
-
- /**
- * Method: draw
- */
- draw: function() {
- this.handler = new OpenLayers.Handler.Box( this,
- {done: this.zoomBox}, {keyMask: this.keyMask} );
- },
-
- /**
- * Method: zoomBox
- *
- * Parameters:
- * position - {<OpenLayers.Bounds>} or {<OpenLayers.Pixel>}
- */
- zoomBox: function (position) {
- if (position instanceof OpenLayers.Bounds) {
- var bounds;
- if (!this.out) {
- var minXY = this.map.getLonLatFromPixel(
- new OpenLayers.Pixel(position.left, position.bottom));
- var maxXY = this.map.getLonLatFromPixel(
- new OpenLayers.Pixel(position.right, position.top));
- bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat,
- maxXY.lon, maxXY.lat);
- } else {
- var pixWidth = Math.abs(position.right-position.left);
- var pixHeight = Math.abs(position.top-position.bottom);
- var zoomFactor = Math.min((this.map.size.h / pixHeight),
- (this.map.size.w / pixWidth));
- var extent = this.map.getExtent();
- var center = this.map.getLonLatFromPixel(
- position.getCenterPixel());
- var xmin = center.lon - (extent.getWidth()/2)*zoomFactor;
- var xmax = center.lon + (extent.getWidth()/2)*zoomFactor;
- var ymin = center.lat - (extent.getHeight()/2)*zoomFactor;
- var ymax = center.lat + (extent.getHeight()/2)*zoomFactor;
- bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax);
- }
- // always zoom in/out
- var lastZoom = this.map.getZoom();
- this.map.zoomToExtent(bounds);
- if (lastZoom == this.map.getZoom() && this.alwaysZoom == true){
- this.map.zoomTo(lastZoom + (this.out ? -1 : 1));
- }
- } else { // it's a pixel
- if (!this.out) {
- this.map.setCenter(this.map.getLonLatFromPixel(position),
- this.map.getZoom() + 1);
- } else {
- this.map.setCenter(this.map.getLonLatFromPixel(position),
- this.map.getZoom() - 1);
- }
- }
- },
-
- CLASS_NAME: "OpenLayers.Control.ZoomBox"
-});
-/* ======================================================================
- OpenLayers/Format/WKT.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Format.js
- * @requires OpenLayers/Feature/Vector.js
- */
-
-/**
- * Class: OpenLayers.Format.WKT
- * Class for reading and writing Well-Known Text. Create a new instance
- * with the <OpenLayers.Format.WKT> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Format>
- */
-OpenLayers.Format.WKT = OpenLayers.Class(OpenLayers.Format, {
+ // Pixel
/**
- * Constructor: OpenLayers.Format.WKT
- * Create a new parser for WKT
- *
+ * APIMethod: getXFromMapObjectPixel
+ *
* Parameters:
- * options - {Object} An optional object whose properties will be set on
- * this instance
- *
+ * moPixel - {Object} MapObject Pixel format
+ *
* Returns:
- * {<OpenLayers.Format.WKT>} A new WKT parser.
+ * {Integer} X value of the MapObject Pixel
*/
- initialize: function(options) {
- this.regExes = {
- 'typeStr': /^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/,
- 'spaces': /\s+/,
- 'parenComma': /\)\s*,\s*\(/,
- 'doubleParenComma': /\)\s*\)\s*,\s*\(\s*\(/, // can't use {2} here
- 'trimParens': /^\s*\(?(.*?)\)?\s*$/
- };
- OpenLayers.Format.prototype.initialize.apply(this, [options]);
+ getXFromMapObjectPixel: function(moPixel) {
+ return moPixel.x;
},
/**
- * Method: read
- * Deserialize a WKT string and return a vector feature or an
- * array of vector features. Supports WKT for POINT, MULTIPOINT,
- * LINESTRING, MULTILINESTRING, POLYGON, MULTIPOLYGON, and
- * GEOMETRYCOLLECTION.
- *
+ * APIMethod: getYFromMapObjectPixel
+ *
* Parameters:
- * wkt - {String} A WKT string
- *
+ * moPixel - {Object} MapObject Pixel format
+ *
* Returns:
- * {<OpenLayers.Feature.Vector>|Array} A feature or array of features for
- * GEOMETRYCOLLECTION WKT.
+ * {Integer} Y value of the MapObject Pixel
*/
- read: function(wkt) {
- var features, type, str;
- var matches = this.regExes.typeStr.exec(wkt);
- if(matches) {
- type = matches[1].toLowerCase();
- str = matches[2];
- if(this.parse[type]) {
- features = this.parse[type].apply(this, [str]);
- }
- if (this.internalProjection && this.externalProjection) {
- if (features &&
- features.CLASS_NAME == "OpenLayers.Feature.Vector") {
- features.geometry.transform(this.externalProjection,
- this.internalProjection);
- } else if (features &&
- type != "geometrycollection" &&
- typeof features == "object") {
- for (var i=0, len=features.length; i<len; i++) {
- var component = features[i];
- component.geometry.transform(this.externalProjection,
- this.internalProjection);
- }
- }
- }
- }
- return features;
+ getYFromMapObjectPixel: function(moPixel) {
+ return moPixel.y;
},
/**
- * Method: write
- * Serialize a feature or array of features into a WKT string.
- *
+ * APIMethod: getMapObjectPixelFromXY
+ *
* Parameters:
- * features - {<OpenLayers.Feature.Vector>|Array} A feature or array of
- * features
- *
+ * x - {Integer}
+ * y - {Integer}
+ *
* Returns:
- * {String} The WKT string representation of the input geometries
+ * {Object} MapObject Pixel from x and y parameters
*/
- write: function(features) {
- var collection, geometry, type, data, isCollection;
- if(features.constructor == Array) {
- collection = features;
- isCollection = true;
- } else {
- collection = [features];
- isCollection = false;
- }
- var pieces = [];
- if(isCollection) {
- pieces.push('GEOMETRYCOLLECTION(');
- }
- for(var i=0, len=collection.length; i<len; ++i) {
- if(isCollection && i>0) {
- pieces.push(',');
- }
- geometry = collection[i].geometry;
- type = geometry.CLASS_NAME.split('.')[2].toLowerCase();
- if(!this.extract[type]) {
- return null;
- }
- if (this.internalProjection && this.externalProjection) {
- geometry = geometry.clone();
- geometry.transform(this.internalProjection,
- this.externalProjection);
- }
- data = this.extract[type].apply(this, [geometry]);
- pieces.push(type.toUpperCase() + '(' + data + ')');
- }
- if(isCollection) {
- pieces.push(')');
- }
- return pieces.join('');
+ getMapObjectPixelFromXY: function(x, y) {
+ //the conditional here is to test if we are running the v6 of VE
+ return (typeof VEPixel != 'undefined') ? new VEPixel(x, y)
+ : new Msn.VE.Pixel(x, y);
},
-
- /**
- * Object with properties corresponding to the geometry types.
- * Property values are functions that do the actual data extraction.
- */
- extract: {
- /**
- * Return a space delimited string of point coordinates.
- * @param {<OpenLayers.Geometry.Point>} point
- * @returns {String} A string of coordinates representing the point
- */
- 'point': function(point) {
- return point.x + ' ' + point.y;
- },
- /**
- * Return a comma delimited string of point coordinates from a multipoint.
- * @param {<OpenLayers.Geometry.MultiPoint>} multipoint
- * @returns {String} A string of point coordinate strings representing
- * the multipoint
- */
- 'multipoint': function(multipoint) {
- var array = [];
- for(var i=0, len=multipoint.components.length; i<len; ++i) {
- array.push('(' +
- this.extract.point.apply(this, [multipoint.components[i]]) +
- ')');
- }
- return array.join(',');
- },
-
- /**
- * Return a comma delimited string of point coordinates from a line.
- * @param {<OpenLayers.Geometry.LineString>} linestring
- * @returns {String} A string of point coordinate strings representing
- * the linestring
- */
- 'linestring': function(linestring) {
- var array = [];
- for(var i=0, len=linestring.components.length; i<len; ++i) {
- array.push(this.extract.point.apply(this, [linestring.components[i]]));
- }
- return array.join(',');
- },
-
- /**
- * Return a comma delimited string of linestring strings from a multilinestring.
- * @param {<OpenLayers.Geometry.MultiLineString>} multilinestring
- * @returns {String} A string of of linestring strings representing
- * the multilinestring
- */
- 'multilinestring': function(multilinestring) {
- var array = [];
- for(var i=0, len=multilinestring.components.length; i<len; ++i) {
- array.push('(' +
- this.extract.linestring.apply(this, [multilinestring.components[i]]) +
- ')');
- }
- return array.join(',');
- },
-
- /**
- * Return a comma delimited string of linear ring arrays from a polygon.
- * @param {<OpenLayers.Geometry.Polygon>} polygon
- * @returns {String} An array of linear ring arrays representing the polygon
- */
- 'polygon': function(polygon) {
- var array = [];
- for(var i=0, len=polygon.components.length; i<len; ++i) {
- array.push('(' +
- this.extract.linestring.apply(this, [polygon.components[i]]) +
- ')');
- }
- return array.join(',');
- },
-
- /**
- * Return an array of polygon arrays from a multipolygon.
- * @param {<OpenLayers.Geometry.MultiPolygon>} multipolygon
- * @returns {Array} An array of polygon arrays representing
- * the multipolygon
- */
- 'multipolygon': function(multipolygon) {
- var array = [];
- for(var i=0, len=multipolygon.components.length; i<len; ++i) {
- array.push('(' +
- this.extract.polygon.apply(this, [multipolygon.components[i]]) +
- ')');
- }
- return array.join(',');
- }
-
- },
-
- /**
- * Object with properties corresponding to the geometry types.
- * Property values are functions that do the actual parsing.
- */
- parse: {
- /**
- * Return point feature given a point WKT fragment.
- * @param {String} str A WKT fragment representing the point
- * @returns {<OpenLayers.Feature.Vector>} A point feature
- * @private
- */
- 'point': function(str) {
- var coords = OpenLayers.String.trim(str).split(this.regExes.spaces);
- return new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.Point(coords[0], coords[1])
- );
- },
-
- /**
- * Return a multipoint feature given a multipoint WKT fragment.
- * @param {String} A WKT fragment representing the multipoint
- * @returns {<OpenLayers.Feature.Vector>} A multipoint feature
- * @private
- */
- 'multipoint': function(str) {
- var point;
- var points = OpenLayers.String.trim(str).split(this.regExes.parenComma);
- var components = [];
- for(var i=0, len=points.length; i<len; ++i) {
- point = points[i].replace(this.regExes.trimParens, '$1');
- components.push(this.parse.point.apply(this, [point]).geometry);
- }
- return new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.MultiPoint(components)
- );
- },
-
- /**
- * Return a linestring feature given a linestring WKT fragment.
- * @param {String} A WKT fragment representing the linestring
- * @returns {<OpenLayers.Feature.Vector>} A linestring feature
- * @private
- */
- 'linestring': function(str) {
- var points = OpenLayers.String.trim(str).split(',');
- var components = [];
- for(var i=0, len=points.length; i<len; ++i) {
- components.push(this.parse.point.apply(this, [points[i]]).geometry);
- }
- return new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.LineString(components)
- );
- },
-
- /**
- * Return a multilinestring feature given a multilinestring WKT fragment.
- * @param {String} A WKT fragment representing the multilinestring
- * @returns {<OpenLayers.Feature.Vector>} A multilinestring feature
- * @private
- */
- 'multilinestring': function(str) {
- var line;
- var lines = OpenLayers.String.trim(str).split(this.regExes.parenComma);
- var components = [];
- for(var i=0, len=lines.length; i<len; ++i) {
- line = lines[i].replace(this.regExes.trimParens, '$1');
- components.push(this.parse.linestring.apply(this, [line]).geometry);
- }
- return new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.MultiLineString(components)
- );
- },
-
- /**
- * Return a polygon feature given a polygon WKT fragment.
- * @param {String} A WKT fragment representing the polygon
- * @returns {<OpenLayers.Feature.Vector>} A polygon feature
- * @private
- */
- 'polygon': function(str) {
- var ring, linestring, linearring;
- var rings = OpenLayers.String.trim(str).split(this.regExes.parenComma);
- var components = [];
- for(var i=0, len=rings.length; i<len; ++i) {
- ring = rings[i].replace(this.regExes.trimParens, '$1');
- linestring = this.parse.linestring.apply(this, [ring]).geometry;
- linearring = new OpenLayers.Geometry.LinearRing(linestring.components);
- components.push(linearring);
- }
- return new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.Polygon(components)
- );
- },
-
- /**
- * Return a multipolygon feature given a multipolygon WKT fragment.
- * @param {String} A WKT fragment representing the multipolygon
- * @returns {<OpenLayers.Feature.Vector>} A multipolygon feature
- * @private
- */
- 'multipolygon': function(str) {
- var polygon;
- var polygons = OpenLayers.String.trim(str).split(this.regExes.doubleParenComma);
- var components = [];
- for(var i=0, len=polygons.length; i<len; ++i) {
- polygon = polygons[i].replace(this.regExes.trimParens, '$1');
- components.push(this.parse.polygon.apply(this, [polygon]).geometry);
- }
- return new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.MultiPolygon(components)
- );
- },
-
- /**
- * Return an array of features given a geometrycollection WKT fragment.
- * @param {String} A WKT fragment representing the geometrycollection
- * @returns {Array} An array of OpenLayers.Feature.Vector
- * @private
- */
- 'geometrycollection': function(str) {
- // separate components of the collection with |
- str = str.replace(/,\s*([A-Za-z])/g, '|$1');
- var wktArray = OpenLayers.String.trim(str).split('|');
- var components = [];
- for(var i=0, len=wktArray.length; i<len; ++i) {
- components.push(OpenLayers.Format.WKT.prototype.read.apply(this,[wktArray[i]]));
- }
- return components;
- }
-
- },
-
- CLASS_NAME: "OpenLayers.Format.WKT"
-});
+ CLASS_NAME: "OpenLayers.Layer.VirtualEarth"
+});
/* ======================================================================
OpenLayers/Layer/Google.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
@@ -27660,6 +11144,7 @@
* @requires OpenLayers/Layer/SphericalMercator.js
* @requires OpenLayers/Layer/EventPane.js
* @requires OpenLayers/Layer/FixedZoomLevels.js
+ * @requires OpenLayers/Lang.js
*/
/**
@@ -28446,1581 +11931,4663 @@
};
/* ======================================================================
- OpenLayers/Layer/Grid.js
+ OpenLayers/Format.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
-
/**
- * @requires OpenLayers/Layer/HTTPRequest.js
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/Util.js
* @requires OpenLayers/Console.js
+ * @requires OpenLayers/Lang.js
*/
/**
- * Class: OpenLayers.Layer.Grid
- * Base class for layers that use a lattice of tiles. Create a new grid
- * layer with the <OpenLayers.Layer.Grid> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Layer.HTTPRequest>
+ * 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.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
+OpenLayers.Format = OpenLayers.Class({
/**
- * APIProperty: tileSize
- * {<OpenLayers.Size>}
+ * Property: options
+ * {Object} A reference to options passed to the constructor.
*/
- tileSize: null,
+ options: null,
/**
- * Property: grid
- * {Array(Array(<OpenLayers.Tile>))} This is an array of rows, each row is
- * an array of tiles.
+ * APIProperty: externalProjection
+ * {<OpenLayers.Projection>} 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
+ * {<OpenLayers.Projection.addTransform>} for more information on
+ * custom transformations.
*/
- grid: null,
+ externalProjection: null,
/**
- * APIProperty: singleTile
- * {Boolean} Moves the layer into single-tile mode, meaning that one tile
- * will be loaded. The tile's size will be determined by the 'ratio'
- * property. When the tile is dragged such that it does not cover the
- * entire viewport, it is reloaded.
+ * APIProperty: internalProjection
+ * {<OpenLayers.Projection>} 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
+ * {<OpenLayers.Projection.addTransform>} for more information on
+ * custom transformations.
*/
- singleTile: false,
+ internalProjection: null,
- /** APIProperty: ratio
- * {Float} Used only when in single-tile mode, this specifies the
- * ratio of the size of the single tile to the size of the map.
+ /**
+ * APIProperty: data
+ * {Object} When <keepData> is true, this is the parsed string sent to
+ * <read>.
*/
- ratio: 1.5,
+ data: null,
/**
- * APIProperty: buffer
- * {Integer} Used only when in gridded mode, this specifies the number of
- * extra rows and colums of tiles on each side which will
- * surround the minimum grid tiles to cover the map.
+ * APIProperty: keepData
+ * {Object} Maintain a reference (<data>) to the most recently read data.
+ * Default is false.
*/
- buffer: 2,
+ keepData: false,
/**
- * APIProperty: numLoadingTiles
- * {Integer} How many tiles are still loading?
+ * 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 <read>, the data property will be
+ * set to the parsed object (e.g. the json or xml object).
+ *
+ * Returns:
+ * An instance of OpenLayers.Format
*/
- numLoadingTiles: 0,
+ initialize: function(options) {
+ OpenLayers.Util.extend(this, options);
+ this.options = options;
+ },
+
+ /**
+ * APIMethod: destroy
+ * Clean up.
+ */
+ destroy: function() {
+ },
/**
- * Constructor: OpenLayers.Layer.Grid
- * Create a new grid layer
+ * 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) {
+ OpenLayers.Console.userError(OpenLayers.i18n("readNotImplemented"));
+ },
+
+ /**
+ * Method: write
+ * Accept an object, and return a string.
+ *
* Parameters:
- * name - {String}
- * url - {String}
- * params - {Object}
- * options - {Object} Hashtable of extra options to tag onto the layer
+ * object - {Object} Object to be serialized
+ *
+ * Returns:
+ * {String} A string representation of the object.
*/
- initialize: function(name, url, params, options) {
- OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,
- arguments);
-
- //grid layers will trigger 'tileloaded' when each new tile is
- // loaded, as a means of progress update to listeners.
- // listeners can access 'numLoadingTiles' if they wish to keep track
- // of the loading progress
- //
- this.events.addEventType("tileloaded");
-
- this.grid = [];
+ write: function(object) {
+ OpenLayers.Console.userError(OpenLayers.i18n("writeNotImplemented"));
},
+ CLASS_NAME: "OpenLayers.Format"
+});
+/* ======================================================================
+ OpenLayers/Format/XML.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format.js
+ */
+
+/**
+ * Class: OpenLayers.Format.XML
+ * Read and write XML. For cross-browser XML generation, use methods on an
+ * instance of the XML format class instead of on <code>document<end>.
+ * The DOM creation and traversing methods exposed here all mimic the
+ * W3C XML DOM methods. Create a new parser with the
+ * <OpenLayers.Format.XML> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Format>
+ */
+OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
+
/**
+ * Property: namespaces
+ * {Object} Mapping of namespace aliases to namespace URIs. Properties
+ * of this object should not be set individually. Read-only. All
+ * XML subclasses should have their own namespaces object. Use
+ * <setNamespace> to add or set a namespace alias after construction.
+ */
+ namespaces: null,
+
+ /**
+ * Property: namespaceAlias
+ * {Object} Mapping of namespace URI to namespace alias. This object
+ * is read-only. Use <setNamespace> to add or set a namespace alias.
+ */
+ namespaceAlias: null,
+
+ /**
+ * Property: defaultPrefix
+ * {String} The default namespace alias for creating element nodes.
+ */
+ defaultPrefix: null,
+
+ /**
+ * Property: readers
+ * Contains public functions, grouped by namespace prefix, that will
+ * be applied when a namespaced node is found matching the function
+ * name. The function will be applied in the scope of this parser
+ * with two arguments: the node being read and a context object passed
+ * from the parent.
+ */
+ readers: {},
+
+ /**
+ * Property: writers
+ * As a compliment to the <readers> property, this structure contains public
+ * writing functions grouped by namespace alias and named like the
+ * node names they produce.
+ */
+ writers: {},
+
+ /**
+ * Property: xmldom
+ * {XMLDom} If this browser uses ActiveX, this will be set to a XMLDOM
+ * object. It is not intended to be a browser sniffing property.
+ * Instead, the xmldom property is used instead of <code>document<end>
+ * where namespaced node creation methods are not supported. In all
+ * other browsers, this remains null.
+ */
+ xmldom: null,
+
+ /**
+ * Constructor: OpenLayers.Format.XML
+ * Construct an XML parser. The parser is used to read and write XML.
+ * Reading XML from a string returns a DOM element. Writing XML from
+ * a DOM element returns a string.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on
+ * the object.
+ */
+ initialize: function(options) {
+ if(window.ActiveXObject) {
+ this.xmldom = new ActiveXObject("Microsoft.XMLDOM");
+ }
+ OpenLayers.Format.prototype.initialize.apply(this, [options]);
+ // clone the namespace object and set all namespace aliases
+ this.namespaces = OpenLayers.Util.extend({}, this.namespaces);
+ this.namespaceAlias = {};
+ for(var alias in this.namespaces) {
+ this.namespaceAlias[this.namespaces[alias]] = alias;
+ }
+ },
+
+ /**
* APIMethod: destroy
- * Deconstruct the layer and clear the grid.
+ * Clean up.
*/
destroy: function() {
- this.clearGrid();
- this.grid = null;
- this.tileSize = null;
- OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments);
+ this.xmldom = null;
+ OpenLayers.Format.prototype.destroy.apply(this, arguments);
},
+
+ /**
+ * Method: setNamespace
+ * Set a namespace alias and URI for the format.
+ *
+ * Parameters:
+ * alias - {String} The namespace alias (prefix).
+ * uri - {String} The namespace URI.
+ */
+ setNamespace: function(alias, uri) {
+ this.namespaces[alias] = uri;
+ this.namespaceAlias[uri] = alias;
+ },
/**
- * Method: clearGrid
- * Go through and remove all tiles from the grid, calling
- * destroy() on each of them to kill circular references
+ * APIMethod: read
+ * Deserialize a XML string and return a DOM node.
+ *
+ * Parameters:
+ * text - {String} A XML string
+
+ * Returns:
+ * {DOMElement} A DOM node
*/
- clearGrid:function() {
- if (this.grid) {
- for(var iRow=0, len=this.grid.length; iRow<len; iRow++) {
- var row = this.grid[iRow];
- for(var iCol=0, clen=row.length; iCol<clen; iCol++) {
- var tile = row[iCol];
- this.removeTileMonitoringHooks(tile);
- tile.destroy();
+ read: function(text) {
+ var index = text.indexOf('<');
+ if(index > 0) {
+ text = text.substring(index);
+ }
+ var node = OpenLayers.Util.Try(
+ OpenLayers.Function.bind((
+ function() {
+ var xmldom;
+ /**
+ * Since we want to be able to call this method on the prototype
+ * itself, this.xmldom may not exist even if in IE.
+ */
+ if(window.ActiveXObject && !this.xmldom) {
+ xmldom = new ActiveXObject("Microsoft.XMLDOM");
+ } else {
+ xmldom = this.xmldom;
+
+ }
+ xmldom.loadXML(text);
+ return xmldom;
}
+ ), this),
+ function() {
+ return new DOMParser().parseFromString(text, 'text/xml');
+ },
+ function() {
+ var req = new XMLHttpRequest();
+ req.open("GET", "data:" + "text/xml" +
+ ";charset=utf-8," + encodeURIComponent(text), false);
+ if(req.overrideMimeType) {
+ req.overrideMimeType("text/xml");
+ }
+ req.send(null);
+ return req.responseXML;
}
- this.grid = [];
+ );
+
+ if(this.keepData) {
+ this.data = node;
}
+
+ return node;
},
/**
- * APIMethod: clone
- * Create a clone of this layer
+ * APIMethod: write
+ * Serialize a DOM node into a XML string.
+ *
+ * Parameters:
+ * node - {DOMElement} A DOM node.
*
+ * Returns:
+ * {String} The XML string representation of the input node.
+ */
+ write: function(node) {
+ var data;
+ if(this.xmldom) {
+ data = node.xml;
+ } else {
+ var serializer = new XMLSerializer();
+ if (node.nodeType == 1) {
+ // Add nodes to a document before serializing. Everything else
+ // is serialized as is. This may need more work. See #1218 .
+ var doc = document.implementation.createDocument("", "", null);
+ if (doc.importNode) {
+ node = doc.importNode(node, true);
+ }
+ doc.appendChild(node);
+ data = serializer.serializeToString(doc);
+ } else {
+ data = serializer.serializeToString(node);
+ }
+ }
+ return data;
+ },
+
+ /**
+ * APIMethod: createElementNS
+ * Create a new element with namespace. This node can be appended to
+ * another node with the standard node.appendChild method. For
+ * cross-browser support, this method must be used instead of
+ * document.createElementNS.
+ *
* Parameters:
- * obj - {Object} Is this ever used?
+ * uri - {String} Namespace URI for the element.
+ * name - {String} The qualified name of the element (prefix:localname).
*
* Returns:
- * {<OpenLayers.Layer.Grid>} An exact clone of this OpenLayers.Layer.Grid
+ * {Element} A DOM element with namespace.
*/
- clone: function (obj) {
-
- if (obj == null) {
- obj = new OpenLayers.Layer.Grid(this.name,
- this.url,
- this.params,
- this.getOptions());
+ createElementNS: function(uri, name) {
+ var element;
+ if(this.xmldom) {
+ if(typeof uri == "string") {
+ element = this.xmldom.createNode(1, name, uri);
+ } else {
+ element = this.xmldom.createNode(1, name, "");
+ }
+ } else {
+ element = document.createElementNS(uri, name);
}
+ return element;
+ },
- //get all additions from superclasses
- obj = OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this, [obj]);
-
- // copy/set any non-init, non-simple values here
- if (this.tileSize != null) {
- obj.tileSize = this.tileSize.clone();
+ /**
+ * APIMethod: createTextNode
+ * Create a text node. This node can be appended to another node with
+ * the standard node.appendChild method. For cross-browser support,
+ * this method must be used instead of document.createTextNode.
+ *
+ * Parameters:
+ * text - {String} The text of the node.
+ *
+ * Returns:
+ * {DOMElement} A DOM text node.
+ */
+ createTextNode: function(text) {
+ var node;
+ if (typeof text !== "string") {
+ text = String(text);
}
-
- // we do not want to copy reference to grid, so we make a new array
- obj.grid = [];
+ if(this.xmldom) {
+ node = this.xmldom.createTextNode(text);
+ } else {
+ node = document.createTextNode(text);
+ }
+ return node;
+ },
- return obj;
- },
-
/**
- * Method: moveTo
- * This function is called whenever the map is moved. All the moving
- * of actual 'tiles' is done by the map, but moveTo's role is to accept
- * a bounds and make sure the data that that bounds requires is pre-loaded.
- *
+ * APIMethod: getElementsByTagNameNS
+ * Get a list of elements on a node given the namespace URI and local name.
+ * To return all nodes in a given namespace, use '*' for the name
+ * argument. To return all nodes of a given (local) name, regardless
+ * of namespace, use '*' for the uri argument.
+ *
* Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * zoomChanged - {Boolean}
- * dragging - {Boolean}
+ * node - {Element} Node on which to search for other nodes.
+ * uri - {String} Namespace URI.
+ * name - {String} Local name of the tag (without the prefix).
+ *
+ * Returns:
+ * {NodeList} A node list or array of elements.
*/
- moveTo:function(bounds, zoomChanged, dragging) {
- OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this, arguments);
-
- bounds = bounds || this.map.getExtent();
-
- if (bounds != null) {
-
- // if grid is empty or zoom has changed, we *must* re-tile
- var forceReTile = !this.grid.length || zoomChanged;
-
- // total bounds of the tiles
- var tilesBounds = this.getTilesBounds();
-
- if (this.singleTile) {
-
- // We want to redraw whenever even the slightest part of the
- // current bounds is not contained by our tile.
- // (thus, we do not specify partial -- its default is false)
- if ( forceReTile ||
- (!dragging && !tilesBounds.containsBounds(bounds))) {
- this.initSingleTile(bounds);
+ getElementsByTagNameNS: function(node, uri, name) {
+ var elements = [];
+ if(node.getElementsByTagNameNS) {
+ elements = node.getElementsByTagNameNS(uri, name);
+ } else {
+ // brute force method
+ var allNodes = node.getElementsByTagName("*");
+ var potentialNode, fullName;
+ for(var i=0, len=allNodes.length; i<len; ++i) {
+ potentialNode = allNodes[i];
+ fullName = (potentialNode.prefix) ?
+ (potentialNode.prefix + ":" + name) : name;
+ if((name == "*") || (fullName == potentialNode.nodeName)) {
+ if((uri == "*") || (uri == potentialNode.namespaceURI)) {
+ elements.push(potentialNode);
+ }
}
- } else {
-
- // if the bounds have changed such that they are not even
- // *partially* contained by our tiles (IE user has
- // programmatically panned to the other side of the earth)
- // then we want to reTile (thus, partial true).
- //
- if (forceReTile || !tilesBounds.containsBounds(bounds, true)) {
- this.initGriddedTiles(bounds);
- } else {
- //we might have to shift our buffer tiles
- this.moveGriddedTiles(bounds);
- }
}
}
+ return elements;
},
-
+
/**
- * APIMethod: setTileSize
- * Check if we are in singleTile mode and if so, set the size as a ratio
- * of the map size (as specified by the layer's 'ratio' property).
+ * APIMethod: getAttributeNodeNS
+ * Get an attribute node given the namespace URI and local name.
*
* Parameters:
- * size - {<OpenLayers.Size>}
+ * node - {Element} Node on which to search for attribute nodes.
+ * uri - {String} Namespace URI.
+ * name - {String} Local name of the attribute (without the prefix).
+ *
+ * Returns:
+ * {DOMElement} An attribute node or null if none found.
*/
- setTileSize: function(size) {
- if (this.singleTile) {
- size = this.map.getSize();
- size.h = parseInt(size.h * this.ratio);
- size.w = parseInt(size.w * this.ratio);
- }
- OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this, [size]);
+ getAttributeNodeNS: function(node, uri, name) {
+ var attributeNode = null;
+ if(node.getAttributeNodeNS) {
+ attributeNode = node.getAttributeNodeNS(uri, name);
+ } else {
+ var attributes = node.attributes;
+ var potentialNode, fullName;
+ for(var i=0, len=attributes.length; i<len; ++i) {
+ potentialNode = attributes[i];
+ if(potentialNode.namespaceURI == uri) {
+ fullName = (potentialNode.prefix) ?
+ (potentialNode.prefix + ":" + name) : name;
+ if(fullName == potentialNode.nodeName) {
+ attributeNode = potentialNode;
+ break;
+ }
+ }
+ }
+ }
+ return attributeNode;
},
-
+
/**
- * Method: getGridBounds
- * Deprecated. This function will be removed in 3.0. Please use
- * getTilesBounds() instead.
+ * APIMethod: getAttributeNS
+ * Get an attribute value given the namespace URI and local name.
*
+ * Parameters:
+ * node - {Element} Node on which to search for an attribute.
+ * uri - {String} Namespace URI.
+ * name - {String} Local name of the attribute (without the prefix).
+ *
* Returns:
- * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
- * currently loaded tiles (including those partially or not at all seen
- * onscreen)
+ * {String} An attribute value or and empty string if none found.
*/
- getGridBounds: function() {
- var msg = "The getGridBounds() function is deprecated. It will be " +
- "removed in 3.0. Please use getTilesBounds() instead.";
- OpenLayers.Console.warn(msg);
- return this.getTilesBounds();
+ getAttributeNS: function(node, uri, name) {
+ var attributeValue = "";
+ if(node.getAttributeNS) {
+ attributeValue = node.getAttributeNS(uri, name) || "";
+ } else {
+ var attributeNode = this.getAttributeNodeNS(node, uri, name);
+ if(attributeNode) {
+ attributeValue = attributeNode.nodeValue;
+ }
+ }
+ return attributeValue;
},
+
+ /**
+ * APIMethod: getChildValue
+ * Get the textual value of the node if it exists, or return an
+ * optional default string. Returns an empty string if no first child
+ * exists and no default value is supplied.
+ *
+ * Parameters:
+ * node - {DOMElement} The element used to look for a first child value.
+ * def - {String} Optional string to return in the event that no
+ * first child value exists.
+ *
+ * Returns:
+ * {String} The value of the first child of the given node.
+ */
+ getChildValue: function(node, def) {
+ var value = def || "";
+ if(node) {
+ for(var child=node.firstChild; child; child=child.nextSibling) {
+ switch(child.nodeType) {
+ case 3: // text node
+ case 4: // cdata section
+ value += child.nodeValue;
+ }
+ }
+ }
+ return value;
+ },
/**
- * APIMethod: getTilesBounds
- * Return the bounds of the tile grid.
+ * APIMethod: concatChildValues
+ * *Deprecated*. Use <getChildValue> instead.
*
+ * Concatenate the value of all child nodes if any exist, or return an
+ * optional default string. Returns an empty string if no children
+ * exist and no default value is supplied. Not optimized for large
+ * numbers of child nodes.
+ *
+ * Parameters:
+ * node - {DOMElement} The element used to look for child values.
+ * def - {String} Optional string to return in the event that no
+ * child exist.
+ *
* Returns:
- * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
- * currently loaded tiles (including those partially or not at all seen
- * onscreen).
+ * {String} The concatenated value of all child nodes of the given node.
*/
- getTilesBounds: function() {
- var bounds = null;
-
- if (this.grid.length) {
- var bottom = this.grid.length - 1;
- var bottomLeftTile = this.grid[bottom][0];
+ concatChildValues: function(node, def) {
+ var value = "";
+ var child = node.firstChild;
+ var childValue;
+ while(child) {
+ childValue = child.nodeValue;
+ if(childValue) {
+ value += childValue;
+ }
+ child = child.nextSibling;
+ }
+ if(value == "" && def != undefined) {
+ value = def;
+ }
+ return value;
+ },
- var right = this.grid[0].length - 1;
- var topRightTile = this.grid[0][right];
+ /**
+ * APIMethod: isSimpleContent
+ * Test if the given node has only simple content (i.e. no child element
+ * nodes).
+ *
+ * Parameters:
+ * node - {DOMElement} An element node.
+ *
+ * Returns:
+ * {Boolean} The node has no child element nodes (nodes of type 1).
+ */
+ isSimpleContent: function(node) {
+ var simple = true;
+ for(var child=node.firstChild; child; child=child.nextSibling) {
+ if(child.nodeType === 1) {
+ simple = false;
+ break;
+ }
+ }
+ return simple;
+ },
- bounds = new OpenLayers.Bounds(bottomLeftTile.bounds.left,
- bottomLeftTile.bounds.bottom,
- topRightTile.bounds.right,
- topRightTile.bounds.top);
+ /**
+ * APIMethod: contentType
+ * Determine the content type for a given node.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ *
+ * Returns:
+ * {Integer} One of OpenLayers.Format.XML.CONTENT_TYPE.{EMPTY,SIMPLE,COMPLEX,MIXED}
+ * if the node has no, simple, complex, or mixed content.
+ */
+ contentType: function(node) {
+ var simple = false,
+ complex = false;
- }
- return bounds;
+ var type = OpenLayers.Format.XML.CONTENT_TYPE.EMPTY;
+
+ for(var child=node.firstChild; child; child=child.nextSibling) {
+ switch(child.nodeType) {
+ case 1: // element
+ complex = true;
+ break;
+ case 8: // comment
+ break;
+ default:
+ simple = true;
+ }
+ if(complex && simple) {
+ break;
+ }
+ }
+
+ if(complex && simple) {
+ type = OpenLayers.Format.XML.CONTENT_TYPE.MIXED;
+ } else if(complex) {
+ return OpenLayers.Format.XML.CONTENT_TYPE.COMPLEX;
+ } else if(simple) {
+ return OpenLayers.Format.XML.CONTENT_TYPE.SIMPLE;
+ }
+ return type;
},
/**
- * Method: initSingleTile
+ * APIMethod: hasAttributeNS
+ * Determine whether a node has a particular attribute matching the given
+ * name and namespace.
*
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
+ * Parameters:
+ * node - {Element} Node on which to search for an attribute.
+ * uri - {String} Namespace URI.
+ * name - {String} Local name of the attribute (without the prefix).
+ *
+ * Returns:
+ * {Boolean} The node has an attribute matching the name and namespace.
*/
- initSingleTile: function(bounds) {
-
- //determine new tile bounds
- var center = bounds.getCenterLonLat();
- var tileWidth = bounds.getWidth() * this.ratio;
- var tileHeight = bounds.getHeight() * this.ratio;
-
- var tileBounds =
- new OpenLayers.Bounds(center.lon - (tileWidth/2),
- center.lat - (tileHeight/2),
- center.lon + (tileWidth/2),
- center.lat + (tileHeight/2));
-
- var ul = new OpenLayers.LonLat(tileBounds.left, tileBounds.top);
- var px = this.map.getLayerPxFromLonLat(ul);
-
- if (!this.grid.length) {
- this.grid[0] = [];
+ hasAttributeNS: function(node, uri, name) {
+ var found = false;
+ if(node.hasAttributeNS) {
+ found = node.hasAttributeNS(uri, name);
+ } else {
+ found = !!this.getAttributeNodeNS(node, uri, name);
}
-
- var tile = this.grid[0][0];
- if (!tile) {
- tile = this.addTile(tileBounds, px);
-
- this.addTileMonitoringHooks(tile);
- tile.draw();
- this.grid[0][0] = tile;
+ return found;
+ },
+
+ /**
+ * APIMethod: setAttributeNS
+ * Adds a new attribute or changes the value of an attribute with the given
+ * namespace and name.
+ *
+ * Parameters:
+ * node - {Element} Element node on which to set the attribute.
+ * uri - {String} Namespace URI for the attribute.
+ * name - {String} Qualified name (prefix:localname) for the attribute.
+ * value - {String} Attribute value.
+ */
+ setAttributeNS: function(node, uri, name, value) {
+ if(node.setAttributeNS) {
+ node.setAttributeNS(uri, name, value);
} else {
- tile.moveTo(tileBounds, px);
- }
-
- //remove all but our single tile
- this.removeExcessTiles(1,1);
+ if(this.xmldom) {
+ if(uri) {
+ var attribute = node.ownerDocument.createNode(
+ 2, name, uri
+ );
+ attribute.nodeValue = value;
+ node.setAttributeNode(attribute);
+ } else {
+ node.setAttribute(name, value);
+ }
+ } else {
+ throw "setAttributeNS not implemented";
+ }
+ }
},
- /**
- * Method: calculateGridLayout
- * Generate parameters for the grid layout. This
+ /**
+ * Method: createElementNSPlus
+ * Shorthand for creating namespaced elements with optional attributes and
+ * child text nodes.
*
* Parameters:
- * bounds - {<OpenLayers.Bound>}
- * extent - {<OpenLayers.Bounds>}
- * resolution - {Number}
+ * name - {String} The qualified node name.
+ * options - {Object} Optional object for node configuration.
*
+ * Valid options:
+ * uri - {String} Optional namespace uri for the element - supply a prefix
+ * instead if the namespace uri is a property of the format's namespace
+ * object.
+ * attributes - {Object} Optional attributes to be set using the
+ * <setAttributes> method.
+ * value - {String} Optional text to be appended as a text node.
+ *
* Returns:
- * Object containing properties tilelon, tilelat, tileoffsetlat,
- * tileoffsetlat, tileoffsetx, tileoffsety
+ * {Element} An element node.
*/
- calculateGridLayout: function(bounds, extent, resolution) {
- var tilelon = resolution * this.tileSize.w;
- var tilelat = resolution * this.tileSize.h;
-
- var offsetlon = bounds.left - extent.left;
- var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
- var tilecolremain = offsetlon/tilelon - tilecol;
- var tileoffsetx = -tilecolremain * this.tileSize.w;
- var tileoffsetlon = extent.left + tilecol * tilelon;
-
- var offsetlat = bounds.top - (extent.bottom + tilelat);
- var tilerow = Math.ceil(offsetlat/tilelat) + this.buffer;
- var tilerowremain = tilerow - offsetlat/tilelat;
- var tileoffsety = -tilerowremain * this.tileSize.h;
- var tileoffsetlat = extent.bottom + tilerow * tilelat;
-
- return {
- tilelon: tilelon, tilelat: tilelat,
- tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
- tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
- };
+ createElementNSPlus: function(name, options) {
+ options = options || {};
+ // order of prefix preference
+ // 1. in the uri option
+ // 2. in the prefix option
+ // 3. in the qualified name
+ // 4. from the defaultPrefix
+ var uri = options.uri || this.namespaces[options.prefix];
+ if(!uri) {
+ var loc = name.indexOf(":");
+ uri = this.namespaces[name.substring(0, loc)];
+ }
+ if(!uri) {
+ uri = this.namespaces[this.defaultPrefix];
+ }
+ var node = this.createElementNS(uri, name);
+ if(options.attributes) {
+ this.setAttributes(node, options.attributes);
+ }
+ var value = options.value;
+ if(value != null) {
+ node.appendChild(this.createTextNode(value));
+ }
+ return node;
+ },
+
+ /**
+ * Method: setAttributes
+ * Set multiple attributes given key value pairs from an object.
+ *
+ * Parameters:
+ * node - {Element} An element node.
+ * obj - {Object || Array} An object whose properties represent attribute
+ * names and values represent attribute values. If an attribute name
+ * is a qualified name ("prefix:local"), the prefix will be looked up
+ * in the parsers {namespaces} object. If the prefix is found,
+ * setAttributeNS will be used instead of setAttribute.
+ */
+ setAttributes: function(node, obj) {
+ var value, uri;
+ for(var name in obj) {
+ if(obj[name] != null && obj[name].toString) {
+ value = obj[name].toString();
+ // check for qualified attribute name ("prefix:local")
+ uri = this.namespaces[name.substring(0, name.indexOf(":"))] || null;
+ this.setAttributeNS(node, uri, name, value);
+ }
+ }
+ },
+ /**
+ * Method: readNode
+ * Shorthand for applying one of the named readers given the node
+ * namespace and local name. Readers take two args (node, obj) and
+ * generally extend or modify the second.
+ *
+ * Parameters:
+ * node - {DOMElement} The node to be read (required).
+ * obj - {Object} The object to be modified (optional).
+ *
+ * Returns:
+ * {Object} The input object, modified (or a new one if none was provided).
+ */
+ readNode: function(node, obj) {
+ if(!obj) {
+ obj = {};
+ }
+ var group = this.readers[node.namespaceURI ? this.namespaceAlias[node.namespaceURI]: this.defaultPrefix];
+ if(group) {
+ var local = node.localName || node.nodeName.split(":").pop();
+ var reader = group[local] || group["*"];
+ if(reader) {
+ reader.apply(this, [node, obj]);
+ }
+ }
+ return obj;
},
/**
- * Method: initGriddedTiles
- *
+ * Method: readChildNodes
+ * Shorthand for applying the named readers to all children of a node.
+ * For each child of type 1 (element), <readSelf> is called.
+ *
* Parameters:
- * bounds - {<OpenLayers.Bounds>}
+ * node - {DOMElement} The node to be read (required).
+ * obj - {Object} The object to be modified (optional).
+ *
+ * Returns:
+ * {Object} The input object, modified.
*/
- initGriddedTiles:function(bounds) {
-
- // work out mininum number of rows and columns; this is the number of
- // tiles required to cover the viewport plus at least one for panning
+ readChildNodes: function(node, obj) {
+ if(!obj) {
+ obj = {};
+ }
+ var children = node.childNodes;
+ var child;
+ for(var i=0, len=children.length; i<len; ++i) {
+ child = children[i];
+ if(child.nodeType == 1) {
+ this.readNode(child, obj);
+ }
+ }
+ return obj;
+ },
- var viewSize = this.map.getSize();
- var minRows = Math.ceil(viewSize.h/this.tileSize.h) +
- Math.max(1, 2 * this.buffer);
- var minCols = Math.ceil(viewSize.w/this.tileSize.w) +
- Math.max(1, 2 * this.buffer);
-
- var extent = this.getMaxExtent();
- var resolution = this.map.getResolution();
-
- var tileLayout = this.calculateGridLayout(bounds, extent, resolution);
+ /**
+ * Method: writeNode
+ * Shorthand for applying one of the named writers and appending the
+ * results to a node. If a qualified name is not provided for the
+ * second argument (and a local name is used instead), the namespace
+ * of the parent node will be assumed.
+ *
+ * Parameters:
+ * name - {String} The name of a node to generate. If a qualified name
+ * (e.g. "pre:Name") is used, the namespace prefix is assumed to be
+ * in the <writers> group. If a local name is used (e.g. "Name") then
+ * the namespace of the parent is assumed. If a local name is used
+ * and no parent is supplied, then the default namespace is assumed.
+ * obj - {Object} Structure containing data for the writer.
+ * parent - {DOMElement} Result will be appended to this node. If no parent
+ * is supplied, the node will not be appended to anything.
+ *
+ * Returns:
+ * {DOMElement} The child node.
+ */
+ writeNode: function(name, obj, parent) {
+ var prefix, local;
+ var split = name.indexOf(":");
+ if(split > 0) {
+ prefix = name.substring(0, split);
+ local = name.substring(split + 1);
+ } else {
+ if(parent) {
+ prefix = this.namespaceAlias[parent.namespaceURI];
+ } else {
+ prefix = this.defaultPrefix;
+ }
+ local = name;
+ }
+ var child = this.writers[prefix][local].apply(this, [obj]);
+ if(parent) {
+ parent.appendChild(child);
+ }
+ return child;
+ },
- var tileoffsetx = Math.round(tileLayout.tileoffsetx); // heaven help us
- var tileoffsety = Math.round(tileLayout.tileoffsety);
+ /**
+ * APIMethod: getChildEl
+ * Get the first child element. Optionally only return the first child
+ * if it matches the given name and namespace URI.
+ *
+ * Parameters:
+ * node - {DOMElement} The parent node.
+ * name - {String} Optional node name (local) to search for.
+ * uri - {String} Optional namespace URI to search for.
+ *
+ * Returns:
+ * {DOMElement} The first child. Returns null if no element is found, if
+ * something significant besides an element is found, or if the element
+ * found does not match the optional name and uri.
+ */
+ getChildEl: function(node, name, uri) {
+ return node && this.getThisOrNextEl(node.firstChild, name, uri);
+ },
+
+ /**
+ * APIMethod: getNextEl
+ * Get the next sibling element. Optionally get the first sibling only
+ * if it matches the given local name and namespace URI.
+ *
+ * Parameters:
+ * node - {DOMElement} The node.
+ * name - {String} Optional local name of the sibling to search for.
+ * uri - {String} Optional namespace URI of the sibling to search for.
+ *
+ * Returns:
+ * {DOMElement} The next sibling element. Returns null if no element is
+ * found, something significant besides an element is found, or the
+ * found element does not match the optional name and uri.
+ */
+ getNextEl: function(node, name, uri) {
+ return node && this.getThisOrNextEl(node.nextSibling, name, uri);
+ },
+
+ /**
+ * Method: getThisOrNextEl
+ * Return this node or the next element node. Optionally get the first
+ * sibling with the given local name or namespace URI.
+ *
+ * Parameters:
+ * node - {DOMElement} The node.
+ * name - {String} Optional local name of the sibling to search for.
+ * uri - {String} Optional namespace URI of the sibling to search for.
+ *
+ * Returns:
+ * {DOMElement} The next sibling element. Returns null if no element is
+ * found, something significant besides an element is found, or the
+ * found element does not match the query.
+ */
+ getThisOrNextEl: function(node, name, uri) {
+ outer: for(var sibling=node; sibling; sibling=sibling.nextSibling) {
+ switch(sibling.nodeType) {
+ case 1: // Element
+ if((!name || name === (sibling.localName || sibling.nodeName.split(":").pop())) &&
+ (!uri || uri === sibling.namespaceURI)) {
+ // matches
+ break outer;
+ }
+ sibling = null;
+ break outer;
+ case 3: // Text
+ if(/^\s*$/.test(sibling.nodeValue)) {
+ break;
+ }
+ case 4: // CDATA
+ case 6: // ENTITY_NODE
+ case 12: // NOTATION_NODE
+ case 10: // DOCUMENT_TYPE_NODE
+ case 11: // DOCUMENT_FRAGMENT_NODE
+ sibling = null;
+ break outer;
+ } // ignore comments and processing instructions
+ }
+ return sibling || null;
+ },
+
+ /**
+ * APIMethod: lookupNamespaceURI
+ * Takes a prefix and returns the namespace URI associated with it on the given
+ * node if found (and null if not). Supplying null for the prefix will
+ * return the default namespace.
+ *
+ * For browsers that support it, this calls the native lookupNamesapceURI
+ * function. In other browsers, this is an implementation of
+ * http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI.
+ *
+ * For browsers that don't support the attribute.ownerElement property, this
+ * method cannot be called on attribute nodes.
+ *
+ * Parameters:
+ * node - {DOMElement} The node from which to start looking.
+ * prefix - {String} The prefix to lookup or null to lookup the default namespace.
+ *
+ * Returns:
+ * {String} The namespace URI for the given prefix. Returns null if the prefix
+ * cannot be found or the node is the wrong type.
+ */
+ lookupNamespaceURI: function(node, prefix) {
+ var uri = null;
+ if(node) {
+ if(node.lookupNamespaceURI) {
+ uri = node.lookupNamespaceURI(prefix);
+ } else {
+ outer: switch(node.nodeType) {
+ case 1: // ELEMENT_NODE
+ if(node.namespaceURI !== null && node.prefix === prefix) {
+ uri = node.namespaceURI;
+ break outer;
+ }
+ var len = node.attributes.length;
+ if(len) {
+ var attr;
+ for(var i=0; i<len; ++i) {
+ attr = node.attributes[i];
+ if(attr.prefix === "xmlns" && attr.name === "xmlns:" + prefix) {
+ uri = attr.value || null;
+ break outer;
+ } else if(attr.name === "xmlns" && prefix === null) {
+ uri = attr.value || null;
+ break outer;
+ }
+ }
+ }
+ uri = this.lookupNamespaceURI(node.parentNode, prefix);
+ break outer;
+ case 2: // ATTRIBUTE_NODE
+ uri = this.lookupNamespaceURI(node.ownerElement, prefix);
+ break outer;
+ case 9: // DOCUMENT_NODE
+ uri = this.lookupNamespaceURI(node.documentElement, prefix);
+ break outer;
+ case 6: // ENTITY_NODE
+ case 12: // NOTATION_NODE
+ case 10: // DOCUMENT_TYPE_NODE
+ case 11: // DOCUMENT_FRAGMENT_NODE
+ break outer;
+ default:
+ // TEXT_NODE (3), CDATA_SECTION_NODE (4), ENTITY_REFERENCE_NODE (5),
+ // PROCESSING_INSTRUCTION_NODE (7), COMMENT_NODE (8)
+ uri = this.lookupNamespaceURI(node.parentNode, prefix);
+ break outer;
+ }
+ }
+ }
+ return uri;
+ },
+
+ CLASS_NAME: "OpenLayers.Format.XML"
- var tileoffsetlon = tileLayout.tileoffsetlon;
- var tileoffsetlat = tileLayout.tileoffsetlat;
-
- var tilelon = tileLayout.tilelon;
- var tilelat = tileLayout.tilelat;
+});
- this.origin = new OpenLayers.Pixel(tileoffsetx, tileoffsety);
+OpenLayers.Format.XML.CONTENT_TYPE = {EMPTY: 0, SIMPLE: 1, COMPLEX: 2, MIXED: 3};
- var startX = tileoffsetx;
- var startLon = tileoffsetlon;
+/**
+ * APIFunction: OpenLayers.Format.XML.lookupNamespaceURI
+ * Takes a prefix and returns the namespace URI associated with it on the given
+ * node if found (and null if not). Supplying null for the prefix will
+ * return the default namespace.
+ *
+ * For browsers that support it, this calls the native lookupNamesapceURI
+ * function. In other browsers, this is an implementation of
+ * http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI.
+ *
+ * For browsers that don't support the attribute.ownerElement property, this
+ * method cannot be called on attribute nodes.
+ *
+ * Parameters:
+ * node - {DOMElement} The node from which to start looking.
+ * prefix - {String} The prefix to lookup or null to lookup the default namespace.
+ *
+ * Returns:
+ * {String} The namespace URI for the given prefix. Returns null if the prefix
+ * cannot be found or the node is the wrong type.
+ */
+OpenLayers.Format.XML.lookupNamespaceURI = OpenLayers.Function.bind(
+ OpenLayers.Format.XML.prototype.lookupNamespaceURI,
+ OpenLayers.Format.XML.prototype
+);
+/* ======================================================================
+ OpenLayers/Format/WFST.js
+ ====================================================================== */
- var rowidx = 0;
-
- var layerContainerDivLeft = parseInt(this.map.layerContainerDiv.style.left);
- var layerContainerDivTop = parseInt(this.map.layerContainerDiv.style.top);
-
-
- do {
- var row = this.grid[rowidx++];
- if (!row) {
- row = [];
- this.grid.push(row);
- }
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
- tileoffsetlon = startLon;
- tileoffsetx = startX;
- var colidx = 0;
-
- do {
- var tileBounds =
- new OpenLayers.Bounds(tileoffsetlon,
- tileoffsetlat,
- tileoffsetlon + tilelon,
- tileoffsetlat + tilelat);
+/**
+ * @requires OpenLayers/Format.js
+ */
- var x = tileoffsetx;
- x -= layerContainerDivLeft;
+/**
+ * Function: OpenLayers.Format.WFST
+ * Used to create a versioned WFS protocol. Default version is 1.0.0.
+ *
+ * Returns:
+ * {<OpenLayers.Format>} A WFST format of the given version.
+ */
+OpenLayers.Format.WFST = function(options) {
+ options = OpenLayers.Util.applyDefaults(
+ options, OpenLayers.Format.WFST.DEFAULTS
+ );
+ var cls = OpenLayers.Format.WFST["v"+options.version.replace(/\./g, "_")];
+ if(!cls) {
+ throw "Unsupported WFST version: " + options.version;
+ }
+ return new cls(options);
+};
- var y = tileoffsety;
- y -= layerContainerDivTop;
+/**
+ * Constant: OpenLayers.Format.WFST.DEFAULTS
+ * {Object} Default properties for the WFST format.
+ */
+OpenLayers.Format.WFST.DEFAULTS = {
+ "version": "1.0.0"
+};
+/* ======================================================================
+ OpenLayers/Format/WFST/v1.js
+ ====================================================================== */
- var px = new OpenLayers.Pixel(x, y);
- var tile = row[colidx++];
- if (!tile) {
- tile = this.addTile(tileBounds, px);
- this.addTileMonitoringHooks(tile);
- row.push(tile);
- } else {
- tile.moveTo(tileBounds, px, false);
- }
-
- tileoffsetlon += tilelon;
- tileoffsetx += this.tileSize.w;
- } while ((tileoffsetlon <= bounds.right + tilelon * this.buffer)
- || colidx < minCols);
-
- tileoffsetlat -= tilelat;
- tileoffsety += this.tileSize.h;
- } while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer)
- || rowidx < minRows);
-
- //shave off exceess rows and colums
- this.removeExcessTiles(rowidx, colidx);
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
- //now actually draw the tiles
- this.spiralTileLoad();
- },
+/**
+ * @requires OpenLayers/Format/XML.js
+ * @requires OpenLayers/Format/WFST.js
+ */
+/**
+ * Class: OpenLayers.Format.WFST.v1
+ * Superclass for WFST parsers.
+ *
+ * Inherits from:
+ * - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.WFST.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
+
/**
- * Method: getMaxExtent
- * Get this layer's maximum extent. (Implemented as a getter for
- * potential specific implementations in sub-classes.)
- *
- * Returns:
- * {OpenLayers.Bounds}
+ * Property: namespaces
+ * {Object} Mapping of namespace aliases to namespace URIs.
*/
- getMaxExtent: function() {
- return this.maxExtent;
+ namespaces: {
+ xlink: "http://www.w3.org/1999/xlink",
+ xsi: "http://www.w3.org/2001/XMLSchema-instance",
+ wfs: "http://www.opengis.net/wfs",
+ gml: "http://www.opengis.net/gml",
+ ogc: "http://www.opengis.net/ogc"
},
/**
- * Method: spiralTileLoad
- * Starts at the top right corner of the grid and proceeds in a spiral
- * towards the center, adding tiles one at a time to the beginning of a
- * queue.
- *
- * Once all the grid's tiles have been added to the queue, we go back
- * and iterate through the queue (thus reversing the spiral order from
- * outside-in to inside-out), calling draw() on each tile.
+ * Property: defaultPrefix
*/
- spiralTileLoad: function() {
- var tileQueue = [];
-
- var directions = ["right", "down", "left", "up"];
+ defaultPrefix: "wfs",
- var iRow = 0;
- var iCell = -1;
- var direction = OpenLayers.Util.indexOf(directions, "right");
- var directionsTried = 0;
-
- while( directionsTried < directions.length) {
+ /**
+ * Property: version
+ * {String} WFS version number.
+ */
+ version: null,
- var testRow = iRow;
- var testCell = iCell;
+ /**
+ * Property: schemaLocation
+ * {String} Schema location for a particular minor version.
+ */
+ schemaLocations: null,
+
+ /**
+ * APIProperty: srsName
+ * {String} URI for spatial reference system.
+ */
+ srsName: null,
- switch (directions[direction]) {
- case "right":
- testCell++;
- break;
- case "down":
- testRow++;
- break;
- case "left":
- testCell--;
- break;
- case "up":
- testRow--;
- break;
- }
+ /**
+ * APIProperty: extractAttributes
+ * {Boolean} Extract attributes from GML. Default is true.
+ */
+ extractAttributes: true,
- // if the test grid coordinates are within the bounds of the
- // grid, get a reference to the tile.
- var tile = null;
- if ((testRow < this.grid.length) && (testRow >= 0) &&
- (testCell < this.grid[0].length) && (testCell >= 0)) {
- tile = this.grid[testRow][testCell];
- }
-
- if ((tile != null) && (!tile.queued)) {
- //add tile to beginning of queue, mark it as queued.
- tileQueue.unshift(tile);
- tile.queued = true;
-
- //restart the directions counter and take on the new coords
- directionsTried = 0;
- iRow = testRow;
- iCell = testCell;
+ /**
+ * APIProperty: xy
+ * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
+ * Changing is not recommended, a new Format should be instantiated.
+ */
+ xy: true,
+
+ /**
+ * Property: stateName
+ * {Object} Maps feature states to node names.
+ */
+ stateName: null,
+
+ /**
+ * Constructor: OpenLayers.Format.WFST.v1
+ * Instances of this class are not created directly. Use the
+ * <OpenLayers.Format.WFST.v1_0_0> or <OpenLayers.Format.WFST.v1_1_0>
+ * constructor instead.
+ *
+ * Parameters:
+ * options - {Object} An optional object whose properties will be set on
+ * this instance.
+ */
+ initialize: function(options) {
+ // set state name mapping
+ this.stateName = {};
+ this.stateName[OpenLayers.State.INSERT] = "wfs:Insert";
+ this.stateName[OpenLayers.State.UPDATE] = "wfs:Update";
+ this.stateName[OpenLayers.State.DELETE] = "wfs:Delete";
+ OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * Method: getSrsName
+ */
+ getSrsName: function(feature, options) {
+ var srsName = options && options.srsName;
+ if(!srsName) {
+ if(feature && feature.layer) {
+ srsName = feature.layer.projection.getCode();
} else {
- //need to try to load a tile in a different direction
- direction = (direction + 1) % 4;
- directionsTried++;
+ srsName = this.srsName;
}
- }
-
- // now we go through and draw the tiles in forward order
- for(var i=0, len=tileQueue.length; i<len; i++) {
- var tile = tileQueue[i];
- tile.draw();
- //mark tile as unqueued for the next time (since tiles are reused)
- tile.queued = false;
}
+ return srsName;
},
/**
- * APIMethod: addTile
- * Gives subclasses of Grid the opportunity to create an
- * OpenLayer.Tile of their choosing. The implementer should initialize
- * the new tile and take whatever steps necessary to display it.
+ * APIMethod: read
+ * Parse the response from a transaction. Because WFS is split into
+ * Transaction requests (create, update, and delete) and GetFeature
+ * requests (read), this method handles parsing of both types of
+ * responses.
*
- * Parameters
- * bounds - {<OpenLayers.Bounds>}
- * position - {<OpenLayers.Pixel>}
+ * Parameters:
+ * data - {String | Document} The WFST document to read
+ * options - {Object} Options for the reader
*
+ * Valid options properties:
+ * output - {String} either "features" or "object". The default is
+ * "features", which means that the method will return an array of
+ * features. If set to "object", an object with a "features" property
+ * and other properties read by the parser will be returned.
+ *
* Returns:
- * {<OpenLayers.Tile>} The added OpenLayers.Tile
+ * {Array | Object} Output depending on the output option.
*/
- addTile:function(bounds, position) {
- // Should be implemented by subclasses
+ read: function(data, options) {
+ options = options || {};
+ OpenLayers.Util.applyDefaults(options, {
+ output: "features"
+ });
+
+ if(typeof data == "string") {
+ data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+ }
+ if(data && data.nodeType == 9) {
+ data = data.documentElement;
+ }
+ var obj = {};
+ if(data) {
+ this.readNode(data, obj);
+ }
+ if(obj.features && options.output === "features") {
+ obj = obj.features;
+ }
+ return obj;
},
- /**
- * Method: addTileMonitoringHooks
- * This function takes a tile as input and adds the appropriate hooks to
- * the tile so that the layer can keep track of the loading tiles.
- *
- * Parameters:
- * tile - {<OpenLayers.Tile>}
+ /**
+ * Property: readers
+ * Contains public functions, grouped by namespace prefix, that will
+ * be applied when a namespaced node is found matching the function
+ * name. The function will be applied in the scope of this parser
+ * with two arguments: the node being read and a context object passed
+ * from the parent.
*/
- addTileMonitoringHooks: function(tile) {
+ readers: {
+ "wfs": {
+ "FeatureCollection": function(node, obj) {
+ obj.features = [];
+ this.readChildNodes(node, obj);
+ }
+ }
+ },
+
+ /**
+ * Method: write
+ * Given an array of features, write a WFS transaction. This assumes
+ * the features have a state property that determines the operation
+ * type - insert, update, or delete.
+ *
+ * Parameters:
+ * features - {Array(<OpenLayers.Feature.Vector>)} A list of features.
+ *
+ * Returns:
+ * {String} A serialized WFS transaction.
+ */
+ write: function(features) {
+ var node = this.writeNode("wfs:Transaction", features);
+ var value = this.schemaLocationAttr();
+ if(value) {
+ this.setAttributeNS(
+ node, this.namespaces["xsi"], "xsi:schemaLocation", value
+ )
+ }
+ return OpenLayers.Format.XML.prototype.write.apply(this, [node]);
+ },
+
+ /**
+ * Property: writers
+ * As a compliment to the readers property, this structure contains public
+ * writing functions grouped by namespace alias and named like the
+ * node names they produce.
+ */
+ writers: {
+ "wfs": {
+ "GetFeature": function(options) {
+ var node = this.createElementNSPlus("wfs:GetFeature", {
+ attributes: {
+ service: "WFS",
+ version: this.version,
+ outputFormat: options && options.outputFormat,
+ maxFeatures: options && options.maxFeatures,
+ "xsi:schemaLocation": this.schemaLocationAttr(options)
+ }
+ });
+ if (typeof this.featureType == "string") {
+ this.writeNode("Query", options, node);
+ } else {
+ for (var i=0,len = this.featureType.length; i<len; i++) {
+ options.featureType = this.featureType[i];
+ this.writeNode("Query", options, node);
+ }
+ }
+ return node;
+ },
+ "Transaction": function(features) {
+ var node = this.createElementNSPlus("wfs:Transaction", {
+ attributes: {
+ service: "WFS",
+ version: this.version
+ }
+ });
+ if(features) {
+ var name, feature;
+ for(var i=0, len=features.length; i<len; ++i) {
+ feature = features[i];
+ name = this.stateName[feature.state];
+ if(name) {
+ this.writeNode(name, feature, node);
+ }
+ }
+ }
+ return node;
+ },
+ "Insert": function(feature) {
+ var node = this.createElementNSPlus("wfs:Insert");
+ this.srsName = this.getSrsName(feature);
+ this.writeNode("feature:_typeName", feature, node);
+ return node;
+ },
+ "Update": function(feature) {
+ var node = this.createElementNSPlus("wfs:Update", {
+ attributes: {
+ typeName: (this.featureNS ? this.featurePrefix + ":" : "") +
+ this.featureType
+ }
+ });
+ if(this.featureNS) {
+ node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS);
+ }
+
+ // add in geometry
+ if (this.geometryName !== null) {
+ this.srsName = this.getSrsName(feature);
+ this.writeNode(
+ "Property", {name: this.geometryName, value: feature.geometry}, node
+ );
+ }
- tile.onLoadStart = function() {
- //if that was first tile then trigger a 'loadstart' on the layer
- if (this.numLoadingTiles == 0) {
- this.events.triggerEvent("loadstart");
+ // add in attributes
+ for(var key in feature.attributes) {
+ if(feature.attributes[key] !== undefined) {
+ this.writeNode(
+ "Property", {name: key, value: feature.attributes[key]}, node
+ );
+ }
+ }
+
+ // add feature id filter
+ this.writeNode("ogc:Filter", new OpenLayers.Filter.FeatureId({
+ fids: [feature.fid]
+ }), node);
+
+ return node;
+ },
+ "Property": function(obj) {
+ var node = this.createElementNSPlus("wfs:Property");
+ this.writeNode("Name", obj.name, node);
+ if(obj.value !== null) {
+ this.writeNode("Value", obj.value, node);
+ }
+ return node;
+ },
+ "Name": function(name) {
+ return this.createElementNSPlus("wfs:Name", {value: name});
+ },
+ "Value": function(obj) {
+ var node;
+ if(obj instanceof OpenLayers.Geometry) {
+ node = this.createElementNSPlus("wfs:Value");
+ var geom = this.writeNode("feature:_geometry", obj).firstChild;
+ node.appendChild(geom);
+ } else {
+ node = this.createElementNSPlus("wfs:Value", {value: obj});
+ }
+ return node;
+ },
+ "Delete": function(feature) {
+ var node = this.createElementNSPlus("wfs:Delete", {
+ attributes: {
+ typeName: (this.featureNS ? this.featurePrefix + ":" : "") +
+ this.featureType
+ }
+ });
+ if(this.featureNS) {
+ node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS);
+ }
+ this.writeNode("ogc:Filter", new OpenLayers.Filter.FeatureId({
+ fids: [feature.fid]
+ }), node);
+ return node;
}
- this.numLoadingTiles++;
- };
- tile.events.register("loadstart", this, tile.onLoadStart);
-
- tile.onLoadEnd = function() {
- this.numLoadingTiles--;
- this.events.triggerEvent("tileloaded");
- //if that was the last tile, then trigger a 'loadend' on the layer
- if (this.numLoadingTiles == 0) {
- this.events.triggerEvent("loadend");
+ }
+ },
+
+ /**
+ * Method: schemaLocationAttr
+ * Generate the xsi:schemaLocation attribute value.
+ *
+ * Returns:
+ * {String} The xsi:schemaLocation attribute or undefined if none.
+ */
+ schemaLocationAttr: function(options) {
+ options = OpenLayers.Util.extend({
+ featurePrefix: this.featurePrefix,
+ schema: this.schema
+ }, options);
+ var schemaLocations = OpenLayers.Util.extend({}, this.schemaLocations);
+ if(options.schema) {
+ schemaLocations[options.featurePrefix] = options.schema;
+ }
+ var parts = [];
+ var uri;
+ for(var key in schemaLocations) {
+ uri = this.namespaces[key];
+ if(uri) {
+ parts.push(uri + " " + schemaLocations[key]);
}
- };
- tile.events.register("loadend", this, tile.onLoadEnd);
- tile.events.register("unload", this, tile.onLoadEnd);
+ }
+ var value = parts.join(" ") || undefined;
+ return value;
},
+
+ /**
+ * Method: setFilterProperty
+ * Set the property of each spatial filter.
+ *
+ * Parameters:
+ * filter - {<OpenLayers.Filter>}
+ */
+ setFilterProperty: function(filter) {
+ if(filter.filters) {
+ for(var i=0, len=filter.filters.length; i<len; ++i) {
+ this.setFilterProperty(filter.filters[i]);
+ }
+ } else {
+ if(filter instanceof OpenLayers.Filter.Spatial) {
+ // got a spatial filter, set its property
+ filter.property = this.geometryName;
+ }
+ }
+ },
+ CLASS_NAME: "OpenLayers.Format.WFST.v1"
+
+});
+/* ======================================================================
+ OpenLayers/Icon.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ */
+
+/**
+ * Class: OpenLayers.Icon
+ *
+ * The icon represents a graphical icon on the screen. Typically used in
+ * conjunction with a <OpenLayers.Marker> to represent markers on a screen.
+ *
+ * An icon has a url, size and position. It also contains an offset which
+ * allows the center point to be represented correctly. This can be
+ * provided either as a fixed offset or a function provided to calculate
+ * the desired offset.
+ *
+ */
+OpenLayers.Icon = OpenLayers.Class({
+
/**
- * Method: removeTileMonitoringHooks
- * This function takes a tile as input and removes the tile hooks
- * that were added in addTileMonitoringHooks()
+ * Property: url
+ * {String} image url
+ */
+ url: null,
+
+ /**
+ * Property: size
+ * {<OpenLayers.Size>}
+ */
+ size: null,
+
+ /**
+ * Property: offset
+ * {<OpenLayers.Pixel>} distance in pixels to offset the image when being rendered
+ */
+ offset: null,
+
+ /**
+ * Property: calculateOffset
+ * {<OpenLayers.Pixel>} Function to calculate the offset (based on the size)
+ */
+ calculateOffset: null,
+
+ /**
+ * Property: imageDiv
+ * {DOMElement}
+ */
+ imageDiv: null,
+
+ /**
+ * Property: px
+ * {<OpenLayers.Pixel>}
+ */
+ px: null,
+
+ /**
+ * Constructor: OpenLayers.Icon
+ * Creates an icon, which is an image tag in a div.
+ *
+ * url - {String}
+ * size - {<OpenLayers.Size>}
+ * offset - {<OpenLayers.Pixel>}
+ * calculateOffset - {Function}
+ */
+ initialize: function(url, size, offset, calculateOffset) {
+ this.url = url;
+ this.size = (size) ? size : new OpenLayers.Size(20,20);
+ this.offset = offset ? offset : new OpenLayers.Pixel(-(this.size.w/2), -(this.size.h/2));
+ this.calculateOffset = calculateOffset;
+
+ var id = OpenLayers.Util.createUniqueID("OL_Icon_");
+ this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);
+ },
+
+ /**
+ * Method: destroy
+ * Nullify references and remove event listeners to prevent circular
+ * references and memory leaks
+ */
+ destroy: function() {
+ // erase any drawn elements
+ this.erase();
+
+ OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);
+ this.imageDiv.innerHTML = "";
+ this.imageDiv = null;
+ },
+
+ /**
+ * Method: clone
*
- * Parameters:
- * tile - {<OpenLayers.Tile>}
+ * Returns:
+ * {<OpenLayers.Icon>} A fresh copy of the icon.
*/
- removeTileMonitoringHooks: function(tile) {
- tile.unload();
- tile.events.un({
- "loadstart": tile.onLoadStart,
- "loadend": tile.onLoadEnd,
- "unload": tile.onLoadEnd,
- scope: this
- });
+ clone: function() {
+ return new OpenLayers.Icon(this.url,
+ this.size,
+ this.offset,
+ this.calculateOffset);
},
/**
- * Method: moveGriddedTiles
+ * Method: setSize
*
* Parameters:
- * bounds - {<OpenLayers.Bounds>}
+ * size - {<OpenLayers.Size>}
*/
- moveGriddedTiles: function(bounds) {
- var buffer = this.buffer || 1;
- while (true) {
- var tlLayer = this.grid[0][0].position;
- var tlViewPort =
- this.map.getViewPortPxFromLayerPx(tlLayer);
- if (tlViewPort.x > -this.tileSize.w * (buffer - 1)) {
- this.shiftColumn(true);
- } else if (tlViewPort.x < -this.tileSize.w * buffer) {
- this.shiftColumn(false);
- } else if (tlViewPort.y > -this.tileSize.h * (buffer - 1)) {
- this.shiftRow(true);
- } else if (tlViewPort.y < -this.tileSize.h * buffer) {
- this.shiftRow(false);
- } else {
- break;
- }
- };
+ setSize: function(size) {
+ if (size != null) {
+ this.size = size;
+ }
+ this.draw();
},
-
+
/**
- * Method: shiftRow
- * Shifty grid work
- *
+ * Method: setUrl
+ *
* Parameters:
- * prepend - {Boolean} if true, prepend to beginning.
- * if false, then append to end
+ * url - {String}
*/
- shiftRow:function(prepend) {
- var modelRowIndex = (prepend) ? 0 : (this.grid.length - 1);
- var grid = this.grid;
- var modelRow = grid[modelRowIndex];
+ setUrl: function(url) {
+ if (url != null) {
+ this.url = url;
+ }
+ this.draw();
+ },
- var resolution = this.map.getResolution();
- var deltaY = (prepend) ? -this.tileSize.h : this.tileSize.h;
- var deltaLat = resolution * -deltaY;
+ /**
+ * Method: draw
+ * Move the div to the given pixel.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {DOMElement} A new DOM Image of this icon set at the location passed-in
+ */
+ draw: function(px) {
+ OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,
+ null,
+ null,
+ this.size,
+ this.url,
+ "absolute");
+ this.moveTo(px);
+ return this.imageDiv;
+ },
- var row = (prepend) ? grid.pop() : grid.shift();
-
- for (var i=0, len=modelRow.length; i<len; i++) {
- var modelTile = modelRow[i];
- var bounds = modelTile.bounds.clone();
- var position = modelTile.position.clone();
- bounds.bottom = bounds.bottom + deltaLat;
- bounds.top = bounds.top + deltaLat;
- position.y = position.y + deltaY;
- row[i].moveTo(bounds, position);
+ /**
+ * Method: erase
+ * Erase the underlying image element.
+ *
+ */
+ erase: function() {
+ if (this.imageDiv != null && this.imageDiv.parentNode != null) {
+ OpenLayers.Element.remove(this.imageDiv);
}
+ },
+
+ /**
+ * Method: setOpacity
+ * Change the icon's opacity
+ *
+ * Parameters:
+ * opacity - {float}
+ */
+ setOpacity: function(opacity) {
+ OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null,
+ null, null, null, null, opacity);
- if (prepend) {
- grid.unshift(row);
- } else {
- grid.push(row);
- }
},
-
+
/**
- * Method: shiftColumn
- * Shift grid work in the other dimension
+ * Method: moveTo
+ * move icon to passed in px.
*
* Parameters:
- * prepend - {Boolean} if true, prepend to beginning.
- * if false, then append to end
+ * px - {<OpenLayers.Pixel>}
*/
- shiftColumn: function(prepend) {
- var deltaX = (prepend) ? -this.tileSize.w : this.tileSize.w;
- var resolution = this.map.getResolution();
- var deltaLon = resolution * deltaX;
+ moveTo: function (px) {
+ //if no px passed in, use stored location
+ if (px != null) {
+ this.px = px;
+ }
- for (var i=0, len=this.grid.length; i<len; i++) {
- var row = this.grid[i];
- var modelTileIndex = (prepend) ? 0 : (row.length - 1);
- var modelTile = row[modelTileIndex];
-
- var bounds = modelTile.bounds.clone();
- var position = modelTile.position.clone();
- bounds.left = bounds.left + deltaLon;
- bounds.right = bounds.right + deltaLon;
- position.x = position.x + deltaX;
-
- var tile = prepend ? this.grid[i].pop() : this.grid[i].shift();
- tile.moveTo(bounds, position);
- if (prepend) {
- row.unshift(tile);
+ if (this.imageDiv != null) {
+ if (this.px == null) {
+ this.display(false);
} else {
- row.push(tile);
+ if (this.calculateOffset) {
+ this.offset = this.calculateOffset(this.size);
+ }
+ var offsetPx = this.px.offset(this.offset);
+ OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, offsetPx);
}
}
},
+ /**
+ * Method: display
+ * Hide or show the icon
+ *
+ * Parameters:
+ * display - {Boolean}
+ */
+ display: function(display) {
+ this.imageDiv.style.display = (display) ? "" : "none";
+ },
+
+
/**
- * Method: removeExcessTiles
- * When the size of the map or the buffer changes, we may need to
- * remove some excess rows and columns.
+ * APIMethod: isDrawn
*
+ * Returns:
+ * {Boolean} Whether or not the icon is drawn.
+ */
+ isDrawn: function() {
+ // nodeType 11 for ie, whose nodes *always* have a parentNode
+ // (of type document fragment)
+ var isDrawn = (this.imageDiv && this.imageDiv.parentNode &&
+ (this.imageDiv.parentNode.nodeType != 11));
+
+ return isDrawn;
+ },
+
+ CLASS_NAME: "OpenLayers.Icon"
+});
+/* ======================================================================
+ OpenLayers/Marker.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/Events.js
+ * @requires OpenLayers/Icon.js
+ */
+
+/**
+ * Class: OpenLayers.Marker
+ * Instances of OpenLayers.Marker are a combination of a
+ * <OpenLayers.LonLat> and an <OpenLayers.Icon>.
+ *
+ * Markers are generally added to a special layer called
+ * <OpenLayers.Layer.Markers>.
+ *
+ * Example:
+ * (code)
+ * var markers = new OpenLayers.Layer.Markers( "Markers" );
+ * map.addLayer(markers);
+ *
+ * var size = new OpenLayers.Size(21,25);
+ * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
+ * var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset);
+ * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon));
+ * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone()));
+ *
+ * (end)
+ *
+ * Note that if you pass an icon into the Marker constructor, it will take
+ * that icon and use it. This means that you should not share icons between
+ * markers -- you use them once, but you should clone() for any additional
+ * markers using that same icon.
+ */
+OpenLayers.Marker = OpenLayers.Class({
+
+ /**
+ * Property: icon
+ * {<OpenLayers.Icon>} The icon used by this marker.
+ */
+ icon: null,
+
+ /**
+ * Property: lonlat
+ * {<OpenLayers.LonLat>} location of object
+ */
+ lonlat: null,
+
+ /**
+ * Property: events
+ * {<OpenLayers.Events>} the event handler.
+ */
+ events: null,
+
+ /**
+ * Property: map
+ * {<OpenLayers.Map>} the map this marker is attached to
+ */
+ map: null,
+
+ /**
+ * Constructor: OpenLayers.Marker
* Parameters:
- * rows - {Integer} Maximum number of rows we want our grid to have.
- * colums - {Integer} Maximum number of columns we want our grid to have.
+ * lonlat - {<OpenLayers.LonLat>} the position of this marker
+ * icon - {<OpenLayers.Icon>} the icon for this marker
*/
- removeExcessTiles: function(rows, columns) {
+ initialize: function(lonlat, icon) {
+ this.lonlat = lonlat;
- // remove extra rows
- while (this.grid.length > rows) {
- var row = this.grid.pop();
- for (var i=0, l=row.length; i<l; i++) {
- var tile = row[i];
- this.removeTileMonitoringHooks(tile);
- tile.destroy();
- }
+ var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon();
+ if (this.icon == null) {
+ this.icon = newIcon;
+ } else {
+ this.icon.url = newIcon.url;
+ this.icon.size = newIcon.size;
+ this.icon.offset = newIcon.offset;
+ this.icon.calculateOffset = newIcon.calculateOffset;
}
-
- // remove extra columns
- while (this.grid[0].length > columns) {
- for (var i=0, l=this.grid.length; i<l; i++) {
- var row = this.grid[i];
- var tile = row.pop();
- this.removeTileMonitoringHooks(tile);
- tile.destroy();
- }
+ this.events = new OpenLayers.Events(this, this.icon.imageDiv, null);
+ },
+
+ /**
+ * APIMethod: destroy
+ * Destroy the marker. You must first remove the marker from any
+ * layer which it has been added to, or you will get buggy behavior.
+ * (This can not be done within the marker since the marker does not
+ * know which layer it is attached to.)
+ */
+ destroy: function() {
+ // erase any drawn features
+ this.erase();
+
+ this.map = null;
+
+ this.events.destroy();
+ this.events = null;
+
+ if (this.icon != null) {
+ this.icon.destroy();
+ this.icon = null;
}
},
+
+ /**
+ * Method: draw
+ * Calls draw on the icon, and returns that output.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {DOMElement} A new DOM Image with this marker's icon set at the
+ * location passed-in
+ */
+ draw: function(px) {
+ return this.icon.draw(px);
+ },
+ /**
+ * Method: erase
+ * Erases any drawn elements for this marker.
+ */
+ erase: function() {
+ if (this.icon != null) {
+ this.icon.erase();
+ }
+ },
+
/**
- * Method: onMapResize
- * For singleTile layers, this will set a new tile size according to the
- * dimensions of the map pane.
+ * Method: moveTo
+ * Move the marker to the new location.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>} the pixel position to move to
+ */
+ moveTo: function (px) {
+ if ((px != null) && (this.icon != null)) {
+ this.icon.moveTo(px);
+ }
+ this.lonlat = this.map.getLonLatFromLayerPx(px);
+ },
+
+ /**
+ * APIMethod: isDrawn
+ *
+ * Returns:
+ * {Boolean} Whether or not the marker is drawn.
*/
- onMapResize: function() {
- if (this.singleTile) {
- this.clearGrid();
- this.setTileSize();
- }
+ isDrawn: function() {
+ var isDrawn = (this.icon && this.icon.isDrawn());
+ return isDrawn;
},
+
+ /**
+ * Method: onScreen
+ *
+ * Returns:
+ * {Boolean} Whether or not the marker is currently visible on screen.
+ */
+ onScreen:function() {
+
+ var onScreen = false;
+ if (this.map) {
+ var screenBounds = this.map.getExtent();
+ onScreen = screenBounds.containsLonLat(this.lonlat);
+ }
+ return onScreen;
+ },
/**
- * APIMethod: getTileBounds
- * Returns The tile bounds for a layer given a pixel location.
+ * Method: inflate
+ * Englarges the markers icon by the specified ratio.
*
* Parameters:
- * viewPortPx - {<OpenLayers.Pixel>} The location in the viewport.
- *
- * Returns:
- * {<OpenLayers.Bounds>} Bounds of the tile at the given pixel location.
+ * inflate - {float} the ratio to enlarge the marker by (passing 2
+ * will double the size).
*/
- getTileBounds: function(viewPortPx) {
- var maxExtent = this.maxExtent;
- var resolution = this.getResolution();
- var tileMapWidth = resolution * this.tileSize.w;
- var tileMapHeight = resolution * this.tileSize.h;
- var mapPoint = this.getLonLatFromViewPortPx(viewPortPx);
- var tileLeft = maxExtent.left + (tileMapWidth *
- Math.floor((mapPoint.lon -
- maxExtent.left) /
- tileMapWidth));
- var tileBottom = maxExtent.bottom + (tileMapHeight *
- Math.floor((mapPoint.lat -
- maxExtent.bottom) /
- tileMapHeight));
- return new OpenLayers.Bounds(tileLeft, tileBottom,
- tileLeft + tileMapWidth,
- tileBottom + tileMapHeight);
+ inflate: function(inflate) {
+ if (this.icon) {
+ var newSize = new OpenLayers.Size(this.icon.size.w * inflate,
+ this.icon.size.h * inflate);
+ this.icon.setSize(newSize);
+ }
},
- CLASS_NAME: "OpenLayers.Layer.Grid"
+ /**
+ * Method: setOpacity
+ * Change the opacity of the marker by changin the opacity of
+ * its icon
+ *
+ * Parameters:
+ * opacity - {float} Specified as fraction (0.4, etc)
+ */
+ setOpacity: function(opacity) {
+ this.icon.setOpacity(opacity);
+ },
+
+ /**
+ * Method: setUrl
+ * Change URL of the Icon Image.
+ *
+ * url - {String}
+ */
+ setUrl: function(url) {
+ this.icon.setUrl(url);
+ },
+
+ /**
+ * Method: display
+ * Hide or show the icon
+ *
+ * display - {Boolean}
+ */
+ display: function(display) {
+ this.icon.display(display);
+ },
+
+ CLASS_NAME: "OpenLayers.Marker"
});
+
+
+/**
+ * Function: defaultIcon
+ * Creates a default <OpenLayers.Icon>.
+ *
+ * Returns:
+ * {<OpenLayers.Icon>} A default OpenLayers.Icon to use for a marker
+ */
+OpenLayers.Marker.defaultIcon = function() {
+ var url = OpenLayers.Util.getImagesLocation() + "marker.png";
+ var size = new OpenLayers.Size(21, 25);
+ var calculateOffset = function(size) {
+ return new OpenLayers.Pixel(-(size.w/2), -size.h);
+ };
+
+ return new OpenLayers.Icon(url, size, null, calculateOffset);
+};
+
+
/* ======================================================================
- OpenLayers/Layer/VirtualEarth.js
+ OpenLayers/Popup.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
-
/**
- * @requires OpenLayers/Layer/SphericalMercator.js
- * @requires OpenLayers/Layer/EventPane.js
- * @requires OpenLayers/Layer/FixedZoomLevels.js
+ * @requires OpenLayers/BaseTypes/Class.js
*/
+
/**
- * Class: OpenLayers.Layer.VirtualEarth
- *
- * Inherits from:
- * - <OpenLayers.Layer.EventPane>
- * - <OpenLayers.Layer.FixedZoomLevels>
+ * Class: OpenLayers.Popup
+ * A popup is a small div that can opened and closed on the map.
+ * Typically opened in response to clicking on a marker.
+ * See <OpenLayers.Marker>. Popup's don't require their own
+ * layer and are added the the map using the <OpenLayers.Map.addPopup>
+ * method.
+ *
+ * Example:
+ * (code)
+ * popup = new OpenLayers.Popup("chicken",
+ * new OpenLayers.LonLat(5,40),
+ * new OpenLayers.Size(200,200),
+ * "example popup",
+ * true);
+ *
+ * map.addPopup(popup);
+ * (end)
*/
-OpenLayers.Layer.VirtualEarth = OpenLayers.Class(
- OpenLayers.Layer.EventPane,
- OpenLayers.Layer.FixedZoomLevels, {
+OpenLayers.Popup = OpenLayers.Class({
+
+ /**
+ * Property: events
+ * {<OpenLayers.Events>} custom event manager
+ */
+ events: null,
+ /** Property: id
+ * {String} the unique identifier assigned to this popup.
+ */
+ id: "",
+
/**
- * Constant: MIN_ZOOM_LEVEL
- * {Integer} 1
+ * Property: lonlat
+ * {<OpenLayers.LonLat>} the position of this popup on the map
*/
- MIN_ZOOM_LEVEL: 1,
+ lonlat: null,
+
+ /**
+ * Property: div
+ * {DOMElement} the div that contains this popup.
+ */
+ div: null,
+
+ /**
+ * Property: contentSize
+ * {<OpenLayers.Size>} the width and height of the content.
+ */
+ contentSize: null,
+
+ /**
+ * Property: size
+ * {<OpenLayers.Size>} the width and height of the popup.
+ */
+ size: null,
+
+ /**
+ * Property: contentHTML
+ * {String} An HTML string for this popup to display.
+ */
+ contentHTML: null,
/**
- * Constant: MAX_ZOOM_LEVEL
- * {Integer} 19
+ * Property: backgroundColor
+ * {String} the background color used by the popup.
*/
- MAX_ZOOM_LEVEL: 19,
+ backgroundColor: "",
+
+ /**
+ * Property: opacity
+ * {float} the opacity of this popup (between 0.0 and 1.0)
+ */
+ opacity: "",
/**
- * Constant: RESOLUTIONS
- * {Array(Float)} Hardcode these resolutions so that they are more closely
- * tied with the standard wms projection
+ * Property: border
+ * {String} the border size of the popup. (eg 2px)
*/
- RESOLUTIONS: [
- 1.40625,
- 0.703125,
- 0.3515625,
- 0.17578125,
- 0.087890625,
- 0.0439453125,
- 0.02197265625,
- 0.010986328125,
- 0.0054931640625,
- 0.00274658203125,
- 0.001373291015625,
- 0.0006866455078125,
- 0.00034332275390625,
- 0.000171661376953125,
- 0.0000858306884765625,
- 0.00004291534423828125,
- 0.00002145767211914062,
- 0.00001072883605957031,
- 0.00000536441802978515
- ],
+ border: "",
+
+ /**
+ * Property: contentDiv
+ * {DOMElement} a reference to the element that holds the content of
+ * the div.
+ */
+ contentDiv: null,
+
+ /**
+ * Property: groupDiv
+ * {DOMElement} First and only child of 'div'. The group Div contains the
+ * 'contentDiv' and the 'closeDiv'.
+ */
+ groupDiv: null,
- /**
- * APIProperty: type
- * {VEMapType}
+ /**
+ * Property: closeDiv
+ * {DOMElement} the optional closer image
*/
- type: null,
+ closeDiv: null,
- /**
- * APIProperty: wrapDateLine
- * {Boolean} Allow user to pan forever east/west. Default is true.
- * Setting this to false only restricts panning if
- * <sphericalMercator> is true.
+ /**
+ * APIProperty: autoSize
+ * {Boolean} Resize the popup to auto-fit the contents.
+ * Default is false.
*/
- wrapDateLine: true,
+ autoSize: false,
/**
- * APIProperty: sphericalMercator
- * {Boolean} Should the map act as a mercator-projected map? This will
- * cause all interactions with the map to be in the actual map
- * projection, which allows support for vector drawing, overlaying
- * other maps, etc.
+ * APIProperty: minSize
+ * {<OpenLayers.Size>} Minimum size allowed for the popup's contents.
*/
- sphericalMercator: false,
-
+ minSize: null,
+
/**
- * APIProperty: animationEnabled
- * {Boolean} If set to true, the transition between zoom levels will be
- * animated. Set to false to match the zooming experience of other
- * layer types. Default is true.
+ * APIProperty: maxSize
+ * {<OpenLayers.Size>} Maximum size allowed for the popup's contents.
*/
- animationEnabled: true,
+ maxSize: null,
/**
- * Constructor: OpenLayers.Layer.VirtualEarth
+ * Property: displayClass
+ * {String} The CSS class of the popup.
+ */
+ displayClass: "olPopup",
+
+ /**
+ * Property: contentDisplayClass
+ * {String} The CSS class of the popup content div.
+ */
+ contentDisplayClass: "olPopupContent",
+
+ /**
+ * Property: padding
+ * {int or <OpenLayers.Bounds>} An extra opportunity to specify internal
+ * padding of the content div inside the popup. This was originally
+ * confused with the css padding as specified in style.css's
+ * 'olPopupContent' class. We would like to get rid of this altogether,
+ * except that it does come in handy for the framed and anchoredbubble
+ * popups, who need to maintain yet another barrier between their
+ * content and the outer border of the popup itself.
*
- * Parameters:
- * name - {String}
- * options - {Object}
+ * Note that in order to not break API, we must continue to support
+ * this property being set as an integer. Really, though, we'd like to
+ * have this specified as a Bounds object so that user can specify
+ * distinct left, top, right, bottom paddings. With the 3.0 release
+ * we can make this only a bounds.
*/
- initialize: function(name, options) {
- OpenLayers.Layer.EventPane.prototype.initialize.apply(this, arguments);
- OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,
- arguments);
- if(this.sphericalMercator) {
- OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
- this.initMercatorParameters();
+ padding: 0,
+
+ /**
+ * Property: disableFirefoxOverflowHack
+ * {Boolean} The hack for overflow in Firefox causes all elements
+ * to be re-drawn, which causes Flash elements to be
+ * re-initialized, which is troublesome.
+ * With this property the hack can be disabled.
+ */
+ disableFirefoxOverflowHack: false,
+
+ /**
+ * Method: fixPadding
+ * To be removed in 3.0, this function merely helps us to deal with the
+ * case where the user may have set an integer value for padding,
+ * instead of an <OpenLayers.Bounds> object.
+ */
+ fixPadding: function() {
+ if (typeof this.padding == "number") {
+ this.padding = new OpenLayers.Bounds(
+ this.padding, this.padding, this.padding, this.padding
+ );
}
},
+
+ /**
+ * APIProperty: panMapIfOutOfView
+ * {Boolean} When drawn, pan map such that the entire popup is visible in
+ * the current viewport (if necessary).
+ * Default is false.
+ */
+ panMapIfOutOfView: false,
/**
- * Method: loadMapObject
+ * APIProperty: keepInMap
+ * {Boolean} If panMapIfOutOfView is false, and this property is true,
+ * contrain the popup such that it always fits in the available map
+ * space. By default, this is not set on the base class. If you are
+ * creating popups that are near map edges and not allowing pannning,
+ * and especially if you have a popup which has a
+ * fixedRelativePosition, setting this to false may be a smart thing to
+ * do. Subclasses may want to override this setting.
+ *
+ * Default is false.
*/
- loadMapObject:function() {
+ keepInMap: false,
- // create div and set to same size as map
- var veDiv = OpenLayers.Util.createDiv(this.name);
- var sz = this.map.getSize();
- veDiv.style.width = sz.w + "px";
- veDiv.style.height = sz.h + "px";
- this.div.appendChild(veDiv);
+ /**
+ * APIProperty: closeOnMove
+ * {Boolean} When map pans, close the popup.
+ * Default is false.
+ */
+ closeOnMove: false,
+
+ /**
+ * Property: map
+ * {<OpenLayers.Map>} this gets set in Map.js when the popup is added to the map
+ */
+ map: null,
- try { // crash prevention
- this.mapObject = new VEMap(this.name);
- } catch (e) { }
+ /**
+ * Constructor: OpenLayers.Popup
+ * Create a popup.
+ *
+ * Parameters:
+ * id - {String} a unqiue identifier for this popup. If null is passed
+ * an identifier will be automatically generated.
+ * lonlat - {<OpenLayers.LonLat>} The position on the map the popup will
+ * be shown.
+ * contentSize - {<OpenLayers.Size>} The size of the content.
+ * contentHTML - {String} An HTML string to display inside the
+ * popup.
+ * closeBox - {Boolean} Whether to display a close box inside
+ * the popup.
+ * closeBoxCallback - {Function} Function to be called on closeBox click.
+ */
+ initialize:function(id, lonlat, contentSize, contentHTML, closeBox, closeBoxCallback) {
+ if (id == null) {
+ id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+ }
- if (this.mapObject != null) {
- try { // this is to catch a Mozilla bug without falling apart
+ this.id = id;
+ this.lonlat = lonlat;
- // The fourth argument is whether the map is 'fixed' -- not
- // draggable. See:
- // http://blogs.msdn.com/virtualearth/archive/2007/09/28/locking-a-virtual-earth-map.aspx
- //
- this.mapObject.LoadMap(null, null, this.type, true);
- this.mapObject.AttachEvent("onmousedown", OpenLayers.Function.True);
-
- } catch (e) { }
- this.mapObject.HideDashboard();
- if(typeof this.mapObject.SetAnimationEnabled == "function") {
- this.mapObject.SetAnimationEnabled(this.animationEnabled);
- }
+ this.contentSize = (contentSize != null) ? contentSize
+ : new OpenLayers.Size(
+ OpenLayers.Popup.WIDTH,
+ OpenLayers.Popup.HEIGHT);
+ if (contentHTML != null) {
+ this.contentHTML = contentHTML;
}
+ this.backgroundColor = OpenLayers.Popup.COLOR;
+ this.opacity = OpenLayers.Popup.OPACITY;
+ this.border = OpenLayers.Popup.BORDER;
- //can we do smooth panning? this is an unpublished method, so we need
- // to be careful
- if ( !this.mapObject ||
- !this.mapObject.vemapcontrol ||
- !this.mapObject.vemapcontrol.PanMap ||
- (typeof this.mapObject.vemapcontrol.PanMap != "function")) {
+ this.div = OpenLayers.Util.createDiv(this.id, null, null,
+ null, null, null, "hidden");
+ this.div.className = this.displayClass;
+
+ var groupDivId = this.id + "_GroupDiv";
+ this.groupDiv = OpenLayers.Util.createDiv(groupDivId, null, null,
+ null, "relative", null,
+ "hidden");
- this.dragPanMapObject = null;
- }
+ var id = this.div.id + "_contentDiv";
+ this.contentDiv = OpenLayers.Util.createDiv(id, null, this.contentSize.clone(),
+ null, "relative");
+ this.contentDiv.className = this.contentDisplayClass;
+ this.groupDiv.appendChild(this.contentDiv);
+ this.div.appendChild(this.groupDiv);
- },
+ if (closeBox) {
+ this.addCloseBox(closeBoxCallback);
+ }
- /**
- * Method: onMapResize
- */
- onMapResize: function() {
- this.mapObject.Resize(this.map.size.w, this.map.size.h);
+ this.registerEvents();
},
/**
- * APIMethod: getWarningHTML
- *
- * Returns:
- * {String} String with information on why layer is broken, how to get
- * it working.
+ * Method: destroy
+ * nullify references to prevent circular references and memory leaks
*/
- getWarningHTML:function() {
- return OpenLayers.i18n(
- "getLayerWarning", {'layerType':'VE', 'layerLib':'VirtualEarth'}
- );
+ destroy: function() {
+
+ this.id = null;
+ this.lonlat = null;
+ this.size = null;
+ this.contentHTML = null;
+
+ this.backgroundColor = null;
+ this.opacity = null;
+ this.border = null;
+
+ if (this.closeOnMove && this.map) {
+ this.map.events.unregister("movestart", this, this.hide);
+ }
+
+ this.events.destroy();
+ this.events = null;
+
+ if (this.closeDiv) {
+ OpenLayers.Event.stopObservingElement(this.closeDiv);
+ this.groupDiv.removeChild(this.closeDiv);
+ }
+ this.closeDiv = null;
+
+ this.div.removeChild(this.groupDiv);
+ this.groupDiv = null;
+
+ if (this.map != null) {
+ this.map.removePopup(this);
+ }
+ this.map = null;
+ this.div = null;
+
+ this.autoSize = null;
+ this.minSize = null;
+ this.maxSize = null;
+ this.padding = null;
+ this.panMapIfOutOfView = null;
},
+ /**
+ * Method: draw
+ * Constructs the elements that make up the popup.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>} the position the popup in pixels.
+ *
+ * Returns:
+ * {DOMElement} Reference to a div that contains the drawn popup
+ */
+ draw: function(px) {
+ if (px == null) {
+ if ((this.lonlat != null) && (this.map != null)) {
+ px = this.map.getLayerPxFromLonLat(this.lonlat);
+ }
+ }
+ // this assumes that this.map already exists, which is okay because
+ // this.draw is only called once the popup has been added to the map.
+ if (this.closeOnMove) {
+ this.map.events.register("movestart", this, this.hide);
+ }
+
+ //listen to movestart, moveend to disable overflow (FF bug)
+ if (!this.disableFirefoxOverflowHack && OpenLayers.BROWSER_NAME == 'firefox') {
+ this.map.events.register("movestart", this, function() {
+ var style = document.defaultView.getComputedStyle(
+ this.contentDiv, null
+ );
+ var currentOverflow = style.getPropertyValue("overflow");
+ if (currentOverflow != "hidden") {
+ this.contentDiv._oldOverflow = currentOverflow;
+ this.contentDiv.style.overflow = "hidden";
+ }
+ });
+ this.map.events.register("moveend", this, function() {
+ var oldOverflow = this.contentDiv._oldOverflow;
+ if (oldOverflow) {
+ this.contentDiv.style.overflow = oldOverflow;
+ this.contentDiv._oldOverflow = null;
+ }
+ });
+ }
- /************************************
- * *
- * MapObject Interface Controls *
- * *
- ************************************/
+ this.moveTo(px);
+ if (!this.autoSize && !this.size) {
+ this.setSize(this.contentSize);
+ }
+ this.setBackgroundColor();
+ this.setOpacity();
+ this.setBorder();
+ this.setContentHTML();
+
+ if (this.panMapIfOutOfView) {
+ this.panIntoView();
+ }
+ return this.div;
+ },
- // Get&Set Center, Zoom
+ /**
+ * Method: updatePosition
+ * if the popup has a lonlat and its map members set,
+ * then have it move itself to its proper position
+ */
+ updatePosition: function() {
+ if ((this.lonlat) && (this.map)) {
+ var px = this.map.getLayerPxFromLonLat(this.lonlat);
+ if (px) {
+ this.moveTo(px);
+ }
+ }
+ },
- /**
- * APIMethod: setMapObjectCenter
- * Set the mapObject to the specified center and zoom
+ /**
+ * Method: moveTo
*
* Parameters:
- * center - {Object} MapObject LonLat format
- * zoom - {int} MapObject zoom format
+ * px - {<OpenLayers.Pixel>} the top and left position of the popup div.
*/
- setMapObjectCenter: function(center, zoom) {
- this.mapObject.SetCenterAndZoom(center, zoom);
+ moveTo: function(px) {
+ if ((px != null) && (this.div != null)) {
+ this.div.style.left = px.x + "px";
+ this.div.style.top = px.y + "px";
+ }
},
-
+
/**
- * APIMethod: getMapObjectCenter
- *
- * Returns:
- * {Object} The mapObject's current center in Map Object format
+ * Method: visible
+ *
+ * Returns:
+ * {Boolean} Boolean indicating whether or not the popup is visible
*/
- getMapObjectCenter: function() {
- return this.mapObject.GetCenter();
+ visible: function() {
+ return OpenLayers.Element.visible(this.div);
},
/**
- * APIMethod: dragPanMapObject
- *
- * Parameters:
- * dX - {Integer}
- * dY - {Integer}
+ * Method: toggle
+ * Toggles visibility of the popup.
*/
- dragPanMapObject: function(dX, dY) {
- this.mapObject.vemapcontrol.PanMap(dX, -dY);
+ toggle: function() {
+ if (this.visible()) {
+ this.hide();
+ } else {
+ this.show();
+ }
},
- /**
- * APIMethod: getMapObjectZoom
- *
- * Returns:
- * {Integer} The mapObject's current zoom, in Map Object format
+ /**
+ * Method: show
+ * Makes the popup visible.
*/
- getMapObjectZoom: function() {
- return this.mapObject.GetZoomLevel();
+ show: function() {
+ OpenLayers.Element.show(this.div);
+
+ if (this.panMapIfOutOfView) {
+ this.panIntoView();
+ }
},
+ /**
+ * Method: hide
+ * Makes the popup invisible.
+ */
+ hide: function() {
+ OpenLayers.Element.hide(this.div);
+ },
- // LonLat - Pixel Translation
-
/**
- * APIMethod: getMapObjectLonLatFromMapObjectPixel
+ * Method: setSize
+ * Used to adjust the size of the popup.
+ *
+ * Parameters:
+ * contentSize - {<OpenLayers.Size>} the new size for the popup's
+ * contents div (in pixels).
+ */
+ setSize:function(contentSize) {
+ this.size = contentSize.clone();
+
+ // if our contentDiv has a css 'padding' set on it by a stylesheet, we
+ // must add that to the desired "size".
+ var contentDivPadding = this.getContentDivPadding();
+ var wPadding = contentDivPadding.left + contentDivPadding.right;
+ var hPadding = contentDivPadding.top + contentDivPadding.bottom;
+
+ // take into account the popup's 'padding' property
+ this.fixPadding();
+ wPadding += this.padding.left + this.padding.right;
+ hPadding += this.padding.top + this.padding.bottom;
+
+ // make extra space for the close div
+ if (this.closeDiv) {
+ var closeDivWidth = parseInt(this.closeDiv.style.width);
+ wPadding += closeDivWidth + contentDivPadding.right;
+ }
+
+ //increase size of the main popup div to take into account the
+ // users's desired padding and close div.
+ this.size.w += wPadding;
+ this.size.h += hPadding;
+
+ //now if our browser is IE, we need to actually make the contents
+ // div itself bigger to take its own padding into effect. this makes
+ // me want to shoot someone, but so it goes.
+ if (OpenLayers.BROWSER_NAME == "msie") {
+ this.contentSize.w +=
+ contentDivPadding.left + contentDivPadding.right;
+ this.contentSize.h +=
+ contentDivPadding.bottom + contentDivPadding.top;
+ }
+
+ if (this.div != null) {
+ this.div.style.width = this.size.w + "px";
+ this.div.style.height = this.size.h + "px";
+ }
+ if (this.contentDiv != null){
+ this.contentDiv.style.width = contentSize.w + "px";
+ this.contentDiv.style.height = contentSize.h + "px";
+ }
+ },
+
+ /**
+ * APIMethod: updateSize
+ * Auto size the popup so that it precisely fits its contents (as
+ * determined by this.contentDiv.innerHTML). Popup size will, of
+ * course, be limited by the available space on the current map
+ */
+ updateSize: function() {
+
+ // determine actual render dimensions of the contents by putting its
+ // contents into a fake contentDiv (for the CSS) and then measuring it
+ var preparedHTML = "<div class='" + this.contentDisplayClass+ "'>" +
+ this.contentDiv.innerHTML +
+ "</div>";
+
+ var containerElement = (this.map) ? this.map.layerContainerDiv
+ : document.body;
+ var realSize = OpenLayers.Util.getRenderedDimensions(
+ preparedHTML, null, {
+ displayClass: this.displayClass,
+ containerElement: containerElement
+ }
+ );
+
+ // is the "real" size of the div is safe to display in our map?
+ var safeSize = this.getSafeContentSize(realSize);
+
+ var newSize = null;
+ if (safeSize.equals(realSize)) {
+ //real size of content is small enough to fit on the map,
+ // so we use real size.
+ newSize = realSize;
+
+ } else {
+
+ //make a new OL.Size object with the clipped dimensions
+ // set or null if not clipped.
+ var fixedSize = new OpenLayers.Size();
+ fixedSize.w = (safeSize.w < realSize.w) ? safeSize.w : null;
+ fixedSize.h = (safeSize.h < realSize.h) ? safeSize.h : null;
+
+ if (fixedSize.w && fixedSize.h) {
+ //content is too big in both directions, so we will use
+ // max popup size (safeSize), knowing well that it will
+ // overflow both ways.
+ newSize = safeSize;
+ } else {
+ //content is clipped in only one direction, so we need to
+ // run getRenderedDimensions() again with a fixed dimension
+ var clippedSize = OpenLayers.Util.getRenderedDimensions(
+ preparedHTML, fixedSize, {
+ displayClass: this.contentDisplayClass,
+ containerElement: containerElement
+ }
+ );
+
+ //if the clipped size is still the same as the safeSize,
+ // that means that our content must be fixed in the
+ // offending direction. If overflow is 'auto', this means
+ // we are going to have a scrollbar for sure, so we must
+ // adjust for that.
+ //
+ var currentOverflow = OpenLayers.Element.getStyle(
+ this.contentDiv, "overflow"
+ );
+ if ( (currentOverflow != "hidden") &&
+ (clippedSize.equals(safeSize)) ) {
+ var scrollBar = OpenLayers.Util.getScrollbarWidth();
+ if (fixedSize.w) {
+ clippedSize.h += scrollBar;
+ } else {
+ clippedSize.w += scrollBar;
+ }
+ }
+
+ newSize = this.getSafeContentSize(clippedSize);
+ }
+ }
+ this.setSize(newSize);
+ },
+
+ /**
+ * Method: setBackgroundColor
+ * Sets the background color of the popup.
+ *
+ * Parameters:
+ * color - {String} the background color. eg "#FFBBBB"
+ */
+ setBackgroundColor:function(color) {
+ if (color != undefined) {
+ this.backgroundColor = color;
+ }
+
+ if (this.div != null) {
+ this.div.style.backgroundColor = this.backgroundColor;
+ }
+ },
+
+ /**
+ * Method: setOpacity
+ * Sets the opacity of the popup.
*
* Parameters:
- * moPixel - {Object} MapObject Pixel format
- *
- * Returns:
- * {Object} MapObject LonLat translated from MapObject Pixel
+ * opacity - {float} A value between 0.0 (transparent) and 1.0 (solid).
*/
- getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
- //the conditional here is to test if we are running the v6 of VE
- return (typeof VEPixel != 'undefined')
- ? this.mapObject.PixelToLatLong(moPixel)
- : this.mapObject.PixelToLatLong(moPixel.x, moPixel.y);
+ setOpacity:function(opacity) {
+ if (opacity != undefined) {
+ this.opacity = opacity;
+ }
+
+ if (this.div != null) {
+ // for Mozilla and Safari
+ this.div.style.opacity = this.opacity;
+
+ // for IE
+ this.div.style.filter = 'alpha(opacity=' + this.opacity*100 + ')';
+ }
+ },
+
+ /**
+ * Method: setBorder
+ * Sets the border style of the popup.
+ *
+ * Parameters:
+ * border - {String} The border style value. eg 2px
+ */
+ setBorder:function(border) {
+ if (border != undefined) {
+ this.border = border;
+ }
+
+ if (this.div != null) {
+ this.div.style.border = this.border;
+ }
+ },
+
+ /**
+ * Method: setContentHTML
+ * Allows the user to set the HTML content of the popup.
+ *
+ * Parameters:
+ * contentHTML - {String} HTML for the div.
+ */
+ setContentHTML:function(contentHTML) {
+
+ if (contentHTML != null) {
+ this.contentHTML = contentHTML;
+ }
+
+ if ((this.contentDiv != null) &&
+ (this.contentHTML != null) &&
+ (this.contentHTML != this.contentDiv.innerHTML)) {
+
+ this.contentDiv.innerHTML = this.contentHTML;
+
+ if (this.autoSize) {
+
+ //if popup has images, listen for when they finish
+ // loading and resize accordingly
+ this.registerImageListeners();
+
+ //auto size the popup to its current contents
+ this.updateSize();
+ }
+ }
+
},
+
+ /**
+ * Method: registerImageListeners
+ * Called when an image contained by the popup loaded. this function
+ * updates the popup size, then unregisters the image load listener.
+ */
+ registerImageListeners: function() {
+ // As the images load, this function will call updateSize() to
+ // resize the popup to fit the content div (which presumably is now
+ // bigger than when the image was not loaded).
+ //
+ // If the 'panMapIfOutOfView' property is set, we will pan the newly
+ // resized popup back into view.
+ //
+ // Note that this function, when called, will have 'popup' and
+ // 'img' properties in the context.
+ //
+ var onImgLoad = function() {
+
+ this.popup.updateSize();
+
+ if ( this.popup.visible() && this.popup.panMapIfOutOfView ) {
+ this.popup.panIntoView();
+ }
+
+ OpenLayers.Event.stopObserving(
+ this.img, "load", this.img._onImageLoad
+ );
+
+ };
+
+ //cycle through the images and if their size is 0x0, that means that
+ // they haven't been loaded yet, so we attach the listener, which
+ // will fire when the images finish loading and will resize the
+ // popup accordingly to its new size.
+ var images = this.contentDiv.getElementsByTagName("img");
+ for (var i = 0, len = images.length; i < len; i++) {
+ var img = images[i];
+ if (img.width == 0 || img.height == 0) {
+
+ var context = {
+ 'popup': this,
+ 'img': img
+ };
+
+ //expando this function to the image itself before registering
+ // it. This way we can easily and properly unregister it.
+ img._onImgLoad = OpenLayers.Function.bind(onImgLoad, context);
+
+ OpenLayers.Event.observe(img, 'load', img._onImgLoad);
+ }
+ }
+ },
+
/**
- * APIMethod: getMapObjectPixelFromMapObjectLonLat
+ * APIMethod: getSafeContentSize
*
* Parameters:
- * moLonLat - {Object} MapObject LonLat format
+ * size - {<OpenLayers.Size>} Desired size to make the popup.
*
* Returns:
- * {Object} MapObject Pixel transtlated from MapObject LonLat
+ * {<OpenLayers.Size>} A size to make the popup which is neither smaller
+ * than the specified minimum size, nor bigger than the maximum
+ * size (which is calculated relative to the size of the viewport).
*/
- getMapObjectPixelFromMapObjectLonLat: function(moLonLat) {
- return this.mapObject.LatLongToPixel(moLonLat);
- },
+ getSafeContentSize: function(size) {
+ var safeContentSize = size.clone();
- /************************************
- * *
- * MapObject Primitives *
- * *
- ************************************/
+ // if our contentDiv has a css 'padding' set on it by a stylesheet, we
+ // must add that to the desired "size".
+ var contentDivPadding = this.getContentDivPadding();
+ var wPadding = contentDivPadding.left + contentDivPadding.right;
+ var hPadding = contentDivPadding.top + contentDivPadding.bottom;
+ // take into account the popup's 'padding' property
+ this.fixPadding();
+ wPadding += this.padding.left + this.padding.right;
+ hPadding += this.padding.top + this.padding.bottom;
- // LonLat
+ if (this.closeDiv) {
+ var closeDivWidth = parseInt(this.closeDiv.style.width);
+ wPadding += closeDivWidth + contentDivPadding.right;
+ }
+
+ // prevent the popup from being smaller than a specified minimal size
+ if (this.minSize) {
+ safeContentSize.w = Math.max(safeContentSize.w,
+ (this.minSize.w - wPadding));
+ safeContentSize.h = Math.max(safeContentSize.h,
+ (this.minSize.h - hPadding));
+ }
+
+ // prevent the popup from being bigger than a specified maximum size
+ if (this.maxSize) {
+ safeContentSize.w = Math.min(safeContentSize.w,
+ (this.maxSize.w - wPadding));
+ safeContentSize.h = Math.min(safeContentSize.h,
+ (this.maxSize.h - hPadding));
+ }
+
+ //make sure the desired size to set doesn't result in a popup that
+ // is bigger than the map's viewport.
+ //
+ if (this.map && this.map.size) {
+
+ var extraX = 0, extraY = 0;
+ if (this.keepInMap && !this.panMapIfOutOfView) {
+ var px = this.map.getPixelFromLonLat(this.lonlat);
+ switch (this.relativePosition) {
+ case "tr":
+ extraX = px.x;
+ extraY = this.map.size.h - px.y;
+ break;
+ case "tl":
+ extraX = this.map.size.w - px.x;
+ extraY = this.map.size.h - px.y;
+ break;
+ case "bl":
+ extraX = this.map.size.w - px.x;
+ extraY = px.y;
+ break;
+ case "br":
+ extraX = px.x;
+ extraY = px.y;
+ break;
+ default:
+ extraX = px.x;
+ extraY = this.map.size.h - px.y;
+ break;
+ }
+ }
+
+ var maxY = this.map.size.h -
+ this.map.paddingForPopups.top -
+ this.map.paddingForPopups.bottom -
+ hPadding - extraY;
+
+ var maxX = this.map.size.w -
+ this.map.paddingForPopups.left -
+ this.map.paddingForPopups.right -
+ wPadding - extraX;
+
+ safeContentSize.w = Math.min(safeContentSize.w, maxX);
+ safeContentSize.h = Math.min(safeContentSize.h, maxY);
+ }
+
+ return safeContentSize;
+ },
/**
- * APIMethod: getLongitudeFromMapObjectLonLat
- *
- * Parameters:
- * moLonLat - {Object} MapObject LonLat format
- *
+ * Method: getContentDivPadding
+ * Glorious, oh glorious hack in order to determine the css 'padding' of
+ * the contentDiv. IE/Opera return null here unless we actually add the
+ * popup's main 'div' element (which contains contentDiv) to the DOM.
+ * So we make it invisible and then add it to the document temporarily.
+ *
+ * Once we've taken the padding readings we need, we then remove it
+ * from the DOM (it will actually get added to the DOM in
+ * Map.js's addPopup)
+ *
* Returns:
- * {Float} Longitude of the given MapObject LonLat
+ * {<OpenLayers.Bounds>}
*/
- getLongitudeFromMapObjectLonLat: function(moLonLat) {
- return this.sphericalMercator ?
- this.forwardMercator(moLonLat.Longitude, moLonLat.Latitude).lon :
- moLonLat.Longitude;
+ getContentDivPadding: function() {
+
+ //use cached value if we have it
+ var contentDivPadding = this._contentDivPadding;
+ if (!contentDivPadding) {
+
+ if (this.div.parentNode == null) {
+ //make the div invisible and add it to the page
+ this.div.style.display = "none";
+ document.body.appendChild(this.div);
+ }
+
+ //read the padding settings from css, put them in an OL.Bounds
+ contentDivPadding = new OpenLayers.Bounds(
+ OpenLayers.Element.getStyle(this.contentDiv, "padding-left"),
+ OpenLayers.Element.getStyle(this.contentDiv, "padding-bottom"),
+ OpenLayers.Element.getStyle(this.contentDiv, "padding-right"),
+ OpenLayers.Element.getStyle(this.contentDiv, "padding-top")
+ );
+
+ //cache the value
+ this._contentDivPadding = contentDivPadding;
+
+ if (this.div.parentNode == document.body) {
+ //remove the div from the page and make it visible again
+ document.body.removeChild(this.div);
+ this.div.style.display = "";
+ }
+ }
+ return contentDivPadding;
},
/**
- * APIMethod: getLatitudeFromMapObjectLonLat
+ * Method: addCloseBox
*
* Parameters:
- * moLonLat - {Object} MapObject LonLat format
- *
- * Returns:
- * {Float} Latitude of the given MapObject LonLat
+ * callback - {Function} The callback to be called when the close button
+ * is clicked.
*/
- getLatitudeFromMapObjectLonLat: function(moLonLat) {
- return this.sphericalMercator ?
- this.forwardMercator(moLonLat.Longitude, moLonLat.Latitude).lat :
- moLonLat.Latitude;
+ addCloseBox: function(callback) {
+
+ this.closeDiv = OpenLayers.Util.createDiv(
+ this.id + "_close", null, new OpenLayers.Size(17, 17)
+ );
+ this.closeDiv.className = "olPopupCloseBox";
+
+ // use the content div's css padding to determine if we should
+ // padd the close div
+ var contentDivPadding = this.getContentDivPadding();
+
+ this.closeDiv.style.right = contentDivPadding.right + "px";
+ this.closeDiv.style.top = contentDivPadding.top + "px";
+ this.groupDiv.appendChild(this.closeDiv);
+
+ var closePopup = callback || function(e) {
+ this.hide();
+ OpenLayers.Event.stop(e);
+ };
+ OpenLayers.Event.observe(this.closeDiv, "click",
+ OpenLayers.Function.bindAsEventListener(closePopup, this));
},
/**
- * APIMethod: getMapObjectLonLatFromLonLat
+ * Method: panIntoView
+ * Pans the map such that the popup is totaly viewable (if necessary)
+ */
+ panIntoView: function() {
+
+ var mapSize = this.map.getSize();
+
+ //start with the top left corner of the popup, in px,
+ // relative to the viewport
+ var origTL = this.map.getViewPortPxFromLayerPx( new OpenLayers.Pixel(
+ parseInt(this.div.style.left),
+ parseInt(this.div.style.top)
+ ));
+ var newTL = origTL.clone();
+
+ //new left (compare to margins, using this.size to calculate right)
+ if (origTL.x < this.map.paddingForPopups.left) {
+ newTL.x = this.map.paddingForPopups.left;
+ } else
+ if ( (origTL.x + this.size.w) > (mapSize.w - this.map.paddingForPopups.right)) {
+ newTL.x = mapSize.w - this.map.paddingForPopups.right - this.size.w;
+ }
+
+ //new top (compare to margins, using this.size to calculate bottom)
+ if (origTL.y < this.map.paddingForPopups.top) {
+ newTL.y = this.map.paddingForPopups.top;
+ } else
+ if ( (origTL.y + this.size.h) > (mapSize.h - this.map.paddingForPopups.bottom)) {
+ newTL.y = mapSize.h - this.map.paddingForPopups.bottom - this.size.h;
+ }
+
+ var dx = origTL.x - newTL.x;
+ var dy = origTL.y - newTL.y;
+
+ this.map.pan(dx, dy);
+ },
+
+ /**
+ * Method: registerEvents
+ * Registers events on the popup.
+ *
+ * Do this in a separate function so that subclasses can
+ * choose to override it if they wish to deal differently
+ * with mouse events
*
+ * Note in the following handler functions that some special
+ * care is needed to deal correctly with mousing and popups.
+ *
+ * Because the user might select the zoom-rectangle option and
+ * then drag it over a popup, we need a safe way to allow the
+ * mousemove and mouseup events to pass through the popup when
+ * they are initiated from outside.
+ *
+ * Otherwise, we want to essentially kill the event propagation
+ * for all other events, though we have to do so carefully,
+ * without disabling basic html functionality, like clicking on
+ * hyperlinks or drag-selecting text.
+ */
+ registerEvents:function() {
+ this.events = new OpenLayers.Events(this, this.div, null, true);
+
+ this.events.on({
+ "mousedown": this.onmousedown,
+ "mousemove": this.onmousemove,
+ "mouseup": this.onmouseup,
+ "click": this.onclick,
+ "mouseout": this.onmouseout,
+ "dblclick": this.ondblclick,
+ scope: this
+ });
+
+ },
+
+ /**
+ * Method: onmousedown
+ * When mouse goes down within the popup, make a note of
+ * it locally, and then do not propagate the mousedown
+ * (but do so safely so that user can select text inside)
+ *
* Parameters:
- * lon - {Float}
- * lat - {Float}
+ * evt - {Event}
+ */
+ onmousedown: function (evt) {
+ this.mousedown = true;
+ OpenLayers.Event.stop(evt, true);
+ },
+
+ /**
+ * Method: onmousemove
+ * If the drag was started within the popup, then
+ * do not propagate the mousemove (but do so safely
+ * so that user can select text inside)
*
- * Returns:
- * {Object} MapObject LonLat built from lon and lat params
+ * Parameters:
+ * evt - {Event}
*/
- getMapObjectLonLatFromLonLat: function(lon, lat) {
- var veLatLong;
- if(this.sphericalMercator) {
- var lonlat = this.inverseMercator(lon, lat);
- veLatLong = new VELatLong(lonlat.lat, lonlat.lon);
- } else {
- veLatLong = new VELatLong(lat, lon);
+ onmousemove: function (evt) {
+ if (this.mousedown) {
+ OpenLayers.Event.stop(evt, true);
}
- return veLatLong;
},
- // Pixel
-
- /**
- * APIMethod: getXFromMapObjectPixel
+ /**
+ * Method: onmouseup
+ * When mouse comes up within the popup, after going down
+ * in it, reset the flag, and then (once again) do not
+ * propagate the event, but do so safely so that user can
+ * select text inside
*
* Parameters:
- * moPixel - {Object} MapObject Pixel format
- *
- * Returns:
- * {Integer} X value of the MapObject Pixel
+ * evt - {Event}
*/
- getXFromMapObjectPixel: function(moPixel) {
- return moPixel.x;
+ onmouseup: function (evt) {
+ if (this.mousedown) {
+ this.mousedown = false;
+ OpenLayers.Event.stop(evt, true);
+ }
},
/**
- * APIMethod: getYFromMapObjectPixel
+ * Method: onclick
+ * Ignore clicks, but allowing default browser handling
*
* Parameters:
- * moPixel - {Object} MapObject Pixel format
- *
- * Returns:
- * {Integer} Y value of the MapObject Pixel
+ * evt - {Event}
*/
- getYFromMapObjectPixel: function(moPixel) {
- return moPixel.y;
+ onclick: function (evt) {
+ OpenLayers.Event.stop(evt, true);
},
- /**
- * APIMethod: getMapObjectPixelFromXY
+ /**
+ * Method: onmouseout
+ * When mouse goes out of the popup set the flag to false so that
+ * if they let go and then drag back in, we won't be confused.
*
* Parameters:
- * x - {Integer}
- * y - {Integer}
+ * evt - {Event}
+ */
+ onmouseout: function (evt) {
+ this.mousedown = false;
+ },
+
+ /**
+ * Method: ondblclick
+ * Ignore double-clicks, but allowing default browser handling
*
- * Returns:
- * {Object} MapObject Pixel from x and y parameters
+ * Parameters:
+ * evt - {Event}
*/
- getMapObjectPixelFromXY: function(x, y) {
- //the conditional here is to test if we are running the v6 of VE
- return (typeof VEPixel != 'undefined') ? new VEPixel(x, y)
- : new Msn.VE.Pixel(x, y);
+ ondblclick: function (evt) {
+ OpenLayers.Event.stop(evt, true);
},
- CLASS_NAME: "OpenLayers.Layer.VirtualEarth"
+ CLASS_NAME: "OpenLayers.Popup"
});
+
+OpenLayers.Popup.WIDTH = 200;
+OpenLayers.Popup.HEIGHT = 200;
+OpenLayers.Popup.COLOR = "white";
+OpenLayers.Popup.OPACITY = 1;
+OpenLayers.Popup.BORDER = "0px";
/* ======================================================================
- OpenLayers/Layer/Yahoo.js
+ OpenLayers/Popup/Anchored.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
- * @requires OpenLayers/Layer/SphericalMercator.js
- * @requires OpenLayers/Layer/EventPane.js
- * @requires OpenLayers/Layer/FixedZoomLevels.js
+ * @requires OpenLayers/Popup.js
*/
/**
- * Class: OpenLayers.Layer.Yahoo
+ * Class: OpenLayers.Popup.Anchored
*
* Inherits from:
- * - <OpenLayers.Layer.EventPane>
- * - <OpenLayers.Layer.FixedZoomLevels>
+ * - <OpenLayers.Popup>
*/
-OpenLayers.Layer.Yahoo = OpenLayers.Class(
- OpenLayers.Layer.EventPane, OpenLayers.Layer.FixedZoomLevels, {
-
+OpenLayers.Popup.Anchored =
+ OpenLayers.Class(OpenLayers.Popup, {
+
/**
- * Constant: MIN_ZOOM_LEVEL
- * {Integer} 0
+ * Parameter: relativePosition
+ * {String} Relative position of the popup ("br", "tr", "tl" or "bl").
*/
- MIN_ZOOM_LEVEL: 0,
+ relativePosition: null,
- /**
- * Constant: MAX_ZOOM_LEVEL
- * {Integer} 17
+ /**
+ * APIProperty: keepInMap
+ * {Boolean} If panMapIfOutOfView is false, and this property is true,
+ * contrain the popup such that it always fits in the available map
+ * space. By default, this is set. If you are creating popups that are
+ * near map edges and not allowing pannning, and especially if you have
+ * a popup which has a fixedRelativePosition, setting this to false may
+ * be a smart thing to do.
+ *
+ * For anchored popups, default is true, since subclasses will
+ * usually want this functionality.
*/
- MAX_ZOOM_LEVEL: 17,
+ keepInMap: true,
+ /**
+ * Parameter: anchor
+ * {Object} Object to which we'll anchor the popup. Must expose a
+ * 'size' (<OpenLayers.Size>) and 'offset' (<OpenLayers.Pixel>).
+ */
+ anchor: null,
+
/**
- * Constant: RESOLUTIONS
- * {Array(Float)} Hardcode these resolutions so that they are more closely
- * tied with the standard wms projection
+ * Constructor: OpenLayers.Popup.Anchored
+ *
+ * Parameters:
+ * id - {String}
+ * lonlat - {<OpenLayers.LonLat>}
+ * contentSize - {<OpenLayers.Size>}
+ * contentHTML - {String}
+ * anchor - {Object} Object which must expose a 'size' <OpenLayers.Size>
+ * and 'offset' <OpenLayers.Pixel> (generally an <OpenLayers.Icon>).
+ * closeBox - {Boolean}
+ * closeBoxCallback - {Function} Function to be called on closeBox click.
+ */
+ initialize:function(id, lonlat, contentSize, contentHTML, anchor, closeBox,
+ closeBoxCallback) {
+ var newArguments = [
+ id, lonlat, contentSize, contentHTML, closeBox, closeBoxCallback
+ ];
+ OpenLayers.Popup.prototype.initialize.apply(this, newArguments);
+
+ this.anchor = (anchor != null) ? anchor
+ : { size: new OpenLayers.Size(0,0),
+ offset: new OpenLayers.Pixel(0,0)};
+ },
+
+ /**
+ * APIMethod: destroy
*/
- RESOLUTIONS: [
- 1.40625,
- 0.703125,
- 0.3515625,
- 0.17578125,
- 0.087890625,
- 0.0439453125,
- 0.02197265625,
- 0.010986328125,
- 0.0054931640625,
- 0.00274658203125,
- 0.001373291015625,
- 0.0006866455078125,
- 0.00034332275390625,
- 0.000171661376953125,
- 0.0000858306884765625,
- 0.00004291534423828125,
- 0.00002145767211914062,
- 0.00001072883605957031
- ],
+ destroy: function() {
+ this.anchor = null;
+ this.relativePosition = null;
+
+ OpenLayers.Popup.prototype.destroy.apply(this, arguments);
+ },
/**
- * APIProperty: type
- * {YahooMapType}
+ * APIMethod: show
+ * Overridden from Popup since user might hide popup and then show() it
+ * in a new location (meaning we might want to update the relative
+ * position on the show)
*/
- type: null,
-
+ show: function() {
+ this.updatePosition();
+ OpenLayers.Popup.prototype.show.apply(this, arguments);
+ },
+
/**
- * APIProperty: wrapDateLine
- * {Boolean} Allow user to pan forever east/west. Default is true.
- * Setting this to false only restricts panning if
- * <sphericalMercator> is true.
+ * Method: moveTo
+ * Since the popup is moving to a new px, it might need also to be moved
+ * relative to where the marker is. We first calculate the new
+ * relativePosition, and then we calculate the new px where we will
+ * put the popup, based on the new relative position.
+ *
+ * If the relativePosition has changed, we must also call
+ * updateRelativePosition() to make any visual changes to the popup
+ * which are associated with putting it in a new relativePosition.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
*/
- wrapDateLine: true,
+ moveTo: function(px) {
+ var oldRelativePosition = this.relativePosition;
+ this.relativePosition = this.calculateRelativePosition(px);
+
+ var newPx = this.calculateNewPx(px);
+
+ var newArguments = new Array(newPx);
+ OpenLayers.Popup.prototype.moveTo.apply(this, newArguments);
+
+ //if this move has caused the popup to change its relative position,
+ // we need to make the appropriate cosmetic changes.
+ if (this.relativePosition != oldRelativePosition) {
+ this.updateRelativePosition();
+ }
+ },
/**
- * APIProperty: sphericalMercator
- * {Boolean} Should the map act as a mercator-projected map? This will
- * cause all interactions with the map to be in the actual map projection,
- * which allows support for vector drawing, overlaying other maps, etc.
+ * APIMethod: setSize
+ *
+ * Parameters:
+ * contentSize - {<OpenLayers.Size>} the new size for the popup's
+ * contents div (in pixels).
*/
- sphericalMercator: false,
+ setSize:function(contentSize) {
+ OpenLayers.Popup.prototype.setSize.apply(this, arguments);
+ if ((this.lonlat) && (this.map)) {
+ var px = this.map.getLayerPxFromLonLat(this.lonlat);
+ this.moveTo(px);
+ }
+ },
+
/**
- * Constructor: OpenLayers.Layer.Yahoo
+ * Method: calculateRelativePosition
*
* Parameters:
- * name - {String}
- * options - {Object}
+ * px - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {String} The relative position ("br" "tr" "tl" "bl") at which the popup
+ * should be placed.
*/
- initialize: function(name, options) {
- OpenLayers.Layer.EventPane.prototype.initialize.apply(this, arguments);
- OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,
- arguments);
- if(this.sphericalMercator) {
- OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
- this.initMercatorParameters();
- }
- },
-
+ calculateRelativePosition:function(px) {
+ var lonlat = this.map.getLonLatFromLayerPx(px);
+
+ var extent = this.map.getExtent();
+ var quadrant = extent.determineQuadrant(lonlat);
+
+ return OpenLayers.Bounds.oppositeQuadrant(quadrant);
+ },
+
/**
- * Method: loadMapObject
+ * Method: updateRelativePosition
+ * The popup has been moved to a new relative location, so we may want to
+ * make some cosmetic adjustments to it.
+ *
+ * Note that in the classic Anchored popup, there is nothing to do
+ * here, since the popup looks exactly the same in all four positions.
+ * Subclasses such as the AnchoredBubble and Framed, however, will
+ * want to do something special here.
*/
- loadMapObject:function() {
- try { //do not crash!
- var size = this.getMapObjectSizeFromOLSize(this.map.getSize());
- this.mapObject = new YMap(this.div, this.type, size);
- this.mapObject.disableKeyControls();
- this.mapObject.disableDragMap();
+ updateRelativePosition: function() {
+ //to be overridden by subclasses
+ },
- //can we do smooth panning? (moveByXY is not an API function)
- if ( !this.mapObject.moveByXY ||
- (typeof this.mapObject.moveByXY != "function" ) ) {
+ /**
+ * Method: calculateNewPx
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} The the new px position of the popup on the screen
+ * relative to the passed-in px.
+ */
+ calculateNewPx:function(px) {
+ var newPx = px.offset(this.anchor.offset);
+
+ //use contentSize if size is not already set
+ var size = this.size || this.contentSize;
- this.dragPanMapObject = null;
- }
- } catch(e) {}
+ var top = (this.relativePosition.charAt(0) == 't');
+ newPx.y += (top) ? -size.h : this.anchor.size.h;
+
+ var left = (this.relativePosition.charAt(1) == 'l');
+ newPx.x += (left) ? -size.w : this.anchor.size.w;
+
+ return newPx;
},
+ CLASS_NAME: "OpenLayers.Popup.Anchored"
+});
+/* ======================================================================
+ Rico/Color.js
+ ====================================================================== */
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ */
+
+
+/*
+ * This file has been edited substantially from the Rico-released version by
+ * the OpenLayers development team.
+ *
+ * This file is licensed under the Apache License, Version 2.0.
+ */
+OpenLayers.Rico = OpenLayers.Rico || {};
+OpenLayers.Rico.Color = OpenLayers.Class({
+
+ initialize: function(red, green, blue) {
+ this.rgb = { r: red, g : green, b : blue };
+ },
+
+ setRed: function(r) {
+ this.rgb.r = r;
+ },
+
+ setGreen: function(g) {
+ this.rgb.g = g;
+ },
+
+ setBlue: function(b) {
+ this.rgb.b = b;
+ },
+
+ setHue: function(h) {
+
+ // get an HSB model, and set the new hue...
+ var hsb = this.asHSB();
+ hsb.h = h;
+
+ // convert back to RGB...
+ this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
+ },
+
+ setSaturation: function(s) {
+ // get an HSB model, and set the new hue...
+ var hsb = this.asHSB();
+ hsb.s = s;
+
+ // convert back to RGB and set values...
+ this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
+ },
+
+ setBrightness: function(b) {
+ // get an HSB model, and set the new hue...
+ var hsb = this.asHSB();
+ hsb.b = b;
+
+ // convert back to RGB and set values...
+ this.rgb = OpenLayers.Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b );
+ },
+
+ darken: function(percent) {
+ var hsb = this.asHSB();
+ this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0));
+ },
+
+ brighten: function(percent) {
+ var hsb = this.asHSB();
+ this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1));
+ },
+
+ blend: function(other) {
+ this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2);
+ this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2);
+ this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2);
+ },
+
+ isBright: function() {
+ var hsb = this.asHSB();
+ return this.asHSB().b > 0.5;
+ },
+
+ isDark: function() {
+ return ! this.isBright();
+ },
+
+ asRGB: function() {
+ return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
+ },
+
+ asHex: function() {
+ return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart();
+ },
+
+ asHSB: function() {
+ return OpenLayers.Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
+ },
+
+ toString: function() {
+ return this.asHex();
+ }
+
+});
+
+OpenLayers.Rico.Color.createFromHex = function(hexCode) {
+ if(hexCode.length==4) {
+ var shortHexCode = hexCode;
+ var hexCode = '#';
+ for(var i=1;i<4;i++) {
+ hexCode += (shortHexCode.charAt(i) +
+shortHexCode.charAt(i));
+ }
+ }
+ if ( hexCode.indexOf('#') == 0 ) {
+ hexCode = hexCode.substring(1);
+ }
+ var red = hexCode.substring(0,2);
+ var green = hexCode.substring(2,4);
+ var blue = hexCode.substring(4,6);
+ return new OpenLayers.Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) );
+};
+
+/**
+ * Factory method for creating a color from the background of
+ * an HTML element.
+ */
+OpenLayers.Rico.Color.createColorFromBackground = function(elem) {
+
+ var actualColor =
+ RicoUtil.getElementsComputedStyle(OpenLayers.Util.getElement(elem),
+ "backgroundColor",
+ "background-color");
+
+ if ( actualColor == "transparent" && elem.parentNode ) {
+ return OpenLayers.Rico.Color.createColorFromBackground(elem.parentNode);
+ }
+ if ( actualColor == null ) {
+ return new OpenLayers.Rico.Color(255,255,255);
+ }
+ if ( actualColor.indexOf("rgb(") == 0 ) {
+ var colors = actualColor.substring(4, actualColor.length - 1 );
+ var colorArray = colors.split(",");
+ return new OpenLayers.Rico.Color( parseInt( colorArray[0] ),
+ parseInt( colorArray[1] ),
+ parseInt( colorArray[2] ) );
+
+ }
+ else if ( actualColor.indexOf("#") == 0 ) {
+ return OpenLayers.Rico.Color.createFromHex(actualColor);
+ }
+ else {
+ return new OpenLayers.Rico.Color(255,255,255);
+ }
+};
+
+OpenLayers.Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {
+
+ var red = 0;
+ var green = 0;
+ var blue = 0;
+
+ if (saturation == 0) {
+ red = parseInt(brightness * 255.0 + 0.5);
+ green = red;
+ blue = red;
+ }
+ else {
+ var h = (hue - Math.floor(hue)) * 6.0;
+ var f = h - Math.floor(h);
+ var p = brightness * (1.0 - saturation);
+ var q = brightness * (1.0 - saturation * f);
+ var t = brightness * (1.0 - (saturation * (1.0 - f)));
+
+ switch (parseInt(h)) {
+ case 0:
+ red = (brightness * 255.0 + 0.5);
+ green = (t * 255.0 + 0.5);
+ blue = (p * 255.0 + 0.5);
+ break;
+ case 1:
+ red = (q * 255.0 + 0.5);
+ green = (brightness * 255.0 + 0.5);
+ blue = (p * 255.0 + 0.5);
+ break;
+ case 2:
+ red = (p * 255.0 + 0.5);
+ green = (brightness * 255.0 + 0.5);
+ blue = (t * 255.0 + 0.5);
+ break;
+ case 3:
+ red = (p * 255.0 + 0.5);
+ green = (q * 255.0 + 0.5);
+ blue = (brightness * 255.0 + 0.5);
+ break;
+ case 4:
+ red = (t * 255.0 + 0.5);
+ green = (p * 255.0 + 0.5);
+ blue = (brightness * 255.0 + 0.5);
+ break;
+ case 5:
+ red = (brightness * 255.0 + 0.5);
+ green = (p * 255.0 + 0.5);
+ blue = (q * 255.0 + 0.5);
+ break;
+ }
+ }
+
+ return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) };
+};
+
+OpenLayers.Rico.Color.RGBtoHSB = function(r, g, b) {
+
+ var hue;
+ var saturation;
+ var brightness;
+
+ var cmax = (r > g) ? r : g;
+ if (b > cmax) {
+ cmax = b;
+ }
+ var cmin = (r < g) ? r : g;
+ if (b < cmin) {
+ cmin = b;
+ }
+ brightness = cmax / 255.0;
+ if (cmax != 0) {
+ saturation = (cmax - cmin)/cmax;
+ } else {
+ saturation = 0;
+ }
+ if (saturation == 0) {
+ hue = 0;
+ } else {
+ var redc = (cmax - r)/(cmax - cmin);
+ var greenc = (cmax - g)/(cmax - cmin);
+ var bluec = (cmax - b)/(cmax - cmin);
+
+ if (r == cmax) {
+ hue = bluec - greenc;
+ } else if (g == cmax) {
+ hue = 2.0 + redc - bluec;
+ } else {
+ hue = 4.0 + greenc - redc;
+ }
+ hue = hue / 6.0;
+ if (hue < 0) {
+ hue = hue + 1.0;
+ }
+ }
+
+ return { h : hue, s : saturation, b : brightness };
+};
+
+/* ======================================================================
+ Rico/Corner.js
+ ====================================================================== */
+
+/**
+ * @requires Rico/Color.js
+ */
+
+
+/*
+ * This file has been edited substantially from the Rico-released
+ * version by the OpenLayers development team.
+ *
+ * Copyright 2005 Sabre Airline Solutions
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the * License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or
+ * implied. See the License for the specific language governing
+ * permissions * and limitations under the License.
+ *
+ */
+OpenLayers.Rico = OpenLayers.Rico || {};
+OpenLayers.Rico.Corner = {
+
+ round: function(e, options) {
+ e = OpenLayers.Util.getElement(e);
+ this._setOptions(options);
+
+ var color = this.options.color;
+ if ( this.options.color == "fromElement" ) {
+ color = this._background(e);
+ }
+ var bgColor = this.options.bgColor;
+ if ( this.options.bgColor == "fromParent" ) {
+ bgColor = this._background(e.offsetParent);
+ }
+ this._roundCornersImpl(e, color, bgColor);
+ },
+
+ /** This is a helper function to change the background
+ * color of <div> that has had Rico rounded corners added.
+ *
+ * It seems we cannot just set the background color for the
+ * outer <div> so each <span> element used to create the
+ * corners must have its background color set individually.
+ *
+ * @param {DOM} theDiv - A child of the outer <div> that was
+ * supplied to the `round` method.
+ *
+ * @param {String} newColor - The new background color to use.
+ */
+ changeColor: function(theDiv, newColor) {
+
+ theDiv.style.backgroundColor = newColor;
+
+ var spanElements = theDiv.parentNode.getElementsByTagName("span");
+
+ for (var currIdx = 0; currIdx < spanElements.length; currIdx++) {
+ spanElements[currIdx].style.backgroundColor = newColor;
+ }
+ },
+
+
+ /** This is a helper function to change the background
+ * opacity of <div> that has had Rico rounded corners added.
+ *
+ * See changeColor (above) for algorithm explanation
+ *
+ * @param {DOM} theDiv A child of the outer <div> that was
+ * supplied to the `round` method.
+ *
+ * @param {int} newOpacity The new opacity to use (0-1).
+ */
+ changeOpacity: function(theDiv, newOpacity) {
+
+ var mozillaOpacity = newOpacity;
+ var ieOpacity = 'alpha(opacity=' + newOpacity * 100 + ')';
+
+ theDiv.style.opacity = mozillaOpacity;
+ theDiv.style.filter = ieOpacity;
+
+ var spanElements = theDiv.parentNode.getElementsByTagName("span");
+
+ for (var currIdx = 0; currIdx < spanElements.length; currIdx++) {
+ spanElements[currIdx].style.opacity = mozillaOpacity;
+ spanElements[currIdx].style.filter = ieOpacity;
+ }
+
+ },
+
+ /** this function takes care of redoing the rico cornering
+ *
+ * you can't just call updateRicoCorners() again and pass it a
+ * new options string. you have to first remove the divs that
+ * rico puts on top and below the content div.
+ *
+ * @param {DOM} theDiv - A child of the outer <div> that was
+ * supplied to the `round` method.
+ *
+ * @param {Object} options - list of options
+ */
+ reRound: function(theDiv, options) {
+
+ var topRico = theDiv.parentNode.childNodes[0];
+ //theDiv would be theDiv.parentNode.childNodes[1]
+ var bottomRico = theDiv.parentNode.childNodes[2];
+
+ theDiv.parentNode.removeChild(topRico);
+ theDiv.parentNode.removeChild(bottomRico);
+
+ this.round(theDiv.parentNode, options);
+ },
+
+ _roundCornersImpl: function(e, color, bgColor) {
+ if(this.options.border) {
+ this._renderBorder(e,bgColor);
+ }
+ if(this._isTopRounded()) {
+ this._roundTopCorners(e,color,bgColor);
+ }
+ if(this._isBottomRounded()) {
+ this._roundBottomCorners(e,color,bgColor);
+ }
+ },
+
+ _renderBorder: function(el,bgColor) {
+ var borderValue = "1px solid " + this._borderColor(bgColor);
+ var borderL = "border-left: " + borderValue;
+ var borderR = "border-right: " + borderValue;
+ var style = "style='" + borderL + ";" + borderR + "'";
+ el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>";
+ },
+
+ _roundTopCorners: function(el, color, bgColor) {
+ var corner = this._createCorner(bgColor);
+ for(var i=0 ; i < this.options.numSlices ; i++ ) {
+ corner.appendChild(this._createCornerSlice(color,bgColor,i,"top"));
+ }
+ el.style.paddingTop = 0;
+ el.insertBefore(corner,el.firstChild);
+ },
+
+ _roundBottomCorners: function(el, color, bgColor) {
+ var corner = this._createCorner(bgColor);
+ for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- ) {
+ corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom"));
+ }
+ el.style.paddingBottom = 0;
+ el.appendChild(corner);
+ },
+
+ _createCorner: function(bgColor) {
+ var corner = document.createElement("div");
+ corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor);
+ return corner;
+ },
+
+ _createCornerSlice: function(color,bgColor, n, position) {
+ var slice = document.createElement("span");
+
+ var inStyle = slice.style;
+ inStyle.backgroundColor = color;
+ inStyle.display = "block";
+ inStyle.height = "1px";
+ inStyle.overflow = "hidden";
+ inStyle.fontSize = "1px";
+
+ var borderColor = this._borderColor(color,bgColor);
+ if ( this.options.border && n == 0 ) {
+ inStyle.borderTopStyle = "solid";
+ inStyle.borderTopWidth = "1px";
+ inStyle.borderLeftWidth = "0px";
+ inStyle.borderRightWidth = "0px";
+ inStyle.borderBottomWidth = "0px";
+ inStyle.height = "0px"; // assumes css compliant box model
+ inStyle.borderColor = borderColor;
+ }
+ else if(borderColor) {
+ inStyle.borderColor = borderColor;
+ inStyle.borderStyle = "solid";
+ inStyle.borderWidth = "0px 1px";
+ }
+
+ if ( !this.options.compact && (n == (this.options.numSlices-1)) ) {
+ inStyle.height = "2px";
+ }
+ this._setMargin(slice, n, position);
+ this._setBorder(slice, n, position);
+ return slice;
+ },
+
+ _setOptions: function(options) {
+ this.options = {
+ corners : "all",
+ color : "fromElement",
+ bgColor : "fromParent",
+ blend : true,
+ border : false,
+ compact : false
+ };
+ OpenLayers.Util.extend(this.options, options || {});
+
+ this.options.numSlices = this.options.compact ? 2 : 4;
+ if ( this._isTransparent() ) {
+ this.options.blend = false;
+ }
+ },
+
+ _whichSideTop: function() {
+ if ( this._hasString(this.options.corners, "all", "top") ) {
+ return "";
+ }
+ if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 ) {
+ return "";
+ }
+ if (this.options.corners.indexOf("tl") >= 0) {
+ return "left";
+ } else if (this.options.corners.indexOf("tr") >= 0) {
+ return "right";
+ }
+ return "";
+ },
+
+ _whichSideBottom: function() {
+ if ( this._hasString(this.options.corners, "all", "bottom") ) {
+ return "";
+ }
+ if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 ) {
+ return "";
+ }
+
+ if(this.options.corners.indexOf("bl") >=0) {
+ return "left";
+ } else if(this.options.corners.indexOf("br")>=0) {
+ return "right";
+ }
+ return "";
+ },
+
+ _borderColor : function(color,bgColor) {
+ if ( color == "transparent" ) {
+ return bgColor;
+ } else if ( this.options.border ) {
+ return this.options.border;
+ } else if ( this.options.blend ) {
+ return this._blend( bgColor, color );
+ } else {
+ return "";
+ }
+ },
+
+
+ _setMargin: function(el, n, corners) {
+ var marginSize = this._marginSize(n);
+ var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
+
+ if ( whichSide == "left" ) {
+ el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px";
+ }
+ else if ( whichSide == "right" ) {
+ el.style.marginRight = marginSize + "px"; el.style.marginLeft = "0px";
+ }
+ else {
+ el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px";
+ }
+ },
+
+ _setBorder: function(el,n,corners) {
+ var borderSize = this._borderSize(n);
+ var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
+ if ( whichSide == "left" ) {
+ el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px";
+ }
+ else if ( whichSide == "right" ) {
+ el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth = "0px";
+ }
+ else {
+ el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
+ }
+ if (this.options.border != false) {
+ el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
+ }
+ },
+
+ _marginSize: function(n) {
+ if ( this._isTransparent() ) {
+ return 0;
+ }
+ var marginSizes = [ 5, 3, 2, 1 ];
+ var blendedMarginSizes = [ 3, 2, 1, 0 ];
+ var compactMarginSizes = [ 2, 1 ];
+ var smBlendedMarginSizes = [ 1, 0 ];
+
+ if ( this.options.compact && this.options.blend ) {
+ return smBlendedMarginSizes[n];
+ } else if ( this.options.compact ) {
+ return compactMarginSizes[n];
+ } else if ( this.options.blend ) {
+ return blendedMarginSizes[n];
+ } else {
+ return marginSizes[n];
+ }
+ },
+
+ _borderSize: function(n) {
+ var transparentBorderSizes = [ 5, 3, 2, 1 ];
+ var blendedBorderSizes = [ 2, 1, 1, 1 ];
+ var compactBorderSizes = [ 1, 0 ];
+ var actualBorderSizes = [ 0, 2, 0, 0 ];
+
+ if ( this.options.compact && (this.options.blend || this._isTransparent()) ) {
+ return 1;
+ } else if ( this.options.compact ) {
+ return compactBorderSizes[n];
+ } else if ( this.options.blend ) {
+ return blendedBorderSizes[n];
+ } else if ( this.options.border ) {
+ return actualBorderSizes[n];
+ } else if ( this._isTransparent() ) {
+ return transparentBorderSizes[n];
+ }
+ return 0;
+ },
+
+ _hasString: function(str) { for(var i=1 ; i<arguments.length ; i++) if (str.indexOf(arguments[i]) >= 0) { return true; } return false; },
+ _blend: function(c1, c2) { var cc1 = OpenLayers.Rico.Color.createFromHex(c1); cc1.blend(OpenLayers.Rico.Color.createFromHex(c2)); return cc1; },
+ _background: function(el) { try { return OpenLayers.Rico.Color.createColorFromBackground(el).asHex(); } catch(err) { return "#ffffff"; } },
+ _isTransparent: function() { return this.options.color == "transparent"; },
+ _isTopRounded: function() { return this._hasString(this.options.corners, "all", "top", "tl", "tr"); },
+ _isBottomRounded: function() { return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); },
+ _hasSingleTextChild: function(el) { return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; }
+};
+/* ======================================================================
+ OpenLayers/Popup/AnchoredBubble.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Popup/Anchored.js
+ * @requires Rico/Corner.js
+ */
+
+/**
+ * Class: OpenLayers.Popup.AnchoredBubble
+ *
+ * Inherits from:
+ * - <OpenLayers.Popup.Anchored>
+ */
+OpenLayers.Popup.AnchoredBubble =
+ OpenLayers.Class(OpenLayers.Popup.Anchored, {
+
/**
- * Method: onMapResize
- *
+ * Property: rounded
+ * {Boolean} Has the popup been rounded yet?
*/
- onMapResize: function() {
- try {
- var size = this.getMapObjectSizeFromOLSize(this.map.getSize());
- this.mapObject.resizeTo(size);
- } catch(e) {}
- },
+ rounded: false,
-
/**
- * APIMethod: setMap
- * Overridden from EventPane because we need to remove this yahoo event
- * pane which prohibits our drag and drop, and we can only do this
- * once the map has been loaded and centered.
+ * Constructor: OpenLayers.Popup.AnchoredBubble
*
* Parameters:
- * map - {<OpenLayers.Map>}
+ * id - {String}
+ * lonlat - {<OpenLayers.LonLat>}
+ * contentSize - {<OpenLayers.Size>}
+ * contentHTML - {String}
+ * anchor - {Object} Object to which we'll anchor the popup. Must expose
+ * a 'size' (<OpenLayers.Size>) and 'offset' (<OpenLayers.Pixel>)
+ * (Note that this is generally an <OpenLayers.Icon>).
+ * closeBox - {Boolean}
+ * closeBoxCallback - {Function} Function to be called on closeBox click.
*/
- setMap: function(map) {
- OpenLayers.Layer.EventPane.prototype.setMap.apply(this, arguments);
-
- this.map.events.register("moveend", this, this.fixYahooEventPane);
+ initialize:function(id, lonlat, contentSize, contentHTML, anchor, closeBox,
+ closeBoxCallback) {
+
+ this.padding = new OpenLayers.Bounds(
+ 0, OpenLayers.Popup.AnchoredBubble.CORNER_SIZE,
+ 0, OpenLayers.Popup.AnchoredBubble.CORNER_SIZE
+ );
+ OpenLayers.Popup.Anchored.prototype.initialize.apply(this, arguments);
},
/**
- * Method: fixYahooEventPane
- * The map has been centered, so the mysterious yahoo eventpane has been
- * added. we remove it so that it doesnt mess with *our* event pane.
+ * Method: draw
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {DOMElement} Reference to a div that contains the drawn popup.
*/
- fixYahooEventPane: function() {
- var yahooEventPane = OpenLayers.Util.getElement("ygddfdiv");
- if (yahooEventPane != null) {
- if (yahooEventPane.parentNode != null) {
- yahooEventPane.parentNode.removeChild(yahooEventPane);
- }
- this.map.events.unregister("moveend", this,
- this.fixYahooEventPane);
- }
+ draw: function(px) {
+
+ OpenLayers.Popup.Anchored.prototype.draw.apply(this, arguments);
+
+ this.setContentHTML();
+
+ //set the popup color and opacity
+ this.setBackgroundColor();
+ this.setOpacity();
+
+ return this.div;
},
- /**
- * APIMethod: getWarningHTML
- *
- * Returns:
- * {String} String with information on why layer is broken, how to get
- * it working.
+ /**
+ * Method: updateRelativePosition
+ * The popup has been moved to a new relative location, in which case
+ * we will want to re-do the rico corners.
*/
- getWarningHTML:function() {
- return OpenLayers.i18n(
- "getLayerWarning", {'layerType':'Yahoo', 'layerLib':'Yahoo'}
- );
+ updateRelativePosition: function() {
+ this.setRicoCorners();
},
- /********************************************************/
- /* */
- /* Translation Functions */
- /* */
- /* The following functions translate GMaps and OL */
- /* formats for Pixel, LonLat, Bounds, and Zoom */
- /* */
- /********************************************************/
+ /**
+ * APIMethod: setSize
+ *
+ * Parameters:
+ * contentSize - {<OpenLayers.Size>} the new size for the popup's
+ * contents div (in pixels).
+ */
+ setSize:function(contentSize) {
+ OpenLayers.Popup.Anchored.prototype.setSize.apply(this, arguments);
+ this.setRicoCorners();
+ },
- //
- // TRANSLATION: MapObject Zoom <-> OpenLayers Zoom
- //
-
/**
- * APIMethod: getOLZoomFromMapObjectZoom
+ * APIMethod: setBackgroundColor
*
* Parameters:
- * gZoom - {Integer}
- *
- * Returns:
- * {Integer} An OpenLayers Zoom level, translated from the passed in gZoom
- * Returns null if null value is passed in.
+ * color - {String}
*/
- getOLZoomFromMapObjectZoom: function(moZoom) {
- var zoom = null;
- if (moZoom != null) {
- zoom = OpenLayers.Layer.FixedZoomLevels.prototype.getOLZoomFromMapObjectZoom.apply(this, [moZoom]);
- zoom = 18 - zoom;
+ setBackgroundColor:function(color) {
+ if (color != undefined) {
+ this.backgroundColor = color;
}
- return zoom;
- },
+
+ if (this.div != null) {
+ if (this.contentDiv != null) {
+ this.div.style.background = "transparent";
+ OpenLayers.Rico.Corner.changeColor(this.groupDiv,
+ this.backgroundColor);
+ }
+ }
+ },
/**
- * APIMethod: getMapObjectZoomFromOLZoom
+ * APIMethod: setOpacity
*
+ * Parameters:
+ * opacity - {float}
+ */
+ setOpacity:function(opacity) {
+ OpenLayers.Popup.Anchored.prototype.setOpacity.call(this, opacity);
+
+ if (this.div != null) {
+ if (this.groupDiv != null) {
+ OpenLayers.Rico.Corner.changeOpacity(this.groupDiv,
+ this.opacity);
+ }
+ }
+ },
+
+ /**
+ * Method: setBorder
+ * Always sets border to 0. Bubble Popups can not have a border.
+ *
* Parameters:
- * olZoom - {Integer}
- *
- * Returns:
- * {Integer} A MapObject level, translated from the passed in olZoom
- * Returns null if null value is passed in
+ * border - {Integer}
*/
- getMapObjectZoomFromOLZoom: function(olZoom) {
- var zoom = null;
- if (olZoom != null) {
- zoom = OpenLayers.Layer.FixedZoomLevels.prototype.getMapObjectZoomFromOLZoom.apply(this, [olZoom]);
- zoom = 18 - zoom;
+ setBorder:function(border) {
+ this.border = 0;
+ },
+
+ /**
+ * Method: setRicoCorners
+ * Update RICO corners according to the popup's current relative postion.
+ */
+ setRicoCorners:function() {
+
+ var corners = this.getCornersToRound(this.relativePosition);
+ var options = {corners: corners,
+ color: this.backgroundColor,
+ bgColor: "transparent",
+ blend: false};
+
+ if (!this.rounded) {
+ OpenLayers.Rico.Corner.round(this.div, options);
+ this.rounded = true;
+ } else {
+ OpenLayers.Rico.Corner.reRound(this.groupDiv, options);
+ //set the popup color and opacity
+ this.setBackgroundColor();
+ this.setOpacity();
}
- return zoom;
},
- /************************************
- * *
- * MapObject Interface Controls *
- * *
- ************************************/
+ /**
+ * Method: getCornersToRound
+ *
+ * Returns:
+ * {String} The proper corners string ("tr tl bl br") for rico to round.
+ */
+ getCornersToRound:function() {
+ var corners = ['tl', 'tr', 'bl', 'br'];
- // Get&Set Center, Zoom
+ //we want to round all the corners _except_ the opposite one.
+ var corner = OpenLayers.Bounds.oppositeQuadrant(this.relativePosition);
+ OpenLayers.Util.removeItem(corners, corner);
+ return corners.join(" ");
+ },
+
+ CLASS_NAME: "OpenLayers.Popup.AnchoredBubble"
+});
+
+/**
+ * Constant: CORNER_SIZE
+ * {Integer} 5. Border space for the RICO corners.
+ */
+OpenLayers.Popup.AnchoredBubble.CORNER_SIZE = 5;
+
+/* ======================================================================
+ OpenLayers/Feature.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/Util.js
+ * @requires OpenLayers/Marker.js
+ * @requires OpenLayers/Popup/AnchoredBubble.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({
+
/**
- * APIMethod: setMapObjectCenter
- * Set the mapObject to the specified center and zoom
- *
- * Parameters:
- * center - {Object} MapObject LonLat format
- * zoom - {int} MapObject zoom format
+ * Property: layer
+ * {<OpenLayers.Layer>}
*/
- setMapObjectCenter: function(center, zoom) {
- this.mapObject.drawZoomAndCenter(center, zoom);
- },
-
+ layer: null,
+
+ /**
+ * Property: id
+ * {String}
+ */
+ id: null,
+
+ /**
+ * Property: lonlat
+ * {<OpenLayers.LonLat>}
+ */
+ lonlat: null,
+
+ /**
+ * Property: data
+ * {Object}
+ */
+ data: null,
+
+ /**
+ * Property: marker
+ * {<OpenLayers.Marker>}
+ */
+ marker: null,
+
/**
- * APIMethod: getMapObjectCenter
+ * APIProperty: popupClass
+ * {<OpenLayers.Class>} The class which will be used to instantiate
+ * a new Popup. Default is <OpenLayers.Popup.AnchoredBubble>.
+ */
+ popupClass: OpenLayers.Popup.AnchoredBubble,
+
+ /**
+ * Property: popup
+ * {<OpenLayers.Popup>}
+ */
+ popup: null,
+
+ /**
+ * Constructor: OpenLayers.Feature
+ * Constructor for features.
+ *
+ * Parameters:
+ * layer - {<OpenLayers.Layer>}
+ * lonlat - {<OpenLayers.LonLat>}
+ * data - {Object}
*
- * Returns:
- * {Object} The mapObject's current center in Map Object format
+ * Returns:
+ * {<OpenLayers.Feature>}
*/
- getMapObjectCenter: function() {
- return this.mapObject.getCenterLatLon();
+ 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;
+ }
+ },
+
/**
- * APIMethod: dragPanMapObject
+ * Method: onScreen
*
- * Parameters:
- * dX - {Integer}
- * dY - {Integer}
+ * Returns:
+ * {Boolean} Whether or not the feature is currently visible on screen
+ * (based on its 'lonlat' property)
*/
- dragPanMapObject: function(dX, dY) {
- this.mapObject.moveByXY({
- 'x': -dX,
- 'y': dY
- });
+ 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;
},
- /**
- * APIMethod: getMapObjectZoom
+
+ /**
+ * Method: createMarker
+ * Based on the data associated with the Feature, create and return a marker object.
+ *
+ * Returns:
+ * {<OpenLayers.Marker>} A Marker Object created from the 'lonlat' and 'icon' properties
+ * set in this.data. If no 'lonlat' is set, returns null. If no
+ * 'icon' is set, OpenLayers.Marker() will load the default image.
+ *
+ * Note - this.marker is set to return value
*
- * Returns:
- * {Integer} The mapObject's current zoom, in Map Object format
*/
- getMapObjectZoom: function() {
- return this.mapObject.getZoomLevel();
+ 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();
+ },
- // LonLat - Pixel Translation
-
/**
- * APIMethod: getMapObjectLonLatFromMapObjectPixel
+ * 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
*
- * Parameters:
- * moPixel - {Object} MapObject Pixel format
+ * Note - this.popup is set to return value
*
+ * Parameters:
+ * closeBox - {Boolean} create popup with closebox or not
+ *
* Returns:
- * {Object} MapObject LonLat translated from MapObject Pixel
+ * {<OpenLayers.Popup>} Returns the created popup, which is also set
+ * as 'popup' property of this feature. Will be of whatever type
+ * specified by this feature's 'popupClass' property, but must be
+ * of type <OpenLayers.Popup>.
+ *
*/
- getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
- return this.mapObject.convertXYLatLon(moPixel);
+ createPopup: function(closeBox) {
+
+ if (this.lonlat != null) {
+
+ var id = this.id + "_popup";
+ var anchor = (this.marker) ? this.marker.icon : null;
+
+ if (!this.popup) {
+ this.popup = new this.popupClass(id,
+ 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;
},
+
/**
- * APIMethod: getMapObjectPixelFromMapObjectLonLat
- *
- * Parameters:
- * moLonLat - {Object} MapObject LonLat format
- *
- * Returns:
- * {Object} MapObject Pixel transtlated from MapObject LonLat
+ * 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
*/
- getMapObjectPixelFromMapObjectLonLat: function(moLonLat) {
- return this.mapObject.convertLatLonXY(moLonLat);
+ destroyPopup: function() {
+ if (this.popup) {
+ this.popup.feature = null;
+ this.popup.destroy();
+ this.popup = null;
+ }
},
+ CLASS_NAME: "OpenLayers.Feature"
+});
+/* ======================================================================
+ OpenLayers/Feature/Vector.js
+ ====================================================================== */
- /************************************
- * *
- * MapObject Primitives *
- * *
- ************************************/
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+// TRASH THIS
+OpenLayers.State = {
+ /** states */
+ UNKNOWN: 'Unknown',
+ INSERT: 'Insert',
+ UPDATE: 'Update',
+ DELETE: 'Delete'
+};
- // LonLat
+/**
+ * @requires OpenLayers/Feature.js
+ * @requires OpenLayers/Util.js
+ */
+
+/**
+ * Class: OpenLayers.Feature.Vector
+ * Vector features use the OpenLayers.Geometry classes as geometry description.
+ * They have an 'attributes' property, which is the data object, and a 'style'
+ * property, the default values of which are defined in the
+ * <OpenLayers.Feature.Vector.style> objects.
+ *
+ * Inherits from:
+ * - <OpenLayers.Feature>
+ */
+OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, {
+
+ /**
+ * Property: fid
+ * {String}
+ */
+ fid: null,
+ /**
+ * APIProperty: geometry
+ * {<OpenLayers.Geometry>}
+ */
+ geometry: null,
+
+ /**
+ * APIProperty: attributes
+ * {Object} This object holds arbitrary, serializable properties that
+ * describe the feature.
+ */
+ attributes: null,
+
/**
- * APIMethod: getLongitudeFromMapObjectLonLat
+ * Property: bounds
+ * {<OpenLayers.Bounds>} The box bounding that feature's geometry, that
+ * property can be set by an <OpenLayers.Format> object when
+ * deserializing the feature, so in most cases it represents an
+ * information set by the server.
+ */
+ bounds: null,
+
+ /**
+ * Property: state
+ * {String}
+ */
+ state: null,
+
+ /**
+ * APIProperty: style
+ * {Object}
+ */
+ style: null,
+
+ /**
+ * APIProperty: url
+ * {String} If this property is set it will be taken into account by
+ * {<OpenLayers.HTTP>} when upadting or deleting the feature.
+ */
+ url: null,
+
+ /**
+ * Property: renderIntent
+ * {String} rendering intent currently being used
+ */
+ renderIntent: "default",
+
+ /**
+ * Constructor: OpenLayers.Feature.Vector
+ * Create a vector feature.
*
* Parameters:
- * moLonLat - {Object} MapObject LonLat format
- *
+ * geometry - {<OpenLayers.Geometry>} The geometry that this feature
+ * represents.
+ * attributes - {Object} An optional object that will be mapped to the
+ * <attributes> property.
+ * style - {Object} An optional style object.
+ */
+ initialize: function(geometry, attributes, style) {
+ OpenLayers.Feature.prototype.initialize.apply(this,
+ [null, null, attributes]);
+ this.lonlat = null;
+ this.geometry = geometry ? geometry : null;
+ this.state = null;
+ this.attributes = {};
+ if (attributes) {
+ this.attributes = OpenLayers.Util.extend(this.attributes,
+ attributes);
+ }
+ this.style = style ? style : null;
+ },
+
+ /**
+ * Method: destroy
+ * nullify references to prevent circular references and memory leaks
+ */
+ destroy: function() {
+ if (this.layer) {
+ this.layer.removeFeatures(this);
+ this.layer = null;
+ }
+
+ this.geometry = null;
+ OpenLayers.Feature.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: clone
+ * Create a clone of this vector feature. Does not set any non-standard
+ * properties.
+ *
* Returns:
- * {Float} Longitude of the given MapObject LonLat
+ * {<OpenLayers.Feature.Vector>} An exact clone of this vector feature.
*/
- getLongitudeFromMapObjectLonLat: function(moLonLat) {
- return this.sphericalMercator ?
- this.forwardMercator(moLonLat.Lon, moLonLat.Lat).lon :
- moLonLat.Lon;
+ clone: function () {
+ return new OpenLayers.Feature.Vector(
+ this.geometry ? this.geometry.clone() : null,
+ this.attributes,
+ this.style);
},
/**
- * APIMethod: getLatitudeFromMapObjectLonLat
- *
+ * 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:
- * moLonLat - {Object} MapObject LonLat format
+ * 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:
- * {Float} Latitude of the given MapObject LonLat
+ * {Boolean} The feature is currently visible on screen (optionally
+ * based on its bounds if boundsOnly is true).
*/
- getLatitudeFromMapObjectLonLat: function(moLonLat) {
- return this.sphericalMercator ?
- this.forwardMercator(moLonLat.Lon, moLonLat.Lat).lat :
- moLonLat.Lat;
+ 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;
},
/**
- * APIMethod: getMapObjectLonLatFromLonLat
+ * Method: getVisibility
+ * Determine whether the feature is displayed or not. It may not displayed
+ * because:
+ * - its style display property is set to 'none',
+ * - it doesn't belong to any layer,
+ * - the styleMap creates a symbolizer with display property set to 'none'
+ * for it,
+ * - the layer which it belongs to is not visible.
*
- * Parameters:
- * lon - {Float}
- * lat - {Float}
- *
* Returns:
- * {Object} MapObject LonLat built from lon and lat params
+ * {Boolean} The feature is currently displayed.
*/
- getMapObjectLonLatFromLonLat: function(lon, lat) {
- var yLatLong;
- if(this.sphericalMercator) {
- var lonlat = this.inverseMercator(lon, lat);
- yLatLong = new YGeoPoint(lonlat.lat, lonlat.lon);
- } else {
- yLatLong = new YGeoPoint(lat, lon);
- }
- return yLatLong;
+ 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());
},
-
- // Pixel
/**
- * APIMethod: getXFromMapObjectPixel
+ * Method: createMarker
+ * HACK - we need to decide if all vector features should be able to
+ * create markers
*
- * Parameters:
- * moPixel - {Object} MapObject Pixel format
- *
* Returns:
- * {Integer} X value of the MapObject Pixel
+ * {<OpenLayers.Marker>} For now just returns null
*/
- getXFromMapObjectPixel: function(moPixel) {
- return moPixel.x;
+ createMarker: function() {
+ return null;
},
/**
- * APIMethod: getYFromMapObjectPixel
+ * Method: destroyMarker
+ * HACK - we need to decide if all vector features should be able to
+ * delete markers
*
- * Parameters:
- * moPixel - {Object} MapObject Pixel format
+ * 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:
- * {Integer} Y value of the MapObject Pixel
+ * {<OpenLayers.Popup>} For now just returns null
*/
- getYFromMapObjectPixel: function(moPixel) {
- return moPixel.y;
+ createPopup: function() {
+ return null;
},
/**
- * APIMethod: getMapObjectPixelFromXY
+ * Method: atPoint
+ * Determins whether the feature intersects with the specified location.
*
- * Parameters:
- * x - {Integer}
- * y - {Integer}
+ * Parameters:
+ * lonlat - {<OpenLayers.LonLat>}
+ * toleranceLon - {float} Optional tolerance in Geometric Coords
+ * toleranceLat - {float} Optional tolerance in Geographic Coords
*
* Returns:
- * {Object} MapObject Pixel from x and y parameters
+ * {Boolean} Whether or not the feature is at the specified location
*/
- getMapObjectPixelFromXY: function(x, y) {
- return new YCoordPoint(x, y);
+ 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:
+ * state - {OpenLayers.LonLat or OpenLayers.Pixel} the
+ * location to which to move the feature.
+ */
+ move: function(location) {
+
+ if(!this.layer || !this.geometry.move){
+ //do nothing if no layer or immoveable geometry
+ return undefined;
+ }
+
+ var pixel;
+ if (location.CLASS_NAME == "OpenLayers.LonLat") {
+ pixel = this.layer.getViewPortPxFromLonLat(location);
+ } else {
+ pixel = location;
+ }
+
+ var lastPixel = this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat());
+ var res = this.layer.map.getResolution();
+ this.geometry.move(res * (pixel.x - lastPixel.x),
+ res * (lastPixel.y - pixel.y));
+ this.layer.drawFeature(this);
+ return lastPixel;
+ },
- // Size
-
/**
- * APIMethod: getMapObjectSizeFromOLSize
- *
+ * Method: toState
+ * Sets the new state
+ *
* Parameters:
- * olSize - {<OpenLayers.Size>}
- *
- * Returns:
- * {Object} MapObject Size from olSize parameter
+ * state - {String}
*/
- getMapObjectSizeFromOLSize: function(olSize) {
- return new YSize(olSize.w, olSize.h);
+ 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.Layer.Yahoo"
+ 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 for an external graphic. Only supported in Firefox and Internet Explorer.
+ * 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". The canvas renderer does not
+ * support vertical alignment, it will always use "b".
+ * labelXOffset - {Number} Pixel offset along the positive x axis for displacing the label.
+ * labelYOffset - {Number} Pixel offset along the positive y axis for displacing the label.
+ * labelSelect - {Boolean} If set to true, labels will be selectable using SelectFeature or similar controls.
+ * Default is false.
+ * 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.
+ * 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"
+ },
+ '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"
+ },
+ '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"
+ },
+ 'delete': {
+ display: "none"
+ }
+};
/* ======================================================================
OpenLayers/Style.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
+ * @requires OpenLayers/BaseTypes/Class.js
* @requires OpenLayers/Util.js
* @requires OpenLayers/Feature/Vector.js
*/
@@ -30458,394 +17025,1500 @@
OpenLayers.Style.SYMBOLIZER_PREFIXES = ['Point', 'Line', 'Polygon', 'Text',
'Raster'];
/* ======================================================================
- OpenLayers/Control/Navigation.js
+ OpenLayers/Filter.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
+
/**
- * @requires OpenLayers/Control/ZoomBox.js
- * @requires OpenLayers/Control/DragPan.js
- * @requires OpenLayers/Handler/MouseWheel.js
- * @requires OpenLayers/Handler/Click.js
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/Util.js
+ * @requires OpenLayers/Style.js
*/
/**
- * Class: OpenLayers.Control.Navigation
- * The navigation control handles map browsing with mouse events (dragging,
- * double-clicking, and scrolling the wheel). Create a new navigation
- * control with the <OpenLayers.Control.Navigation> control.
+ * Class: OpenLayers.Filter
+ * This class represents an OGC Filter.
+ */
+OpenLayers.Filter = OpenLayers.Class({
+
+ /**
+ * Constructor: OpenLayers.Filter
+ * This class represents a generic filter.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ *
+ * Returns:
+ * {<OpenLayers.Filter>}
+ */
+ initialize: function(options) {
+ OpenLayers.Util.extend(this, options);
+ },
+
+ /**
+ * APIMethod: destroy
+ * Remove reference to anything added.
+ */
+ destroy: function() {
+ },
+
+ /**
+ * APIMethod: evaluate
+ * Evaluates this filter in a specific context. Instances or subclasses
+ * are supposed to override this method.
+ *
+ * Parameters:
+ * context - {Object} Context to use in evaluating the filter. If a vector
+ * feature is provided, the feature.attributes will be used as context.
+ *
+ * Returns:
+ * {Boolean} The filter applies.
+ */
+ evaluate: function(context) {
+ return true;
+ },
+
+ /**
+ * APIMethod: clone
+ * Clones this filter. Should be implementted by subclasses.
+ *
+ * Returns:
+ * {<OpenLayers.Filter>} Clone of this filter.
+ */
+ clone: function() {
+ return null;
+ },
+
+ CLASS_NAME: "OpenLayers.Filter"
+});
+/* ======================================================================
+ OpenLayers/Filter/FeatureId.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Filter.js
+ */
+
+/**
+ * Class: OpenLayers.Filter.FeatureId
+ * This class represents a ogc:FeatureId Filter, as being used for rule-based SLD
+ * styling
*
- * Note that this control is added to the map by default (if no controls
- * array is sent in the options object to the <OpenLayers.Map>
- * constructor).
- *
- * Inherits:
- * - <OpenLayers.Control>
+ * Inherits from
+ * - <OpenLayers.Filter>
*/
-OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, {
+OpenLayers.Filter.FeatureId = OpenLayers.Class(OpenLayers.Filter, {
/**
- * Property: dragPan
- * {<OpenLayers.Control.DragPan>}
+ * APIProperty: fids
+ * {Array(String)} Feature Ids to evaluate this rule against. To be passed
+ * To be passed inside the params object.
*/
- dragPan: null,
+ fids: null,
+
+ /**
+ * Constructor: OpenLayers.Filter.FeatureId
+ * Creates an ogc:FeatureId rule.
+ *
+ * Parameters:
+ * options - {Object} An optional object with properties to set on the
+ * rule
+ *
+ * Returns:
+ * {<OpenLayers.Filter.FeatureId>}
+ */
+ initialize: function(options) {
+ this.fids = [];
+ OpenLayers.Filter.prototype.initialize.apply(this, [options]);
+ },
/**
- * APIProprety: dragPanOptions
- * {Object} Options passed to the DragPan control.
+ * APIMethod: evaluate
+ * evaluates this rule for a specific feature
+ *
+ * Parameters:
+ * feature - {<OpenLayers.Feature>} feature to apply the rule to.
+ * For vector features, the check is run against the fid,
+ * for plain features against the id.
+ *
+ * Returns:
+ * {Boolean} true if the rule applies, false if it does not
*/
- dragPanOptions: null,
+ evaluate: function(feature) {
+ for (var i=0, len=this.fids.length; i<len; i++) {
+ var fid = feature.fid || feature.id;
+ if (fid == this.fids[i]) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /**
+ * APIMethod: clone
+ * Clones this filter.
+ *
+ * Returns:
+ * {<OpenLayers.Filter.FeatureId>} Clone of this filter.
+ */
+ clone: function() {
+ var filter = new OpenLayers.Filter.FeatureId();
+ OpenLayers.Util.extend(filter, this);
+ filter.fids = this.fids.slice();
+ return filter;
+ },
+
+ CLASS_NAME: "OpenLayers.Filter.FeatureId"
+});
+/* ======================================================================
+ OpenLayers/Filter/Logical.js
+ ====================================================================== */
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Filter.js
+ */
+
+/**
+ * Class: OpenLayers.Filter.Logical
+ * This class represents ogc:And, ogc:Or and ogc:Not rules.
+ *
+ * Inherits from
+ * - <OpenLayers.Filter>
+ */
+OpenLayers.Filter.Logical = OpenLayers.Class(OpenLayers.Filter, {
+
/**
- * APIProperty: documentDrag
- * {Boolean} Allow panning of the map by dragging outside map viewport.
- * Default is false.
+ * APIProperty: filters
+ * {Array(<OpenLayers.Filter>)} Child filters for this filter.
*/
- documentDrag: false,
+ filters: null,
+
+ /**
+ * APIProperty: type
+ * {String} type of logical operator. Available types are:
+ * - OpenLayers.Filter.Logical.AND = "&&";
+ * - OpenLayers.Filter.Logical.OR = "||";
+ * - OpenLayers.Filter.Logical.NOT = "!";
+ */
+ type: null,
/**
- * Property: zoomBox
- * {<OpenLayers.Control.ZoomBox>}
+ * Constructor: OpenLayers.Filter.Logical
+ * Creates a logical filter (And, Or, Not).
+ *
+ * Parameters:
+ * options - {Object} An optional object with properties to set on the
+ * filter.
+ *
+ * Returns:
+ * {<OpenLayers.Filter.Logical>}
*/
- zoomBox: null,
+ initialize: function(options) {
+ this.filters = [];
+ OpenLayers.Filter.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * APIMethod: destroy
+ * Remove reference to child filters.
+ */
+ destroy: function() {
+ this.filters = null;
+ OpenLayers.Filter.prototype.destroy.apply(this);
+ },
/**
- * APIProperty: zoomBoxEnabled
- * {Boolean} Whether the user can draw a box to zoom
+ * APIMethod: evaluate
+ * Evaluates this filter in a specific context.
+ *
+ * Parameters:
+ * context - {Object} Context to use in evaluating the filter. A vector
+ * feature may also be provided to evaluate feature attributes in
+ * comparison filters or geometries in spatial filters.
+ *
+ * Returns:
+ * {Boolean} The filter applies.
*/
- zoomBoxEnabled: true,
+ evaluate: function(context) {
+ var i, len;
+ switch(this.type) {
+ case OpenLayers.Filter.Logical.AND:
+ for (i=0, len=this.filters.length; i<len; i++) {
+ if (this.filters[i].evaluate(context) == false) {
+ return false;
+ }
+ }
+ return true;
+
+ case OpenLayers.Filter.Logical.OR:
+ for (i=0, len=this.filters.length; i<len; i++) {
+ if (this.filters[i].evaluate(context) == true) {
+ return true;
+ }
+ }
+ return false;
+
+ case OpenLayers.Filter.Logical.NOT:
+ return (!this.filters[0].evaluate(context));
+ }
+ return undefined;
+ },
+
+ /**
+ * APIMethod: clone
+ * Clones this filter.
+ *
+ * Returns:
+ * {<OpenLayers.Filter.Logical>} Clone of this filter.
+ */
+ clone: function() {
+ var filters = [];
+ for(var i=0, len=this.filters.length; i<len; ++i) {
+ filters.push(this.filters[i].clone());
+ }
+ return new OpenLayers.Filter.Logical({
+ type: this.type,
+ filters: filters
+ });
+ },
+
+ CLASS_NAME: "OpenLayers.Filter.Logical"
+});
+
+OpenLayers.Filter.Logical.AND = "&&";
+OpenLayers.Filter.Logical.OR = "||";
+OpenLayers.Filter.Logical.NOT = "!";
+/* ======================================================================
+ OpenLayers/Filter/Comparison.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Filter.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Filter.Comparison
+ * This class represents a comparison filter.
+ *
+ * Inherits from
+ * - <OpenLayers.Filter>
+ */
+OpenLayers.Filter.Comparison = OpenLayers.Class(OpenLayers.Filter, {
+
/**
- * APIProperty: zoomWheelEnabled
- * {Boolean} Whether the mousewheel should zoom the map
+ * APIProperty: type
+ * {String} type: type of the comparison. This is one of
+ * - OpenLayers.Filter.Comparison.EQUAL_TO = "==";
+ * - OpenLayers.Filter.Comparison.NOT_EQUAL_TO = "!=";
+ * - OpenLayers.Filter.Comparison.LESS_THAN = "<";
+ * - OpenLayers.Filter.Comparison.GREATER_THAN = ">";
+ * - OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO = "<=";
+ * - OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO = ">=";
+ * - OpenLayers.Filter.Comparison.BETWEEN = "..";
+ * - OpenLayers.Filter.Comparison.LIKE = "~";
*/
- zoomWheelEnabled: true,
+ type: null,
/**
- * Property: mouseWheelOptions
- * {Object} Options passed to the MouseWheel control (only useful if
- * <zoomWheelEnabled> is set to true)
+ * APIProperty: property
+ * {String}
+ * name of the context property to compare
*/
- mouseWheelOptions: null,
-
+ property: null,
+
/**
- * APIProperty: handleRightClicks
- * {Boolean} Whether or not to handle right clicks. Default is false.
+ * APIProperty: value
+ * {Number} or {String}
+ * comparison value for binary comparisons. In the case of a String, this
+ * can be a combination of text and propertyNames in the form
+ * "literal ${propertyName}"
*/
- handleRightClicks: false,
-
+ value: null,
+
/**
- * APIProperty: zoomBoxKeyMask
- * {Integer} <OpenLayers.Handler> key code of the key, which has to be
- * pressed, while drawing the zoom box with the mouse on the screen.
- * You should probably set handleRightClicks to true if you use this
- * with MOD_CTRL, to disable the context menu for machines which use
- * CTRL-Click as a right click.
- * Default: <OpenLayers.Handler.MOD_SHIFT
+ * Property: matchCase
+ * {Boolean} Force case sensitive searches for EQUAL_TO and NOT_EQUAL_TO
+ * comparisons. The Filter Encoding 1.1 specification added a matchCase
+ * attribute to ogc:PropertyIsEqualTo and ogc:PropertyIsNotEqualTo
+ * elements. This property will be serialized with those elements only
+ * if using the v1.1.0 filter format. However, when evaluating filters
+ * here, the matchCase property will always be respected (for EQUAL_TO
+ * and NOT_EQUAL_TO). Default is true.
*/
- zoomBoxKeyMask: OpenLayers.Handler.MOD_SHIFT,
+ matchCase: true,
/**
- * APIProperty: autoActivate
- * {Boolean} Activate the control when it is added to a map. Default is
- * true.
+ * APIProperty: lowerBoundary
+ * {Number} or {String}
+ * lower boundary for between comparisons. In the case of a String, this
+ * can be a combination of text and propertyNames in the form
+ * "literal ${propertyName}"
*/
- autoActivate: true,
+ lowerBoundary: null,
+
+ /**
+ * APIProperty: upperBoundary
+ * {Number} or {String}
+ * upper boundary for between comparisons. In the case of a String, this
+ * can be a combination of text and propertyNames in the form
+ * "literal ${propertyName}"
+ */
+ upperBoundary: null,
- /**
- * Constructor: OpenLayers.Control.Navigation
- * Create a new navigation control
+ /**
+ * Constructor: OpenLayers.Filter.Comparison
+ * Creates a comparison rule.
+ *
+ * Parameters:
+ * options - {Object} An optional object with properties to set on the
+ * rule
*
- * Parameters:
- * options - {Object} An optional object whose properties will be set on
- * the control
+ * Returns:
+ * {<OpenLayers.Filter.Comparison>}
*/
initialize: function(options) {
- this.handlers = {};
- OpenLayers.Control.prototype.initialize.apply(this, arguments);
+ OpenLayers.Filter.prototype.initialize.apply(this, [options]);
},
/**
- * Method: destroy
- * The destroy method is used to perform any clean up before the control
- * is dereferenced. Typically this is where event listeners are removed
- * to prevent memory leaks.
+ * APIMethod: evaluate
+ * Evaluates this filter in a specific context.
+ *
+ * Parameters:
+ * context - {Object} Context to use in evaluating the filter. If a vector
+ * feature is provided, the feature.attributes will be used as context.
+ *
+ * Returns:
+ * {Boolean} The filter applies.
*/
- destroy: function() {
- this.deactivate();
-
- if (this.dragPan) {
- this.dragPan.destroy();
+ evaluate: function(context) {
+ if (context instanceof OpenLayers.Feature.Vector) {
+ context = context.attributes;
}
- this.dragPan = null;
-
- if (this.zoomBox) {
- this.zoomBox.destroy();
+ var result = false;
+ var got = context[this.property];
+ var exp;
+ switch(this.type) {
+ case OpenLayers.Filter.Comparison.EQUAL_TO:
+ exp = this.value;
+ if(!this.matchCase &&
+ typeof got == "string" && typeof exp == "string") {
+ result = (got.toUpperCase() == exp.toUpperCase());
+ } else {
+ result = (got == exp);
+ }
+ break;
+ case OpenLayers.Filter.Comparison.NOT_EQUAL_TO:
+ exp = this.value;
+ if(!this.matchCase &&
+ typeof got == "string" && typeof exp == "string") {
+ result = (got.toUpperCase() != exp.toUpperCase());
+ } else {
+ result = (got != exp);
+ }
+ break;
+ case OpenLayers.Filter.Comparison.LESS_THAN:
+ result = got < this.value;
+ break;
+ case OpenLayers.Filter.Comparison.GREATER_THAN:
+ result = got > this.value;
+ break;
+ case OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO:
+ result = got <= this.value;
+ break;
+ case OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO:
+ result = got >= this.value;
+ break;
+ case OpenLayers.Filter.Comparison.BETWEEN:
+ result = (got >= this.lowerBoundary) &&
+ (got <= this.upperBoundary);
+ break;
+ case OpenLayers.Filter.Comparison.LIKE:
+ var regexp = new RegExp(this.value, "gi");
+ result = regexp.test(got);
+ break;
}
- this.zoomBox = null;
- OpenLayers.Control.prototype.destroy.apply(this,arguments);
+ return result;
},
/**
- * Method: activate
+ * APIMethod: value2regex
+ * Converts the value of this rule into a regular expression string,
+ * according to the wildcard characters specified. This method has to
+ * be called after instantiation of this class, if the value is not a
+ * regular expression already.
+ *
+ * Parameters:
+ * wildCard - {<Char>} wildcard character in the above value, default
+ * is "*"
+ * singleChar - {<Char>) single-character wildcard in the above value
+ * default is "."
+ * escape - {<Char>) escape character in the above value, default is
+ * "!"
+ *
+ * Returns:
+ * {String} regular expression string
*/
- activate: function() {
- this.dragPan.activate();
- if (this.zoomWheelEnabled) {
- this.handlers.wheel.activate();
- }
- this.handlers.click.activate();
- if (this.zoomBoxEnabled) {
- this.zoomBox.activate();
+ value2regex: function(wildCard, singleChar, escapeChar) {
+ if (wildCard == ".") {
+ var msg = "'.' is an unsupported wildCard character for "+
+ "OpenLayers.Filter.Comparison";
+ OpenLayers.Console.error(msg);
+ return null;
}
- return OpenLayers.Control.prototype.activate.apply(this,arguments);
+
+
+ // set UMN MapServer defaults for unspecified parameters
+ wildCard = wildCard ? wildCard : "*";
+ singleChar = singleChar ? singleChar : ".";
+ escapeChar = escapeChar ? escapeChar : "!";
+
+ this.value = this.value.replace(
+ new RegExp("\\"+escapeChar+"(.|$)", "g"), "\\$1");
+ this.value = this.value.replace(
+ new RegExp("\\"+singleChar, "g"), ".");
+ this.value = this.value.replace(
+ new RegExp("\\"+wildCard, "g"), ".*");
+ this.value = this.value.replace(
+ new RegExp("\\\\.\\*", "g"), "\\"+wildCard);
+ this.value = this.value.replace(
+ new RegExp("\\\\\\.", "g"), "\\"+singleChar);
+
+ return this.value;
},
-
+
/**
- * Method: deactivate
+ * Method: regex2value
+ * Convert the value of this rule from a regular expression string into an
+ * ogc literal string using a wildCard of *, a singleChar of ., and an
+ * escape of !. Leaves the <value> property unmodified.
+ *
+ * Returns:
+ * {String} A string value.
*/
- deactivate: function() {
- this.zoomBox.deactivate();
- this.dragPan.deactivate();
- this.handlers.click.deactivate();
- this.handlers.wheel.deactivate();
- return OpenLayers.Control.prototype.deactivate.apply(this,arguments);
+ regex2value: function() {
+
+ var value = this.value;
+
+ // replace ! with !!
+ value = value.replace(/!/g, "!!");
+
+ // replace \. with !. (watching out for \\.)
+ value = value.replace(/(\\)?\\\./g, function($0, $1) {
+ return $1 ? $0 : "!.";
+ });
+
+ // replace \* with #* (watching out for \\*)
+ value = value.replace(/(\\)?\\\*/g, function($0, $1) {
+ return $1 ? $0 : "!*";
+ });
+
+ // replace \\ with \
+ value = value.replace(/\\\\/g, "\\");
+
+ // convert .* to * (the sequence #.* is not allowed)
+ value = value.replace(/\.\*/g, "*");
+
+ return value;
},
/**
- * Method: draw
+ * APIMethod: clone
+ * Clones this filter.
+ *
+ * Returns:
+ * {<OpenLayers.Filter.Comparison>} Clone of this filter.
*/
- draw: function() {
- // disable right mouse context menu for support of right click events
- if (this.handleRightClicks) {
- this.map.viewPortDiv.oncontextmenu = OpenLayers.Function.False;
- }
-
- var clickCallbacks = {
- 'dblclick': this.defaultDblClick,
- 'dblrightclick': this.defaultDblRightClick
- };
- var clickOptions = {
- 'double': true,
- 'stopDouble': true
- };
- this.handlers.click = new OpenLayers.Handler.Click(
- this, clickCallbacks, clickOptions
- );
- this.dragPan = new OpenLayers.Control.DragPan(
- OpenLayers.Util.extend({
- map: this.map,
- documentDrag: this.documentDrag
- }, this.dragPanOptions)
- );
- this.zoomBox = new OpenLayers.Control.ZoomBox(
- {map: this.map, keyMask: this.zoomBoxKeyMask});
- this.dragPan.draw();
- this.zoomBox.draw();
- this.handlers.wheel = new OpenLayers.Handler.MouseWheel(
- this, {"up" : this.wheelUp,
- "down": this.wheelDown},
- this.mouseWheelOptions );
+ clone: function() {
+ return OpenLayers.Util.extend(new OpenLayers.Filter.Comparison(), this);
},
+
+ CLASS_NAME: "OpenLayers.Filter.Comparison"
+});
+
+OpenLayers.Filter.Comparison.EQUAL_TO = "==";
+OpenLayers.Filter.Comparison.NOT_EQUAL_TO = "!=";
+OpenLayers.Filter.Comparison.LESS_THAN = "<";
+OpenLayers.Filter.Comparison.GREATER_THAN = ">";
+OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO = "<=";
+OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO = ">=";
+OpenLayers.Filter.Comparison.BETWEEN = "..";
+OpenLayers.Filter.Comparison.LIKE = "~";
+/* ======================================================================
+ OpenLayers/Format/Filter.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/XML.js
+ * @requires OpenLayers/Filter/FeatureId.js
+ * @requires OpenLayers/Filter/Logical.js
+ * @requires OpenLayers/Filter/Comparison.js
+ */
+
+/**
+ * Class: OpenLayers.Format.Filter
+ * Read/Wite ogc:Filter. Create a new instance with the <OpenLayers.Format.Filter>
+ * constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.Filter = OpenLayers.Class(OpenLayers.Format.XML, {
+
/**
- * Method: defaultDblClick
- *
+ * APIProperty: defaultVersion
+ * {String} Version number to assume if none found. Default is "1.0.0".
+ */
+ defaultVersion: "1.0.0",
+
+ /**
+ * APIProperty: version
+ * {String} Specify a version string if one is known.
+ */
+ version: null,
+
+ /**
+ * Property: parser
+ * {Object} Instance of the versioned parser. Cached for multiple read and
+ * write calls of the same version.
+ */
+ parser: null,
+
+ /**
+ * Constructor: OpenLayers.Format.Filter
+ * Create a new parser for Filter.
+ *
* Parameters:
- * evt - {Event}
+ * options - {Object} An optional object whose properties will be set on
+ * this instance.
*/
- defaultDblClick: function (evt) {
- var newCenter = this.map.getLonLatFromViewPortPx( evt.xy );
- this.map.setCenter(newCenter, this.map.zoom + 1);
+ initialize: function(options) {
+ OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
},
/**
- * Method: defaultDblRightClick
- *
+ * APIMethod: write
+ * Write an ogc:Filter given a filter object.
+ *
* Parameters:
- * evt - {Event}
+ * filter - {<OpenLayers.Filter>} An filter.
+ * options - {Object} Optional configuration object.
+ *
+ * Returns:
+ * {Elment} An ogc:Filter element node.
*/
- defaultDblRightClick: function (evt) {
- var newCenter = this.map.getLonLatFromViewPortPx( evt.xy );
- this.map.setCenter(newCenter, this.map.zoom - 1);
+ write: function(filter, options) {
+ var version = (options && options.version) ||
+ this.version || this.defaultVersion;
+ if(!this.parser || this.parser.VERSION != version) {
+ var format = OpenLayers.Format.Filter[
+ "v" + version.replace(/\./g, "_")
+ ];
+ if(!format) {
+ throw "Can't find a Filter parser for version " +
+ version;
+ }
+ this.parser = new format(this.options);
+ }
+ return this.parser.write(filter);
+ //return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
},
/**
- * Method: wheelChange
+ * APIMethod: read
+ * Read and Filter doc and return an object representing the Filter.
*
* Parameters:
- * evt - {Event}
- * deltaZ - {Integer}
+ * data - {String | DOMElement} Data to read.
+ *
+ * Returns:
+ * {<OpenLayers.Filter>} A filter object.
*/
- wheelChange: function(evt, deltaZ) {
- var currentZoom = this.map.getZoom();
- var newZoom = this.map.getZoom() + Math.round(deltaZ);
- newZoom = Math.max(newZoom, 0);
- newZoom = Math.min(newZoom, this.map.getNumZoomLevels());
- if (newZoom === currentZoom) {
- return;
+ read: function(data) {
+ if(typeof data == "string") {
+ data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
}
- var size = this.map.getSize();
- var deltaX = size.w/2 - evt.xy.x;
- var deltaY = evt.xy.y - size.h/2;
- var newRes = this.map.baseLayer.getResolutionForZoom(newZoom);
- var zoomPoint = this.map.getLonLatFromPixel(evt.xy);
- var newCenter = new OpenLayers.LonLat(
- zoomPoint.lon + deltaX * newRes,
- zoomPoint.lat + deltaY * newRes );
- this.map.setCenter( newCenter, newZoom );
+ var version = this.version;
+ if(!version) {
+ version = this.defaultVersion;
+ }
+ if(!this.parser || this.parser.VERSION != version) {
+ var format = OpenLayers.Format.Filter[
+ "v" + version.replace(/\./g, "_")
+ ];
+ if(!format) {
+ throw "Can't find a Filter parser for version " +
+ version;
+ }
+ this.parser = new format(this.options);
+ }
+ var filter = this.parser.read(data);
+ return filter;
},
- /**
- * Method: wheelUp
- * User spun scroll wheel up
- *
- * Parameters:
- * evt - {Event}
- * delta - {Integer}
+ CLASS_NAME: "OpenLayers.Format.Filter"
+});
+/* ======================================================================
+ OpenLayers/Format/Filter/v1.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+/**
+ * @requires OpenLayers/Format/Filter.js
+ * @requires OpenLayers/Format/XML.js
+ */
+
+/**
+ * Class: OpenLayers.Format.Filter.v1
+ * Superclass for Filter version 1 parsers.
+ *
+ * Inherits from:
+ * - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.Filter.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
+
+ /**
+ * Property: namespaces
+ * {Object} Mapping of namespace aliases to namespace URIs.
*/
- wheelUp: function(evt, delta) {
- this.wheelChange(evt, delta || 1);
+ namespaces: {
+ ogc: "http://www.opengis.net/ogc",
+ gml: "http://www.opengis.net/gml",
+ xlink: "http://www.w3.org/1999/xlink",
+ xsi: "http://www.w3.org/2001/XMLSchema-instance"
},
+
+ /**
+ * Property: defaultPrefix
+ */
+ defaultPrefix: "ogc",
- /**
- * Method: wheelDown
- * User spun scroll wheel down
- *
+ /**
+ * Property: schemaLocation
+ * {String} Schema location for a particular minor version.
+ */
+ schemaLocation: null,
+
+ /**
+ * Constructor: OpenLayers.Format.Filter.v1
+ * Instances of this class are not created directly. Use the
+ * <OpenLayers.Format.Filter> constructor instead.
+ *
* Parameters:
- * evt - {Event}
- * delta - {Integer}
+ * options - {Object} An optional object whose properties will be set on
+ * this instance.
*/
- wheelDown: function(evt, delta) {
- this.wheelChange(evt, delta || -1);
+ initialize: function(options) {
+ OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
},
/**
- * Method: disableZoomBox
+ * Method: read
+ *
+ * Parameters:
+ * data - {DOMElement} A Filter document element.
+ *
+ * Returns:
+ * {<OpenLayers.Filter>} A filter object.
*/
- disableZoomBox : function() {
- this.zoomBoxEnabled = false;
- this.zoomBox.deactivate();
+ read: function(data) {
+ var obj = {};
+ this.readers.ogc["Filter"].apply(this, [data, obj]);
+ return obj.filter;
},
/**
- * Method: enableZoomBox
+ * Property: readers
+ * Contains public functions, grouped by namespace prefix, that will
+ * be applied when a namespaced node is found matching the function
+ * name. The function will be applied in the scope of this parser
+ * with two arguments: the node being read and a context object passed
+ * from the parent.
*/
- enableZoomBox : function() {
- this.zoomBoxEnabled = true;
- if (this.active) {
- this.zoomBox.activate();
- }
+ readers: {
+ "ogc": {
+ "Filter": function(node, parent) {
+ // Filters correspond to subclasses of OpenLayers.Filter.
+ // Since they contain information we don't persist, we
+ // create a temporary object and then pass on the filter
+ // (ogc:Filter) to the parent obj.
+ var obj = {
+ fids: [],
+ filters: []
+ };
+ this.readChildNodes(node, obj);
+ if(obj.fids.length > 0) {
+ parent.filter = new OpenLayers.Filter.FeatureId({
+ fids: obj.fids
+ });
+ } else if(obj.filters.length > 0) {
+ parent.filter = obj.filters[0];
+ }
+ },
+ "FeatureId": function(node, obj) {
+ var fid = node.getAttribute("fid");
+ if(fid) {
+ obj.fids.push(fid);
+ }
+ },
+ "And": function(node, obj) {
+ var filter = new OpenLayers.Filter.Logical({
+ type: OpenLayers.Filter.Logical.AND
+ });
+ this.readChildNodes(node, filter);
+ obj.filters.push(filter);
+ },
+ "Or": function(node, obj) {
+ var filter = new OpenLayers.Filter.Logical({
+ type: OpenLayers.Filter.Logical.OR
+ });
+ this.readChildNodes(node, filter);
+ obj.filters.push(filter);
+ },
+ "Not": function(node, obj) {
+ var filter = new OpenLayers.Filter.Logical({
+ type: OpenLayers.Filter.Logical.NOT
+ });
+ this.readChildNodes(node, filter);
+ obj.filters.push(filter);
+ },
+ "PropertyIsLessThan": function(node, obj) {
+ var filter = new OpenLayers.Filter.Comparison({
+ type: OpenLayers.Filter.Comparison.LESS_THAN
+ });
+ this.readChildNodes(node, filter);
+ obj.filters.push(filter);
+ },
+ "PropertyIsGreaterThan": function(node, obj) {
+ var filter = new OpenLayers.Filter.Comparison({
+ type: OpenLayers.Filter.Comparison.GREATER_THAN
+ });
+ this.readChildNodes(node, filter);
+ obj.filters.push(filter);
+ },
+ "PropertyIsLessThanOrEqualTo": function(node, obj) {
+ var filter = new OpenLayers.Filter.Comparison({
+ type: OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO
+ });
+ this.readChildNodes(node, filter);
+ obj.filters.push(filter);
+ },
+ "PropertyIsGreaterThanOrEqualTo": function(node, obj) {
+ var filter = new OpenLayers.Filter.Comparison({
+ type: OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO
+ });
+ this.readChildNodes(node, filter);
+ obj.filters.push(filter);
+ },
+ "PropertyIsBetween": function(node, obj) {
+ var filter = new OpenLayers.Filter.Comparison({
+ type: OpenLayers.Filter.Comparison.BETWEEN
+ });
+ this.readChildNodes(node, filter);
+ obj.filters.push(filter);
+ },
+ "Literal": function(node, obj) {
+ obj.value = OpenLayers.String.numericIf(
+ this.getChildValue(node));
+ },
+ "PropertyName": function(node, filter) {
+ filter.property = this.getChildValue(node);
+ },
+ "LowerBoundary": function(node, filter) {
+ filter.lowerBoundary = OpenLayers.String.numericIf(
+ this.readOgcExpression(node));
+ },
+ "UpperBoundary": function(node, filter) {
+ filter.upperBoundary = OpenLayers.String.numericIf(
+ this.readOgcExpression(node));
+ },
+ "Intersects": function(node, obj) {
+ this.readSpatial(node, obj, OpenLayers.Filter.Spatial.INTERSECTS);
+ },
+ "Within": function(node, obj) {
+ this.readSpatial(node, obj, OpenLayers.Filter.Spatial.WITHIN);
+ },
+ "Contains": function(node, obj) {
+ this.readSpatial(node, obj, OpenLayers.Filter.Spatial.CONTAINS);
+ },
+ "DWithin": function(node, obj) {
+ this.readSpatial(node, obj, OpenLayers.Filter.Spatial.DWITHIN);
+ },
+ "Distance": function(node, obj) {
+ obj.distance = parseInt(this.getChildValue(node));
+ obj.distanceUnits = node.getAttribute("units");
+ }
+ }
},
/**
- * Method: disableZoomWheel
+ * Method: readSpatial
+ *
+ * Read a {<OpenLayers.Filter.Spatial>} filter.
+ *
+ * Parameters:
+ * node - {DOMElement} A DOM element that contains an ogc:expression.
+ * obj - {Object} The target object.
+ * type - {String} One of the OpenLayers.Filter.Spatial.* constants.
+ *
+ * Returns:
+ * {<OpenLayers.Filter.Spatial>} The created filter.
*/
+ readSpatial: function(node, obj, type) {
+ var filter = new OpenLayers.Filter.Spatial({
+ type: type
+ });
+ this.readChildNodes(node, filter);
+ filter.value = filter.components[0];
+ delete filter.components;
+ obj.filters.push(filter);
+ },
+
+ /**
+ * Method: readOgcExpression
+ * Limited support for OGC expressions.
+ *
+ * Parameters:
+ * node - {DOMElement} A DOM element that contains an ogc:expression.
+ *
+ * Returns:
+ * {String} A value to be used in a symbolizer.
+ */
+ readOgcExpression: function(node) {
+ var obj = {};
+ this.readChildNodes(node, obj);
+ var value = obj.value;
+ if(value === undefined) {
+ value = this.getChildValue(node);
+ }
+ return value;
+ },
+
+ /**
+ * Method: write
+ *
+ * Parameters:
+ * filter - {<OpenLayers.Filter>} A filter object.
+ *
+ * Returns:
+ * {DOMElement} An ogc:Filter element.
+ */
+ write: function(filter) {
+ return this.writers.ogc["Filter"].apply(this, [filter]);
+ },
- disableZoomWheel : function() {
- this.zoomWheelEnabled = false;
- this.handlers.wheel.deactivate();
+ /**
+ * Property: writers
+ * As a compliment to the readers property, this structure contains public
+ * writing functions grouped by namespace alias and named like the
+ * node names they produce.
+ */
+ writers: {
+ "ogc": {
+ "Filter": function(filter) {
+ var node = this.createElementNSPlus("ogc:Filter");
+ var sub = filter.CLASS_NAME.split(".").pop();
+ if(sub == "FeatureId") {
+ for(var i=0; i<filter.fids.length; ++i) {
+ this.writeNode("FeatureId", filter.fids[i], node);
+ }
+ } else {
+ this.writeNode(this.getFilterType(filter), filter, node);
+ }
+ return node;
+ },
+ "FeatureId": function(fid) {
+ return this.createElementNSPlus("ogc:FeatureId", {
+ attributes: {fid: fid}
+ });
+ },
+ "And": function(filter) {
+ var node = this.createElementNSPlus("ogc:And");
+ var childFilter;
+ for(var i=0; i<filter.filters.length; ++i) {
+ childFilter = filter.filters[i];
+ this.writeNode(
+ this.getFilterType(childFilter), childFilter, node
+ );
+ }
+ return node;
+ },
+ "Or": function(filter) {
+ var node = this.createElementNSPlus("ogc:Or");
+ var childFilter;
+ for(var i=0; i<filter.filters.length; ++i) {
+ childFilter = filter.filters[i];
+ this.writeNode(
+ this.getFilterType(childFilter), childFilter, node
+ );
+ }
+ return node;
+ },
+ "Not": function(filter) {
+ var node = this.createElementNSPlus("ogc:Not");
+ var childFilter = filter.filters[0];
+ this.writeNode(
+ this.getFilterType(childFilter), childFilter, node
+ );
+ return node;
+ },
+ "PropertyIsLessThan": function(filter) {
+ var node = this.createElementNSPlus("ogc:PropertyIsLessThan");
+ // no ogc:expression handling for now
+ this.writeNode("PropertyName", filter, node);
+ this.writeNode("Literal", filter.value, node);
+ return node;
+ },
+ "PropertyIsGreaterThan": function(filter) {
+ var node = this.createElementNSPlus("ogc:PropertyIsGreaterThan");
+ // no ogc:expression handling for now
+ this.writeNode("PropertyName", filter, node);
+ this.writeNode("Literal", filter.value, node);
+ return node;
+ },
+ "PropertyIsLessThanOrEqualTo": function(filter) {
+ var node = this.createElementNSPlus("ogc:PropertyIsLessThanOrEqualTo");
+ // no ogc:expression handling for now
+ this.writeNode("PropertyName", filter, node);
+ this.writeNode("Literal", filter.value, node);
+ return node;
+ },
+ "PropertyIsGreaterThanOrEqualTo": function(filter) {
+ var node = this.createElementNSPlus("ogc:PropertyIsGreaterThanOrEqualTo");
+ // no ogc:expression handling for now
+ this.writeNode("PropertyName", filter, node);
+ this.writeNode("Literal", filter.value, node);
+ return node;
+ },
+ "PropertyIsBetween": function(filter) {
+ var node = this.createElementNSPlus("ogc:PropertyIsBetween");
+ // no ogc:expression handling for now
+ this.writeNode("PropertyName", filter, node);
+ this.writeNode("LowerBoundary", filter, node);
+ this.writeNode("UpperBoundary", filter, node);
+ return node;
+ },
+ "PropertyName": function(filter) {
+ // no ogc:expression handling for now
+ return this.createElementNSPlus("ogc:PropertyName", {
+ value: filter.property
+ });
+ },
+ "Literal": function(value) {
+ // no ogc:expression handling for now
+ return this.createElementNSPlus("ogc:Literal", {
+ value: value
+ });
+ },
+ "LowerBoundary": function(filter) {
+ // no ogc:expression handling for now
+ var node = this.createElementNSPlus("ogc:LowerBoundary");
+ this.writeNode("Literal", filter.lowerBoundary, node);
+ return node;
+ },
+ "UpperBoundary": function(filter) {
+ // no ogc:expression handling for now
+ var node = this.createElementNSPlus("ogc:UpperBoundary");
+ this.writeNode("Literal", filter.upperBoundary, node);
+ return node;
+ },
+ "INTERSECTS": function(filter) {
+ return this.writeSpatial(filter, "Intersects");
+ },
+ "WITHIN": function(filter) {
+ return this.writeSpatial(filter, "Within");
+ },
+ "CONTAINS": function(filter) {
+ return this.writeSpatial(filter, "Contains");
+ },
+ "DWITHIN": function(filter) {
+ var node = this.writeSpatial(filter, "DWithin");
+ this.writeNode("Distance", filter, node);
+ return node;
+ },
+ "Distance": function(filter) {
+ return this.createElementNSPlus("ogc:Distance", {
+ attributes: {
+ units: filter.distanceUnits
+ },
+ value: filter.distance
+ });
+ }
+ }
},
+
+ /**
+ * Method: getFilterType
+ */
+ getFilterType: function(filter) {
+ var filterType = this.filterMap[filter.type];
+ if(!filterType) {
+ throw "Filter writing not supported for rule type: " + filter.type;
+ }
+ return filterType;
+ },
/**
- * Method: enableZoomWheel
+ * Property: filterMap
+ * {Object} Contains a member for each filter type. Values are node names
+ * for corresponding OGC Filter child elements.
*/
-
- enableZoomWheel : function() {
- this.zoomWheelEnabled = true;
- if (this.active) {
- this.handlers.wheel.activate();
- }
+ filterMap: {
+ "&&": "And",
+ "||": "Or",
+ "!": "Not",
+ "==": "PropertyIsEqualTo",
+ "!=": "PropertyIsNotEqualTo",
+ "<": "PropertyIsLessThan",
+ ">": "PropertyIsGreaterThan",
+ "<=": "PropertyIsLessThanOrEqualTo",
+ ">=": "PropertyIsGreaterThanOrEqualTo",
+ "..": "PropertyIsBetween",
+ "~": "PropertyIsLike",
+ "BBOX": "BBOX",
+ "DWITHIN": "DWITHIN",
+ "WITHIN": "WITHIN",
+ "CONTAINS": "CONTAINS",
+ "INTERSECTS": "INTERSECTS"
},
- CLASS_NAME: "OpenLayers.Control.Navigation"
+ CLASS_NAME: "OpenLayers.Format.Filter.v1"
+
});
/* ======================================================================
- OpenLayers/Filter.js
+ OpenLayers/Format/WKT.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
-
/**
- * @requires OpenLayers/Util.js
- * @requires OpenLayers/Style.js
+ * @requires OpenLayers/Format.js
+ * @requires OpenLayers/Feature/Vector.js
*/
/**
- * Class: OpenLayers.Filter
- * This class represents an OGC Filter.
+ * Class: OpenLayers.Format.WKT
+ * Class for reading and writing Well-Known Text. Create a new instance
+ * with the <OpenLayers.Format.WKT> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Format>
*/
-OpenLayers.Filter = OpenLayers.Class({
+OpenLayers.Format.WKT = OpenLayers.Class(OpenLayers.Format, {
- /**
- * Constructor: OpenLayers.Filter
- * This is an abstract class. Create an instance of a filter subclass.
+ /**
+ * Constructor: OpenLayers.Format.WKT
+ * Create a new parser for WKT
*
* Parameters:
- * options - {Object} Optional object whose properties will be set on the
- * instance.
- *
+ * options - {Object} An optional object whose properties will be set on
+ * this instance
+ *
* Returns:
- * {<OpenLayers.Filter>}
+ * {<OpenLayers.Format.WKT>} A new WKT parser.
*/
initialize: function(options) {
- OpenLayers.Util.extend(this, options);
+ this.regExes = {
+ 'typeStr': /^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/,
+ 'spaces': /\s+/,
+ 'parenComma': /\)\s*,\s*\(/,
+ 'doubleParenComma': /\)\s*\)\s*,\s*\(\s*\(/, // can't use {2} here
+ 'trimParens': /^\s*\(?(.*?)\)?\s*$/
+ };
+ OpenLayers.Format.prototype.initialize.apply(this, [options]);
},
- /**
- * APIMethod: destroy
- * Remove reference to anything added.
+ /**
+ * Method: read
+ * Deserialize a WKT string and return a vector feature or an
+ * array of vector features. Supports WKT for POINT, MULTIPOINT,
+ * LINESTRING, MULTILINESTRING, POLYGON, MULTIPOLYGON, and
+ * GEOMETRYCOLLECTION.
+ *
+ * Parameters:
+ * wkt - {String} A WKT string
+ *
+ * Returns:
+ * {<OpenLayers.Feature.Vector>|Array} A feature or array of features for
+ * GEOMETRYCOLLECTION WKT.
*/
- destroy: function() {
+ read: function(wkt) {
+ var features, type, str;
+ var matches = this.regExes.typeStr.exec(wkt);
+ if(matches) {
+ type = matches[1].toLowerCase();
+ str = matches[2];
+ if(this.parse[type]) {
+ features = this.parse[type].apply(this, [str]);
+ }
+ if (this.internalProjection && this.externalProjection) {
+ if (features &&
+ features.CLASS_NAME == "OpenLayers.Feature.Vector") {
+ features.geometry.transform(this.externalProjection,
+ this.internalProjection);
+ } else if (features &&
+ type != "geometrycollection" &&
+ typeof features == "object") {
+ for (var i=0, len=features.length; i<len; i++) {
+ var component = features[i];
+ component.geometry.transform(this.externalProjection,
+ this.internalProjection);
+ }
+ }
+ }
+ }
+ return features;
},
/**
- * APIMethod: evaluate
- * Evaluates this filter in a specific context. Should be implemented by
- * subclasses.
- *
+ * Method: write
+ * Serialize a feature or array of features into a WKT string.
+ *
* Parameters:
- * context - {Object} Context to use in evaluating the filter. If a vector
- * feature is provided, the feature.attributes will be used as context.
- *
+ * features - {<OpenLayers.Feature.Vector>|Array} A feature or array of
+ * features
+ *
* Returns:
- * {Boolean} The filter applies.
+ * {String} The WKT string representation of the input geometries
*/
- evaluate: function(context) {
- return true;
+ write: function(features) {
+ var collection, geometry, type, data, isCollection;
+ if (features.constructor == Array) {
+ collection = features;
+ isCollection = true;
+ } else {
+ collection = [features];
+ isCollection = false;
+ }
+ var pieces = [];
+ if (isCollection) {
+ pieces.push('GEOMETRYCOLLECTION(');
+ }
+ for (var i=0, len=collection.length; i<len; ++i) {
+ if (isCollection && i>0) {
+ pieces.push(',');
+ }
+ geometry = collection[i].geometry;
+ pieces.push(this.extractGeometry(geometry));
+ }
+ if (isCollection) {
+ pieces.push(')');
+ }
+ return pieces.join('');
},
-
+
/**
- * APIMethod: clone
- * Clones this filter. Should be implementted by subclasses.
- *
+ * Method: extractGeometry
+ * Entry point to construct the WKT for a single Geometry object.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry.Geometry>}
+ *
* Returns:
- * {<OpenLayers.Filter>} Clone of this filter.
+ * {String} A WKT string of representing the geometry
*/
- clone: function() {
- return null;
+ extractGeometry: function(geometry) {
+ var type = geometry.CLASS_NAME.split('.')[2].toLowerCase();
+ if (!this.extract[type]) {
+ return null;
+ }
+ if (this.internalProjection && this.externalProjection) {
+ geometry = geometry.clone();
+ geometry.transform(this.internalProjection, this.externalProjection);
+ }
+ var wktType = type == 'collection' ? 'GEOMETRYCOLLECTION' : type.toUpperCase();
+ var data = wktType + '(' + this.extract[type].apply(this, [geometry]) + ')';
+ return data;
},
- CLASS_NAME: "OpenLayers.Filter"
-});
+ /**
+ * Object with properties corresponding to the geometry types.
+ * Property values are functions that do the actual data extraction.
+ */
+ extract: {
+ /**
+ * Return a space delimited string of point coordinates.
+ * @param {<OpenLayers.Geometry.Point>} point
+ * @returns {String} A string of coordinates representing the point
+ */
+ 'point': function(point) {
+ return point.x + ' ' + point.y;
+ },
+
+ /**
+ * Return a comma delimited string of point coordinates from a multipoint.
+ * @param {<OpenLayers.Geometry.MultiPoint>} multipoint
+ * @returns {String} A string of point coordinate strings representing
+ * the multipoint
+ */
+ 'multipoint': function(multipoint) {
+ var array = [];
+ for(var i=0, len=multipoint.components.length; i<len; ++i) {
+ array.push('(' +
+ this.extract.point.apply(this, [multipoint.components[i]]) +
+ ')');
+ }
+ return array.join(',');
+ },
+
+ /**
+ * Return a comma delimited string of point coordinates from a line.
+ * @param {<OpenLayers.Geometry.LineString>} linestring
+ * @returns {String} A string of point coordinate strings representing
+ * the linestring
+ */
+ 'linestring': function(linestring) {
+ var array = [];
+ for(var i=0, len=linestring.components.length; i<len; ++i) {
+ array.push(this.extract.point.apply(this, [linestring.components[i]]));
+ }
+ return array.join(',');
+ },
+
+ /**
+ * Return a comma delimited string of linestring strings from a multilinestring.
+ * @param {<OpenLayers.Geometry.MultiLineString>} multilinestring
+ * @returns {String} A string of of linestring strings representing
+ * the multilinestring
+ */
+ 'multilinestring': function(multilinestring) {
+ var array = [];
+ for(var i=0, len=multilinestring.components.length; i<len; ++i) {
+ array.push('(' +
+ this.extract.linestring.apply(this, [multilinestring.components[i]]) +
+ ')');
+ }
+ return array.join(',');
+ },
+
+ /**
+ * Return a comma delimited string of linear ring arrays from a polygon.
+ * @param {<OpenLayers.Geometry.Polygon>} polygon
+ * @returns {String} An array of linear ring arrays representing the polygon
+ */
+ 'polygon': function(polygon) {
+ var array = [];
+ for(var i=0, len=polygon.components.length; i<len; ++i) {
+ array.push('(' +
+ this.extract.linestring.apply(this, [polygon.components[i]]) +
+ ')');
+ }
+ return array.join(',');
+ },
+
+ /**
+ * Return an array of polygon arrays from a multipolygon.
+ * @param {<OpenLayers.Geometry.MultiPolygon>} multipolygon
+ * @returns {String} An array of polygon arrays representing
+ * the multipolygon
+ */
+ 'multipolygon': function(multipolygon) {
+ var array = [];
+ for(var i=0, len=multipolygon.components.length; i<len; ++i) {
+ array.push('(' +
+ this.extract.polygon.apply(this, [multipolygon.components[i]]) +
+ ')');
+ }
+ return array.join(',');
+ },
+
+ /**
+ * Return the WKT portion between 'GEOMETRYCOLLECTION(' and ')' for an <OpenLayers.Geometry.Collection>
+ * @param {<OpenLayers.Geometry.Collection>} collection
+ * @returns {String} internal WKT representation of the collection
+ */
+ 'collection': function(collection) {
+ var array = [];
+ for(var i=0, len=collection.components.length; i<len; ++i) {
+ array.push(this.extractGeometry.apply(this, [collection.components[i]]));
+ }
+ return array.join(',');
+ }
+
+ },
+
+ /**
+ * Object with properties corresponding to the geometry types.
+ * Property values are functions that do the actual parsing.
+ */
+ parse: {
+ /**
+ * Return point feature given a point WKT fragment.
+ * @param {String} str A WKT fragment representing the point
+ * @returns {<OpenLayers.Feature.Vector>} A point feature
+ * @private
+ */
+ 'point': function(str) {
+ var coords = OpenLayers.String.trim(str).split(this.regExes.spaces);
+ return new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.Point(coords[0], coords[1])
+ );
+ },
+
+ /**
+ * Return a multipoint feature given a multipoint WKT fragment.
+ * @param {String} A WKT fragment representing the multipoint
+ * @returns {<OpenLayers.Feature.Vector>} A multipoint feature
+ * @private
+ */
+ 'multipoint': function(str) {
+ var point;
+ var points = OpenLayers.String.trim(str).split(this.regExes.parenComma);
+ var components = [];
+ for(var i=0, len=points.length; i<len; ++i) {
+ point = points[i].replace(this.regExes.trimParens, '$1');
+ components.push(this.parse.point.apply(this, [point]).geometry);
+ }
+ return new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.MultiPoint(components)
+ );
+ },
+
+ /**
+ * Return a linestring feature given a linestring WKT fragment.
+ * @param {String} A WKT fragment representing the linestring
+ * @returns {<OpenLayers.Feature.Vector>} A linestring feature
+ * @private
+ */
+ 'linestring': function(str) {
+ var points = OpenLayers.String.trim(str).split(',');
+ var components = [];
+ for(var i=0, len=points.length; i<len; ++i) {
+ components.push(this.parse.point.apply(this, [points[i]]).geometry);
+ }
+ return new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.LineString(components)
+ );
+ },
+
+ /**
+ * Return a multilinestring feature given a multilinestring WKT fragment.
+ * @param {String} A WKT fragment representing the multilinestring
+ * @returns {<OpenLayers.Feature.Vector>} A multilinestring feature
+ * @private
+ */
+ 'multilinestring': function(str) {
+ var line;
+ var lines = OpenLayers.String.trim(str).split(this.regExes.parenComma);
+ var components = [];
+ for(var i=0, len=lines.length; i<len; ++i) {
+ line = lines[i].replace(this.regExes.trimParens, '$1');
+ components.push(this.parse.linestring.apply(this, [line]).geometry);
+ }
+ return new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.MultiLineString(components)
+ );
+ },
+
+ /**
+ * Return a polygon feature given a polygon WKT fragment.
+ * @param {String} A WKT fragment representing the polygon
+ * @returns {<OpenLayers.Feature.Vector>} A polygon feature
+ * @private
+ */
+ 'polygon': function(str) {
+ var ring, linestring, linearring;
+ var rings = OpenLayers.String.trim(str).split(this.regExes.parenComma);
+ var components = [];
+ for(var i=0, len=rings.length; i<len; ++i) {
+ ring = rings[i].replace(this.regExes.trimParens, '$1');
+ linestring = this.parse.linestring.apply(this, [ring]).geometry;
+ linearring = new OpenLayers.Geometry.LinearRing(linestring.components);
+ components.push(linearring);
+ }
+ return new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.Polygon(components)
+ );
+ },
+
+ /**
+ * Return a multipolygon feature given a multipolygon WKT fragment.
+ * @param {String} A WKT fragment representing the multipolygon
+ * @returns {<OpenLayers.Feature.Vector>} A multipolygon feature
+ * @private
+ */
+ 'multipolygon': function(str) {
+ var polygon;
+ var polygons = OpenLayers.String.trim(str).split(this.regExes.doubleParenComma);
+ var components = [];
+ for(var i=0, len=polygons.length; i<len; ++i) {
+ polygon = polygons[i].replace(this.regExes.trimParens, '$1');
+ components.push(this.parse.polygon.apply(this, [polygon]).geometry);
+ }
+ return new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.MultiPolygon(components)
+ );
+ },
+
+ /**
+ * Return an array of features given a geometrycollection WKT fragment.
+ * @param {String} A WKT fragment representing the geometrycollection
+ * @returns {Array} An array of OpenLayers.Feature.Vector
+ * @private
+ */
+ 'geometrycollection': function(str) {
+ // separate components of the collection with |
+ str = str.replace(/,\s*([A-Za-z])/g, '|$1');
+ var wktArray = OpenLayers.String.trim(str).split('|');
+ var components = [];
+ for(var i=0, len=wktArray.length; i<len; ++i) {
+ components.push(OpenLayers.Format.WKT.prototype.read.apply(this,[wktArray[i]]));
+ }
+ return components;
+ }
+
+ },
+
+ CLASS_NAME: "OpenLayers.Format.WKT"
+});
/* ======================================================================
OpenLayers/Geometry.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
+ * @requires OpenLayers/BaseTypes/Class.js
* @requires OpenLayers/Format/WKT.js
* @requires OpenLayers/Feature/Vector.js
*/
@@ -31297,2526 +18970,297 @@
};
};
/* ======================================================================
- OpenLayers/Layer/Google/v3.js
+ OpenLayers/Geometry/Point.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
-
/**
- * @requires OpenLayers/Layer/Google.js
+ * @requires OpenLayers/Geometry.js
*/
/**
- * Constant: OpenLayers.Layer.Google.v3
+ * Class: OpenLayers.Geometry.Point
+ * Point geometry class.
*
- * Mixin providing functionality specific to the Google Maps API v3. Note that
- * this layer configures the google.maps.map object with the "disableDefaultUI"
- * option set to true. Using UI controls that the Google Maps API provides is
- * not supported by the OpenLayers API.
+ * Inherits from:
+ * - <OpenLayers.Geometry>
*/
-OpenLayers.Layer.Google.v3 = {
-
- /**
- * Constant: DEFAULTS
- * {Object} It is not recommended to change the properties set here. Note
- * that Google.v3 layers only work when sphericalMercator is set to true.
- *
- * (code)
- * {
- * maxExtent: new OpenLayers.Bounds(
- * -128 * 156543.0339,
- * -128 * 156543.0339,
- * 128 * 156543.0339,
- * 128 * 156543.0339
- * ),
- * sphericalMercator: true,
- * maxResolution: 156543.0339,
- * units: "m",
- * projection: "EPSG:900913"
- * }
- * (end)
+OpenLayers.Geometry.Point = OpenLayers.Class(OpenLayers.Geometry, {
+
+ /**
+ * APIProperty: x
+ * {float}
*/
- DEFAULTS: {
- maxExtent: new OpenLayers.Bounds(
- -128 * 156543.0339,
- -128 * 156543.0339,
- 128 * 156543.0339,
- 128 * 156543.0339
- ),
- sphericalMercator: true,
- maxResolution: 156543.0339,
- units: "m",
- projection: "EPSG:900913"
- },
+ x: null,
/**
- * Method: loadMapObject
- * Load the GMap and register appropriate event listeners. If we can't
- * load GMap2, then display a warning message.
+ * APIProperty: y
+ * {float}
*/
- loadMapObject:function() {
- if (!this.type) {
- this.type = google.maps.MapTypeId.ROADMAP;
- }
- var mapObject;
- var cache = OpenLayers.Layer.Google.cache[this.map.id];
- if (cache) {
- // there are already Google layers added to this map
- mapObject = cache.mapObject;
- // increment the layer count
- ++cache.count;
- } else {
- // this is the first Google layer for this map
+ y: null,
- var container = this.map.viewPortDiv;
- var div = document.createElement("div");
- div.id = this.map.id + "_GMapContainer";
- div.style.position = "absolute";
- div.style.width = "100%";
- div.style.height = "100%";
- container.appendChild(div);
-
- // create GMap and shuffle elements
- var center = this.map.getCenter();
- mapObject = new google.maps.Map(div, {
- center: center ?
- new google.maps.LatLng(center.lat, center.lon) :
- new google.maps.LatLng(0, 0),
- zoom: this.map.getZoom() || 0,
- mapTypeId: this.type,
- disableDefaultUI: true,
- keyboardShortcuts: false,
- draggable: false,
- disableDoubleClickZoom: true,
- scrollwheel: false
- });
-
- // cache elements for use by any other google layers added to
- // this same map
- cache = {
- mapObject: mapObject,
- count: 1
- };
- OpenLayers.Layer.Google.cache[this.map.id] = cache;
- this.repositionListener = google.maps.event.addListenerOnce(
- mapObject,
- "center_changed",
- OpenLayers.Function.bind(this.repositionMapElements, this)
- );
- }
- this.mapObject = mapObject;
- this.setGMapVisibility(this.visibility);
- },
-
/**
- * Method: repositionMapElements
+ * Constructor: OpenLayers.Geometry.Point
+ * Construct a point geometry.
*
- * Waits until powered by and terms of use elements are available and then
- * moves them so they are clickable.
- */
- repositionMapElements: function() {
-
- // This is the first time any Google layer in this mapObject has been
- // made visible. The mapObject needs to know the container size.
- google.maps.event.trigger(this.mapObject, "resize");
-
- var div = this.mapObject.getDiv().firstChild;
- if (!div || div.childNodes.length < 3) {
- this.repositionTimer = window.setTimeout(
- OpenLayers.Function.bind(this.repositionMapElements, this),
- 250
- );
- return false;
- }
-
- var cache = OpenLayers.Layer.Google.cache[this.map.id];
- var container = this.map.viewPortDiv;
-
- // move the ToS and branding stuff up to the container div
- var termsOfUse = div.lastChild;
- container.appendChild(termsOfUse);
- termsOfUse.style.zIndex = "1100";
- termsOfUse.style.bottom = "";
- termsOfUse.className = "olLayerGoogleCopyright olLayerGoogleV3";
- termsOfUse.style.display = "";
- cache.termsOfUse = termsOfUse;
-
- var poweredBy = div.lastChild;
- container.appendChild(poweredBy);
- poweredBy.style.zIndex = "1100";
- poweredBy.style.bottom = "";
- poweredBy.className = "olLayerGooglePoweredBy olLayerGoogleV3 gmnoprint";
- poweredBy.style.display = "";
- cache.poweredBy = poweredBy;
-
- this.setGMapVisibility(this.visibility);
-
- },
-
- /**
- * APIMethod: onMapResize
- */
- onMapResize: function() {
- if (this.visibility) {
- google.maps.event.trigger(this.mapObject, "resize");
- } else {
- if (!this._resized) {
- var layer = this;
- google.maps.event.addListenerOnce(this.mapObject, "tilesloaded", function() {
- delete layer._resized;
- google.maps.event.trigger(layer.mapObject, "resize");
- layer.moveTo(layer.map.getCenter(), layer.map.getZoom());
- });
- }
- this._resized = true;
- }
- },
-
- /**
- * Method: setGMapVisibility
- * Display the GMap container and associated elements.
- *
* Parameters:
- * visible - {Boolean} Display the GMap elements.
- */
- setGMapVisibility: function(visible) {
- var cache = OpenLayers.Layer.Google.cache[this.map.id];
- if (cache) {
- var type = this.type;
- var layers = this.map.layers;
- var layer;
- for (var i=layers.length-1; i>=0; --i) {
- layer = layers[i];
- if (layer instanceof OpenLayers.Layer.Google &&
- layer.visibility === true && layer.inRange === true) {
- type = layer.type;
- visible = true;
- break;
- }
- }
- var container = this.mapObject.getDiv();
- if (visible === true) {
- this.mapObject.setMapTypeId(type);
- container.style.left = "";
- if (cache.termsOfUse && cache.termsOfUse.style) {
- cache.termsOfUse.style.left = "";
- cache.termsOfUse.style.display = "";
- cache.poweredBy.style.display = "";
- }
- cache.displayed = this.id;
- } else {
- delete cache.displayed;
- container.style.left = "-9999px";
- if (cache.termsOfUse && cache.termsOfUse.style) {
- cache.termsOfUse.style.display = "none";
- // move ToU far to the left in addition to setting
- // display to "none", because at the end of the GMap
- // load sequence, display: none will be unset and ToU
- // would be visible after loading a map with a google
- // layer that is initially hidden.
- cache.termsOfUse.style.left = "-9999px";
- cache.poweredBy.style.display = "none";
- }
- }
- }
- },
-
- /**
- * Method: getMapContainer
+ * x - {float}
+ * y - {float}
*
- * Returns:
- * {DOMElement} the GMap container's div
*/
- getMapContainer: function() {
- return this.mapObject.getDiv();
+ initialize: function(x, y) {
+ OpenLayers.Geometry.prototype.initialize.apply(this, arguments);
+
+ this.x = parseFloat(x);
+ this.y = parseFloat(y);
},
-
- //
- // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds
- //
/**
- * APIMethod: getMapObjectBoundsFromOLBounds
+ * APIMethod: clone
*
- * Parameters:
- * olBounds - {<OpenLayers.Bounds>}
- *
* Returns:
- * {Object} A MapObject Bounds, translated from olBounds
- * Returns null if null value is passed in
+ * {<OpenLayers.Geometry.Point>} An exact clone of this OpenLayers.Geometry.Point
*/
- getMapObjectBoundsFromOLBounds: function(olBounds) {
- var moBounds = null;
- if (olBounds != null) {
- var sw = this.sphericalMercator ?
- this.inverseMercator(olBounds.bottom, olBounds.left) :
- new OpenLayers.LonLat(olBounds.bottom, olBounds.left);
- var ne = this.sphericalMercator ?
- this.inverseMercator(olBounds.top, olBounds.right) :
- new OpenLayers.LonLat(olBounds.top, olBounds.right);
- moBounds = new google.maps.LatLngBounds(
- new google.maps.LatLng(sw.lat, sw.lon),
- new google.maps.LatLng(ne.lat, ne.lon)
- );
+ clone: function(obj) {
+ if (obj == null) {
+ obj = new OpenLayers.Geometry.Point(this.x, this.y);
}
- return moBounds;
- },
+ // catch any randomly tagged-on properties
+ OpenLayers.Util.applyDefaults(obj, this);
- /************************************
- * *
- * MapObject Interface Controls *
- * *
- ************************************/
-
-
- // LonLat - Pixel Translation
-
- /**
- * APIMethod: getMapObjectLonLatFromMapObjectPixel
- *
- * Parameters:
- * moPixel - {Object} MapObject Pixel format
- *
- * Returns:
- * {Object} MapObject LonLat translated from MapObject Pixel
- */
- getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
- var size = this.map.getSize();
- var lon = this.getLongitudeFromMapObjectLonLat(this.mapObject.center);
- var lat = this.getLatitudeFromMapObjectLonLat(this.mapObject.center);
- var res = this.map.getResolution();
-
- var delta_x = moPixel.x - (size.w / 2);
- var delta_y = moPixel.y - (size.h / 2);
-
- var lonlat = new OpenLayers.LonLat(
- lon + delta_x * res,
- lat - delta_y * res
- );
-
- if (this.wrapDateLine) {
- lonlat = lonlat.wrapDateLine(this.maxExtent);
- }
- return this.getMapObjectLonLatFromLonLat(lonlat.lon, lonlat.lat);
+ return obj;
},
- /**
- * APIMethod: getMapObjectPixelFromMapObjectLonLat
- *
- * Parameters:
- * moLonLat - {Object} MapObject LonLat format
- *
- * Returns:
- * {Object} MapObject Pixel transtlated from MapObject LonLat
- */
- getMapObjectPixelFromMapObjectLonLat: function(moLonLat) {
- var lon = this.getLongitudeFromMapObjectLonLat(moLonLat);
- var lat = this.getLatitudeFromMapObjectLonLat(moLonLat);
- var res = this.map.getResolution();
- var extent = this.map.getExtent();
- var px = new OpenLayers.Pixel(
- (1/res * (lon - extent.left)),
- (1/res * (extent.top - lat))
- );
- return this.getMapObjectPixelFromXY(px.x, px.y);
- },
-
-
/**
- * APIMethod: setMapObjectCenter
- * Set the mapObject to the specified center and zoom
- *
- * Parameters:
- * center - {Object} MapObject LonLat format
- * zoom - {int} MapObject zoom format
+ * Method: calculateBounds
+ * Create a new Bounds based on the lon/lat
*/
- setMapObjectCenter: function(center, zoom) {
- this.mapObject.setOptions({
- center: center,
- zoom: zoom
- });
+ calculateBounds: function () {
+ this.bounds = new OpenLayers.Bounds(this.x, this.y,
+ this.x, this.y);
},
-
-
- // Bounds
-
- /**
- * APIMethod: getMapObjectZoomFromMapObjectBounds
- *
- * Parameters:
- * moBounds - {Object} MapObject Bounds format
- *
- * Returns:
- * {Object} MapObject Zoom for specified MapObject Bounds
- */
- getMapObjectZoomFromMapObjectBounds: function(moBounds) {
- return this.mapObject.getBoundsZoomLevel(moBounds);
- },
- /************************************
- * *
- * MapObject Primitives *
- * *
- ************************************/
-
-
- // LonLat
-
/**
- * APIMethod: getMapObjectLonLatFromLonLat
- *
- * Parameters:
- * lon - {Float}
- * lat - {Float}
- *
- * Returns:
- * {Object} MapObject LonLat built from lon and lat params
- */
- getMapObjectLonLatFromLonLat: function(lon, lat) {
- var gLatLng;
- if(this.sphericalMercator) {
- var lonlat = this.inverseMercator(lon, lat);
- gLatLng = new google.maps.LatLng(lonlat.lat, lonlat.lon);
- } else {
- gLatLng = new google.maps.LatLng(lat, lon);
- }
- return gLatLng;
- },
-
- // Pixel
-
- /**
- * APIMethod: getMapObjectPixelFromXY
- *
- * Parameters:
- * x - {Integer}
- * y - {Integer}
- *
- * Returns:
- * {Object} MapObject Pixel from x and y parameters
- */
- getMapObjectPixelFromXY: function(x, y) {
- return new google.maps.Point(x, y);
- },
-
- /**
- * APIMethod: destroy
- * Clean up this layer.
- */
- destroy: function() {
- if (this.repositionListener) {
- google.maps.event.removeListener(this.repositionListener);
- }
- if (this.repositionTimer) {
- window.clearTimeout(this.repositionTimer);
- }
- OpenLayers.Layer.Google.prototype.destroy.apply(this, arguments);
- }
-
-};
-/* ======================================================================
- OpenLayers/Layer/MapGuide.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Request/XMLHttpRequest.js
- * @requires OpenLayers/Layer/Grid.js
- */
-
-/**
- * Class: OpenLayers.Layer.MapGuide
- * Instances of OpenLayers.Layer.MapGuide are used to display
- * data from a MapGuide OS instance.
- *
- * Inherits from:
- * - <OpenLayers.Layer.Grid>
- */
-OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, {
-
- /**
- * APIProperty: isBaseLayer
- * {Boolean} Treat this layer as a base layer. Default is true.
- **/
- isBaseLayer: true,
-
- /**
- * APIProperty: useHttpTile
- * {Boolean} use a tile cache exposed directly via a webserver rather than the
- * via mapguide server. This does require extra configuration on the Mapguide Server,
- * and will only work when singleTile is false. The url for the layer must be set to the
- * webserver path rather than the Mapguide mapagent.
- * See http://trac.osgeo.org/mapguide/wiki/CodeSamples/Tiles/ServingTilesViaHttp
- **/
- useHttpTile: false,
-
- /**
- * APIProperty: singleTile
- * {Boolean} use tile server or request single tile image.
- **/
- singleTile: false,
-
- /**
- * APIProperty: useOverlay
- * {Boolean} flag to indicate if the layer should be retrieved using
- * GETMAPIMAGE (default) or using GETDYNAMICOVERLAY requests.
- **/
- useOverlay: false,
-
- /**
- * APIProperty: useAsyncOverlay
- * {Boolean} indicates if the MapGuide site supports the asynchronous
- * GETDYNAMICOVERLAY requests which is available in MapGuide Enterprise 2010
- * and MapGuide Open Source v2.0.3 or higher. The newer versions of MG
- * is called asynchronously, allows selections to be drawn separately from
- * the map and offers styling options.
- *
- * With older versions of MapGuide, set useAsyncOverlay=false. Note that in
- * this case a synchronous AJAX call is issued and the mapname and session
- * parameters must be used to initialize the layer, not the mapdefinition
- * parameter. Also note that this will issue a synchronous AJAX request
- * before the image request can be issued so the users browser may lock
- * up if the MG Web tier does not respond in a timely fashion.
- **/
- useAsyncOverlay: true,
-
- /**
- * Constant: TILE_PARAMS
- * {Object} Hashtable of default parameter key/value pairs for tiled layer
- */
- TILE_PARAMS: {
- operation: 'GETTILEIMAGE',
- version: '1.2.0'
- },
-
- /**
- * Constant: SINGLE_TILE_PARAMS
- * {Object} Hashtable of default parameter key/value pairs for untiled layer
- */
- SINGLE_TILE_PARAMS: {
- operation: 'GETMAPIMAGE',
- format: 'PNG',
- locale: 'en',
- clip: '1',
- version: '1.0.0'
- },
-
- /**
- * Constant: OVERLAY_PARAMS
- * {Object} Hashtable of default parameter key/value pairs for untiled layer
- */
- OVERLAY_PARAMS: {
- operation: 'GETDYNAMICMAPOVERLAYIMAGE',
- format: 'PNG',
- locale: 'en',
- clip: '1',
- version: '2.0.0'
- },
-
- /**
- * Constant: FOLDER_PARAMS
- * {Object} Hashtable of parameter key/value pairs which describe
- * the folder structure for tiles as configured in the mapguide
- * serverconfig.ini section [TileServiceProperties]
- */
- FOLDER_PARAMS: {
- tileColumnsPerFolder: 30,
- tileRowsPerFolder: 30,
- format: 'png',
- querystring: null
- },
-
- /**
- * Property: defaultSize
- * {<OpenLayers.Size>} Tile size as produced by MapGuide server
- **/
- defaultSize: new OpenLayers.Size(300,300),
-
- /**
- * Constructor: OpenLayers.Layer.MapGuide
- * Create a new Mapguide layer, either tiled or untiled.
+ * APIMethod: distanceTo
+ * Calculate the closest distance between two geometries (on the x-y plane).
*
- * For tiled layers, the 'groupName' and 'mapDefinition' values
- * must be specified as parameters in the constructor.
- *
- * For untiled base layers, specify either combination of 'mapName' and
- * 'session', or 'mapDefinition' and 'locale'.
- *
- * For older versions of MapGuide and overlay layers, set useAsyncOverlay
- * to false and in this case mapName and session are required parameters
- * for the constructor.
- *
- * NOTE: MapGuide OS uses a DPI value and degrees to meters conversion
- * factor that are different than the defaults used in OpenLayers,
- * so these must be adjusted accordingly in your application.
- * See the MapGuide example for how to set these values for MGOS.
- *
* Parameters:
- * name - {String} Name of the layer displayed in the interface
- * url - {String} Location of the MapGuide mapagent executable
- * (e.g. http://localhost:8008/mapguide/mapagent/mapagent.fcgi)
- * params - {Object} hashtable of additional parameters to use. Some
- * parameters may require additional code on the server. The ones that
- * you may want to use are:
- * - mapDefinition - {String} The MapGuide resource definition
- * (e.g. Library://Samples/Gmap/Maps/gmapTiled.MapDefinition)
- * - locale - Locale setting
- * (for untiled overlays layers only)
- * - mapName - {String} Name of the map as stored in the MapGuide session.
- * (for untiled layers with a session parameter only)
- * - session - { String} MapGuide session ID
- * (for untiled overlays layers only)
- * - basemaplayergroupname - {String} GroupName for tiled MapGuide layers only
- * - format - Image format to be returned (for untiled overlay layers only)
- * - showLayers - {String} A comma separated list of GUID's for the
- * layers to display eg: 'cvc-xcv34,453-345-345sdf'.
- * - hideLayers - {String} A comma separated list of GUID's for the
- * layers to hide eg: 'cvc-xcv34,453-345-345sdf'.
- * - showGroups - {String} A comma separated list of GUID's for the
- * groups to display eg: 'cvc-xcv34,453-345-345sdf'.
- * - hideGroups - {String} A comma separated list of GUID's for the
- * groups to hide eg: 'cvc-xcv34,453-345-345sdf'
- * - selectionXml - {String} A selection xml string Some server plumbing
- * is required to read such a value.
- * options - {Ojbect} Hashtable of extra options to tag onto the layer;
- * will vary depending if tiled or untiled maps are being requested
- */
- initialize: function(name, url, params, options) {
-
- OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments);
-
- // unless explicitly set in options, if the layer is transparent,
- // it will be an overlay
- if (options == null || options.isBaseLayer == null) {
- this.isBaseLayer = ((this.transparent != "true") &&
- (this.transparent != true));
- }
-
- if (options && options.useOverlay!=null) {
- this.useOverlay = options.useOverlay;
- }
-
- //initialize for untiled layers
- if (this.singleTile) {
- if (this.useOverlay) {
- OpenLayers.Util.applyDefaults(
- this.params,
- this.OVERLAY_PARAMS
- );
- if (!this.useAsyncOverlay) {
- this.params.version = "1.0.0";
- }
- } else {
- OpenLayers.Util.applyDefaults(
- this.params,
- this.SINGLE_TILE_PARAMS
- );
- }
- } else {
- //initialize for tiled layers
- if (this.useHttpTile) {
- OpenLayers.Util.applyDefaults(
- this.params,
- this.FOLDER_PARAMS
- );
- } else {
- OpenLayers.Util.applyDefaults(
- this.params,
- this.TILE_PARAMS
- );
- }
- this.setTileSize(this.defaultSize);
- }
- },
-
- /**
- * Method: clone
- * Create a clone of this layer
+ * geometry - {<OpenLayers.Geometry>} The target geometry.
+ * options - {Object} Optional properties for configuring the distance
+ * calculation.
*
- * Returns:
- * {<OpenLayers.Layer.MapGuide>} An exact clone of this layer
- */
- clone: function (obj) {
- if (obj == null) {
- obj = new OpenLayers.Layer.MapGuide(this.name,
- this.url,
- this.params,
- this.getOptions());
- }
- //get all additions from superclasses
- obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
-
- return obj;
- },
-
- /**
- * Method: addTile
- * Creates a tile, initializes it, and adds it to the layer div.
+ * 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.
*
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * position - {<OpenLayers.Pixel>}
- *
* Returns:
- * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+ * {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.
*/
- addTile:function(bounds,position) {
- return new OpenLayers.Tile.Image(this, position, bounds,
- null, this.tileSize);
- },
-
- /**
- * Method: getURL
- * Return a query string for this layer
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox
- * for the request
- *
- * Returns:
- * {String} A string with the layer's url and parameters and also
- * the passed-in bounds and appropriate tile size specified
- * as parameters.
- */
- getURL: function (bounds) {
- var url;
- var center = bounds.getCenterLonLat();
- var mapSize = this.map.getSize();
-
- if (this.singleTile) {
- //set up the call for GETMAPIMAGE or GETDYNAMICMAPOVERLAY with
- //dynamic map parameters
- var params = {
- setdisplaydpi: OpenLayers.DOTS_PER_INCH,
- setdisplayheight: mapSize.h*this.ratio,
- setdisplaywidth: mapSize.w*this.ratio,
- setviewcenterx: center.lon,
- setviewcentery: center.lat,
- setviewscale: this.map.getScale()
- };
-
- if (this.useOverlay && !this.useAsyncOverlay) {
- //first we need to call GETVISIBLEMAPEXTENT to set the extent
- var getVisParams = {};
- getVisParams = OpenLayers.Util.extend(getVisParams, params);
- getVisParams.operation = "GETVISIBLEMAPEXTENT";
- getVisParams.version = "1.0.0";
- getVisParams.session = this.params.session;
- getVisParams.mapName = this.params.mapName;
- getVisParams.format = 'text/xml';
- url = this.getFullRequestString( getVisParams );
-
- OpenLayers.Request.GET({url: url, async: false});
- }
- //construct the full URL
- url = this.getFullRequestString( params );
+ 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 {
-
- //tiled version
- var currentRes = this.map.getResolution();
- var colidx = Math.floor((bounds.left-this.maxExtent.left)/currentRes);
- colidx = Math.round(colidx/this.tileSize.w);
- var rowidx = Math.floor((this.maxExtent.top-bounds.top)/currentRes);
- rowidx = Math.round(rowidx/this.tileSize.h);
-
- if (this.useHttpTile){
- url = this.getImageFilePath(
- {
- tilecol: colidx,
- tilerow: rowidx,
- scaleindex: this.resolutions.length - this.map.zoom - 1
- });
-
- } else {
- url = this.getFullRequestString(
- {
- tilecol: colidx,
- tilerow: rowidx,
- scaleindex: this.resolutions.length - this.map.zoom - 1
- });
- }
- }
- return url;
- },
-
- /**
- * Method: getFullRequestString
- * getFullRequestString on MapGuide layers is special, because we
- * do a regular expression replace on ',' in parameters to '+'.
- * This is why it is subclassed here.
- *
- * Parameters:
- * altUrl - {String} Alternative base URL to use.
- *
- * Returns:
- * {String} A string with the layer's url appropriately encoded for MapGuide
- */
- getFullRequestString:function(newParams, altUrl) {
- // use layer's url unless altUrl passed in
- var url = (altUrl == null) ? this.url : altUrl;
-
- // if url is not a string, it should be an array of strings,
- // in which case we will randomly select one of them in order
- // to evenly distribute requests to different urls.
- if (typeof url == "object") {
- url = url[Math.floor(Math.random()*url.length)];
- }
- // requestString always starts with url
- var requestString = url;
-
- // create a new params hashtable with all the layer params and the
- // new params together. then convert to string
- var allParams = OpenLayers.Util.extend({}, this.params);
- allParams = OpenLayers.Util.extend(allParams, newParams);
- // ignore parameters that are already in the url search string
- var urlParams = OpenLayers.Util.upperCaseObject(
- OpenLayers.Util.getParameters(url));
- for(var key in allParams) {
- if(key.toUpperCase() in urlParams) {
- delete allParams[key];
+ 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
+ };
}
}
- var paramsString = OpenLayers.Util.getParameterString(allParams);
-
- /* MapGuide needs '+' seperating things like bounds/height/width.
- Since typically this is URL encoded, we use a slight hack: we
- depend on the list-like functionality of getParameterString to
- leave ',' only in the case of list items (since otherwise it is
- encoded) then do a regular expression replace on the , characters
- to '+' */
- paramsString = paramsString.replace(/,/g, "+");
-
- if (paramsString != "") {
- var lastServerChar = url.charAt(url.length - 1);
- if ((lastServerChar == "&") || (lastServerChar == "?")) {
- requestString += paramsString;
- } else {
- if (url.indexOf('?') == -1) {
- //serverPath has no ? -- add one
- requestString += '?' + paramsString;
- } else {
- //serverPath contains ?, so must already have paramsString at the end
- requestString += '&' + paramsString;
- }
- }
- }
- return requestString;
+ return result;
},
-
- /**
- * Method: getImageFilePath
- * special handler to request mapguide tiles from an http exposed tilecache
- *
- * Parameters:
- * altUrl - {String} Alternative base URL to use.
- *
- * Returns:
- * {String} A string with the url for the tile image
- */
- getImageFilePath:function(newParams, altUrl) {
- // use layer's url unless altUrl passed in
- var url = (altUrl == null) ? this.url : altUrl;
-
- // if url is not a string, it should be an array of strings,
- // in which case we will randomly select one of them in order
- // to evenly distribute requests to different urls.
- if (typeof url == "object") {
- url = url[Math.floor(Math.random()*url.length)];
- }
- // requestString always starts with url
- var requestString = url;
-
- var tileRowGroup = "";
- var tileColGroup = "";
-
- if (newParams.tilerow < 0) {
- tileRowGroup = '-';
- }
-
- if (newParams.tilerow == 0 ) {
- tileRowGroup += '0';
- } else {
- tileRowGroup += Math.floor(Math.abs(newParams.tilerow/this.params.tileRowsPerFolder)) * this.params.tileRowsPerFolder;
- }
-
- if (newParams.tilecol < 0) {
- tileColGroup = '-';
- }
-
- if (newParams.tilecol == 0) {
- tileColGroup += '0';
- } else {
- tileColGroup += Math.floor(Math.abs(newParams.tilecol/this.params.tileColumnsPerFolder)) * this.params.tileColumnsPerFolder;
- }
-
- var tilePath = '/S' + Math.floor(newParams.scaleindex)
- + '/' + this.params.basemaplayergroupname
- + '/R' + tileRowGroup
- + '/C' + tileColGroup
- + '/' + (newParams.tilerow % this.params.tileRowsPerFolder)
- + '_' + (newParams.tilecol % this.params.tileColumnsPerFolder)
- + '.' + this.params.format;
- if (this.params.querystring) {
- tilePath += "?" + this.params.querystring;
- }
-
- requestString += tilePath;
- return requestString;
- },
-
/**
- * Method: calculateGridLayout
- * Generate parameters for the grid layout. This
- *
+ * APIMethod: equals
+ * Determine whether another geometry is equivalent to this one. Geometries
+ * are considered equivalent if all components have the same coordinates.
+ *
* Parameters:
- * bounds - {<OpenLayers.Bound>}
- * extent - {<OpenLayers.Bounds>}
- * resolution - {Number}
+ * geom - {<OpenLayers.Geometry.Point>} The geometry to test.
*
* Returns:
- * Object containing properties tilelon, tilelat, tileoffsetlat,
- * tileoffsetlat, tileoffsetx, tileoffsety
+ * {Boolean} The supplied geometry is equivalent to this geometry.
*/
- calculateGridLayout: function(bounds, extent, resolution) {
- var tilelon = resolution * this.tileSize.w;
- var tilelat = resolution * this.tileSize.h;
-
- var offsetlon = bounds.left - extent.left;
- var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
- var tilecolremain = offsetlon/tilelon - tilecol;
- var tileoffsetx = -tilecolremain * this.tileSize.w;
- var tileoffsetlon = extent.left + tilecol * tilelon;
-
- var offsetlat = extent.top - bounds.top + tilelat;
- var tilerow = Math.floor(offsetlat/tilelat) - this.buffer;
- var tilerowremain = tilerow - offsetlat/tilelat;
- var tileoffsety = tilerowremain * this.tileSize.h;
- var tileoffsetlat = extent.top - tilelat*tilerow;
-
- return {
- tilelon: tilelon, tilelat: tilelat,
- tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
- tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
- };
+ 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;
},
- CLASS_NAME: "OpenLayers.Layer.MapGuide"
-});
-/* ======================================================================
- OpenLayers/Layer/MapServer.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Layer/Grid.js
- */
-
-/**
- * Class: OpenLayers.Layer.MapServer
- * Instances of OpenLayers.Layer.MapServer are used to display
- * data from a MapServer CGI instance.
- *
- * Inherits from:
- * - <OpenLayers.Layer.Grid>
- */
-OpenLayers.Layer.MapServer = OpenLayers.Class(OpenLayers.Layer.Grid, {
-
/**
- * Constant: DEFAULT_PARAMS
- * {Object} Hashtable of default parameter key/value pairs
- */
- DEFAULT_PARAMS: {
- mode: "map",
- map_imagetype: "png"
- },
-
- /**
- * Constructor: OpenLayers.Layer.MapServer
- * Create a new MapServer layer object
+ * Method: toShortString
*
- * Parameters:
- * name - {String} A name for the layer
- * url - {String} Base url for the MapServer CGI
- * (e.g. http://www2.dmsolutions.ca/cgi-bin/mapserv)
- * params - {Object} An object with key/value pairs representing the
- * GetMap query string parameters and parameter values.
- * options - {Ojbect} Hashtable of extra options to tag onto the layer
- */
- initialize: function(name, url, params, options) {
- var newArguments = [];
- newArguments.push(name, url, params, options);
- OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
-
- this.params = OpenLayers.Util.applyDefaults(
- this.params, this.DEFAULT_PARAMS
- );
-
- // unless explicitly set in options, if the layer is transparent,
- // it will be an overlay
- if (options == null || options.isBaseLayer == null) {
- this.isBaseLayer = ((this.params.transparent != "true") &&
- (this.params.transparent != true));
- }
- },
-
- /**
- * Method: clone
- * Create a clone of this layer
- *
* Returns:
- * {<OpenLayers.Layer.MapServer>} An exact clone of this layer
+ * {String} Shortened String representation of Point object.
+ * (ex. <i>"5, 42"</i>)
*/
- clone: function (obj) {
- if (obj == null) {
- obj = new OpenLayers.Layer.MapServer(this.name,
- this.url,
- this.params,
- this.getOptions());
- }
- //get all additions from superclasses
- obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
-
- // copy/set any non-init, non-simple values here
-
- return obj;
+ toShortString: function() {
+ return (this.x + ", " + this.y);
},
-
- /**
- * Method: addTile
- * Creates a tile, initializes it, and adds it to the layer div.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * position - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
- */
- addTile:function(bounds,position) {
- return new OpenLayers.Tile.Image(this, position, bounds,
- null, this.tileSize);
- },
/**
- * Method: getURL
- * Return a query string for this layer
+ * 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:
- * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox
- * for the request
- *
- * Returns:
- * {String} A string with the layer's url and parameters and also
- * the passed-in bounds and appropriate tile size specified
- * as parameters.
+ * x - {Float} Distance to move geometry in positive x direction.
+ * y - {Float} Distance to move geometry in positive y direction.
*/
- getURL: function (bounds) {
- bounds = this.adjustBounds(bounds);
- // Make a list, so that getFullRequestString uses literal ","
- var extent = [bounds.left, bounds. bottom, bounds.right, bounds.top];
-
- var imageSize = this.getImageSize();
-
- // make lists, so that literal ','s are used
- var url = this.getFullRequestString(
- {mapext: extent,
- imgext: extent,
- map_size: [imageSize.w, imageSize.h],
- imgx: imageSize.w / 2,
- imgy: imageSize.h / 2,
- imgxy: [imageSize.w, imageSize.h]
- });
-
- return url;
+ move: function(x, y) {
+ this.x = this.x + x;
+ this.y = this.y + y;
+ this.clearBounds();
},
-
- /**
- * Method: getFullRequestString
- * combine the layer's url with its params and these newParams.
- *
- * Parameter:
- * newParams - {Object} New parameters that should be added to the
- * request string.
- * altUrl - {String} (optional) Replace the URL in the full request
- * string with the provided URL.
- *
- * Returns:
- * {String} A string with the layer's url and parameters embedded in it.
- */
- getFullRequestString:function(newParams, altUrl) {
- // use layer's url unless altUrl passed in
- var url = (altUrl == null) ? this.url : altUrl;
-
- // create a new params hashtable with all the layer params and the
- // new params together. then convert to string
- var allParams = OpenLayers.Util.extend({}, this.params);
- allParams = OpenLayers.Util.extend(allParams, newParams);
- var paramsString = OpenLayers.Util.getParameterString(allParams);
-
- // if url is not a string, it should be an array of strings,
- // in which case we will deterministically select one of them in
- // order to evenly distribute requests to different urls.
- if (url instanceof Array) {
- url = this.selectUrl(paramsString, url);
- }
-
- // ignore parameters that are already in the url search string
- var urlParams = OpenLayers.Util.upperCaseObject(
- OpenLayers.Util.getParameters(url));
- for(var key in allParams) {
- if(key.toUpperCase() in urlParams) {
- delete allParams[key];
- }
- }
- paramsString = OpenLayers.Util.getParameterString(allParams);
-
- // requestString always starts with url
- var requestString = url;
- // MapServer needs '+' seperating things like bounds/height/width.
- // Since typically this is URL encoded, we use a slight hack: we
- // depend on the list-like functionality of getParameterString to
- // leave ',' only in the case of list items (since otherwise it is
- // encoded) then do a regular expression replace on the , characters
- // to '+'
- //
- paramsString = paramsString.replace(/,/g, "+");
-
- if (paramsString != "") {
- var lastServerChar = url.charAt(url.length - 1);
- if ((lastServerChar == "&") || (lastServerChar == "?")) {
- requestString += paramsString;
- } else {
- if (url.indexOf('?') == -1) {
- //serverPath has no ? -- add one
- requestString += '?' + paramsString;
- } else {
- //serverPath contains ?, so must already have paramsString at the end
- requestString += '&' + paramsString;
- }
- }
- }
- return requestString;
- },
-
- CLASS_NAME: "OpenLayers.Layer.MapServer"
-});
-/* ======================================================================
- OpenLayers/Layer/WMS.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Layer/Grid.js
- * @requires OpenLayers/Tile/Image.js
- */
-
-/**
- * Class: OpenLayers.Layer.WMS
- * Instances of OpenLayers.Layer.WMS are used to display data from OGC Web
- * Mapping Services. Create a new WMS layer with the <OpenLayers.Layer.WMS>
- * constructor.
- *
- * Inherits from:
- * - <OpenLayers.Layer.Grid>
- */
-OpenLayers.Layer.WMS = OpenLayers.Class(OpenLayers.Layer.Grid, {
-
/**
- * Constant: DEFAULT_PARAMS
- * {Object} Hashtable of default parameter key/value pairs
- */
- DEFAULT_PARAMS: { service: "WMS",
- version: "1.1.1",
- request: "GetMap",
- styles: "",
- exceptions: "application/vnd.ogc.se_inimage",
- format: "image/jpeg"
- },
-
- /**
- * Property: reproject
- * *Deprecated*. See http://trac.openlayers.org/wiki/SphericalMercator
- * for information on the replacement for this functionality.
- * {Boolean} Try to reproject this layer if its coordinate reference system
- * is different than that of the base layer. Default is true.
- * Set this in the layer options. Should be set to false in
- * most cases.
- */
- reproject: false,
-
- /**
- * APIProperty: isBaseLayer
- * {Boolean} Default is true for WMS layer
- */
- isBaseLayer: true,
-
- /**
- * APIProperty: encodeBBOX
- * {Boolean} Should the BBOX commas be encoded? The WMS spec says 'no',
- * but some services want it that way. Default false.
- */
- encodeBBOX: false,
-
- /**
- * APIProperty: noMagic
- * {Boolean} If true, the image format will not be automagicaly switched
- * from image/jpeg to image/png or image/gif when using
- * TRANSPARENT=TRUE. Also isBaseLayer will not changed by the
- * constructor. Default false.
- */
- noMagic: false,
-
- /**
- * Property: yx
- * {Object} Keys in this object are EPSG codes for which the axis order
- * is to be reversed (yx instead of xy, LatLon instead of LonLat), with
- * true as value. This is only relevant for WMS versions >= 1.3.0.
- */
- yx: {'EPSG:4326': true},
-
- /**
- * Constructor: OpenLayers.Layer.WMS
- * Create a new WMS layer object
+ * APIMethod: rotate
+ * Rotate a point around another.
*
- * Example:
- * (code)
- * var wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
- * "http://wms.jpl.nasa.gov/wms.cgi",
- * {layers: "modis,global_mosaic"});
- * (end)
- *
* Parameters:
- * name - {String} A name for the layer
- * url - {String} Base url for the WMS
- * (e.g. http://wms.jpl.nasa.gov/wms.cgi)
- * params - {Object} An object with key/value pairs representing the
- * GetMap query string parameters and parameter values.
- * options - {Ojbect} Hashtable of extra options to tag onto the layer
+ * angle - {Float} Rotation angle in degrees (measured counterclockwise
+ * from the positive x-axis)
+ * origin - {<OpenLayers.Geometry.Point>} Center point for the rotation
*/
- initialize: function(name, url, params, options) {
- var newArguments = [];
- //uppercase params
- params = OpenLayers.Util.upperCaseObject(params);
- if (parseFloat(params.VERSION) >= 1.3 && !params.EXCEPTIONS) {
- params.EXCEPTIONS = "INIMAGE";
- }
- newArguments.push(name, url, params, options);
- OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
- OpenLayers.Util.applyDefaults(
- this.params,
- OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)
- );
-
-
- //layer is transparent
- if (!this.noMagic && this.params.TRANSPARENT &&
- this.params.TRANSPARENT.toString().toLowerCase() == "true") {
-
- // unless explicitly set in options, make layer an overlay
- if ( (options == null) || (!options.isBaseLayer) ) {
- this.isBaseLayer = false;
- }
-
- // jpegs can never be transparent, so intelligently switch the
- // format, depending on teh browser's capabilities
- if (this.params.FORMAT == "image/jpeg") {
- this.params.FORMAT = OpenLayers.Util.alphaHack() ? "image/gif"
- : "image/png";
- }
- }
-
- },
-
- /**
- * Method: destroy
- * Destroy this layer
- */
- destroy: function() {
- // for now, nothing special to do here.
- OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);
+ 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();
},
-
/**
- * Method: clone
- * Create a clone of this layer
+ * APIMethod: getCentroid
*
* Returns:
- * {<OpenLayers.Layer.WMS>} An exact clone of this layer
+ * {<OpenLayers.Geometry.Point>} The centroid of the collection
*/
- clone: function (obj) {
-
- if (obj == null) {
- obj = new OpenLayers.Layer.WMS(this.name,
- this.url,
- this.params,
- this.getOptions());
- }
-
- //get all additions from superclasses
- obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
-
- // copy/set any non-init, non-simple values here
-
- return obj;
- },
-
- /**
- * APIMethod: reverseAxisOrder
- * Returns true if the axis order is reversed for the WMS version and
- * projection of the layer.
- *
- * Returns:
- * {Boolean} true if the axis order is reversed, false otherwise.
- */
- reverseAxisOrder: function() {
- return (parseFloat(this.params.VERSION) >= 1.3 &&
- !!this.yx[this.map.getProjectionObject().getCode()]);
+ getCentroid: function() {
+ return new OpenLayers.Geometry.Point(this.x, this.y);
},
-
- /**
- * Method: getURL
- * Return a GetMap query string for this layer
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the
- * request.
- *
- * Returns:
- * {String} A string with the layer's url and parameters and also the
- * passed-in bounds and appropriate tile size specified as
- * parameters.
- */
- getURL: function (bounds) {
- bounds = this.adjustBounds(bounds);
-
- var imageSize = this.getImageSize();
- var newParams = {};
- // WMS 1.3 introduced axis order
- var reverseAxisOrder = this.reverseAxisOrder();
- newParams.BBOX = this.encodeBBOX ?
- bounds.toBBOX(null, reverseAxisOrder) :
- bounds.toArray(reverseAxisOrder);
- newParams.WIDTH = imageSize.w;
- newParams.HEIGHT = imageSize.h;
- var requestString = this.getFullRequestString(newParams);
- return requestString;
- },
/**
- * Method: addTile
- * addTile creates a tile, initializes it, and adds it to the layer div.
+ * 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:
- * bounds - {<OpenLayers.Bounds>}
- * position - {<OpenLayers.Pixel>}
+ * 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 - {<OpenLayers.Geometry.Point>} Point of origin for resizing
+ * ratio - {Float} Optional x:y ratio for resizing. Default ratio is 1.
*
* Returns:
- * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+ * {OpenLayers.Geometry} - The current geometry.
*/
- addTile:function(bounds,position) {
- return new OpenLayers.Tile.Image(this, position, bounds,
- null, this.tileSize);
+ 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: mergeNewParams
- * Catch changeParams and uppercase the new params to be merged in
- * before calling changeParams on the super class.
- *
- * Once params have been changed, the tiles will be reloaded with
- * the new parameters.
- *
- * Parameters:
- * newParams - {Object} Hashtable of new params to use
- */
- mergeNewParams:function(newParams) {
- var upperParams = OpenLayers.Util.upperCaseObject(newParams);
- var newArguments = [upperParams];
- return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,
- newArguments);
- },
-
- /**
- * APIMethod: getFullRequestString
- * Combine the layer's url with its params and these newParams.
- *
- * Add the SRS parameter from projection -- this is probably
- * more eloquently done via a setProjection() method, but this
- * works for now and always.
- *
- * Parameters:
- * newParams - {Object}
- * altUrl - {String} Use this as the url instead of the layer's url
- *
- * Returns:
- * {String}
- */
- getFullRequestString:function(newParams, altUrl) {
- var projectionCode = this.map.getProjection();
- var value = (projectionCode == "none") ? null : projectionCode
- if (parseFloat(this.params.VERSION) >= 1.3) {
- this.params.CRS = value;
- } else {
- this.params.SRS = value;
- }
-
- return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(
- this, arguments);
- },
-
- CLASS_NAME: "OpenLayers.Layer.WMS"
-});
-/* ======================================================================
- OpenLayers/Layer/XYZ.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Layer/Grid.js
- * @requires OpenLayers/Tile/Image.js
- */
-
-/**
- * Class: OpenLayers.Layer.XYZ
- * The XYZ class is designed to make it easier for people who have tiles
- * arranged by a standard XYZ grid.
- *
- * Inherits from:
- * - <OpenLayers.Layer.Grid>
- */
-OpenLayers.Layer.XYZ = OpenLayers.Class(OpenLayers.Layer.Grid, {
/**
- * APIProperty: isBaseLayer
- * Default is true, as this is designed to be a base tile source.
- */
- isBaseLayer: true,
-
- /**
- * APIProperty: sphericalMecator
- * Whether the tile extents should be set to the defaults for
- * spherical mercator. Useful for things like OpenStreetMap.
- * Default is false, except for the OSM subclass.
- */
- sphericalMercator: false,
-
- /**
- * APIProperty: zoomOffset
- * {Number} If your cache has more zoom levels than you want to provide
- * access to with this layer, supply a zoomOffset. This zoom offset
- * is added to the current map zoom level to determine the level
- * for a requested tile. For example, if you supply a zoomOffset
- * of 3, when the map is at the zoom 0, tiles will be requested from
- * level 3 of your cache. Default is 0 (assumes cache level and map
- * zoom are equivalent).
- */
- zoomOffset: 0,
-
- /**
- * Constructor: OpenLayers.Layer.XYZ
+ * APIMethod: intersects
+ * Determine if the input geometry intersects this one.
*
* Parameters:
- * name - {String}
- * url - {String}
- * options - {Object} Hashtable of extra options to tag onto the layer
- */
- initialize: function(name, url, options) {
- if (options && options.sphericalMercator || this.sphericalMercator) {
- options = OpenLayers.Util.extend({
- maxExtent: new OpenLayers.Bounds(
- -128 * 156543.0339,
- -128 * 156543.0339,
- 128 * 156543.0339,
- 128 * 156543.0339
- ),
- maxResolution: 156543.0339,
- numZoomLevels: 19,
- units: "m",
- projection: "EPSG:900913"
- }, options);
- }
- url = url || this.url;
- name = name || this.name;
- var newArguments = [name, url, {}, options];
- OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
- },
-
- /**
- * APIMethod: clone
- * Create a clone of this layer
+ * geometry - {<OpenLayers.Geometry>} Any type of geometry.
*
- * Parameters:
- * obj - {Object} Is this ever used?
- *
* Returns:
- * {<OpenLayers.Layer.XYZ>} An exact clone of this OpenLayers.Layer.XYZ
+ * {Boolean} The input geometry intersects this one.
*/
- clone: function (obj) {
-
- if (obj == null) {
- obj = new OpenLayers.Layer.XYZ(this.name,
- this.url,
- this.getOptions());
- }
-
- //get all additions from superclasses
- obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
-
- return obj;
- },
-
- /**
- * Method: getUrl
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {String} A string with the layer's url and parameters and also the
- * passed-in bounds and appropriate tile size specified as
- * parameters
- */
- getURL: function (bounds) {
- var res = this.map.getResolution();
- var x = Math.round((bounds.left - this.maxExtent.left)
- / (res * this.tileSize.w));
- var y = Math.round((this.maxExtent.top - bounds.top)
- / (res * this.tileSize.h));
- var z = this.map.getZoom() + this.zoomOffset;
-
- var url = this.url;
- var s = '' + x + y + z;
- if (url instanceof Array)
- {
- url = this.selectUrl(s, url);
- }
-
- var path = OpenLayers.String.format(url, {'x': x, 'y': y, 'z': z});
-
- return path;
- },
-
- /**
- * Method: addTile
- * addTile creates a tile, initializes it, and adds it to the layer div.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * position - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
- */
- addTile:function(bounds,position) {
- return new OpenLayers.Tile.Image(this, position, bounds,
- null, this.tileSize);
- },
-
- /* APIMethod: setMap
- * When the layer is added to a map, then we can fetch our origin
- * (if we don't have one.)
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- setMap: function(map) {
- OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments);
- if (!this.tileOrigin) {
- this.tileOrigin = new OpenLayers.LonLat(this.maxExtent.left,
- this.maxExtent.bottom);
- }
- },
-
- CLASS_NAME: "OpenLayers.Layer.XYZ"
-});
-
-
-/**
- * Class: OpenLayers.Layer.OSM
- * A class to access OpenStreetMap tiles. By default, uses the OpenStreetMap
- * hosted tile.openstreetmap.org 'Mapnik' tileset. If you wish to use
- * tiles at home / osmarender layer instead, you can pass a layer like:
- *
- * (code)
- * new OpenLayers.Layer.OSM("t at h",
- * "http://tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png");
- * (end)
- *
- * This layer defaults to Spherical Mercator.
- *
- * Inherits from:
- * - <OpenLayers.Layer.XYZ>
- */
-OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
- name: "OpenStreetMap",
- attribution: "Data CC-By-SA by <a href='http://openstreetmap.org/'>OpenStreetMap</a>",
- sphericalMercator: true,
- url: 'http://tile.openstreetmap.org/${z}/${x}/${y}.png',
- clone: function(obj) {
- if (obj == null) {
- obj = new OpenLayers.Layer.OSM(
- this.name, this.url, this.getOptions());
- }
- obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]);
- return obj;
- },
- CLASS_NAME: "OpenLayers.Layer.OSM"
-});
-/* ======================================================================
- OpenLayers/Rule.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Util.js
- * @requires OpenLayers/Style.js
- * @requires OpenLayers/Symbolizer/Point.js
- * @requires OpenLayers/Symbolizer/Line.js
- * @requires OpenLayers/Symbolizer/Polygon.js
- * @requires OpenLayers/Symbolizer/Text.js
- * @requires OpenLayers/Symbolizer/Raster.js
- */
-
-/**
- * Class: OpenLayers.Rule
- * This class represents an SLD Rule, as being used for rule-based SLD styling.
- */
-OpenLayers.Rule = OpenLayers.Class({
-
- /**
- * Property: id
- * {String} A unique id for this session.
- */
- id: null,
-
- /**
- * APIProperty: name
- * {String} name of this rule
- */
- name: null,
-
- /**
- * Property: title
- * {String} Title of this rule (set if included in SLD)
- */
- title: null,
-
- /**
- * Property: description
- * {String} Description of this rule (set if abstract is included in SLD)
- */
- description: null,
-
- /**
- * Property: context
- * {Object} An optional object with properties that the rule should be
- * evaluated against. If no context is specified, feature.attributes will
- * be used.
- */
- context: null,
-
- /**
- * Property: filter
- * {<OpenLayers.Filter>} Optional filter for the rule.
- */
- filter: null,
-
- /**
- * Property: elseFilter
- * {Boolean} Determines whether this rule is only to be applied only if
- * no other rules match (ElseFilter according to the SLD specification).
- * Default is false. For instances of OpenLayers.Rule, if elseFilter is
- * false, the rule will always apply. For subclasses, the else property is
- * ignored.
- */
- elseFilter: false,
-
- /**
- * Property: symbolizer
- * {Object} Symbolizer or hash of symbolizers for this rule. If hash of
- * symbolizers, keys are one or more of ["Point", "Line", "Polygon"]. The
- * latter if useful if it is required to style e.g. vertices of a line
- * with a point symbolizer. Note, however, that this is not implemented
- * yet in OpenLayers, but it is the way how symbolizers are defined in
- * SLD.
- */
- symbolizer: null,
-
- /**
- * Property: symbolizers
- * {Array} Collection of symbolizers associated with this rule. If
- * provided at construction, the symbolizers array has precedence
- * over the deprecated symbolizer property. Note that multiple
- * symbolizers are not currently supported by the vector renderers.
- * Rules with multiple symbolizers are currently only useful for
- * maintaining elements in an SLD document.
- */
- symbolizers: null,
-
- /**
- * APIProperty: minScaleDenominator
- * {Number} or {String} minimum scale at which to draw the feature.
- * In the case of a String, this can be a combination of text and
- * propertyNames in the form "literal ${propertyName}"
- */
- minScaleDenominator: null,
-
- /**
- * APIProperty: maxScaleDenominator
- * {Number} or {String} maximum scale at which to draw the feature.
- * In the case of a String, this can be a combination of text and
- * propertyNames in the form "literal ${propertyName}"
- */
- maxScaleDenominator: null,
-
- /**
- * Constructor: OpenLayers.Rule
- * Creates a Rule.
- *
- * Parameters:
- * options - {Object} An optional object with properties to set on the
- * rule
- *
- * Returns:
- * {<OpenLayers.Rule>}
- */
- initialize: function(options) {
- this.symbolizer = {};
- OpenLayers.Util.extend(this, options);
- if (this.symbolizers) {
- delete this.symbolizer;
- }
- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
- },
-
- /**
- * APIMethod: destroy
- * nullify references to prevent circular references and memory leaks
- */
- destroy: function() {
- for (var i in this.symbolizer) {
- this.symbolizer[i] = null;
- }
- this.symbolizer = null;
- delete this.symbolizers;
- },
-
- /**
- * APIMethod: evaluate
- * evaluates this rule for a specific feature
- *
- * Parameters:
- * feature - {<OpenLayers.Feature>} feature to apply the rule to.
- *
- * Returns:
- * {Boolean} true if the rule applies, false if it does not.
- * This rule is the default rule and always returns true.
- */
- evaluate: function(feature) {
- var context = this.getContext(feature);
- var applies = true;
-
- if (this.minScaleDenominator || this.maxScaleDenominator) {
- var scale = feature.layer.map.getScale();
- }
-
- // check if within minScale/maxScale bounds
- if (this.minScaleDenominator) {
- applies = scale >= OpenLayers.Style.createLiteral(
- this.minScaleDenominator, context);
- }
- if (applies && this.maxScaleDenominator) {
- applies = scale < OpenLayers.Style.createLiteral(
- this.maxScaleDenominator, context);
- }
-
- // check if optional filter applies
- if(applies && this.filter) {
- // feature id filters get the feature, others get the context
- if(this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") {
- applies = this.filter.evaluate(feature);
- } else {
- applies = this.filter.evaluate(context);
- }
- }
-
- return applies;
- },
-
- /**
- * Method: getContext
- * Gets the context for evaluating this rule
- *
- * Paramters:
- * feature - {<OpenLayers.Feature>} feature to take the context from if
- * none is specified.
- */
- getContext: function(feature) {
- var context = this.context;
- if (!context) {
- context = feature.attributes || feature.data;
- }
- if (typeof this.context == "function") {
- context = this.context(feature);
- }
- return context;
- },
-
- /**
- * APIMethod: clone
- * Clones this rule.
- *
- * Returns:
- * {<OpenLayers.Rule>} Clone of this rule.
- */
- clone: function() {
- var options = OpenLayers.Util.extend({}, this);
- if (this.symbolizers) {
- // clone symbolizers
- var len = this.symbolizers.length;
- options.symbolizers = new Array(len);
- for (var i=0; i<len; ++i) {
- options.symbolizers[i] = this.symbolizers[i].clone();
- }
+ intersects: function(geometry) {
+ var intersect = false;
+ if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
+ intersect = this.equals(geometry);
} else {
- // clone symbolizer
- options.symbolizer = {};
- var value, type;
- for(var key in this.symbolizer) {
- value = this.symbolizer[key];
- type = typeof value;
- if(type === "object") {
- options.symbolizer[key] = OpenLayers.Util.extend({}, value);
- } else if(type === "string") {
- options.symbolizer[key] = value;
- }
- }
+ intersect = geometry.intersects(this);
}
- // clone filter
- options.filter = this.filter && this.filter.clone();
- // clone context
- options.context = this.context && OpenLayers.Util.extend({}, this.context);
- return new OpenLayers.Rule(options);
+ return intersect;
},
-
- CLASS_NAME: "OpenLayers.Rule"
-});
-/* ======================================================================
- OpenLayers/StyleMap.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Style.js
- * @requires OpenLayers/Feature/Vector.js
- */
-
-/**
- * Class: OpenLayers.StyleMap
- */
-OpenLayers.StyleMap = OpenLayers.Class({
/**
- * Property: styles
- * Hash of {<OpenLayers.Style>}, keyed by names of well known
- * rendering intents (e.g. "default", "temporary", "select", "delete").
- */
- styles: null,
-
- /**
- * Property: extendDefault
- * {Boolean} if true, every render intent will extend the symbolizers
- * specified for the "default" intent at rendering time. Otherwise, every
- * rendering intent will be treated as a completely independent style.
- */
- extendDefault: true,
-
- /**
- * Constructor: OpenLayers.StyleMap
+ * APIMethod: transform
+ * Translate the x,y properties of the point from source to dest.
*
* Parameters:
- * style - {Object} Optional. Either a style hash, or a style object, or
- * a hash of style objects (style hashes) keyed by rendering
- * intent. If just one style hash or style object is passed,
- * this will be used for all known render intents (default,
- * select, temporary)
- * options - {Object} optional hash of additional options for this
- * instance
- */
- initialize: function (style, options) {
- this.styles = {
- "default": new OpenLayers.Style(
- OpenLayers.Feature.Vector.style["default"]),
- "select": new OpenLayers.Style(
- OpenLayers.Feature.Vector.style["select"]),
- "temporary": new OpenLayers.Style(
- OpenLayers.Feature.Vector.style["temporary"]),
- "delete": new OpenLayers.Style(
- OpenLayers.Feature.Vector.style["delete"])
- };
-
- // take whatever the user passed as style parameter and convert it
- // into parts of stylemap.
- if(style instanceof OpenLayers.Style) {
- // user passed a style object
- this.styles["default"] = style;
- this.styles["select"] = style;
- this.styles["temporary"] = style;
- this.styles["delete"] = style;
- } else if(typeof style == "object") {
- for(var key in style) {
- if(style[key] instanceof OpenLayers.Style) {
- // user passed a hash of style objects
- this.styles[key] = style[key];
- } else if(typeof style[key] == "object") {
- // user passsed a hash of style hashes
- this.styles[key] = new OpenLayers.Style(style[key]);
- } else {
- // user passed a style hash (i.e. symbolizer)
- this.styles["default"] = new OpenLayers.Style(style);
- this.styles["select"] = new OpenLayers.Style(style);
- this.styles["temporary"] = new OpenLayers.Style(style);
- this.styles["delete"] = new OpenLayers.Style(style);
- break;
- }
- }
- }
- OpenLayers.Util.extend(this, options);
- },
-
- /**
- * Method: destroy
- */
- destroy: function() {
- for(var key in this.styles) {
- this.styles[key].destroy();
- }
- this.styles = null;
- },
-
- /**
- * Method: createSymbolizer
- * Creates the symbolizer for a feature for a render intent.
+ * source - {<OpenLayers.Projection>}
+ * dest - {<OpenLayers.Projection>}
*
- * Parameters:
- * feature - {<OpenLayers.Feature>} The feature to evaluate the rules
- * of the intended style against.
- * intent - {String} The intent determines the symbolizer that will be
- * used to draw the feature. Well known intents are "default"
- * (for just drawing the features), "select" (for selected
- * features) and "temporary" (for drawing features).
- *
* Returns:
- * {Object} symbolizer hash
+ * {<OpenLayers.Geometry>}
*/
- createSymbolizer: function(feature, intent) {
- if(!feature) {
- feature = new OpenLayers.Feature.Vector();
- }
- if(!this.styles[intent]) {
- intent = "default";
- }
- feature.renderIntent = intent;
- var defaultSymbolizer = {};
- if(this.extendDefault && intent != "default") {
- defaultSymbolizer = this.styles["default"].createSymbolizer(feature);
- }
- return OpenLayers.Util.extend(defaultSymbolizer,
- this.styles[intent].createSymbolizer(feature));
+ transform: function(source, dest) {
+ if ((source && dest)) {
+ OpenLayers.Projection.transform(
+ this, source, dest);
+ this.bounds = null;
+ }
+ return this;
},
-
- /**
- * Method: addUniqueValueRules
- * Convenience method to create comparison rules for unique values of a
- * property. The rules will be added to the style object for a specified
- * rendering intent. This method is a shortcut for creating something like
- * the "unique value legends" familiar from well known desktop GIS systems
- *
- * Parameters:
- * renderIntent - {String} rendering intent to add the rules to
- * property - {String} values of feature attributes to create the
- * rules for
- * symbolizers - {Object} Hash of symbolizers, keyed by the desired
- * property values
- * context - {Object} An optional object with properties that
- * symbolizers' property values should be evaluated
- * against. If no context is specified, feature.attributes
- * will be used
- */
- addUniqueValueRules: function(renderIntent, property, symbolizers, context) {
- var rules = [];
- for (var value in symbolizers) {
- rules.push(new OpenLayers.Rule({
- symbolizer: symbolizers[value],
- context: context,
- filter: new OpenLayers.Filter.Comparison({
- type: OpenLayers.Filter.Comparison.EQUAL_TO,
- property: property,
- value: value
- })
- }));
- }
- this.styles[renderIntent].addRules(rules);
- },
- CLASS_NAME: "OpenLayers.StyleMap"
-});
-/* ======================================================================
- OpenLayers/Filter/Comparison.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Filter.js
- * @requires OpenLayers/Console.js
- */
-
-/**
- * Class: OpenLayers.Filter.Comparison
- * This class represents a comparison filter.
- *
- * Inherits from
- * - <OpenLayers.Filter>
- */
-OpenLayers.Filter.Comparison = OpenLayers.Class(OpenLayers.Filter, {
-
/**
- * APIProperty: type
- * {String} type: type of the comparison. This is one of
- * - OpenLayers.Filter.Comparison.EQUAL_TO = "==";
- * - OpenLayers.Filter.Comparison.NOT_EQUAL_TO = "!=";
- * - OpenLayers.Filter.Comparison.LESS_THAN = "<";
- * - OpenLayers.Filter.Comparison.GREATER_THAN = ">";
- * - OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO = "<=";
- * - OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO = ">=";
- * - OpenLayers.Filter.Comparison.BETWEEN = "..";
- * - OpenLayers.Filter.Comparison.LIKE = "~";
- */
- type: null,
-
- /**
- * APIProperty: property
- * {String}
- * name of the context property to compare
- */
- property: null,
-
- /**
- * APIProperty: value
- * {Number} or {String}
- * comparison value for binary comparisons. In the case of a String, this
- * can be a combination of text and propertyNames in the form
- * "literal ${propertyName}"
- */
- value: null,
-
- /**
- * Property: matchCase
- * {Boolean} Force case sensitive searches for EQUAL_TO and NOT_EQUAL_TO
- * comparisons. The Filter Encoding 1.1 specification added a matchCase
- * attribute to ogc:PropertyIsEqualTo and ogc:PropertyIsNotEqualTo
- * elements. This property will be serialized with those elements only
- * if using the v1.1.0 filter format. However, when evaluating filters
- * here, the matchCase property will always be respected (for EQUAL_TO
- * and NOT_EQUAL_TO). Default is true.
- */
- matchCase: true,
-
- /**
- * APIProperty: lowerBoundary
- * {Number} or {String}
- * lower boundary for between comparisons. In the case of a String, this
- * can be a combination of text and propertyNames in the form
- * "literal ${propertyName}"
- */
- lowerBoundary: null,
-
- /**
- * APIProperty: upperBoundary
- * {Number} or {String}
- * upper boundary for between comparisons. In the case of a String, this
- * can be a combination of text and propertyNames in the form
- * "literal ${propertyName}"
- */
- upperBoundary: null,
-
- /**
- * Constructor: OpenLayers.Filter.Comparison
- * Creates a comparison rule.
+ * APIMethod: getVertices
+ * Return a list of all points in this geometry.
*
* Parameters:
- * options - {Object} An optional object with properties to set on the
- * rule
- *
- * Returns:
- * {<OpenLayers.Filter.Comparison>}
- */
- initialize: function(options) {
- OpenLayers.Filter.prototype.initialize.apply(this, [options]);
- },
-
- /**
- * APIMethod: evaluate
- * Evaluates this filter in a specific context.
- *
- * Parameters:
- * context - {Object} Context to use in evaluating the filter. If a vector
- * feature is provided, the feature.attributes will be used as context.
- *
- * Returns:
- * {Boolean} The filter applies.
- */
- evaluate: function(context) {
- if (context instanceof OpenLayers.Feature.Vector) {
- context = context.attributes;
- }
- var result = false;
- var got = context[this.property];
- switch(this.type) {
- case OpenLayers.Filter.Comparison.EQUAL_TO:
- var exp = this.value;
- if(!this.matchCase &&
- typeof got == "string" && typeof exp == "string") {
- result = (got.toUpperCase() == exp.toUpperCase());
- } else {
- result = (got == exp);
- }
- break;
- case OpenLayers.Filter.Comparison.NOT_EQUAL_TO:
- var exp = this.value;
- if(!this.matchCase &&
- typeof got == "string" && typeof exp == "string") {
- result = (got.toUpperCase() != exp.toUpperCase());
- } else {
- result = (got != exp);
- }
- break;
- case OpenLayers.Filter.Comparison.LESS_THAN:
- result = got < this.value;
- break;
- case OpenLayers.Filter.Comparison.GREATER_THAN:
- result = got > this.value;
- break;
- case OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO:
- result = got <= this.value;
- break;
- case OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO:
- result = got >= this.value;
- break;
- case OpenLayers.Filter.Comparison.BETWEEN:
- result = (got >= this.lowerBoundary) &&
- (got <= this.upperBoundary);
- break;
- case OpenLayers.Filter.Comparison.LIKE:
- var regexp = new RegExp(this.value, "gi");
- result = regexp.test(got);
- break;
- }
- return result;
- },
-
- /**
- * APIMethod: value2regex
- * Converts the value of this rule into a regular expression string,
- * according to the wildcard characters specified. This method has to
- * be called after instantiation of this class, if the value is not a
- * regular expression already.
- *
- * Parameters:
- * wildCard - {<Char>} wildcard character in the above value, default
- * is "*"
- * singleChar - {<Char>) single-character wildcard in the above value
- * default is "."
- * escape - {<Char>) escape character in the above value, default is
- * "!"
- *
- * Returns:
- * {String} regular expression string
- */
- value2regex: function(wildCard, singleChar, escapeChar) {
- if (wildCard == ".") {
- var msg = "'.' is an unsupported wildCard character for "+
- "OpenLayers.Filter.Comparison";
- OpenLayers.Console.error(msg);
- return null;
- }
-
-
- // set UMN MapServer defaults for unspecified parameters
- wildCard = wildCard ? wildCard : "*";
- singleChar = singleChar ? singleChar : ".";
- escapeChar = escapeChar ? escapeChar : "!";
-
- this.value = this.value.replace(
- new RegExp("\\"+escapeChar+"(.|$)", "g"), "\\$1");
- this.value = this.value.replace(
- new RegExp("\\"+singleChar, "g"), ".");
- this.value = this.value.replace(
- new RegExp("\\"+wildCard, "g"), ".*");
- this.value = this.value.replace(
- new RegExp("\\\\.\\*", "g"), "\\"+wildCard);
- this.value = this.value.replace(
- new RegExp("\\\\\\.", "g"), "\\"+singleChar);
-
- return this.value;
- },
-
- /**
- * Method: regex2value
- * Convert the value of this rule from a regular expression string into an
- * ogc literal string using a wildCard of *, a singleChar of ., and an
- * escape of !. Leaves the <value> property unmodified.
- *
- * Returns:
- * {String} A string value.
- */
- regex2value: function() {
-
- var value = this.value;
-
- // replace ! with !!
- value = value.replace(/!/g, "!!");
-
- // replace \. with !. (watching out for \\.)
- value = value.replace(/(\\)?\\\./g, function($0, $1) {
- return $1 ? $0 : "!.";
- });
-
- // replace \* with #* (watching out for \\*)
- value = value.replace(/(\\)?\\\*/g, function($0, $1) {
- return $1 ? $0 : "!*";
- });
-
- // replace \\ with \
- value = value.replace(/\\\\/g, "\\");
-
- // convert .* to * (the sequence #.* is not allowed)
- value = value.replace(/\.\*/g, "*");
-
- return value;
- },
-
- /**
- * APIMethod: clone
- * Clones this filter.
- *
- * Returns:
- * {<OpenLayers.Filter.Comparison>} Clone of this filter.
- */
- clone: function() {
- return OpenLayers.Util.extend(new OpenLayers.Filter.Comparison(), this);
- },
-
- CLASS_NAME: "OpenLayers.Filter.Comparison"
-});
-
-
-OpenLayers.Filter.Comparison.EQUAL_TO = "==";
-OpenLayers.Filter.Comparison.NOT_EQUAL_TO = "!=";
-OpenLayers.Filter.Comparison.LESS_THAN = "<";
-OpenLayers.Filter.Comparison.GREATER_THAN = ">";
-OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO = "<=";
-OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO = ">=";
-OpenLayers.Filter.Comparison.BETWEEN = "..";
-OpenLayers.Filter.Comparison.LIKE = "~";
-/* ======================================================================
- OpenLayers/Filter/Logical.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Filter.js
- */
-
-/**
- * Class: OpenLayers.Filter.Logical
- * This class represents ogc:And, ogc:Or and ogc:Not rules.
- *
- * Inherits from
- * - <OpenLayers.Filter>
- */
-OpenLayers.Filter.Logical = OpenLayers.Class(OpenLayers.Filter, {
-
- /**
- * APIProperty: filters
- * {Array(<OpenLayers.Filter>)} Child filters for this filter.
- */
- filters: null,
-
- /**
- * APIProperty: type
- * {String} type of logical operator. Available types are:
- * - OpenLayers.Filter.Logical.AND = "&&";
- * - OpenLayers.Filter.Logical.OR = "||";
- * - OpenLayers.Filter.Logical.NOT = "!";
- */
- type: null,
-
- /**
- * Constructor: OpenLayers.Filter.Logical
- * Creates a logical filter (And, Or, Not).
+ * 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.
*
- * Parameters:
- * options - {Object} An optional object with properties to set on the
- * filter.
- *
* Returns:
- * {<OpenLayers.Filter.Logical>}
+ * {Array} A list of all vertices in the geometry.
*/
- initialize: function(options) {
- this.filters = [];
- OpenLayers.Filter.prototype.initialize.apply(this, [options]);
+ getVertices: function(nodes) {
+ return [this];
},
-
- /**
- * APIMethod: destroy
- * Remove reference to child filters.
- */
- destroy: function() {
- this.filters = null;
- OpenLayers.Filter.prototype.destroy.apply(this);
- },
- /**
- * APIMethod: evaluate
- * Evaluates this filter in a specific context.
- *
- * Parameters:
- * context - {Object} Context to use in evaluating the filter. A vector
- * feature may also be provided to evaluate feature attributes in
- * comparison filters or geometries in spatial filters.
- *
- * Returns:
- * {Boolean} The filter applies.
- */
- evaluate: function(context) {
- switch(this.type) {
- case OpenLayers.Filter.Logical.AND:
- for (var i=0, len=this.filters.length; i<len; i++) {
- if (this.filters[i].evaluate(context) == false) {
- return false;
- }
- }
- return true;
-
- case OpenLayers.Filter.Logical.OR:
- for (var i=0, len=this.filters.length; i<len; i++) {
- if (this.filters[i].evaluate(context) == true) {
- return true;
- }
- }
- return false;
-
- case OpenLayers.Filter.Logical.NOT:
- return (!this.filters[0].evaluate(context));
- }
- },
-
- /**
- * APIMethod: clone
- * Clones this filter.
- *
- * Returns:
- * {<OpenLayers.Filter.Logical>} Clone of this filter.
- */
- clone: function() {
- var filters = [];
- for(var i=0, len=this.filters.length; i<len; ++i) {
- filters.push(this.filters[i].clone());
- }
- return new OpenLayers.Filter.Logical({
- type: this.type,
- filters: filters
- });
- },
-
- CLASS_NAME: "OpenLayers.Filter.Logical"
+ CLASS_NAME: "OpenLayers.Geometry.Point"
});
-
-
-OpenLayers.Filter.Logical.AND = "&&";
-OpenLayers.Filter.Logical.OR = "||";
-OpenLayers.Filter.Logical.NOT = "!";
/* ======================================================================
- OpenLayers/Filter/Spatial.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Filter.js
- * @requires OpenLayers/Console.js
- */
-
-/**
- * Class: OpenLayers.Filter.Spatial
- * This class represents a spatial filter.
- * Currently implemented: BBOX, DWithin and Intersects
- *
- * Inherits from
- * - <OpenLayers.Filter>
- */
-OpenLayers.Filter.Spatial = OpenLayers.Class(OpenLayers.Filter, {
-
- /**
- * APIProperty: type
- * {String} Type of spatial filter.
- *
- * The type should be one of:
- * - OpenLayers.Filter.Spatial.BBOX
- * - OpenLayers.Filter.Spatial.INTERSECTS
- * - OpenLayers.Filter.Spatial.DWITHIN
- * - OpenLayers.Filter.Spatial.WITHIN
- * - OpenLayers.Filter.Spatial.CONTAINS
- */
- type: null,
-
- /**
- * APIProperty: property
- * {String} Name of the context property to compare.
- */
- property: null,
-
- /**
- * APIProperty: value
- * {<OpenLayers.Bounds> || <OpenLayers.Geometry>} The bounds or geometry
- * to be used by the filter. Use bounds for BBOX filters and geometry
- * for INTERSECTS or DWITHIN filters.
- */
- value: null,
-
- /**
- * APIProperty: distance
- * {Number} The distance to use in a DWithin spatial filter.
- */
- distance: null,
-
- /**
- * APIProperty: distanceUnits
- * {String} The units to use for the distance, e.g. 'm'.
- */
- distanceUnits: null,
-
- /**
- * Constructor: OpenLayers.Filter.Spatial
- * Creates a spatial filter.
- *
- * Parameters:
- * options - {Object} An optional object with properties to set on the
- * filter.
- *
- * Returns:
- * {<OpenLayers.Filter.Spatial>}
- */
- initialize: function(options) {
- OpenLayers.Filter.prototype.initialize.apply(this, [options]);
- },
-
- /**
- * Method: evaluate
- * Evaluates this filter for a specific feature.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>} feature to apply the filter to.
- *
- * Returns:
- * {Boolean} The feature meets filter criteria.
- */
- evaluate: function(feature) {
- var intersect = false;
- switch(this.type) {
- case OpenLayers.Filter.Spatial.BBOX:
- case OpenLayers.Filter.Spatial.INTERSECTS:
- if(feature.geometry) {
- var geom = this.value;
- if(this.value.CLASS_NAME == "OpenLayers.Bounds") {
- geom = this.value.toGeometry();
- }
- if(feature.geometry.intersects(geom)) {
- intersect = true;
- }
- }
- break;
- default:
- OpenLayers.Console.error(
- OpenLayers.i18n("filterEvaluateNotImplemented"));
- break;
- }
- return intersect;
- },
-
- /**
- * APIMethod: clone
- * Clones this filter.
- *
- * Returns:
- * {<OpenLayers.Filter.Spatial>} Clone of this filter.
- */
- clone: function() {
- var options = OpenLayers.Util.applyDefaults({
- value: this.value && this.value.clone && this.value.clone()
- }, this);
- return new OpenLayers.Filter.Spatial(options);
- },
- CLASS_NAME: "OpenLayers.Filter.Spatial"
-});
-
-OpenLayers.Filter.Spatial.BBOX = "BBOX";
-OpenLayers.Filter.Spatial.INTERSECTS = "INTERSECTS";
-OpenLayers.Filter.Spatial.DWITHIN = "DWITHIN";
-OpenLayers.Filter.Spatial.WITHIN = "WITHIN";
-OpenLayers.Filter.Spatial.CONTAINS = "CONTAINS";
-/* ======================================================================
OpenLayers/Geometry/Collection.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
@@ -33926,12 +19370,19 @@
*/
calculateBounds: function() {
this.bounds = null;
- if ( this.components && this.components.length > 0) {
- this.setBounds(this.components[0].getBounds());
- for (var i=1, len=this.components.length; i<len; i++) {
- this.extendBounds(this.components[i].getBounds());
+ var bounds = new OpenLayers.Bounds();
+ var components = this.components;
+ if (components) {
+ for (var i=0, len=components.length; i<len; i++) {
+ bounds.extend(components[i].getBounds());
}
}
+ // to preserve old behavior, we only set bounds if non-null
+ // in the future, we could add bounds.isEmpty()
+ if (bounds.left != null && bounds.bottom != null &&
+ bounds.right != null && bounds.top != null) {
+ this.setBounds(bounds);
+ }
},
/**
@@ -34363,1248 +19814,10 @@
CLASS_NAME: "OpenLayers.Geometry.Collection"
});
/* ======================================================================
- OpenLayers/Geometry/Point.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Geometry.js
- */
-
-/**
- * Class: OpenLayers.Geometry.Point
- * Point geometry class.
- *
- * Inherits from:
- * - <OpenLayers.Geometry>
- */
-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:
- * {<OpenLayers.Geometry.Point>} 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 - {<OpenLayers.Geometry>} The target geometry.
- * options - {Object} Optional properties for configuring the distance
- * calculation.
- *
- * Valid options:
- * details - {Boolean} Return details from the distance calculation.
- * Default is false.
- * edge - {Boolean} Calculate the distance from this geometry to the
- * nearest edge of the target geometry. Default is true. If true,
- * calling distanceTo from a geometry that is wholly contained within
- * the target will result in a non-zero distance. If false, whenever
- * geometries intersect, calling distanceTo will return 0. If false,
- * details cannot be returned.
- *
- * Returns:
- * {Number | Object} The distance between this geometry and the target.
- * If details is true, the return will be an object with distance,
- * x0, y0, x1, and x2 properties. The x0 and y0 properties represent
- * the coordinates of the closest point on this geometry. The x1 and y1
- * properties represent the coordinates of the closest point on the
- * target geometry.
- */
- distanceTo: function(geometry, options) {
- var edge = !(options && options.edge === false);
- var details = edge && options && options.details;
- var 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 - {<OpenLayers.Geometry.Point>} 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. <i>"5, 42"</i>)
- */
- 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 - {<OpenLayers.Geometry.Point>} 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:
- * {<OpenLayers.Geometry.Point>} 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 - {<OpenLayers.Geometry.Point>} Point of origin for resizing
- * ratio - {Float} Optional x:y ratio for resizing. Default ratio is 1.
- *
- * Returns:
- * {OpenLayers.Geometry} - The current geometry.
- */
- resize: function(scale, origin, ratio) {
- 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 - {<OpenLayers.Geometry>} Any type of geometry.
- *
- * Returns:
- * {Boolean} The input geometry intersects this one.
- */
- intersects: function(geometry) {
- var intersect = false;
- if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
- intersect = this.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 - {<OpenLayers.Projection>}
- * dest - {<OpenLayers.Projection>}
- *
- * Returns:
- * {<OpenLayers.Geometry>}
- */
- 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/Layer/Vector.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Layer.js
- * @requires OpenLayers/Renderer.js
- * @requires OpenLayers/StyleMap.js
- * @requires OpenLayers/Feature/Vector.js
- * @requires OpenLayers/Console.js
- */
-
-/**
- * Class: OpenLayers.Layer.Vector
- * Instances of OpenLayers.Layer.Vector are used to render vector data from
- * a variety of sources. Create a new vector layer with the
- * <OpenLayers.Layer.Vector> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Layer>
- */
-OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
-
- /**
- * Constant: EVENT_TYPES
- * {Array(String)} Supported application event types. Register a listener
- * for a particular event with the following syntax:
- * (code)
- * layer.events.register(type, obj, listener);
- * (end)
- *
- * Listeners will be called with a reference to an event object. The
- * properties of this event depends on exactly what happened.
- *
- * All event objects have at least the following properties:
- * object - {Object} A reference to layer.events.object.
- * element - {DOMElement} A reference to layer.events.element.
- *
- * Supported map event types (in addition to those from <OpenLayers.Layer>):
- * beforefeatureadded - Triggered before a feature is added. Listeners
- * will receive an object with a *feature* property referencing the
- * feature to be added. To stop the feature from being added, a
- * listener should return false.
- * beforefeaturesadded - Triggered before an array of features is added.
- * Listeners will receive an object with a *features* property
- * referencing the feature to be added. To stop the features from
- * being added, a listener should return false.
- * featureadded - Triggered after a feature is added. The event
- * object passed to listeners will have a *feature* property with a
- * reference to the added feature.
- * featuresadded - Triggered after features are added. The event
- * object passed to listeners will have a *features* property with a
- * reference to an array of added features.
- * beforefeatureremoved - Triggered before a feature is removed. Listeners
- * will receive an object with a *feature* property referencing the
- * feature to be removed.
- * beforefeaturesremoved - Triggered before multiple features are removed.
- * Listeners will receive an object with a *features* property
- * referencing the features to be removed.
- * featureremoved - Triggerd after a feature is removed. The event
- * object passed to listeners will have a *feature* property with a
- * reference to the removed feature.
- * featuresremoved - Triggered after features are removed. The event
- * object passed to listeners will have a *features* property with a
- * reference to an array of removed features.
- * featureselected - Triggered after a feature is selected. Listeners
- * will receive an object with a *feature* property referencing the
- * selected feature.
- * featureunselected - Triggered after a feature is unselected.
- * Listeners will receive an object with a *feature* property
- * referencing the unselected feature.
- * beforefeaturemodified - Triggered when a feature is selected to
- * be modified. Listeners will receive an object with a *feature*
- * property referencing the selected feature.
- * featuremodified - Triggered when a feature has been modified.
- * Listeners will receive an object with a *feature* property referencing
- * the modified feature.
- * afterfeaturemodified - Triggered when a feature is finished being modified.
- * Listeners will receive an object with a *feature* property referencing
- * the modified feature.
- * vertexmodified - Triggered when a vertex within any feature geometry
- * has been modified. Listeners will receive an object with a
- * *feature* property referencing the modified feature, a *vertex*
- * property referencing the vertex modified (always a point geometry),
- * and a *pixel* property referencing the pixel location of the
- * modification.
- * sketchstarted - Triggered when a feature sketch bound for this layer
- * is started. Listeners will receive an object with a *feature*
- * property referencing the new sketch feature and a *vertex* property
- * referencing the creation point.
- * sketchmodified - Triggered when a feature sketch bound for this layer
- * is modified. Listeners will receive an object with a *vertex*
- * property referencing the modified vertex and a *feature* property
- * referencing the sketch feature.
- * sketchcomplete - Triggered when a feature sketch bound for this layer
- * is complete. Listeners will receive an object with a *feature*
- * property referencing the sketch feature. By returning false, a
- * listener can stop the sketch feature from being added to the layer.
- * refresh - Triggered when something wants a strategy to ask the protocol
- * for a new set of features.
- */
- EVENT_TYPES: ["beforefeatureadded", "beforefeaturesadded",
- "featureadded", "featuresadded", "beforefeatureremoved",
- "beforefeaturesremoved", "featureremoved", "featuresremoved",
- "beforefeatureselected", "featureselected", "featureunselected",
- "beforefeaturemodified", "featuremodified", "afterfeaturemodified",
- "vertexmodified", "sketchstarted", "sketchmodified",
- "sketchcomplete", "refresh"],
-
- /**
- * APIProperty: isBaseLayer
- * {Boolean} The layer is a base layer. Default is false. Set this property
- * in the layer options.
- */
- isBaseLayer: false,
-
- /**
- * APIProperty: isFixed
- * {Boolean} Whether the layer remains in one place while dragging the
- * map.
- */
- isFixed: false,
-
- /**
- * APIProperty: isVector
- * {Boolean} Whether the layer is a vector layer.
- */
- isVector: true,
-
- /**
- * APIProperty: features
- * {Array(<OpenLayers.Feature.Vector>)}
- */
- features: null,
-
- /**
- * Property: filter
- * {<OpenLayers.Filter>} The filter set in this layer,
- * a strategy launching read requests can combined
- * this filter with its own filter.
- */
- filter: null,
-
- /**
- * Property: selectedFeatures
- * {Array(<OpenLayers.Feature.Vector>)}
- */
- selectedFeatures: null,
-
- /**
- * Property: unrenderedFeatures
- * {Object} hash of features, keyed by feature.id, that the renderer
- * failed to draw
- */
- unrenderedFeatures: null,
-
- /**
- * APIProperty: reportError
- * {Boolean} report friendly error message when loading of renderer
- * fails.
- */
- reportError: true,
-
- /**
- * APIProperty: style
- * {Object} Default style for the layer
- */
- style: null,
-
- /**
- * Property: styleMap
- * {<OpenLayers.StyleMap>}
- */
- styleMap: null,
-
- /**
- * Property: strategies
- * {Array(<OpenLayers.Strategy>})} Optional list of strategies for the layer.
- */
- strategies: null,
-
- /**
- * Property: protocol
- * {<OpenLayers.Protocol>} Optional protocol for the layer.
- */
- protocol: null,
-
- /**
- * Property: renderers
- * {Array(String)} List of supported Renderer classes. Add to this list to
- * add support for additional renderers. This list is ordered:
- * the first renderer which returns true for the 'supported()'
- * method will be used, if not defined in the 'renderer' option.
- */
- renderers: ['SVG', 'VML', 'Canvas'],
-
- /**
- * Property: renderer
- * {<OpenLayers.Renderer>}
- */
- renderer: null,
-
- /**
- * APIProperty: rendererOptions
- * {Object} Options for the renderer. See {<OpenLayers.Renderer>} for
- * supported options.
- */
- rendererOptions: null,
-
- /**
- * APIProperty: geometryType
- * {String} geometryType allows you to limit the types of geometries this
- * layer supports. This should be set to something like
- * "OpenLayers.Geometry.Point" to limit types.
- */
- geometryType: null,
-
- /**
- * Property: drawn
- * {Boolean} Whether the Vector Layer features have been drawn yet.
- */
- drawn: false,
-
- /**
- * Constructor: OpenLayers.Layer.Vector
- * Create a new vector layer
- *
- * Parameters:
- * name - {String} A name for the layer
- * options - {Object} Optional object with non-default properties to set on
- * the layer.
- *
- * Returns:
- * {<OpenLayers.Layer.Vector>} A new vector layer
- */
- initialize: function(name, options) {
-
- // concatenate events specific to vector with those from the base
- this.EVENT_TYPES =
- OpenLayers.Layer.Vector.prototype.EVENT_TYPES.concat(
- OpenLayers.Layer.prototype.EVENT_TYPES
- );
-
- OpenLayers.Layer.prototype.initialize.apply(this, arguments);
-
- // allow user-set renderer, otherwise assign one
- if (!this.renderer || !this.renderer.supported()) {
- this.assignRenderer();
- }
-
- // if no valid renderer found, display error
- if (!this.renderer || !this.renderer.supported()) {
- this.renderer = null;
- this.displayError();
- }
-
- if (!this.styleMap) {
- this.styleMap = new OpenLayers.StyleMap();
- }
-
- this.features = [];
- this.selectedFeatures = [];
- this.unrenderedFeatures = {};
-
- // Allow for custom layer behavior
- if(this.strategies){
- for(var i=0, len=this.strategies.length; i<len; i++) {
- this.strategies[i].setLayer(this);
- }
- }
-
- },
-
- /**
- * APIMethod: destroy
- * Destroy this layer
- */
- destroy: function() {
- if (this.strategies) {
- var strategy, i, len;
- for(i=0, len=this.strategies.length; i<len; i++) {
- strategy = this.strategies[i];
- if(strategy.autoDestroy) {
- strategy.destroy();
- }
- }
- this.strategies = null;
- }
- if (this.protocol) {
- if(this.protocol.autoDestroy) {
- this.protocol.destroy();
- }
- this.protocol = null;
- }
- this.destroyFeatures();
- this.features = null;
- this.selectedFeatures = null;
- this.unrenderedFeatures = null;
- if (this.renderer) {
- this.renderer.destroy();
- }
- this.renderer = null;
- this.geometryType = null;
- this.drawn = null;
- OpenLayers.Layer.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: clone
- * Create a clone of this layer.
- *
- * Note: Features of the layer are also cloned.
- *
- * Returns:
- * {<OpenLayers.Layer.Vector>} An exact clone of this layer
- */
- clone: function (obj) {
-
- if (obj == null) {
- obj = new OpenLayers.Layer.Vector(this.name, this.getOptions());
- }
-
- //get all additions from superclasses
- obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]);
-
- // copy/set any non-init, non-simple values here
- var features = this.features;
- var len = features.length;
- var clonedFeatures = new Array(len);
- for(var i=0; i<len; ++i) {
- clonedFeatures[i] = features[i].clone();
- }
- obj.features = clonedFeatures;
-
- return obj;
- },
-
- /**
- * Method: refresh
- * Ask the layer to request features again and redraw them. Triggers
- * the refresh event if the layer is in range and visible.
- *
- * Parameters:
- * obj - {Object} Optional object with properties for any listener of
- * the refresh event.
- */
- refresh: function(obj) {
- if(this.calculateInRange() && this.visibility) {
- this.events.triggerEvent("refresh", obj);
- }
- },
-
- /**
- * Method: assignRenderer
- * Iterates through the available renderer implementations and selects
- * and assigns the first one whose "supported()" function returns true.
- */
- assignRenderer: function() {
- for (var i=0, len=this.renderers.length; i<len; i++) {
- var rendererClass = this.renderers[i];
- var renderer = (typeof rendererClass == "function") ?
- rendererClass :
- OpenLayers.Renderer[rendererClass];
- if (renderer && renderer.prototype.supported()) {
- this.renderer = new renderer(this.div, this.rendererOptions);
- break;
- }
- }
- },
-
- /**
- * Method: displayError
- * Let the user know their browser isn't supported.
- */
- displayError: function() {
- if (this.reportError) {
- OpenLayers.Console.userError(OpenLayers.i18n("browserNotSupported",
- {'renderers':this.renderers.join("\n")}));
- }
- },
-
- /**
- * Method: setMap
- * The layer has been added to the map.
- *
- * If there is no renderer set, the layer can't be used. Remove it.
- * Otherwise, give the renderer a reference to the map and set its size.
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- setMap: function(map) {
- OpenLayers.Layer.prototype.setMap.apply(this, arguments);
-
- if (!this.renderer) {
- this.map.removeLayer(this);
- } else {
- this.renderer.map = this.map;
- this.renderer.setSize(this.map.getSize());
- }
- },
-
- /**
- * Method: afterAdd
- * Called at the end of the map.addLayer sequence. At this point, the map
- * will have a base layer. Any autoActivate strategies will be
- * activated here.
- */
- afterAdd: function() {
- if(this.strategies) {
- var strategy, i, len;
- for(i=0, len=this.strategies.length; i<len; i++) {
- strategy = this.strategies[i];
- if(strategy.autoActivate) {
- strategy.activate();
- }
- }
- }
- },
-
- /**
- * Method: removeMap
- * The layer has been removed from the map.
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- removeMap: function(map) {
- this.drawn = false;
- if(this.strategies) {
- var strategy, i, len;
- for(i=0, len=this.strategies.length; i<len; i++) {
- strategy = this.strategies[i];
- if(strategy.autoActivate) {
- strategy.deactivate();
- }
- }
- }
- },
-
- /**
- * Method: onMapResize
- * Notify the renderer of the change in size.
- *
- */
- onMapResize: function() {
- OpenLayers.Layer.prototype.onMapResize.apply(this, arguments);
- this.renderer.setSize(this.map.getSize());
- },
-
- /**
- * Method: moveTo
- * Reset the vector layer's div so that it once again is lined up with
- * the map. Notify the renderer of the change of extent, and in the
- * case of a change of zoom level (resolution), have the
- * renderer redraw features.
- *
- * If the layer has not yet been drawn, cycle through the layer's
- * features and draw each one.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * zoomChanged - {Boolean}
- * dragging - {Boolean}
- */
- moveTo: function(bounds, zoomChanged, dragging) {
- OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
-
- var coordSysUnchanged = true;
-
- if (!dragging) {
- this.renderer.root.style.visibility = "hidden";
-
- this.div.style.left = -parseInt(this.map.layerContainerDiv.style.left) + "px";
- this.div.style.top = -parseInt(this.map.layerContainerDiv.style.top) + "px";
- var extent = this.map.getExtent();
- coordSysUnchanged = this.renderer.setExtent(extent, zoomChanged);
-
- this.renderer.root.style.visibility = "visible";
-
- // Force a reflow on gecko based browsers to prevent jump/flicker.
- // This seems to happen on only certain configurations; it was originally
- // noticed in FF 2.0 and Linux.
- if (navigator.userAgent.toLowerCase().indexOf("gecko") != -1) {
- this.div.scrollLeft = this.div.scrollLeft;
- }
-
- if(!zoomChanged && coordSysUnchanged) {
- for(var i in this.unrenderedFeatures) {
- var feature = this.unrenderedFeatures[i];
- this.drawFeature(feature);
- }
- }
- }
-
- if (!this.drawn || zoomChanged || !coordSysUnchanged) {
- this.drawn = true;
- var feature;
- for(var i=0, len=this.features.length; i<len; i++) {
- this.renderer.locked = (i !== (len - 1));
- feature = this.features[i];
- this.drawFeature(feature);
- }
- }
- },
-
- /**
- * APIMethod: display
- * Hide or show the Layer
- *
- * Parameters:
- * display - {Boolean}
- */
- display: function(display) {
- OpenLayers.Layer.prototype.display.apply(this, arguments);
- // we need to set the display style of the root in case it is attached
- // to a foreign layer
- var currentDisplay = this.div.style.display;
- if(currentDisplay != this.renderer.root.style.display) {
- this.renderer.root.style.display = currentDisplay;
- }
- },
-
- /**
- * APIMethod: addFeatures
- * Add Features to the layer.
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>)}
- * options - {Object}
- */
- addFeatures: function(features, options) {
- if (!(features instanceof Array)) {
- features = [features];
- }
-
- var notify = !options || !options.silent;
- if(notify) {
- var event = {features: features};
- var ret = this.events.triggerEvent("beforefeaturesadded", event);
- if(ret === false) {
- return;
- }
- features = event.features;
- }
-
- // Track successfully added features for featuresadded event, since
- // beforefeatureadded can veto single features.
- var featuresAdded = [];
- for (var i=0, len=features.length; i<len; i++) {
- if (i != (features.length - 1)) {
- this.renderer.locked = true;
- } else {
- this.renderer.locked = false;
- }
- var feature = features[i];
-
- if (this.geometryType &&
- !(feature.geometry instanceof this.geometryType)) {
- var throwStr = OpenLayers.i18n('componentShouldBe',
- {'geomType':this.geometryType.prototype.CLASS_NAME});
- throw throwStr;
- }
-
- //give feature reference to its layer
- feature.layer = this;
-
- if (!feature.style && this.style) {
- feature.style = OpenLayers.Util.extend({}, this.style);
- }
-
- if (notify) {
- if(this.events.triggerEvent("beforefeatureadded",
- {feature: feature}) === false) {
- continue;
- };
- this.preFeatureInsert(feature);
- }
-
- featuresAdded.push(feature);
- this.features.push(feature);
- this.drawFeature(feature);
-
- if (notify) {
- this.events.triggerEvent("featureadded", {
- feature: feature
- });
- this.onFeatureInsert(feature);
- }
- }
-
- if(notify) {
- this.events.triggerEvent("featuresadded", {features: featuresAdded});
- }
- },
-
-
- /**
- * APIMethod: removeFeatures
- * Remove features from the layer. This erases any drawn features and
- * removes them from the layer's control. The beforefeatureremoved
- * and featureremoved events will be triggered for each feature. The
- * featuresremoved event will be triggered after all features have
- * been removed. To supress event triggering, use the silent option.
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>)} List of features to be
- * removed.
- * options - {Object} Optional properties for changing behavior of the
- * removal.
- *
- * Valid options:
- * silent - {Boolean} Supress event triggering. Default is false.
- */
- removeFeatures: function(features, options) {
- if(!features || features.length === 0) {
- return;
- }
- if (features === this.features) {
- return this.removeAllFeatures(options);
- }
- if (!(features instanceof Array)) {
- features = [features];
- }
- if (features === this.selectedFeatures) {
- features = features.slice();
- }
-
- var notify = !options || !options.silent;
-
- if (notify) {
- this.events.triggerEvent(
- "beforefeaturesremoved", {features: features}
- );
- }
-
- for (var i = features.length - 1; i >= 0; i--) {
- // We remain locked so long as we're not at 0
- // and the 'next' feature has a geometry. We do the geometry check
- // because if all the features after the current one are 'null', we
- // won't call eraseGeometry, so we break the 'renderer functions
- // will always be called with locked=false *last*' rule. The end result
- // is a possible gratiutious unlocking to save a loop through the rest
- // of the list checking the remaining features every time. So long as
- // null geoms are rare, this is probably okay.
- if (i != 0 && features[i-1].geometry) {
- this.renderer.locked = true;
- } else {
- this.renderer.locked = false;
- }
-
- var feature = features[i];
- delete this.unrenderedFeatures[feature.id];
-
- if (notify) {
- this.events.triggerEvent("beforefeatureremoved", {
- feature: feature
- });
- }
-
- this.features = OpenLayers.Util.removeItem(this.features, feature);
- // feature has no layer at this point
- feature.layer = null;
-
- if (feature.geometry) {
- this.renderer.eraseFeatures(feature);
- }
-
- //in the case that this feature is one of the selected features,
- // remove it from that array as well.
- if (OpenLayers.Util.indexOf(this.selectedFeatures, feature) != -1){
- OpenLayers.Util.removeItem(this.selectedFeatures, feature);
- }
-
- if (notify) {
- this.events.triggerEvent("featureremoved", {
- feature: feature
- });
- }
- }
-
- if (notify) {
- this.events.triggerEvent("featuresremoved", {features: features});
- }
- },
-
- /**
- * APIMethod: removeAllFeatures
- * Remove all features from the layer.
- *
- * Parameters:
- * options - {Object} Optional properties for changing behavior of the
- * removal.
- *
- * Valid options:
- * silent - {Boolean} Supress event triggering. Default is false.
- */
- removeAllFeatures: function(options) {
- var notify = !options || !options.silent;
- var features = this.features;
- if (notify) {
- this.events.triggerEvent(
- "beforefeaturesremoved", {features: features}
- );
- }
- var feature;
- for (var i = features.length-1; i >= 0; i--) {
- feature = features[i];
- if (notify) {
- this.events.triggerEvent("beforefeatureremoved", {
- feature: feature
- });
- }
- feature.layer = null;
- if (notify) {
- this.events.triggerEvent("featureremoved", {
- feature: feature
- });
- }
- }
- this.renderer.clear();
- this.features = [];
- this.unrenderedFeatures = {};
- this.selectedFeatures = [];
- if (notify) {
- this.events.triggerEvent("featuresremoved", {features: features});
- }
- },
-
- /**
- * APIMethod: destroyFeatures
- * Erase and destroy features on the layer.
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>)} An optional array of
- * features to destroy. If not supplied, all features on the layer
- * will be destroyed.
- * options - {Object}
- */
- destroyFeatures: function(features, options) {
- var all = (features == undefined); // evaluates to true if
- // features is null
- if(all) {
- features = this.features;
- }
- if(features) {
- this.removeFeatures(features, options);
- for(var i=features.length-1; i>=0; i--) {
- features[i].destroy();
- }
- }
- },
-
- /**
- * APIMethod: drawFeature
- * Draw (or redraw) a feature on the layer. If the optional style argument
- * is included, this style will be used. If no style is included, the
- * feature's style will be used. If the feature doesn't have a style,
- * the layer's style will be used.
- *
- * This function is not designed to be used when adding features to
- * the layer (use addFeatures instead). It is meant to be used when
- * the style of a feature has changed, or in some other way needs to
- * visually updated *after* it has already been added to a layer. You
- * must add the feature to the layer for most layer-related events to
- * happen.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- * style - {String | Object} Named render intent or full symbolizer object.
- */
- drawFeature: function(feature, style) {
- // don't try to draw the feature with the renderer if the layer is not
- // drawn itself
- if (!this.drawn) {
- return
- }
- if (typeof style != "object") {
- if(!style && feature.state === OpenLayers.State.DELETE) {
- style = "delete";
- }
- var renderIntent = style || feature.renderIntent;
- style = feature.style || this.style;
- if (!style) {
- style = this.styleMap.createSymbolizer(feature, renderIntent);
- }
- }
-
- if (!this.renderer.drawFeature(feature, style)) {
- this.unrenderedFeatures[feature.id] = feature;
- } else {
- delete this.unrenderedFeatures[feature.id];
- };
- },
-
- /**
- * Method: eraseFeatures
- * Erase features from the layer.
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>)}
- */
- eraseFeatures: function(features) {
- this.renderer.eraseFeatures(features);
- },
-
- /**
- * Method: getFeatureFromEvent
- * Given an event, return a feature if the event occurred over one.
- * Otherwise, return null.
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {<OpenLayers.Feature.Vector>} A feature if one was under the event.
- */
- getFeatureFromEvent: function(evt) {
- if (!this.renderer) {
- OpenLayers.Console.error(OpenLayers.i18n("getFeatureError"));
- return null;
- }
- var featureId = this.renderer.getFeatureIdFromEvent(evt);
- return this.getFeatureById(featureId);
- },
-
- /**
- * APIMethod: getFeatureBy
- * Given a property value, return the feature if it exists in the features array
- *
- * Parameters:
- * property - {String}
- * value - {String}
- *
- * Returns:
- * {<OpenLayers.Feature.Vector>} A feature corresponding to the given
- * property value or null if there is no such feature.
- */
- getFeatureBy: function(property, value) {
- //TBD - would it be more efficient to use a hash for this.features?
- var feature = null;
- for(var i=0, len=this.features.length; i<len; ++i) {
- if(this.features[i][property] == value) {
- feature = this.features[i];
- break;
- }
- }
- return feature;
- },
-
- /**
- * APIMethod: getFeatureById
- * Given a feature id, return the feature if it exists in the features array
- *
- * Parameters:
- * featureId - {String}
- *
- * Returns:
- * {<OpenLayers.Feature.Vector>} A feature corresponding to the given
- * featureId or null if there is no such feature.
- */
- getFeatureById: function(featureId) {
- return this.getFeatureBy('id', featureId);
- },
-
- /**
- * APIMethod: getFeatureByFid
- * Given a feature fid, return the feature if it exists in the features array
- *
- * Parameters:
- * featureFid - {String}
- *
- * Returns:
- * {<OpenLayers.Feature.Vector>} A feature corresponding to the given
- * featureFid or null if there is no such feature.
- */
- getFeatureByFid: function(featureFid) {
- return this.getFeatureBy('fid', featureFid);
- },
-
- /**
- * Unselect the selected features
- * i.e. clears the featureSelection array
- * change the style back
- clearSelection: function() {
-
- var vectorLayer = this.map.vectorLayer;
- for (var i = 0; i < this.map.featureSelection.length; i++) {
- var featureSelection = this.map.featureSelection[i];
- vectorLayer.drawFeature(featureSelection, vectorLayer.style);
- }
- this.map.featureSelection = [];
- },
- */
-
-
- /**
- * APIMethod: onFeatureInsert
- * method called after a feature is inserted.
- * Does nothing by default. Override this if you
- * need to do something on feature updates.
- *
- * Paarameters:
- * feature - {<OpenLayers.Feature.Vector>}
- */
- onFeatureInsert: function(feature) {
- },
-
- /**
- * APIMethod: preFeatureInsert
- * method called before a feature is inserted.
- * Does nothing by default. Override this if you
- * need to do something when features are first added to the
- * layer, but before they are drawn, such as adjust the style.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- */
- preFeatureInsert: function(feature) {
- },
-
- /**
- * APIMethod: getDataExtent
- * Calculates the max extent which includes all of the features.
- *
- * Returns:
- * {<OpenLayers.Bounds>}
- */
- getDataExtent: function () {
- var maxExtent = null;
- var features = this.features;
- if(features && (features.length > 0)) {
- maxExtent = new OpenLayers.Bounds();
- var geometry = null;
- for(var i=0, len=features.length; i<len; i++) {
- geometry = features[i].geometry;
- if (geometry) {
- maxExtent.extend(geometry.getBounds());
- }
- }
- }
- return maxExtent;
- },
-
- CLASS_NAME: "OpenLayers.Layer.Vector"
-});
-/* ======================================================================
OpenLayers/Geometry/MultiPoint.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
@@ -35675,1046 +19888,10 @@
CLASS_NAME: "OpenLayers.Geometry.MultiPoint"
});
/* ======================================================================
- OpenLayers/Handler/Point.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Handler.js
- * @requires OpenLayers/Geometry/Point.js
- */
-
-/**
- * Class: OpenLayers.Handler.Point
- * Handler to draw a point on the map. Point is displayed on mouse down,
- * moves on mouse move, and is finished on mouse up. The handler triggers
- * callbacks for 'done', 'cancel', and 'modify'. The modify callback is
- * called with each change in the sketch and will receive the latest point
- * drawn. Create a new instance with the <OpenLayers.Handler.Point>
- * constructor.
- *
- * Inherits from:
- * - <OpenLayers.Handler>
- */
-OpenLayers.Handler.Point = OpenLayers.Class(OpenLayers.Handler, {
-
- /**
- * Property: point
- * {<OpenLayers.Feature.Vector>} The currently drawn point
- */
- point: null,
-
- /**
- * Property: layer
- * {<OpenLayers.Layer.Vector>} The temporary drawing layer
- */
- layer: null,
-
- /**
- * APIProperty: multi
- * {Boolean} Cast features to multi-part geometries before passing to the
- * layer. Default is false.
- */
- multi: false,
-
- /**
- * Property: drawing
- * {Boolean} A point is being drawn
- */
- drawing: false,
-
- /**
- * Property: mouseDown
- * {Boolean} The mouse is down
- */
- mouseDown: false,
-
- /**
- * Property: lastDown
- * {<OpenLayers.Pixel>} Location of the last mouse down
- */
- lastDown: null,
-
- /**
- * Property: lastUp
- * {<OpenLayers.Pixel>}
- */
- lastUp: null,
-
- /**
- * APIProperty: persist
- * {Boolean} Leave the feature rendered until destroyFeature is called.
- * Default is false. If set to true, the feature remains rendered until
- * destroyFeature is called, typically by deactivating the handler or
- * starting another drawing.
- */
- persist: false,
-
- /**
- * Property: layerOptions
- * {Object} Any optional properties to be set on the sketch layer.
- */
- layerOptions: null,
-
- /**
- * Constructor: OpenLayers.Handler.Point
- * Create a new point handler.
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that owns this handler
- * callbacks - {Object} An object with a properties whose values are
- * functions. Various callbacks described below.
- * options - {Object} An optional object with properties to be set on the
- * handler
- *
- * Named callbacks:
- * create - Called when a sketch is first created. Callback called with
- * the creation point geometry and sketch feature.
- * modify - Called with each move of a vertex with the vertex (point)
- * geometry and the sketch feature.
- * done - Called when the point drawing is finished. The callback will
- * recieve a single argument, the point geometry.
- * cancel - Called when the handler is deactivated while drawing. The
- * cancel callback will receive a geometry.
- */
- initialize: function(control, callbacks, options) {
- if(!(options && options.layerOptions && options.layerOptions.styleMap)) {
- this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {});
- }
-
- OpenLayers.Handler.prototype.initialize.apply(this, arguments);
- },
-
- /**
- * APIMethod: activate
- * turn on the handler
- */
- activate: function() {
- if(!OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
- return false;
- }
- // create temporary vector layer for rendering geometry sketch
- // TBD: this could be moved to initialize/destroy - setting visibility here
- var options = OpenLayers.Util.extend({
- displayInLayerSwitcher: false,
- // indicate that the temp vector layer will never be out of range
- // without this, resolution properties must be specified at the
- // map-level for this temporary layer to init its resolutions
- // correctly
- calculateInRange: OpenLayers.Function.True
- }, this.layerOptions);
- this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options);
- this.map.addLayer(this.layer);
- return true;
- },
-
- /**
- * Method: createFeature
- * Add temporary features
- *
- * Parameters:
- * pixel - {<OpenLayers.Pixel>} A pixel location on the map.
- */
- createFeature: function(pixel) {
- var lonlat = this.map.getLonLatFromPixel(pixel);
- this.point = new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
- );
- this.callback("create", [this.point.geometry, this.point]);
- this.point.geometry.clearBounds();
- this.layer.addFeatures([this.point], {silent: true});
- },
-
- /**
- * APIMethod: deactivate
- * turn off the handler
- */
- deactivate: function() {
- if(!OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
- return false;
- }
- // call the cancel callback if mid-drawing
- if(this.drawing) {
- this.cancel();
- }
- this.destroyFeature();
- // If a layer's map property is set to null, it means that that layer
- // isn't added to the map. Since we ourself added the layer to the map
- // in activate(), we can assume that if this.layer.map is null it means
- // that the layer has been destroyed (as a result of map.destroy() for
- // example.
- if (this.layer.map != null) {
- this.layer.destroy(false);
- }
- this.layer = null;
- return true;
- },
-
- /**
- * Method: destroyFeature
- * Destroy the temporary geometries
- */
- destroyFeature: function() {
- if(this.layer) {
- this.layer.destroyFeatures();
- }
- this.point = null;
- },
-
- /**
- * Method: finalize
- * Finish the geometry and call the "done" callback.
- *
- * Parameters:
- * cancel - {Boolean} Call cancel instead of done callback. Default is
- * false.
- */
- finalize: function(cancel) {
- var key = cancel ? "cancel" : "done";
- this.drawing = false;
- this.mouseDown = false;
- this.lastDown = null;
- this.lastUp = null;
- this.callback(key, [this.geometryClone()]);
- if(cancel || !this.persist) {
- this.destroyFeature();
- }
- },
-
- /**
- * APIMethod: cancel
- * Finish the geometry and call the "cancel" callback.
- */
- cancel: function() {
- this.finalize(true);
- },
-
- /**
- * Method: click
- * Handle clicks. Clicks are stopped from propagating to other listeners
- * on map.events or other dom elements.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- click: function(evt) {
- OpenLayers.Event.stop(evt);
- return false;
- },
-
- /**
- * Method: dblclick
- * Handle double-clicks. Double-clicks are stopped from propagating to other
- * listeners on map.events or other dom elements.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- dblclick: function(evt) {
- OpenLayers.Event.stop(evt);
- return false;
- },
-
- /**
- * Method: modifyFeature
- * Modify the existing geometry given a pixel location.
- *
- * Parameters:
- * pixel - {<OpenLayers.Pixel>} A pixel location on the map.
- */
- modifyFeature: function(pixel) {
- var lonlat = this.map.getLonLatFromPixel(pixel);
- this.point.geometry.x = lonlat.lon;
- this.point.geometry.y = lonlat.lat;
- this.callback("modify", [this.point.geometry, this.point]);
- this.point.geometry.clearBounds();
- this.drawFeature();
- },
-
- /**
- * Method: drawFeature
- * Render features on the temporary layer.
- */
- drawFeature: function() {
- this.layer.drawFeature(this.point, this.style);
- },
-
- /**
- * Method: getGeometry
- * Return the sketch geometry. If <multi> is true, this will return
- * a multi-part geometry.
- *
- * Returns:
- * {<OpenLayers.Geometry.Point>}
- */
- getGeometry: function() {
- var geometry = this.point && this.point.geometry;
- if(geometry && this.multi) {
- geometry = new OpenLayers.Geometry.MultiPoint([geometry]);
- }
- return geometry;
- },
-
- /**
- * Method: geometryClone
- * Return a clone of the relevant geometry.
- *
- * Returns:
- * {<OpenLayers.Geometry>}
- */
- geometryClone: function() {
- var geom = this.getGeometry();
- return geom && geom.clone();
- },
-
- /**
- * Method: mousedown
- * Handle mouse down. Adjust the geometry and redraw.
- * Return determines whether to propagate the event on the map.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- mousedown: function(evt) {
- // check keyboard modifiers
- if(!this.checkModifiers(evt)) {
- return true;
- }
- // ignore double-clicks
- if(this.lastDown && this.lastDown.equals(evt.xy)) {
- return true;
- }
- this.drawing = true;
- if(this.lastDown == null) {
- if(this.persist) {
- this.destroyFeature();
- }
- this.createFeature(evt.xy);
- } else {
- this.modifyFeature(evt.xy);
- }
- this.lastDown = evt.xy;
- return false;
- },
-
- /**
- * Method: mousemove
- * Handle mouse move. Adjust the geometry and redraw.
- * Return determines whether to propagate the event on the map.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- mousemove: function (evt) {
- if(this.drawing) {
- this.modifyFeature(evt.xy);
- }
- return true;
- },
-
- /**
- * Method: mouseup
- * Handle mouse up. Send the latest point in the geometry to the control.
- * Return determines whether to propagate the event on the map.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- mouseup: function (evt) {
- if(this.drawing) {
- this.finalize();
- return false;
- } else {
- return true;
- }
- },
-
- CLASS_NAME: "OpenLayers.Handler.Point"
-});
-/* ======================================================================
- OpenLayers/Protocol/HTTP.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Protocol.js
- * @requires OpenLayers/Feature/Vector.js
- * @requires OpenLayers/Filter/Spatial.js
- * @requires OpenLayers/Filter/Comparison.js
- * @requires OpenLayers/Filter/Logical.js
- * @requires OpenLayers/Request/XMLHttpRequest.js
- */
-
-/**
- * Class: OpenLayers.Protocol.HTTP
- * A basic HTTP protocol for vector layers. Create a new instance with the
- * <OpenLayers.Protocol.HTTP> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Protocol>
- */
-OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
-
- /**
- * Property: url
- * {String} Service URL, read-only, set through the options
- * passed to constructor.
- */
- url: null,
-
- /**
- * Property: headers
- * {Object} HTTP request headers, read-only, set through the options
- * passed to the constructor,
- * Example: {'Content-Type': 'plain/text'}
- */
- headers: null,
-
- /**
- * Property: params
- * {Object} Parameters of GET requests, read-only, set through the options
- * passed to the constructor,
- * Example: {'bbox': '5,5,5,5'}
- */
- params: null,
-
- /**
- * Property: callback
- * {Object} Function to be called when the <read>, <create>,
- * <update>, <delete> or <commit> operation completes, read-only,
- * set through the options passed to the constructor.
- */
- callback: null,
-
- /**
- * Property: scope
- * {Object} Callback execution scope, read-only, set through the
- * options passed to the constructor.
- */
- scope: null,
-
- /**
- * Property: readWithPOST
- * {Boolean} true if read operations are done with POST requests
- * instead of GET, defaults to false.
- */
- readWithPOST: false,
-
- /**
- * Property: wildcarded.
- * {Boolean} If true percent signs are added around values
- * read from LIKE filters, for example if the protocol
- * read method is passed a LIKE filter whose property
- * is "foo" and whose value is "bar" the string
- * "foo__ilike=%bar%" will be sent in the query string;
- * defaults to false.
- */
- wildcarded: false,
-
- /**
- * Constructor: OpenLayers.Protocol.HTTP
- * A class for giving layers generic HTTP protocol.
- *
- * Parameters:
- * options - {Object} Optional object whose properties will be set on the
- * instance.
- *
- * Valid options include:
- * url - {String}
- * headers - {Object}
- * params - {Object}
- * format - {<OpenLayers.Format>}
- * callback - {Function}
- * scope - {Object}
- */
- initialize: function(options) {
- options = options || {};
- this.params = {};
- this.headers = {};
- OpenLayers.Protocol.prototype.initialize.apply(this, arguments);
- },
-
- /**
- * APIMethod: destroy
- * Clean up the protocol.
- */
- destroy: function() {
- this.params = null;
- this.headers = null;
- OpenLayers.Protocol.prototype.destroy.apply(this);
- },
-
- /**
- * APIMethod: read
- * Construct a request for reading new features.
- *
- * Parameters:
- * options - {Object} Optional object for configuring the request.
- * This object is modified and should not be reused.
- *
- * Valid options:
- * url - {String} Url for the request.
- * params - {Object} Parameters to get serialized as a query string.
- * headers - {Object} Headers to be set on the request.
- * filter - {<OpenLayers.Filter>} Filter to get serialized as a
- * query string.
- * readWithPOST - {Boolean} If the request should be done with POST.
- *
- * Returns:
- * {<OpenLayers.Protocol.Response>} A response object, whose "priv" property
- * references the HTTP request, this object is also passed to the
- * callback function when the request completes, its "features" property
- * is then populated with the the features received from the server.
- */
- read: function(options) {
- OpenLayers.Protocol.prototype.read.apply(this, arguments);
- options = OpenLayers.Util.applyDefaults(options, this.options);
- options.params = OpenLayers.Util.applyDefaults(
- options.params, this.options.params);
- if(options.filter) {
- options.params = this.filterToParams(
- options.filter, options.params);
- }
- var readWithPOST = (options.readWithPOST !== undefined) ?
- options.readWithPOST : this.readWithPOST;
- var resp = new OpenLayers.Protocol.Response({requestType: "read"});
- if(readWithPOST) {
- resp.priv = OpenLayers.Request.POST({
- url: options.url,
- callback: this.createCallback(this.handleRead, resp, options),
- data: OpenLayers.Util.getParameterString(options.params),
- headers: {
- "Content-Type": "application/x-www-form-urlencoded"
- }
- });
- } else {
- resp.priv = OpenLayers.Request.GET({
- url: options.url,
- callback: this.createCallback(this.handleRead, resp, options),
- params: options.params,
- headers: options.headers
- });
- }
- return resp;
- },
-
- /**
- * Method: handleRead
- * Individual callbacks are created for read, create and update, should
- * a subclass need to override each one separately.
- *
- * Parameters:
- * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
- * the user callback.
- * options - {Object} The user options passed to the read call.
- */
- handleRead: function(resp, options) {
- this.handleResponse(resp, options);
- },
-
- /**
- * Method: filterToParams
- * Convert an <OpenLayers.Filter> object to parameters.
- *
- * Parameters:
- * filter - {OpenLayers.Filter} filter to convert.
- * params - {Object} The parameters object.
- *
- * Returns:
- * {Object} The resulting parameters object.
- */
- filterToParams: function(filter, params) {
- params = params || {};
- var className = filter.CLASS_NAME;
- var filterType = className.substring(className.lastIndexOf(".") + 1);
- switch(filterType) {
- case "Spatial":
- switch(filter.type) {
- case OpenLayers.Filter.Spatial.BBOX:
- params.bbox = filter.value.toArray();
- break;
- case OpenLayers.Filter.Spatial.DWITHIN:
- params.tolerance = filter.distance;
- // no break here
- case OpenLayers.Filter.Spatial.WITHIN:
- params.lon = filter.value.x;
- params.lat = filter.value.y;
- break;
- default:
- OpenLayers.Console.warn(
- "Unknown spatial filter type " + filter.type);
- }
- break;
- case "Comparison":
- var op = OpenLayers.Protocol.HTTP.COMP_TYPE_TO_OP_STR[filter.type];
- if(op !== undefined) {
- var value = filter.value;
- if(filter.type == OpenLayers.Filter.Comparison.LIKE) {
- value = this.regex2value(value);
- if(this.wildcarded) {
- value = "%" + value + "%";
- }
- }
- params[filter.property + "__" + op] = value;
- params.queryable = params.queryable || [];
- params.queryable.push(filter.property);
- } else {
- OpenLayers.Console.warn(
- "Unknown comparison filter type " + filter.type);
- }
- break;
- case "Logical":
- if(filter.type === OpenLayers.Filter.Logical.AND) {
- for(var i=0,len=filter.filters.length; i<len; i++) {
- params = this.filterToParams(filter.filters[i], params);
- }
- } else {
- OpenLayers.Console.warn(
- "Unsupported logical filter type " + filter.type);
- }
- break;
- default:
- OpenLayers.Console.warn("Unknown filter type " + filterType);
- }
- return params;
- },
-
- /**
- * Method: regex2value
- * Convert the value from a regular expression string to a LIKE/ILIKE
- * string known to the web service.
- *
- * Parameters:
- * value - {String} The regex string.
- *
- * Returns:
- * {String} The converted string.
- */
- regex2value: function(value) {
-
- // highly sensitive!! Do not change this without running the
- // Protocol/HTTP.html unit tests
-
- // convert % to \%
- value = value.replace(/%/g, "\\%");
-
- // convert \\. to \\_ (\\.* occurences converted later)
- value = value.replace(/\\\\\.(\*)?/g, function($0, $1) {
- return $1 ? $0 : "\\\\_";
- });
-
- // convert \\.* to \\%
- value = value.replace(/\\\\\.\*/g, "\\\\%");
-
- // convert . to _ (\. and .* occurences converted later)
- value = value.replace(/(\\)?\.(\*)?/g, function($0, $1, $2) {
- return $1 || $2 ? $0 : "_";
- });
-
- // convert .* to % (\.* occurnces converted later)
- value = value.replace(/(\\)?\.\*/g, function($0, $1) {
- return $1 ? $0 : "%";
- });
-
- // convert \. to .
- value = value.replace(/\\\./g, ".");
-
- // replace \* with * (watching out for \\*)
- value = value.replace(/(\\)?\\\*/g, function($0, $1) {
- return $1 ? $0 : "*";
- });
-
- return value;
- },
-
- /**
- * APIMethod: create
- * Construct a request for writing newly created features.
- *
- * Parameters:
- * features - {Array({<OpenLayers.Feature.Vector>})} or
- * {<OpenLayers.Feature.Vector>}
- * options - {Object} Optional object for configuring the request.
- * This object is modified and should not be reused.
- *
- * Returns:
- * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
- * object, whose "priv" property references the HTTP request, this
- * object is also passed to the callback function when the request
- * completes, its "features" property is then populated with the
- * the features received from the server.
- */
- create: function(features, options) {
- options = OpenLayers.Util.applyDefaults(options, this.options);
-
- var resp = new OpenLayers.Protocol.Response({
- reqFeatures: features,
- requestType: "create"
- });
-
- resp.priv = OpenLayers.Request.POST({
- url: options.url,
- callback: this.createCallback(this.handleCreate, resp, options),
- headers: options.headers,
- data: this.format.write(features)
- });
-
- return resp;
- },
-
- /**
- * Method: handleCreate
- * Called the the request issued by <create> is complete. May be overridden
- * by subclasses.
- *
- * Parameters:
- * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
- * any user callback.
- * options - {Object} The user options passed to the create call.
- */
- handleCreate: function(resp, options) {
- this.handleResponse(resp, options);
- },
-
- /**
- * APIMethod: update
- * Construct a request updating modified feature.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- * options - {Object} Optional object for configuring the request.
- * This object is modified and should not be reused.
- *
- * Returns:
- * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
- * object, whose "priv" property references the HTTP request, this
- * object is also passed to the callback function when the request
- * completes, its "features" property is then populated with the
- * the feature received from the server.
- */
- update: function(feature, options) {
- options = options || {};
- var url = options.url ||
- feature.url ||
- this.options.url + "/" + feature.fid;
- options = OpenLayers.Util.applyDefaults(options, this.options);
-
- var resp = new OpenLayers.Protocol.Response({
- reqFeatures: feature,
- requestType: "update"
- });
-
- resp.priv = OpenLayers.Request.PUT({
- url: url,
- callback: this.createCallback(this.handleUpdate, resp, options),
- headers: options.headers,
- data: this.format.write(feature)
- });
-
- return resp;
- },
-
- /**
- * Method: handleUpdate
- * Called the the request issued by <update> is complete. May be overridden
- * by subclasses.
- *
- * Parameters:
- * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
- * any user callback.
- * options - {Object} The user options passed to the update call.
- */
- handleUpdate: function(resp, options) {
- this.handleResponse(resp, options);
- },
-
- /**
- * APIMethod: delete
- * Construct a request deleting a removed feature.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- * options - {Object} Optional object for configuring the request.
- * This object is modified and should not be reused.
- *
- * Returns:
- * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
- * object, whose "priv" property references the HTTP request, this
- * object is also passed to the callback function when the request
- * completes.
- */
- "delete": function(feature, options) {
- options = options || {};
- var url = options.url ||
- feature.url ||
- this.options.url + "/" + feature.fid;
- options = OpenLayers.Util.applyDefaults(options, this.options);
-
- var resp = new OpenLayers.Protocol.Response({
- reqFeatures: feature,
- requestType: "delete"
- });
-
- resp.priv = OpenLayers.Request.DELETE({
- url: url,
- callback: this.createCallback(this.handleDelete, resp, options),
- headers: options.headers
- });
-
- return resp;
- },
-
- /**
- * Method: handleDelete
- * Called the the request issued by <delete> is complete. May be overridden
- * by subclasses.
- *
- * Parameters:
- * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
- * any user callback.
- * options - {Object} The user options passed to the delete call.
- */
- handleDelete: function(resp, options) {
- this.handleResponse(resp, options);
- },
-
- /**
- * Method: handleResponse
- * Called by CRUD specific handlers.
- *
- * Parameters:
- * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
- * any user callback.
- * options - {Object} The user options passed to the create, read, update,
- * or delete call.
- */
- handleResponse: function(resp, options) {
- var request = resp.priv;
- if(options.callback) {
- if(request.status >= 200 && request.status < 300) {
- // success
- if(resp.requestType != "delete") {
- resp.features = this.parseFeatures(request);
- }
- resp.code = OpenLayers.Protocol.Response.SUCCESS;
- } else {
- // failure
- resp.code = OpenLayers.Protocol.Response.FAILURE;
- }
- options.callback.call(options.scope, resp);
- }
- },
-
- /**
- * Method: parseFeatures
- * Read HTTP response body and return features.
- *
- * Parameters:
- * request - {XMLHttpRequest} The request object
- *
- * Returns:
- * {Array({<OpenLayers.Feature.Vector>})} or
- * {<OpenLayers.Feature.Vector>} Array of features or a single feature.
- */
- parseFeatures: function(request) {
- var doc = request.responseXML;
- if (!doc || !doc.documentElement) {
- doc = request.responseText;
- }
- if (!doc || doc.length <= 0) {
- return null;
- }
- return this.format.read(doc);
- },
-
- /**
- * APIMethod: commit
- * Iterate over each feature and take action based on the feature state.
- * Possible actions are create, update and delete.
- *
- * Parameters:
- * features - {Array({<OpenLayers.Feature.Vector>})}
- * options - {Object} Optional object for setting up intermediate commit
- * callbacks.
- *
- * Valid options:
- * create - {Object} Optional object to be passed to the <create> method.
- * update - {Object} Optional object to be passed to the <update> method.
- * delete - {Object} Optional object to be passed to the <delete> method.
- * callback - {Function} Optional function to be called when the commit
- * is complete.
- * scope - {Object} Optional object to be set as the scope of the callback.
- *
- * Returns:
- * {Array(<OpenLayers.Protocol.Response>)} An array of response objects,
- * one per request made to the server, each object's "priv" property
- * references the corresponding HTTP request.
- */
- commit: function(features, options) {
- options = OpenLayers.Util.applyDefaults(options, this.options);
- var resp = [], nResponses = 0;
-
- // Divide up features before issuing any requests. This properly
- // counts requests in the event that any responses come in before
- // all requests have been issued.
- var types = {};
- types[OpenLayers.State.INSERT] = [];
- types[OpenLayers.State.UPDATE] = [];
- types[OpenLayers.State.DELETE] = [];
- var feature, list, requestFeatures = [];
- for(var i=0, len=features.length; i<len; ++i) {
- feature = features[i];
- list = types[feature.state];
- if(list) {
- list.push(feature);
- requestFeatures.push(feature);
- }
- }
- // tally up number of requests
- var nRequests = (types[OpenLayers.State.INSERT].length > 0 ? 1 : 0) +
- types[OpenLayers.State.UPDATE].length +
- types[OpenLayers.State.DELETE].length;
-
- // This response will be sent to the final callback after all the others
- // have been fired.
- var success = true;
- var finalResponse = new OpenLayers.Protocol.Response({
- reqFeatures: requestFeatures
- });
-
- function insertCallback(response) {
- var len = response.features ? response.features.length : 0;
- var fids = new Array(len);
- for(var i=0; i<len; ++i) {
- fids[i] = response.features[i].fid;
- }
- finalResponse.insertIds = fids;
- callback.apply(this, [response]);
- }
-
- function callback(response) {
- this.callUserCallback(response, options);
- success = success && response.success();
- nResponses++;
- if (nResponses >= nRequests) {
- if (options.callback) {
- finalResponse.code = success ?
- OpenLayers.Protocol.Response.SUCCESS :
- OpenLayers.Protocol.Response.FAILURE;
- options.callback.apply(options.scope, [finalResponse]);
- }
- }
- }
-
- // start issuing requests
- var queue = types[OpenLayers.State.INSERT];
- if(queue.length > 0) {
- resp.push(this.create(
- queue, OpenLayers.Util.applyDefaults(
- {callback: insertCallback, scope: this}, options.create
- )
- ));
- }
- queue = types[OpenLayers.State.UPDATE];
- for(var i=queue.length-1; i>=0; --i) {
- resp.push(this.update(
- queue[i], OpenLayers.Util.applyDefaults(
- {callback: callback, scope: this}, options.update
- ))
- );
- }
- queue = types[OpenLayers.State.DELETE];
- for(var i=queue.length-1; i>=0; --i) {
- resp.push(this["delete"](
- queue[i], OpenLayers.Util.applyDefaults(
- {callback: callback, scope: this}, options["delete"]
- ))
- );
- }
- return resp;
- },
-
- /**
- * APIMethod: abort
- * Abort an ongoing request, the response object passed to
- * this method must come from this HTTP protocol (as a result
- * of a create, read, update, delete or commit operation).
- *
- * Parameters:
- * response - {<OpenLayers.Protocol.Response>}
- */
- abort: function(response) {
- if (response) {
- response.priv.abort();
- }
- },
-
- /**
- * Method: callUserCallback
- * This method is used from within the commit method each time an
- * an HTTP response is received from the server, it is responsible
- * for calling the user-supplied callbacks.
- *
- * Parameters:
- * resp - {<OpenLayers.Protocol.Response>}
- * options - {Object} The map of options passed to the commit call.
- */
- callUserCallback: function(resp, options) {
- var opt = options[resp.requestType];
- if(opt && opt.callback) {
- opt.callback.call(opt.scope, resp);
- }
- },
-
- CLASS_NAME: "OpenLayers.Protocol.HTTP"
-});
-
-/**
- * Property: OpenLayers.Protocol.HTTP.COMP_TYPE_TO_OP_STR
- * {Object} A private class-level property mapping the
- * OpenLayers.Filter.Comparison types to the operation
- * strings of the protocol.
- */
-(function() {
- var o = OpenLayers.Protocol.HTTP.COMP_TYPE_TO_OP_STR = {};
- o[OpenLayers.Filter.Comparison.EQUAL_TO] = "eq";
- o[OpenLayers.Filter.Comparison.NOT_EQUAL_TO] = "ne";
- o[OpenLayers.Filter.Comparison.LESS_THAN] = "lt";
- o[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO] = "lte";
- o[OpenLayers.Filter.Comparison.GREATER_THAN] = "gt";
- o[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO] = "gte";
- o[OpenLayers.Filter.Comparison.LIKE] = "ilike";
-})();
-
-/* ======================================================================
OpenLayers/Geometry/Curve.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
@@ -36811,7 +19988,7 @@
OpenLayers/Geometry/LineString.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
@@ -37360,14 +20537,372 @@
}
return best;
},
+
+ /**
+ * APIMethod: simplify
+ * This function will return a simplified LineString.
+ * Simplification is based on the Douglas-Peucker algorithm.
+ *
+ *
+ * Parameters:
+ * tolerance - {number} threshhold for simplification in map units
+ *
+ * Returns:
+ * {OpenLayers.Geometry.LineString} the simplified LineString
+ */
+ simplify: function(tolerance){
+ if (this && this !== null) {
+ var points = this.getVertices();
+ if (points.length < 3) {
+ return this;
+ }
+
+ var compareNumbers = function(a, b){
+ return (a-b);
+ };
+
+ /**
+ * Private function doing the Douglas-Peucker reduction
+ */
+ var douglasPeuckerReduction = function(points, firstPoint, lastPoint, tolerance){
+ var maxDistance = 0;
+ var indexFarthest = 0;
+
+ for (var index = firstPoint, distance; index < lastPoint; index++) {
+ distance = perpendicularDistance(points[firstPoint], points[lastPoint], points[index]);
+ if (distance > maxDistance) {
+ maxDistance = distance;
+ indexFarthest = index;
+ }
+ }
+
+ if (maxDistance > tolerance && indexFarthest != firstPoint) {
+ //Add the largest point that exceeds the tolerance
+ pointIndexsToKeep.push(indexFarthest);
+ douglasPeuckerReduction(points, firstPoint, indexFarthest, tolerance);
+ douglasPeuckerReduction(points, indexFarthest, lastPoint, tolerance);
+ }
+ };
+
+ /**
+ * Private function calculating the perpendicular distance
+ * TODO: check whether OpenLayers.Geometry.LineString::distanceTo() is faster or slower
+ */
+ var perpendicularDistance = function(point1, point2, point){
+ //Area = |(1/2)(x1y2 + x2y3 + x3y1 - x2y1 - x3y2 - x1y3)| *Area of triangle
+ //Base = v((x1-x2)²+(x1-x2)²) *Base of Triangle*
+ //Area = .5*Base*H *Solve for height
+ //Height = Area/.5/Base
+
+ var area = Math.abs(0.5 * (point1.x * point2.y + point2.x * point.y + point.x * point1.y - point2.x * point1.y - point.x * point2.y - point1.x * point.y));
+ var bottom = Math.sqrt(Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2));
+ var height = area / bottom * 2;
+
+ return height;
+ };
+
+ var firstPoint = 0;
+ var lastPoint = points.length - 1;
+ var pointIndexsToKeep = [];
+
+ //Add the first and last index to the keepers
+ pointIndexsToKeep.push(firstPoint);
+ pointIndexsToKeep.push(lastPoint);
+
+ //The first and the last point cannot be the same
+ while (points[firstPoint].equals(points[lastPoint])) {
+ lastPoint--;
+ //Addition: the first point not equal to first point in the LineString is kept as well
+ pointIndexsToKeep.push(lastPoint);
+ }
+
+ douglasPeuckerReduction(points, firstPoint, lastPoint, tolerance);
+ var returnPoints = [];
+ pointIndexsToKeep.sort(compareNumbers);
+ for (var index = 0; index < pointIndexsToKeep.length; index++) {
+ returnPoints.push(points[pointIndexsToKeep[index]]);
+ }
+ return new OpenLayers.Geometry.LineString(returnPoints);
+
+ }
+ else {
+ return this;
+ }
+ },
CLASS_NAME: "OpenLayers.Geometry.LineString"
});
/* ======================================================================
+ OpenLayers/Geometry/MultiLineString.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Geometry/Collection.js
+ * @requires OpenLayers/Geometry/LineString.js
+ */
+
+/**
+ * Class: OpenLayers.Geometry.MultiLineString
+ * A MultiLineString is a geometry with multiple <OpenLayers.Geometry.LineString>
+ * components.
+ *
+ * Inherits from:
+ * - <OpenLayers.Geometry.Collection>
+ * - <OpenLayers.Geometry>
+ */
+OpenLayers.Geometry.MultiLineString = OpenLayers.Class(
+ OpenLayers.Geometry.Collection, {
+
+ /**
+ * Property: componentTypes
+ * {Array(String)} An array of class names representing the types of
+ * components that the collection can include. A null value means the
+ * component types are not restricted.
+ */
+ componentTypes: ["OpenLayers.Geometry.LineString"],
+
+ /**
+ * Constructor: OpenLayers.Geometry.MultiLineString
+ * Constructor for a MultiLineString Geometry.
+ *
+ * Parameters:
+ * components - {Array(<OpenLayers.Geometry.LineString>)}
+ *
+ */
+ initialize: function(components) {
+ OpenLayers.Geometry.Collection.prototype.initialize.apply(this,
+ arguments);
+ },
+
+ /**
+ * Method: split
+ * Use this geometry (the source) to attempt to split a target geometry.
+ *
+ * Parameters:
+ * target - {<OpenLayers.Geometry>} The target geometry.
+ * options - {Object} Properties of this object will be used to determine
+ * how the split is conducted.
+ *
+ * Valid options:
+ * mutual - {Boolean} Split the source geometry in addition to the target
+ * geometry. Default is false.
+ * edge - {Boolean} Allow splitting when only edges intersect. Default is
+ * true. If false, a vertex on the source must be within the tolerance
+ * distance of the intersection to be considered a split.
+ * tolerance - {Number} If a non-null value is provided, intersections
+ * within the tolerance distance of an existing vertex on the source
+ * will be assumed to occur at the vertex.
+ *
+ * Returns:
+ * {Array} A list of geometries (of this same type as the target) that
+ * result from splitting the target with the source geometry. The
+ * source and target geometry will remain unmodified. If no split
+ * results, null will be returned. If mutual is true and a split
+ * results, return will be an array of two arrays - the first will be
+ * all geometries that result from splitting the source geometry and
+ * the second will be all geometries that result from splitting the
+ * target geometry.
+ */
+ split: function(geometry, options) {
+ var results = null;
+ var mutual = options && options.mutual;
+ var splits, sourceLine, sourceLines, sourceSplit, targetSplit;
+ var sourceParts = [];
+ var targetParts = [geometry];
+ for(var i=0, len=this.components.length; i<len; ++i) {
+ sourceLine = this.components[i];
+ sourceSplit = false;
+ for(var j=0; j < targetParts.length; ++j) {
+ splits = sourceLine.split(targetParts[j], options);
+ if(splits) {
+ if(mutual) {
+ sourceLines = splits[0];
+ for(var k=0, klen=sourceLines.length; k<klen; ++k) {
+ if(k===0 && sourceParts.length) {
+ sourceParts[sourceParts.length-1].addComponent(
+ sourceLines[k]
+ );
+ } else {
+ sourceParts.push(
+ new OpenLayers.Geometry.MultiLineString([
+ sourceLines[k]
+ ])
+ );
+ }
+ }
+ sourceSplit = true;
+ splits = splits[1];
+ }
+ if(splits.length) {
+ // splice in new target parts
+ splits.unshift(j, 1);
+ Array.prototype.splice.apply(targetParts, splits);
+ break;
+ }
+ }
+ }
+ if(!sourceSplit) {
+ // source line was not hit
+ if(sourceParts.length) {
+ // add line to existing multi
+ sourceParts[sourceParts.length-1].addComponent(
+ sourceLine.clone()
+ );
+ } else {
+ // create a fresh multi
+ sourceParts = [
+ new OpenLayers.Geometry.MultiLineString(
+ sourceLine.clone()
+ )
+ ];
+ }
+ }
+ }
+ if(sourceParts && sourceParts.length > 1) {
+ sourceSplit = true;
+ } else {
+ sourceParts = [];
+ }
+ if(targetParts && targetParts.length > 1) {
+ targetSplit = true;
+ } else {
+ targetParts = [];
+ }
+ if(sourceSplit || targetSplit) {
+ if(mutual) {
+ results = [sourceParts, targetParts];
+ } else {
+ results = targetParts;
+ }
+ }
+ return results;
+ },
+
+ /**
+ * Method: splitWith
+ * Split this geometry (the target) with the given geometry (the source).
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>} A geometry used to split this
+ * geometry (the source).
+ * options - {Object} Properties of this object will be used to determine
+ * how the split is conducted.
+ *
+ * Valid options:
+ * mutual - {Boolean} Split the source geometry in addition to the target
+ * geometry. Default is false.
+ * edge - {Boolean} Allow splitting when only edges intersect. Default is
+ * true. If false, a vertex on the source must be within the tolerance
+ * distance of the intersection to be considered a split.
+ * tolerance - {Number} If a non-null value is provided, intersections
+ * within the tolerance distance of an existing vertex on the source
+ * will be assumed to occur at the vertex.
+ *
+ * Returns:
+ * {Array} A list of geometries (of this same type as the target) that
+ * result from splitting the target with the source geometry. The
+ * source and target geometry will remain unmodified. If no split
+ * results, null will be returned. If mutual is true and a split
+ * results, return will be an array of two arrays - the first will be
+ * all geometries that result from splitting the source geometry and
+ * the second will be all geometries that result from splitting the
+ * target geometry.
+ */
+ splitWith: function(geometry, options) {
+ var results = null;
+ var mutual = options && options.mutual;
+ var splits, targetLine, sourceLines, sourceSplit, targetSplit, sourceParts, targetParts;
+ if(geometry instanceof OpenLayers.Geometry.LineString) {
+ targetParts = [];
+ sourceParts = [geometry];
+ for(var i=0, len=this.components.length; i<len; ++i) {
+ targetSplit = false;
+ targetLine = this.components[i];
+ for(var j=0; j<sourceParts.length; ++j) {
+ splits = sourceParts[j].split(targetLine, options);
+ if(splits) {
+ if(mutual) {
+ sourceLines = splits[0];
+ if(sourceLines.length) {
+ // splice in new source parts
+ sourceLines.unshift(j, 1);
+ Array.prototype.splice.apply(sourceParts, sourceLines);
+ j += sourceLines.length - 2;
+ }
+ splits = splits[1];
+ if(splits.length === 0) {
+ splits = [targetLine.clone()];
+ }
+ }
+ for(var k=0, klen=splits.length; k<klen; ++k) {
+ if(k===0 && targetParts.length) {
+ targetParts[targetParts.length-1].addComponent(
+ splits[k]
+ );
+ } else {
+ targetParts.push(
+ new OpenLayers.Geometry.MultiLineString([
+ splits[k]
+ ])
+ );
+ }
+ }
+ targetSplit = true;
+ }
+ }
+ if(!targetSplit) {
+ // target component was not hit
+ if(targetParts.length) {
+ // add it to any existing multi-line
+ targetParts[targetParts.length-1].addComponent(
+ targetLine.clone()
+ );
+ } else {
+ // or start with a fresh multi-line
+ targetParts = [
+ new OpenLayers.Geometry.MultiLineString([
+ targetLine.clone()
+ ])
+ ];
+ }
+
+ }
+ }
+ } else {
+ results = geometry.split(this);
+ }
+ if(sourceParts && sourceParts.length > 1) {
+ sourceSplit = true;
+ } else {
+ sourceParts = [];
+ }
+ if(targetParts && targetParts.length > 1) {
+ targetSplit = true;
+ } else {
+ targetParts = [];
+ }
+ if(sourceSplit || targetSplit) {
+ if(mutual) {
+ results = [sourceParts, targetParts];
+ } else {
+ results = targetParts;
+ }
+ }
+ return results;
+ },
+
+ CLASS_NAME: "OpenLayers.Geometry.MultiLineString"
+});
+/* ======================================================================
OpenLayers/Geometry/LinearRing.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
@@ -37785,582 +21320,10 @@
CLASS_NAME: "OpenLayers.Geometry.LinearRing"
});
/* ======================================================================
- OpenLayers/Geometry/MultiLineString.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Geometry/Collection.js
- * @requires OpenLayers/Geometry/LineString.js
- */
-
-/**
- * Class: OpenLayers.Geometry.MultiLineString
- * A MultiLineString is a geometry with multiple <OpenLayers.Geometry.LineString>
- * components.
- *
- * Inherits from:
- * - <OpenLayers.Geometry.Collection>
- * - <OpenLayers.Geometry>
- */
-OpenLayers.Geometry.MultiLineString = OpenLayers.Class(
- OpenLayers.Geometry.Collection, {
-
- /**
- * Property: componentTypes
- * {Array(String)} An array of class names representing the types of
- * components that the collection can include. A null value means the
- * component types are not restricted.
- */
- componentTypes: ["OpenLayers.Geometry.LineString"],
-
- /**
- * Constructor: OpenLayers.Geometry.MultiLineString
- * Constructor for a MultiLineString Geometry.
- *
- * Parameters:
- * components - {Array(<OpenLayers.Geometry.LineString>)}
- *
- */
- initialize: function(components) {
- OpenLayers.Geometry.Collection.prototype.initialize.apply(this,
- arguments);
- },
-
- /**
- * Method: split
- * Use this geometry (the source) to attempt to split a target geometry.
- *
- * Parameters:
- * target - {<OpenLayers.Geometry>} The target geometry.
- * options - {Object} Properties of this object will be used to determine
- * how the split is conducted.
- *
- * Valid options:
- * mutual - {Boolean} Split the source geometry in addition to the target
- * geometry. Default is false.
- * edge - {Boolean} Allow splitting when only edges intersect. Default is
- * true. If false, a vertex on the source must be within the tolerance
- * distance of the intersection to be considered a split.
- * tolerance - {Number} If a non-null value is provided, intersections
- * within the tolerance distance of an existing vertex on the source
- * will be assumed to occur at the vertex.
- *
- * Returns:
- * {Array} A list of geometries (of this same type as the target) that
- * result from splitting the target with the source geometry. The
- * source and target geometry will remain unmodified. If no split
- * results, null will be returned. If mutual is true and a split
- * results, return will be an array of two arrays - the first will be
- * all geometries that result from splitting the source geometry and
- * the second will be all geometries that result from splitting the
- * target geometry.
- */
- split: function(geometry, options) {
- var results = null;
- var mutual = options && options.mutual;
- var splits, sourceLine, sourceLines, sourceSplit, targetSplit;
- var sourceParts = [];
- var targetParts = [geometry];
- for(var i=0, len=this.components.length; i<len; ++i) {
- sourceLine = this.components[i];
- sourceSplit = false;
- for(var j=0; j < targetParts.length; ++j) {
- splits = sourceLine.split(targetParts[j], options);
- if(splits) {
- if(mutual) {
- sourceLines = splits[0];
- for(var k=0, klen=sourceLines.length; k<klen; ++k) {
- if(k===0 && sourceParts.length) {
- sourceParts[sourceParts.length-1].addComponent(
- sourceLines[k]
- );
- } else {
- sourceParts.push(
- new OpenLayers.Geometry.MultiLineString([
- sourceLines[k]
- ])
- );
- }
- }
- sourceSplit = true;
- splits = splits[1];
- }
- if(splits.length) {
- // splice in new target parts
- splits.unshift(j, 1);
- Array.prototype.splice.apply(targetParts, splits);
- break;
- }
- }
- }
- if(!sourceSplit) {
- // source line was not hit
- if(sourceParts.length) {
- // add line to existing multi
- sourceParts[sourceParts.length-1].addComponent(
- sourceLine.clone()
- );
- } else {
- // create a fresh multi
- sourceParts = [
- new OpenLayers.Geometry.MultiLineString(
- sourceLine.clone()
- )
- ];
- }
- }
- }
- if(sourceParts && sourceParts.length > 1) {
- sourceSplit = true;
- } else {
- sourceParts = [];
- }
- if(targetParts && targetParts.length > 1) {
- targetSplit = true;
- } else {
- targetParts = [];
- }
- if(sourceSplit || targetSplit) {
- if(mutual) {
- results = [sourceParts, targetParts];
- } else {
- results = targetParts;
- }
- }
- return results;
- },
-
- /**
- * Method: splitWith
- * Split this geometry (the target) with the given geometry (the source).
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} A geometry used to split this
- * geometry (the source).
- * options - {Object} Properties of this object will be used to determine
- * how the split is conducted.
- *
- * Valid options:
- * mutual - {Boolean} Split the source geometry in addition to the target
- * geometry. Default is false.
- * edge - {Boolean} Allow splitting when only edges intersect. Default is
- * true. If false, a vertex on the source must be within the tolerance
- * distance of the intersection to be considered a split.
- * tolerance - {Number} If a non-null value is provided, intersections
- * within the tolerance distance of an existing vertex on the source
- * will be assumed to occur at the vertex.
- *
- * Returns:
- * {Array} A list of geometries (of this same type as the target) that
- * result from splitting the target with the source geometry. The
- * source and target geometry will remain unmodified. If no split
- * results, null will be returned. If mutual is true and a split
- * results, return will be an array of two arrays - the first will be
- * all geometries that result from splitting the source geometry and
- * the second will be all geometries that result from splitting the
- * target geometry.
- */
- splitWith: function(geometry, options) {
- var results = null;
- var mutual = options && options.mutual;
- var splits, targetLine, sourceLines, sourceSplit, targetSplit, sourceParts, targetParts;
- if(geometry instanceof OpenLayers.Geometry.LineString) {
- targetParts = [];
- sourceParts = [geometry];
- for(var i=0, len=this.components.length; i<len; ++i) {
- targetSplit = false;
- targetLine = this.components[i];
- for(var j=0; j<sourceParts.length; ++j) {
- splits = sourceParts[j].split(targetLine, options);
- if(splits) {
- if(mutual) {
- sourceLines = splits[0];
- if(sourceLines.length) {
- // splice in new source parts
- sourceLines.unshift(j, 1);
- Array.prototype.splice.apply(sourceParts, sourceLines);
- j += sourceLines.length - 2;
- }
- splits = splits[1];
- if(splits.length === 0) {
- splits = [targetLine.clone()];
- }
- }
- for(var k=0, klen=splits.length; k<klen; ++k) {
- if(k===0 && targetParts.length) {
- targetParts[targetParts.length-1].addComponent(
- splits[k]
- );
- } else {
- targetParts.push(
- new OpenLayers.Geometry.MultiLineString([
- splits[k]
- ])
- );
- }
- }
- targetSplit = true;
- }
- }
- if(!targetSplit) {
- // target component was not hit
- if(targetParts.length) {
- // add it to any existing multi-line
- targetParts[targetParts.length-1].addComponent(
- targetLine.clone()
- );
- } else {
- // or start with a fresh multi-line
- targetParts = [
- new OpenLayers.Geometry.MultiLineString([
- targetLine.clone()
- ])
- ];
- }
-
- }
- }
- } else {
- results = geometry.split(this);
- }
- if(sourceParts && sourceParts.length > 1) {
- sourceSplit = true;
- } else {
- sourceParts = [];
- }
- if(targetParts && targetParts.length > 1) {
- targetSplit = true;
- } else {
- targetParts = [];
- }
- if(sourceSplit || targetSplit) {
- if(mutual) {
- results = [sourceParts, targetParts];
- } else {
- results = targetParts;
- }
- }
- return results;
- },
-
- CLASS_NAME: "OpenLayers.Geometry.MultiLineString"
-});
-/* ======================================================================
- OpenLayers/Handler/Path.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Handler/Point.js
- * @requires OpenLayers/Geometry/Point.js
- * @requires OpenLayers/Geometry/LineString.js
- */
-
-/**
- * Class: OpenLayers.Handler.Path
- * Handler to draw a path on the map. Path is displayed on mouse down,
- * moves on mouse move, and is finished on mouse up.
- *
- * Inherits from:
- * - <OpenLayers.Handler.Point>
- */
-OpenLayers.Handler.Path = OpenLayers.Class(OpenLayers.Handler.Point, {
-
- /**
- * Property: line
- * {<OpenLayers.Feature.Vector>}
- */
- line: null,
-
- /**
- * Property: freehand
- * {Boolean} In freehand mode, the handler starts the path on mouse down,
- * adds a point for every mouse move, and finishes the path on mouse up.
- * Outside of freehand mode, a point is added to the path on every mouse
- * click and double-click finishes the path.
- */
- freehand: false,
-
- /**
- * Property: freehandToggle
- * {String} If set, freehandToggle is checked on mouse events and will set
- * the freehand mode to the opposite of this.freehand. To disallow
- * toggling between freehand and non-freehand mode, set freehandToggle to
- * null. Acceptable toggle values are 'shiftKey', 'ctrlKey', and 'altKey'.
- */
- freehandToggle: 'shiftKey',
-
- /**
- * Constructor: OpenLayers.Handler.Path
- * Create a new path hander
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that owns this handler
- * callbacks - {Object} An object with a properties whose values are
- * functions. Various callbacks described below.
- * options - {Object} An optional object with properties to be set on the
- * handler
- *
- * Named callbacks:
- * create - Called when a sketch is first created. Callback called with
- * the creation point geometry and sketch feature.
- * modify - Called with each move of a vertex with the vertex (point)
- * geometry and the sketch feature.
- * point - Called as each point is added. Receives the new point geometry.
- * done - Called when the point drawing is finished. The callback will
- * recieve a single argument, the linestring geometry.
- * cancel - Called when the handler is deactivated while drawing. The
- * cancel callback will receive a geometry.
- */
- initialize: function(control, callbacks, options) {
- OpenLayers.Handler.Point.prototype.initialize.apply(this, arguments);
- },
-
- /**
- * Method: createFeature
- * Add temporary geometries
- *
- * Parameters:
- * pixel - {<OpenLayers.Pixel>} The initial pixel location for the new
- * feature.
- */
- createFeature: function(pixel) {
- var lonlat = this.control.map.getLonLatFromPixel(pixel);
- this.point = new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
- );
- this.line = new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.LineString([this.point.geometry])
- );
- this.callback("create", [this.point.geometry, this.getSketch()]);
- this.point.geometry.clearBounds();
- this.layer.addFeatures([this.line, this.point], {silent: true});
- },
-
- /**
- * Method: destroyFeature
- * Destroy temporary geometries
- */
- destroyFeature: function() {
- OpenLayers.Handler.Point.prototype.destroyFeature.apply(this);
- this.line = null;
- },
-
- /**
- * Method: removePoint
- * Destroy the temporary point.
- */
- removePoint: function() {
- if(this.point) {
- this.layer.removeFeatures([this.point]);
- }
- },
-
- /**
- * Method: addPoint
- * Add point to geometry. Send the point index to override
- * the behavior of LinearRing that disregards adding duplicate points.
- *
- * Parameters:
- * pixel - {<OpenLayers.Pixel>} The pixel location for the new point.
- */
- addPoint: function(pixel) {
- this.layer.removeFeatures([this.point]);
- var lonlat = this.control.map.getLonLatFromPixel(pixel);
- this.point = new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
- );
- this.line.geometry.addComponent(
- this.point.geometry, this.line.geometry.components.length
- );
- this.callback("point", [this.point.geometry, this.getGeometry()]);
- this.callback("modify", [this.point.geometry, this.getSketch()]);
- this.drawFeature();
- },
-
- /**
- * Method: freehandMode
- * Determine whether to behave in freehand mode or not.
- *
- * Returns:
- * {Boolean}
- */
- freehandMode: function(evt) {
- return (this.freehandToggle && evt[this.freehandToggle]) ?
- !this.freehand : this.freehand;
- },
-
- /**
- * Method: modifyFeature
- * Modify the existing geometry given the new point
- *
- * Parameters:
- * pixel - {<OpenLayers.Pixel>} The updated pixel location for the latest
- * point.
- */
- modifyFeature: function(pixel) {
- var lonlat = this.control.map.getLonLatFromPixel(pixel);
- this.point.geometry.x = lonlat.lon;
- this.point.geometry.y = lonlat.lat;
- this.callback("modify", [this.point.geometry, this.getSketch()]);
- this.point.geometry.clearBounds();
- this.drawFeature();
- },
-
- /**
- * Method: drawFeature
- * Render geometries on the temporary layer.
- */
- drawFeature: function() {
- this.layer.drawFeature(this.line, this.style);
- this.layer.drawFeature(this.point, this.style);
- },
-
- /**
- * Method: getSketch
- * Return the sketch feature.
- *
- * Returns:
- * {<OpenLayers.Feature.Vector>}
- */
- getSketch: function() {
- return this.line;
- },
-
- /**
- * Method: getGeometry
- * Return the sketch geometry. If <multi> is true, this will return
- * a multi-part geometry.
- *
- * Returns:
- * {<OpenLayers.Geometry.LineString>}
- */
- getGeometry: function() {
- var geometry = this.line && this.line.geometry;
- if(geometry && this.multi) {
- geometry = new OpenLayers.Geometry.MultiLineString([geometry]);
- }
- return geometry;
- },
-
- /**
- * Method: mousedown
- * Handle mouse down. Add a new point to the geometry and
- * render it. Return determines whether to propagate the event on the map.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- mousedown: function(evt) {
- // ignore double-clicks
- if (this.lastDown && this.lastDown.equals(evt.xy)) {
- return false;
- }
- if(this.lastDown == null) {
- if(this.persist) {
- this.destroyFeature();
- }
- this.createFeature(evt.xy);
- } else if((this.lastUp == null) || !this.lastUp.equals(evt.xy)) {
- this.addPoint(evt.xy);
- }
- this.mouseDown = true;
- this.lastDown = evt.xy;
- this.drawing = true;
- return false;
- },
-
- /**
- * Method: mousemove
- * Handle mouse move. Adjust the geometry and redraw.
- * Return determines whether to propagate the event on the map.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- mousemove: function (evt) {
- if(this.drawing) {
- if(this.mouseDown && this.freehandMode(evt)) {
- this.addPoint(evt.xy);
- } else {
- this.modifyFeature(evt.xy);
- }
- }
- return true;
- },
-
- /**
- * Method: mouseup
- * Handle mouse up. Send the latest point in the geometry to
- * the control. Return determines whether to propagate the event on the map.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- mouseup: function (evt) {
- this.mouseDown = false;
- if(this.drawing) {
- if(this.freehandMode(evt)) {
- this.removePoint();
- this.finalize();
- } else {
- if(this.lastUp == null) {
- this.addPoint(evt.xy);
- }
- this.lastUp = evt.xy;
- }
- return false;
- }
- return true;
- },
-
- /**
- * Method: dblclick
- * Handle double-clicks. Finish the geometry and send it back
- * to the control.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- dblclick: function(evt) {
- if(!this.freehandMode(evt)) {
- var index = this.line.geometry.components.length - 1;
- this.line.geometry.removeComponent(this.line.geometry.components[index]);
- this.removePoint();
- this.finalize();
- }
- return false;
- },
-
- CLASS_NAME: "OpenLayers.Handler.Path"
-});
-/* ======================================================================
OpenLayers/Geometry/Polygon.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
@@ -38623,7 +21586,7 @@
OpenLayers/Geometry/MultiPolygon.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
@@ -38670,158 +21633,10 @@
CLASS_NAME: "OpenLayers.Geometry.MultiPolygon"
});
/* ======================================================================
- OpenLayers/Handler/Polygon.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Handler/Path.js
- * @requires OpenLayers/Geometry/Polygon.js
- */
-
-/**
- * Class: OpenLayers.Handler.Polygon
- * Handler to draw a polygon on the map. Polygon is displayed on mouse down,
- * moves on mouse move, and is finished on mouse up.
- *
- * Inherits from:
- * - <OpenLayers.Handler.Path>
- * - <OpenLayers.Handler>
- */
-OpenLayers.Handler.Polygon = OpenLayers.Class(OpenLayers.Handler.Path, {
-
- /**
- * Parameter: polygon
- * {<OpenLayers.Feature.Vector>}
- */
- polygon: null,
-
- /**
- * Constructor: OpenLayers.Handler.Polygon
- * Create a Polygon Handler.
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that owns this handler
- * callbacks - {Object} An object with a properties whose values are
- * functions. Various callbacks described below.
- * options - {Object} An optional object with properties to be set on the
- * handler
- *
- * Named callbacks:
- * create - Called when a sketch is first created. Callback called with
- * the creation point geometry and sketch feature.
- * modify - Called with each move of a vertex with the vertex (point)
- * geometry and the sketch feature.
- * point - Called as each point is added. Receives the new point geometry.
- * done - Called when the point drawing is finished. The callback will
- * recieve a single argument, the polygon geometry.
- * cancel - Called when the handler is deactivated while drawing. The
- * cancel callback will receive a geometry.
- */
- initialize: function(control, callbacks, options) {
- OpenLayers.Handler.Path.prototype.initialize.apply(this, arguments);
- },
-
- /**
- * Method: createFeature
- * Add temporary geometries
- *
- * Parameters:
- * pixel - {<OpenLayers.Pixel>} The initial pixel location for the new
- * feature.
- */
- createFeature: function(pixel) {
- var lonlat = this.control.map.getLonLatFromPixel(pixel);
- this.point = new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
- );
- this.line = new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.LinearRing([this.point.geometry])
- );
- this.polygon = new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.Polygon([this.line.geometry])
- );
- this.callback("create", [this.point.geometry, this.getSketch()]);
- this.point.geometry.clearBounds();
- this.layer.addFeatures([this.polygon, this.point], {silent: true});
- },
-
- /**
- * Method: destroyFeature
- * Destroy temporary geometries
- */
- destroyFeature: function() {
- OpenLayers.Handler.Path.prototype.destroyFeature.apply(this);
- this.polygon = null;
- },
-
- /**
- * Method: drawFeature
- * Render geometries on the temporary layer.
- */
- drawFeature: function() {
- this.layer.drawFeature(this.polygon, this.style);
- this.layer.drawFeature(this.point, this.style);
- },
-
- /**
- * Method: getSketch
- * Return the sketch feature.
- *
- * Returns:
- * {<OpenLayers.Feature.Vector>}
- */
- getSketch: function() {
- return this.polygon;
- },
-
- /**
- * Method: getGeometry
- * Return the sketch geometry. If <multi> is true, this will return
- * a multi-part geometry.
- *
- * Returns:
- * {<OpenLayers.Geometry.Polygon>}
- */
- getGeometry: function() {
- var geometry = this.polygon && this.polygon.geometry;
- if(geometry && this.multi) {
- geometry = new OpenLayers.Geometry.MultiPolygon([geometry]);
- }
- return geometry;
- },
-
- /**
- * Method: dblclick
- * Handle double-clicks. Finish the geometry and send it back
- * to the control.
- *
- * Parameters:
- * evt - {Event}
- */
- dblclick: function(evt) {
- if(!this.freehandMode(evt)) {
- // remove the penultimate point
- var index = this.line.geometry.components.length - 2;
- this.line.geometry.removeComponent(this.line.geometry.components[index]);
- this.removePoint();
- this.finalize();
- }
- return false;
- },
-
- CLASS_NAME: "OpenLayers.Handler.Polygon"
-});
-/* ======================================================================
OpenLayers/Format/GML.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
@@ -38836,6 +21651,7 @@
* @requires OpenLayers/Geometry/Polygon.js
* @requires OpenLayers/Geometry/MultiPolygon.js
* @requires OpenLayers/Console.js
+ * @requires OpenLayers/Lang.js
*/
/**
@@ -39749,7 +22565,7 @@
OpenLayers/Format/GML/Base.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
@@ -40328,207 +23144,10 @@
});
/* ======================================================================
- OpenLayers/Format/GML/v2.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the Clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Format/GML/Base.js
- */
-
-/**
- * Class: OpenLayers.Format.GML.v2
- * Parses GML version 2.
- *
- * Inherits from:
- * - <OpenLayers.Format.GML.Base>
- */
-OpenLayers.Format.GML.v2 = OpenLayers.Class(OpenLayers.Format.GML.Base, {
-
- /**
- * Property: schemaLocation
- * {String} Schema location for a particular minor version.
- */
- schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd",
-
- /**
- * Constructor: OpenLayers.Format.GML.v2
- * Create a parser for GML v2.
- *
- * Parameters:
- * options - {Object} An optional object whose properties will be set on
- * this instance.
- *
- * Valid options properties:
- * featureType - {String} Local (without prefix) feature typeName (required).
- * featureNS - {String} Feature namespace (required).
- * geometryName - {String} Geometry element name.
- */
- initialize: function(options) {
- OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]);
- },
-
- /**
- * Property: readers
- * Contains public functions, grouped by namespace prefix, that will
- * be applied when a namespaced node is found matching the function
- * name. The function will be applied in the scope of this parser
- * with two arguments: the node being read and a context object passed
- * from the parent.
- */
- readers: {
- "gml": OpenLayers.Util.applyDefaults({
- "outerBoundaryIs": function(node, container) {
- var obj = {};
- this.readChildNodes(node, obj);
- container.outer = obj.components[0];
- },
- "innerBoundaryIs": function(node, container) {
- var obj = {};
- this.readChildNodes(node, obj);
- container.inner.push(obj.components[0]);
- },
- "Box": function(node, container) {
- var obj = {};
- this.readChildNodes(node, obj);
- if(!container.components) {
- container.components = [];
- }
- var min = obj.points[0];
- var max = obj.points[1];
- container.components.push(
- new OpenLayers.Bounds(min.x, min.y, max.x, max.y)
- );
- }
- }, OpenLayers.Format.GML.Base.prototype.readers["gml"]),
- "feature": OpenLayers.Format.GML.Base.prototype.readers["feature"],
- "wfs": OpenLayers.Format.GML.Base.prototype.readers["wfs"]
- },
-
- /**
- * Method: write
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector}
- * An array of features or a single feature.
- *
- * Returns:
- * {String} Given an array of features, a doc with a gml:featureMembers
- * element will be returned. Given a single feature, a doc with a
- * gml:featureMember element will be returned.
- */
- write: function(features) {
- var name;
- if(features instanceof Array) {
- // GML2 only has abstract feature collections
- // wfs provides a feature collection from a well-known schema
- name = "wfs:FeatureCollection";
- } else {
- name = "gml:featureMember";
- }
- var root = this.writeNode(name, features);
- this.setAttributeNS(
- root, this.namespaces["xsi"],
- "xsi:schemaLocation", this.schemaLocation
- );
-
- return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
- },
-
- /**
- * Property: writers
- * As a compliment to the readers property, this structure contains public
- * writing functions grouped by namespace alias and named like the
- * node names they produce.
- */
- writers: {
- "gml": OpenLayers.Util.applyDefaults({
- "Point": function(geometry) {
- var node = this.createElementNSPlus("gml:Point");
- this.writeNode("coordinates", [geometry], node);
- return node;
- },
- "coordinates": function(points) {
- var numPoints = points.length;
- var parts = new Array(numPoints);
- var point;
- for(var i=0; i<numPoints; ++i) {
- point = points[i];
- if(this.xy) {
- parts[i] = point.x + "," + point.y;
- } else {
- parts[i] = point.y + "," + point.x;
- }
- if(point.z != undefined) { // allow null or undefined
- parts[i] += "," + point.z;
- }
- }
- return this.createElementNSPlus("gml:coordinates", {
- attributes: {
- decimal: ".", cs: ",", ts: " "
- },
- value: (numPoints == 1) ? parts[0] : parts.join(" ")
- });
- },
- "LineString": function(geometry) {
- var node = this.createElementNSPlus("gml:LineString");
- this.writeNode("coordinates", geometry.components, node);
- return node;
- },
- "Polygon": function(geometry) {
- var node = this.createElementNSPlus("gml:Polygon");
- this.writeNode("outerBoundaryIs", geometry.components[0], node);
- for(var i=1; i<geometry.components.length; ++i) {
- this.writeNode(
- "innerBoundaryIs", geometry.components[i], node
- );
- }
- return node;
- },
- "outerBoundaryIs": function(ring) {
- var node = this.createElementNSPlus("gml:outerBoundaryIs");
- this.writeNode("LinearRing", ring, node);
- return node;
- },
- "innerBoundaryIs": function(ring) {
- var node = this.createElementNSPlus("gml:innerBoundaryIs");
- this.writeNode("LinearRing", ring, node);
- return node;
- },
- "LinearRing": function(ring) {
- var node = this.createElementNSPlus("gml:LinearRing");
- this.writeNode("coordinates", ring.components, node);
- return node;
- },
- "Box": function(bounds) {
- var node = this.createElementNSPlus("gml:Box");
- this.writeNode("coordinates", [
- {x: bounds.left, y: bounds.bottom},
- {x: bounds.right, y: bounds.top}
- ], node);
- // srsName attribute is optional for gml:Box
- if(this.srsName) {
- node.setAttribute("srsName", this.srsName);
- }
- return node;
- }
- }, OpenLayers.Format.GML.Base.prototype.writers["gml"]),
- "feature": OpenLayers.Format.GML.Base.prototype.writers["feature"],
- "wfs": OpenLayers.Format.GML.Base.prototype.writers["wfs"]
- },
-
- CLASS_NAME: "OpenLayers.Format.GML.v2"
-
-});
-/* ======================================================================
OpenLayers/Format/GML/v3.js
====================================================================== */
-/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
@@ -40990,3 +23609,22975 @@
CLASS_NAME: "OpenLayers.Format.GML.v3"
});
+/* ======================================================================
+ OpenLayers/Format/Filter/v1_1_0.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/Filter/v1.js
+ * @requires OpenLayers/Format/GML/v3.js
+ */
+
+/**
+ * Class: OpenLayers.Format.Filter.v1_1_0
+ * Write ogc:Filter version 1.1.0.
+ *
+ * Differences from the v1.0.0 parser:
+ * - uses GML v3 instead of GML v2
+ * - reads matchCase attribute on ogc:PropertyIsEqual and
+ * ogc:PropertyIsNotEqualelements.
+ * - writes matchCase attribute from comparison filters of type EQUAL_TO and
+ * type NOT_EQUAL_TO.
+ *
+ * Inherits from:
+ * - <OpenLayers.Format.Filter.v1>
+ */
+OpenLayers.Format.Filter.v1_1_0 = OpenLayers.Class(
+ OpenLayers.Format.GML.v3, OpenLayers.Format.Filter.v1, {
+
+ /**
+ * Constant: VERSION
+ * {String} 1.1.0
+ */
+ VERSION: "1.1.0",
+
+ /**
+ * Property: schemaLocation
+ * {String} http://www.opengis.net/ogc/filter/1.1.0/filter.xsd
+ */
+ schemaLocation: "http://www.opengis.net/ogc/filter/1.1.0/filter.xsd",
+
+ /**
+ * Constructor: OpenLayers.Format.Filter.v1_1_0
+ * Instances of this class are not created directly. Use the
+ * <OpenLayers.Format.Filter> constructor instead.
+ *
+ * Parameters:
+ * options - {Object} An optional object whose properties will be set on
+ * this instance.
+ */
+ initialize: function(options) {
+ OpenLayers.Format.GML.v3.prototype.initialize.apply(
+ this, [options]
+ );
+ },
+
+ /**
+ * Property: readers
+ * Contains public functions, grouped by namespace prefix, that will
+ * be applied when a namespaced node is found matching the function
+ * name. The function will be applied in the scope of this parser
+ * with two arguments: the node being read and a context object passed
+ * from the parent.
+ */
+ readers: {
+ "ogc": OpenLayers.Util.applyDefaults({
+ "PropertyIsEqualTo": function(node, obj) {
+ var matchCase = node.getAttribute("matchCase");
+ var filter = new OpenLayers.Filter.Comparison({
+ type: OpenLayers.Filter.Comparison.EQUAL_TO,
+ matchCase: !(matchCase === "false" || matchCase === "0")
+ });
+ this.readChildNodes(node, filter);
+ obj.filters.push(filter);
+ },
+ "PropertyIsNotEqualTo": function(node, obj) {
+ var matchCase = node.getAttribute("matchCase");
+ var filter = new OpenLayers.Filter.Comparison({
+ type: OpenLayers.Filter.Comparison.NOT_EQUAL_TO,
+ matchCase: !(matchCase === "false" || matchCase === "0")
+ });
+ this.readChildNodes(node, filter);
+ obj.filters.push(filter);
+ },
+ "PropertyIsLike": function(node, obj) {
+ var filter = new OpenLayers.Filter.Comparison({
+ type: OpenLayers.Filter.Comparison.LIKE
+ });
+ this.readChildNodes(node, filter);
+ var wildCard = node.getAttribute("wildCard");
+ var singleChar = node.getAttribute("singleChar");
+ var esc = node.getAttribute("escapeChar");
+ filter.value2regex(wildCard, singleChar, esc);
+ obj.filters.push(filter);
+ }
+ }, OpenLayers.Format.Filter.v1.prototype.readers["ogc"]),
+ "gml": OpenLayers.Format.GML.v3.prototype.readers["gml"],
+ "feature": OpenLayers.Format.GML.v3.prototype.readers["feature"]
+ },
+
+ /**
+ * Property: writers
+ * As a compliment to the readers property, this structure contains public
+ * writing functions grouped by namespace alias and named like the
+ * node names they produce.
+ */
+ writers: {
+ "ogc": OpenLayers.Util.applyDefaults({
+ "PropertyIsEqualTo": function(filter) {
+ var node = this.createElementNSPlus("ogc:PropertyIsEqualTo", {
+ attributes: {matchCase: filter.matchCase}
+ });
+ // no ogc:expression handling for now
+ this.writeNode("PropertyName", filter, node);
+ this.writeNode("Literal", filter.value, node);
+ return node;
+ },
+ "PropertyIsNotEqualTo": function(filter) {
+ var node = this.createElementNSPlus("ogc:PropertyIsNotEqualTo", {
+ attributes: {matchCase: filter.matchCase}
+ });
+ // no ogc:expression handling for now
+ this.writeNode("PropertyName", filter, node);
+ this.writeNode("Literal", filter.value, node);
+ return node;
+ },
+ "PropertyIsLike": function(filter) {
+ var node = this.createElementNSPlus("ogc:PropertyIsLike", {
+ attributes: {
+ wildCard: "*", singleChar: ".", escapeChar: "!"
+ }
+ });
+ // no ogc:expression handling for now
+ this.writeNode("PropertyName", filter, node);
+ // convert regex string to ogc string
+ this.writeNode("Literal", filter.regex2value(), node);
+ return node;
+ },
+ "BBOX": function(filter) {
+ var node = this.createElementNSPlus("ogc:BBOX");
+ this.writeNode("PropertyName", filter, node);
+ var box = this.writeNode("gml:Envelope", filter.value);
+ if(filter.projection) {
+ box.setAttribute("srsName", filter.projection);
+ }
+ node.appendChild(box);
+ return node;
+ }}, OpenLayers.Format.Filter.v1.prototype.writers["ogc"]),
+
+ "gml": OpenLayers.Format.GML.v3.prototype.writers["gml"],
+ "feature": OpenLayers.Format.GML.v3.prototype.writers["feature"]
+ },
+
+ /**
+ * Method: writeSpatial
+ *
+ * Read a {<OpenLayers.Filter.Spatial>} filter and converts it into XML.
+ *
+ * Parameters:
+ * filter - {<OpenLayers.Filter.Spatial>} The filter.
+ * name - {String} Name of the generated XML element.
+ *
+ * Returns:
+ * {DOMElement} The created XML element.
+ */
+ writeSpatial: function(filter, name) {
+ var node = this.createElementNSPlus("ogc:"+name);
+ this.writeNode("PropertyName", filter, node);
+ var child;
+ if(filter.value instanceof OpenLayers.Geometry) {
+ child = this.writeNode("feature:_geometry", filter.value).firstChild;
+ } else {
+ child = this.writeNode("gml:Envelope", filter.value);
+ }
+ if(filter.projection) {
+ child.setAttribute("srsName", filter.projection);
+ }
+ node.appendChild(child);
+ return node;
+ },
+
+ CLASS_NAME: "OpenLayers.Format.Filter.v1_1_0"
+
+});
+/* ======================================================================
+ OpenLayers/Format/WFST/v1_1_0.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/WFST/v1.js
+ * @requires OpenLayers/Format/Filter/v1_1_0.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WFST.v1_1_0
+ * A format for creating WFS v1.1.0 transactions. Create a new instance with the
+ * <OpenLayers.Format.WFST.v1_1_0> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Format.Filter.v1_1_0>
+ * - <OpenLayers.Format.WFST.v1>
+ */
+OpenLayers.Format.WFST.v1_1_0 = OpenLayers.Class(
+ OpenLayers.Format.Filter.v1_1_0, OpenLayers.Format.WFST.v1, {
+
+ /**
+ * Property: version
+ * {String} WFS version number.
+ */
+ version: "1.1.0",
+
+ /**
+ * Property: schemaLocations
+ * {Object} Properties are namespace aliases, values are schema locations.
+ */
+ schemaLocations: {
+ "wfs": "http://schemas.opengis.net/wfs/1.1.0/wfs.xsd"
+ },
+
+ /**
+ * Constructor: OpenLayers.Format.WFST.v1_1_0
+ * A class for parsing and generating WFS v1.1.0 transactions.
+ *
+ * To read additional information like hit count (numberOfFeatures) from
+ * the FeatureCollection, call the <OpenLayers.Format.WFST.v1.read> method
+ * with {output: "object"} as 2nd argument. Note that it is possible to
+ * just request the hit count from a WFS 1.1.0 server with the
+ * resultType="hits" request parameter.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ *
+ * Valid options properties:
+ * featureType - {String} Local (without prefix) feature typeName (required).
+ * featureNS - {String} Feature namespace (optional).
+ * featurePrefix - {String} Feature namespace alias (optional - only used
+ * if featureNS is provided). Default is 'feature'.
+ * geometryName - {String} Name of geometry attribute. Default is 'the_geom'.
+ */
+ initialize: function(options) {
+ OpenLayers.Format.Filter.v1_1_0.prototype.initialize.apply(this, [options]);
+ OpenLayers.Format.WFST.v1.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * Property: readers
+ * Contains public functions, grouped by namespace prefix, that will
+ * be applied when a namespaced node is found matching the function
+ * name. The function will be applied in the scope of this parser
+ * with two arguments: the node being read and a context object passed
+ * from the parent.
+ */
+ readers: {
+ "wfs": OpenLayers.Util.applyDefaults({
+ "FeatureCollection": function(node, obj) {
+ obj.numberOfFeatures = parseInt(node.getAttribute(
+ "numberOfFeatures"));
+ OpenLayers.Format.WFST.v1.prototype.readers["wfs"]["FeatureCollection"].apply(
+ this, arguments);
+ },
+ "TransactionResponse": function(node, obj) {
+ obj.insertIds = [];
+ obj.success = false;
+ this.readChildNodes(node, obj);
+ },
+ "TransactionSummary": function(node, obj) {
+ // this is a limited test of success
+ obj.success = true;
+ },
+ "InsertResults": function(node, obj) {
+ this.readChildNodes(node, obj);
+ },
+ "Feature": function(node, container) {
+ var obj = {fids: []};
+ this.readChildNodes(node, obj);
+ container.insertIds.push(obj.fids[0]);
+ }
+ }, OpenLayers.Format.WFST.v1.prototype.readers["wfs"]),
+ "gml": OpenLayers.Format.GML.v3.prototype.readers["gml"],
+ "feature": OpenLayers.Format.GML.v3.prototype.readers["feature"],
+ "ogc": OpenLayers.Format.Filter.v1_1_0.prototype.readers["ogc"]
+ },
+
+ /**
+ * Property: writers
+ * As a compliment to the readers property, this structure contains public
+ * writing functions grouped by namespace alias and named like the
+ * node names they produce.
+ */
+ writers: {
+ "wfs": OpenLayers.Util.applyDefaults({
+ "GetFeature": function(options) {
+ var node = OpenLayers.Format.WFST.v1.prototype.writers["wfs"]["GetFeature"].apply(this, arguments);
+ options && options.resultType && this.setAttributes(node, {
+ resultType: options.resultType
+ });
+ return node;
+ },
+ "Query": function(options) {
+ options = OpenLayers.Util.extend({
+ featureNS: this.featureNS,
+ featurePrefix: this.featurePrefix,
+ featureType: this.featureType,
+ srsName: this.srsName
+ }, options);
+ var node = this.createElementNSPlus("wfs:Query", {
+ attributes: {
+ typeName: (options.featureNS ? options.featurePrefix + ":" : "") +
+ options.featureType,
+ srsName: options.srsName
+ }
+ });
+ if(options.featureNS) {
+ node.setAttribute("xmlns:" + options.featurePrefix, options.featureNS);
+ }
+ if(options.propertyNames) {
+ for(var i=0,len = options.propertyNames.length; i<len; i++) {
+ this.writeNode(
+ "wfs:PropertyName",
+ {property: options.propertyNames[i]},
+ node
+ );
+ }
+ }
+ if(options.filter) {
+ this.setFilterProperty(options.filter);
+ this.writeNode("ogc:Filter", options.filter, node);
+ }
+ return node;
+ },
+ "PropertyName": function(obj) {
+ return this.createElementNSPlus("wfs:PropertyName", {
+ value: obj.property
+ });
+ }
+ }, OpenLayers.Format.WFST.v1.prototype.writers["wfs"]),
+ "gml": OpenLayers.Format.GML.v3.prototype.writers["gml"],
+ "feature": OpenLayers.Format.GML.v3.prototype.writers["feature"],
+ "ogc": OpenLayers.Format.Filter.v1_1_0.prototype.writers["ogc"]
+ },
+
+ CLASS_NAME: "OpenLayers.Format.WFST.v1_1_0"
+});
+/* ======================================================================
+ OpenLayers/Strategy.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy
+ * Abstract vector layer strategy class. Not to be instantiated directly. Use
+ * one of the strategy subclasses instead.
+ */
+OpenLayers.Strategy = OpenLayers.Class({
+
+ /**
+ * Property: layer
+ * {<OpenLayers.Layer.Vector>} The layer this strategy belongs to.
+ */
+ layer: null,
+
+ /**
+ * Property: options
+ * {Object} Any options sent to the constructor.
+ */
+ options: null,
+
+ /**
+ * Property: active
+ * {Boolean} The control is active.
+ */
+ active: null,
+
+ /**
+ * Property: autoActivate
+ * {Boolean} The creator of the strategy can set autoActivate to false
+ * to fully control when the protocol is activated and deactivated.
+ * Defaults to true.
+ */
+ autoActivate: true,
+
+ /**
+ * Property: autoDestroy
+ * {Boolean} The creator of the strategy can set autoDestroy to false
+ * to fully control when the strategy is destroyed. Defaults to
+ * true.
+ */
+ autoDestroy: true,
+
+ /**
+ * Constructor: OpenLayers.Strategy
+ * Abstract class for vector strategies. Create instances of a subclass.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ */
+ initialize: function(options) {
+ OpenLayers.Util.extend(this, options);
+ this.options = options;
+ // set the active property here, so that user cannot override it
+ this.active = false;
+ },
+
+ /**
+ * APIMethod: destroy
+ * Clean up the strategy.
+ */
+ destroy: function() {
+ this.deactivate();
+ this.layer = null;
+ this.options = null;
+ },
+
+ /**
+ * Method: setLayer
+ * Called to set the <layer> property.
+ *
+ * Parameters:
+ * {<OpenLayers.Layer.Vector>}
+ */
+ setLayer: function(layer) {
+ this.layer = layer;
+ },
+
+ /**
+ * Method: activate
+ * Activate the strategy. Register any listeners, do appropriate setup.
+ *
+ * Returns:
+ * {Boolean} True if the strategy was successfully activated or false if
+ * the strategy was already active.
+ */
+ activate: function() {
+ if (!this.active) {
+ this.active = true;
+ return true;
+ }
+ return false;
+ },
+
+ /**
+ * Method: deactivate
+ * Deactivate the strategy. Unregister any listeners, do appropriate
+ * tear-down.
+ *
+ * Returns:
+ * {Boolean} True if the strategy was successfully deactivated or false if
+ * the strategy was already inactive.
+ */
+ deactivate: function() {
+ if (this.active) {
+ this.active = false;
+ return true;
+ }
+ return false;
+ },
+
+ CLASS_NAME: "OpenLayers.Strategy"
+});
+/* ======================================================================
+ OpenLayers/Strategy/Filter.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Strategy.js
+ * @requires OpenLayers/Filter.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.Filter
+ * Strategy for limiting features that get added to a layer by
+ * evaluating a filter. The strategy maintains a cache of
+ * all features until removeFeatures is called on the layer.
+ *
+ * Inherits from:
+ * - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.Filter = OpenLayers.Class(OpenLayers.Strategy, {
+
+ /**
+ * APIProperty: filter
+ * {<OpenLayers.Filter>} Filter for limiting features sent to the layer.
+ * Use the <setFilter> method to update this filter after construction.
+ */
+ filter: null,
+
+ /**
+ * Property: cache
+ * {Array(<OpenLayers.Feature.Vector>)} List of currently cached
+ * features.
+ */
+ cache: null,
+
+ /**
+ * Property: caching
+ * {Boolean} The filter is currently caching features.
+ */
+ caching: false,
+
+ /**
+ * Constructor: OpenLayers.Strategy.Filter
+ * Create a new filter strategy.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ */
+ initialize: function(options) {
+ OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * APIMethod: activate
+ * Activate the strategy. Register any listeners, do appropriate setup.
+ * By default, this strategy automatically activates itself when a layer
+ * is added to a map.
+ *
+ * Returns:
+ * {Boolean} True if the strategy was successfully activated or false if
+ * the strategy was already active.
+ */
+ activate: function() {
+ var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments);
+ if (activated) {
+ this.cache = [];
+ this.layer.events.on({
+ "beforefeaturesadded": this.handleAdd,
+ "beforefeaturesremoved": this.handleRemove,
+ scope: this
+ });
+ }
+ return activated;
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Deactivate the strategy. Clear the feature cache.
+ *
+ * Returns:
+ * {Boolean} True if the strategy was successfully deactivated or false if
+ * the strategy was already inactive.
+ */
+ deactivate: function() {
+ this.cache = null;
+ if (this.layer && this.layer.events) {
+ this.layer.events.un({
+ "beforefeaturesadded": this.handleAdd,
+ "beforefeaturesremoved": this.handleRemove,
+ scope: this
+ });
+ }
+ return OpenLayers.Strategy.prototype.deactivate.apply(this, arguments);
+ },
+
+ /**
+ * Method: handleAdd
+ */
+ handleAdd: function(event) {
+ if (!this.caching && this.filter) {
+ var features = event.features;
+ event.features = [];
+ var feature;
+ for (var i=0, ii=features.length; i<ii; ++i) {
+ feature = features[i];
+ if (this.filter.evaluate(feature)) {
+ event.features.push(feature);
+ } else {
+ this.cache.push(feature);
+ }
+ }
+ }
+ },
+
+ /**
+ * Method: handleRemove
+ */
+ handleRemove: function(event) {
+ if (!this.caching) {
+ this.cache = [];
+ }
+ },
+
+ /**
+ * APIMethod: setFilter
+ * Update the filter for this strategy. This will re-evaluate
+ * any features on the layer and in the cache. Only features
+ * for which filter.evalute(feature) returns true will be
+ * added to the layer. Others will be cached by the strategy.
+ *
+ * Parameters:
+ * filter - <OpenLayers.Filter> A filter for evaluating features.
+ */
+ setFilter: function(filter) {
+ this.filter = filter;
+ var previousCache = this.cache;
+ this.cache = [];
+ // look through layer for features to remove from layer
+ this.handleAdd({features: this.layer.features});
+ // cache now contains features to remove from layer
+ if (this.cache.length > 0) {
+ this.caching = true;
+ this.layer.removeFeatures(this.cache.slice(), {silent: true});
+ this.caching = false;
+ }
+ // now look through previous cache for features to add to layer
+ if (previousCache.length > 0) {
+ var event = {features: previousCache};
+ this.handleAdd(event);
+ // event has features to add to layer
+ this.caching = true;
+ this.layer.addFeatures(event.features, {silent: true});
+ this.caching = false;
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Strategy.Filter"
+
+});
+/* ======================================================================
+ OpenLayers/Format/WFSCapabilities.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/XML.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WFSCapabilities
+ * Read WFS Capabilities.
+ *
+ * Inherits from:
+ * - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.WFSCapabilities = OpenLayers.Class(OpenLayers.Format.XML, {
+
+ /**
+ * APIProperty: defaultVersion
+ * {String} Version number to assume if none found. Default is "1.1.0".
+ */
+ defaultVersion: "1.1.0",
+
+ /**
+ * APIProperty: version
+ * {String} Specify a version string if one is known.
+ */
+ version: null,
+
+ /**
+ * Constructor: OpenLayers.Format.WFSCapabilities
+ * Create a new parser for WFS capabilities.
+ *
+ * Parameters:
+ * options - {Object} An optional object whose properties will be set on
+ * this instance.
+ */
+ initialize: function(options) {
+ OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+ this.options = options;
+ },
+
+ /**
+ * APIMethod: read
+ * Read capabilities data from a string, and return a list of layers.
+ *
+ * Parameters:
+ * data - {String} or {DOMElement} data to read/parse.
+ *
+ * Returns:
+ * {Array} List of named layers.
+ */
+ read: function(data) {
+ if(typeof data == "string") {
+ data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+ }
+ var root = data.documentElement;
+ var version = this.version;
+ if(!version) {
+ version = root.getAttribute("version");
+ if(!version) {
+ version = this.defaultVersion;
+ }
+ }
+ var constr = OpenLayers.Format.WFSCapabilities[
+ "v" + version.replace(/\./g, "_")
+ ];
+ if(!constr) {
+ throw "Can't find a WFS capabilities parser for version " + version;
+ }
+ var parser = new constr(this.options);
+ var capabilities = parser.read(data);
+ capabilities.version = version;
+ return capabilities;
+ },
+
+ CLASS_NAME: "OpenLayers.Format.WFSCapabilities"
+
+});
+/* ======================================================================
+ OpenLayers/Format/WFSCapabilities/v1.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/WFSCapabilities.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WFSCapabilities.v1
+ * Abstract class not to be instantiated directly.
+ *
+ * Inherits from:
+ * - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.WFSCapabilities.v1 = OpenLayers.Class(
+ OpenLayers.Format.WFSCapabilities, {
+
+ /**
+ * Constructor: OpenLayers.Format.WFSCapabilities.v1_1
+ * Create an instance of one of the subclasses.
+ *
+ * Parameters:
+ * options - {Object} An optional object whose properties will be set on
+ * this instance.
+ */
+ initialize: function(options) {
+ OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+ this.options = options;
+ },
+
+ /**
+ * APIMethod: read
+ * Read capabilities data from a string, and return a list of layers.
+ *
+ * Parameters:
+ * data - {String} or {DOMElement} data to read/parse.
+ *
+ * Returns:
+ * {Array} List of named layers.
+ */
+ read: function(data) {
+ if(typeof data == "string") {
+ data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+ }
+ var capabilities = {};
+ var root = data.documentElement;
+ this.runChildNodes(capabilities, root);
+ return capabilities;
+ },
+
+ /**
+ * Method: runChildNodes
+ */
+ runChildNodes: function(obj, node) {
+ var children = node.childNodes;
+ var childNode, processor;
+ for(var i=0; i<children.length; ++i) {
+ childNode = children[i];
+ if(childNode.nodeType == 1) {
+ processor = this["read_cap_" + childNode.nodeName];
+ if(processor) {
+ processor.apply(this, [obj, childNode]);
+ }
+ }
+ }
+ },
+
+ /**
+ * Method: read_cap_FeatureTypeList
+ */
+ read_cap_FeatureTypeList: function(request, node) {
+ var featureTypeList = {
+ featureTypes: []
+ };
+ this.runChildNodes(featureTypeList, node);
+ request.featureTypeList = featureTypeList;
+ },
+
+ /**
+ * Method: read_cap_FeatureType
+ */
+ read_cap_FeatureType: function(featureTypeList, node, parentLayer) {
+ var featureType = {};
+ this.runChildNodes(featureType, node);
+ featureTypeList.featureTypes.push(featureType);
+ },
+
+ /**
+ * Method: read_cap_Name
+ */
+ read_cap_Name: function(obj, node) {
+ var name = this.getChildValue(node);
+ if(name) {
+ var parts = name.split(":");
+ obj.name = parts.pop();
+ if(parts.length > 0) {
+ obj.featureNS = this.lookupNamespaceURI(node, parts[0]);
+ }
+ }
+ },
+
+ /**
+ * Method: read_cap_Title
+ */
+ read_cap_Title: function(obj, node) {
+ var title = this.getChildValue(node);
+ if(title) {
+ obj.title = title;
+ }
+ },
+
+ /**
+ * Method: read_cap_Abstract
+ */
+ read_cap_Abstract: function(obj, node) {
+ var abst = this.getChildValue(node);
+ if(abst) {
+ obj["abstract"] = abst;
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1"
+
+});
+/* ======================================================================
+ OpenLayers/Format/WFSCapabilities/v1_1_0.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/WFSCapabilities/v1.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WFSCapabilities/v1_1_0
+ * Read WFS Capabilities version 1.1.0.
+ *
+ * Inherits from:
+ * - <OpenLayers.Format.WFSCapabilities>
+ */
+OpenLayers.Format.WFSCapabilities.v1_1_0 = OpenLayers.Class(
+ OpenLayers.Format.WFSCapabilities.v1, {
+
+ /**
+ * Constructor: OpenLayers.Format.WFSCapabilities.v1_1_0
+ * Create a new parser for WFS capabilities version 1.1.0.
+ *
+ * Parameters:
+ * options - {Object} An optional object whose properties will be set on
+ * this instance.
+ */
+ initialize: function(options) {
+ OpenLayers.Format.WFSCapabilities.v1.prototype.initialize.apply(
+ this, [options]
+ );
+ },
+
+ CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_1_0"
+
+});
+/* ======================================================================
+ OpenLayers/Strategy/Save.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Strategy.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.Save
+ * A strategy that commits newly created or modified features. By default
+ * the strategy waits for a call to <save> before persisting changes. By
+ * configuring the strategy with the <auto> option, changes can be saved
+ * automatically.
+ *
+ * Inherits from:
+ * - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.Save = OpenLayers.Class(OpenLayers.Strategy, {
+
+ /**
+ * Constant: EVENT_TYPES
+ * {Array(String)} Supported application event types. Register a listener
+ * for a particular event with the following syntax:
+ * (code)
+ * strategy.events.register(type, obj, listener);
+ * (end)
+ *
+ * - *start* Triggered before saving
+ * - *success* Triggered after a successful transaction
+ * - *fail* Triggered after a failed transaction
+ *
+ */
+ EVENT_TYPES: ["start", "success", "fail"],
+
+ /**
+ * Property: events
+ * {<OpenLayers.Events>} Events instance for triggering this protocol
+ * events.
+ */
+ events: null,
+
+ /**
+ * APIProperty: auto
+ * {Boolean | Number} Auto-save. Default is false. If true, features will be
+ * saved immediately after being added to the layer and with each
+ * modification or deletion. If auto is a number, features will be
+ * saved on an interval provided by the value (in seconds).
+ */
+ auto: false,
+
+ /**
+ * Property: timer
+ * {Number} The id of the timer.
+ */
+ timer: null,
+
+ /**
+ * Constructor: OpenLayers.Strategy.Save
+ * Create a new Save strategy.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ */
+ initialize: function(options) {
+ OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
+ this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
+ },
+
+ /**
+ * APIMethod: activate
+ * Activate the strategy. Register any listeners, do appropriate setup.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully activated.
+ */
+ activate: function() {
+ var activated = OpenLayers.Strategy.prototype.activate.call(this);
+ if(activated) {
+ if(this.auto) {
+ if(typeof this.auto === "number") {
+ this.timer = window.setInterval(
+ OpenLayers.Function.bind(this.save, this),
+ this.auto * 1000
+ );
+ } else {
+ this.layer.events.on({
+ "featureadded": this.triggerSave,
+ "afterfeaturemodified": this.triggerSave,
+ scope: this
+ });
+ }
+ }
+ }
+ return activated;
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Deactivate the strategy. Unregister any listeners, do appropriate
+ * tear-down.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
+ if(deactivated) {
+ if(this.auto) {
+ if(typeof this.auto === "number") {
+ window.clearInterval(this.timer);
+ } else {
+ this.layer.events.un({
+ "featureadded": this.triggerSave,
+ "afterfeaturemodified": this.triggerSave,
+ scope: this
+ });
+ }
+ }
+ }
+ return deactivated;
+ },
+
+ /**
+ * Method: triggerSave
+ * Registered as a listener. Calls save if a feature has insert, update,
+ * or delete state.
+ *
+ * Parameters:
+ * event - {Object} The event this function is listening for.
+ */
+ triggerSave: function(event) {
+ var feature = event.feature;
+ if(feature.state === OpenLayers.State.INSERT ||
+ feature.state === OpenLayers.State.UPDATE ||
+ feature.state === OpenLayers.State.DELETE) {
+ this.save([event.feature]);
+ }
+ },
+
+ /**
+ * APIMethod: save
+ * Tell the layer protocol to commit unsaved features. If the layer
+ * projection differs from the map projection, features will be
+ * transformed into the layer projection before being committed.
+ *
+ * Parameters:
+ * features - {Array} Features to be saved. If null, then default is all
+ * features in the layer. Features are assumed to be in the map
+ * projection.
+ */
+ save: function(features) {
+ if(!features) {
+ features = this.layer.features;
+ }
+ this.events.triggerEvent("start", {features:features});
+ var remote = this.layer.projection;
+ var local = this.layer.map.getProjectionObject();
+ if(!local.equals(remote)) {
+ var len = features.length;
+ var clones = new Array(len);
+ var orig, clone;
+ for(var i=0; i<len; ++i) {
+ orig = features[i];
+ clone = orig.clone();
+ clone.fid = orig.fid;
+ clone.state = orig.state;
+ if(orig.url) {
+ clone.url = orig.url;
+ }
+ clone._original = orig;
+ clone.geometry.transform(local, remote);
+ clones[i] = clone;
+ }
+ features = clones;
+ }
+ this.layer.protocol.commit(features, {
+ callback: this.onCommit,
+ scope: this
+ });
+ },
+
+ /**
+ * Method: onCommit
+ * Called after protocol commit.
+ *
+ * Parameters:
+ * response - {<OpenLayers.Protocol.Response>} A response object.
+ */
+ onCommit: function(response) {
+ var evt = {"response": response};
+ if(response.success()) {
+ var features = response.reqFeatures;
+ // deal with inserts, updates, and deletes
+ var state, feature;
+ var destroys = [];
+ var insertIds = response.insertIds || [];
+ var j = 0;
+ for(var i=0, len=features.length; i<len; ++i) {
+ feature = features[i];
+ // if projection was different, we may be dealing with clones
+ feature = feature._original || feature;
+ state = feature.state;
+ if(state) {
+ if(state == OpenLayers.State.DELETE) {
+ destroys.push(feature);
+ } else if(state == OpenLayers.State.INSERT) {
+ feature.fid = insertIds[j];
+ ++j;
+ }
+ feature.state = null;
+ }
+ }
+
+ if(destroys.length > 0) {
+ this.layer.destroyFeatures(destroys);
+ }
+
+ this.events.triggerEvent("success", evt);
+
+ } else {
+ this.events.triggerEvent("fail", evt);
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Strategy.Save"
+});
+/* ======================================================================
+ OpenLayers/Handler.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/Events.js
+ */
+
+/**
+ * Class: OpenLayers.Handler
+ * Base class to construct a higher-level handler for event sequences. All
+ * handlers have activate and deactivate methods. In addition, they have
+ * methods named like browser events. When a handler is activated, any
+ * additional methods named like a browser event is registered as a
+ * listener for the corresponding event. When a handler is deactivated,
+ * those same methods are unregistered as event listeners.
+ *
+ * Handlers also typically have a callbacks object with keys named like
+ * the abstracted events or event sequences that they are in charge of
+ * handling. The controls that wrap handlers define the methods that
+ * correspond to these abstract events - so instead of listening for
+ * individual browser events, they only listen for the abstract events
+ * defined by the handler.
+ *
+ * Handlers are created by controls, which ultimately have the responsibility
+ * of making changes to the the state of the application. Handlers
+ * themselves may make temporary changes, but in general are expected to
+ * return the application in the same state that they found it.
+ */
+OpenLayers.Handler = OpenLayers.Class({
+
+ /**
+ * Property: id
+ * {String}
+ */
+ id: null,
+
+ /**
+ * APIProperty: control
+ * {<OpenLayers.Control>}. The control that initialized this handler. The
+ * control is assumed to have a valid map property - that map is used
+ * in the handler's own setMap method.
+ */
+ control: null,
+
+ /**
+ * Property: map
+ * {<OpenLayers.Map>}
+ */
+ map: null,
+
+ /**
+ * APIProperty: keyMask
+ * {Integer} Use bitwise operators and one or more of the OpenLayers.Handler
+ * constants to construct a keyMask. The keyMask is used by
+ * <checkModifiers>. If the keyMask matches the combination of keys
+ * down on an event, checkModifiers returns true.
+ *
+ * Example:
+ * (code)
+ * // handler only responds if the Shift key is down
+ * handler.keyMask = OpenLayers.Handler.MOD_SHIFT;
+ *
+ * // handler only responds if Ctrl-Shift is down
+ * handler.keyMask = OpenLayers.Handler.MOD_SHIFT |
+ * OpenLayers.Handler.MOD_CTRL;
+ * (end)
+ */
+ keyMask: null,
+
+ /**
+ * Property: active
+ * {Boolean}
+ */
+ active: false,
+
+ /**
+ * Property: evt
+ * {Event} This property references the last event handled by the handler.
+ * Note that this property is not part of the stable API. Use of the
+ * evt property should be restricted to controls in the library
+ * or other applications that are willing to update with changes to
+ * the OpenLayers code.
+ */
+ evt: null,
+
+ /**
+ * Constructor: OpenLayers.Handler
+ * Construct a handler.
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>} The control that initialized this
+ * handler. The control is assumed to have a valid map property; that
+ * map is used in the handler's own setMap method. If a map property
+ * is present in the options argument it will be used instead.
+ * callbacks - {Object} An object whose properties correspond to abstracted
+ * events or sequences of browser events. The values for these
+ * properties are functions defined by the control that get called by
+ * the handler.
+ * options - {Object} An optional object whose properties will be set on
+ * the handler.
+ */
+ initialize: function(control, callbacks, options) {
+ OpenLayers.Util.extend(this, options);
+ this.control = control;
+ this.callbacks = callbacks;
+
+ var map = this.map || control.map;
+ if (map) {
+ this.setMap(map);
+ }
+
+ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+ },
+
+ /**
+ * Method: setMap
+ */
+ setMap: function (map) {
+ this.map = map;
+ },
+
+ /**
+ * Method: checkModifiers
+ * Check the keyMask on the handler. If no <keyMask> is set, this always
+ * returns true. If a <keyMask> is set and it matches the combination
+ * of keys down on an event, this returns true.
+ *
+ * Returns:
+ * {Boolean} The keyMask matches the keys down on an event.
+ */
+ checkModifiers: function (evt) {
+ if(this.keyMask == null) {
+ return true;
+ }
+ /* calculate the keyboard modifier mask for this event */
+ var keyModifiers =
+ (evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) |
+ (evt.ctrlKey ? OpenLayers.Handler.MOD_CTRL : 0) |
+ (evt.altKey ? OpenLayers.Handler.MOD_ALT : 0);
+
+ /* if it differs from the handler object's key mask,
+ bail out of the event handler */
+ return (keyModifiers == this.keyMask);
+ },
+
+ /**
+ * APIMethod: activate
+ * Turn on the handler. Returns false if the handler was already active.
+ *
+ * Returns:
+ * {Boolean} The handler was activated.
+ */
+ activate: function() {
+ if(this.active) {
+ return false;
+ }
+ // register for event handlers defined on this class.
+ var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
+ for (var i=0, len=events.length; i<len; i++) {
+ if (this[events[i]]) {
+ this.register(events[i], this[events[i]]);
+ }
+ }
+ this.active = true;
+ return true;
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Turn off the handler. Returns false if the handler was already inactive.
+ *
+ * Returns:
+ * {Boolean} The handler was deactivated.
+ */
+ deactivate: function() {
+ if(!this.active) {
+ return false;
+ }
+ // unregister event handlers defined on this class.
+ var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
+ for (var i=0, len=events.length; i<len; i++) {
+ if (this[events[i]]) {
+ this.unregister(events[i], this[events[i]]);
+ }
+ }
+ this.active = false;
+ return true;
+ },
+
+ /**
+ * Method: callback
+ * Trigger the control's named callback with the given arguments
+ *
+ * Parameters:
+ * name - {String} The key for the callback that is one of the properties
+ * of the handler's callbacks object.
+ * args - {Array(*)} An array of arguments (any type) with which to call
+ * the callback (defined by the control).
+ */
+ callback: function (name, args) {
+ if (name && this.callbacks[name]) {
+ this.callbacks[name].apply(this.control, args);
+ }
+ },
+
+ /**
+ * Method: register
+ * register an event on the map
+ */
+ register: function (name, method) {
+ // TODO: deal with registerPriority in 3.0
+ this.map.events.registerPriority(name, this, method);
+ this.map.events.registerPriority(name, this, this.setEvent);
+ },
+
+ /**
+ * Method: unregister
+ * unregister an event from the map
+ */
+ unregister: function (name, method) {
+ this.map.events.unregister(name, this, method);
+ this.map.events.unregister(name, this, this.setEvent);
+ },
+
+ /**
+ * Method: setEvent
+ * With each registered browser event, the handler sets its own evt
+ * property. This property can be accessed by controls if needed
+ * to get more information about the event that the handler is
+ * processing.
+ *
+ * This allows modifier keys on the event to be checked (alt, shift,
+ * and ctrl cannot be checked with the keyboard handler). For a
+ * control to determine which modifier keys are associated with the
+ * event that a handler is currently processing, it should access
+ * (code)handler.evt.altKey || handler.evt.shiftKey ||
+ * handler.evt.ctrlKey(end).
+ *
+ * Parameters:
+ * evt - {Event} The browser event.
+ */
+ setEvent: function(evt) {
+ this.evt = evt;
+ return true;
+ },
+
+ /**
+ * Method: destroy
+ * Deconstruct the handler.
+ */
+ destroy: function () {
+ // unregister event listeners
+ this.deactivate();
+ // eliminate circular references
+ this.control = this.map = null;
+ },
+
+ CLASS_NAME: "OpenLayers.Handler"
+});
+
+/**
+ * Constant: OpenLayers.Handler.MOD_NONE
+ * If set as the <keyMask>, <checkModifiers> returns false if any key is down.
+ */
+OpenLayers.Handler.MOD_NONE = 0;
+
+/**
+ * Constant: OpenLayers.Handler.MOD_SHIFT
+ * If set as the <keyMask>, <checkModifiers> returns false if Shift is down.
+ */
+OpenLayers.Handler.MOD_SHIFT = 1;
+
+/**
+ * Constant: OpenLayers.Handler.MOD_CTRL
+ * If set as the <keyMask>, <checkModifiers> returns false if Ctrl is down.
+ */
+OpenLayers.Handler.MOD_CTRL = 2;
+
+/**
+ * Constant: OpenLayers.Handler.MOD_ALT
+ * If set as the <keyMask>, <checkModifiers> returns false if Alt is down.
+ */
+OpenLayers.Handler.MOD_ALT = 4;
+
+
+/* ======================================================================
+ OpenLayers/Handler/Point.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Handler.js
+ * @requires OpenLayers/Geometry/Point.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Point
+ * Handler to draw a point on the map. Point is displayed on mouse down,
+ * moves on mouse move, and is finished on mouse up. The handler triggers
+ * callbacks for 'done', 'cancel', and 'modify'. The modify callback is
+ * called with each change in the sketch and will receive the latest point
+ * drawn. Create a new instance with the <OpenLayers.Handler.Point>
+ * constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.Point = OpenLayers.Class(OpenLayers.Handler, {
+
+ /**
+ * Property: point
+ * {<OpenLayers.Feature.Vector>} The currently drawn point
+ */
+ point: null,
+
+ /**
+ * Property: layer
+ * {<OpenLayers.Layer.Vector>} The temporary drawing layer
+ */
+ layer: null,
+
+ /**
+ * APIProperty: multi
+ * {Boolean} Cast features to multi-part geometries before passing to the
+ * layer. Default is false.
+ */
+ multi: false,
+
+ /**
+ * Property: drawing
+ * {Boolean} A point is being drawn
+ */
+ drawing: false,
+
+ /**
+ * Property: mouseDown
+ * {Boolean} The mouse is down
+ */
+ mouseDown: false,
+
+ /**
+ * Property: lastDown
+ * {<OpenLayers.Pixel>} Location of the last mouse down
+ */
+ lastDown: null,
+
+ /**
+ * Property: lastUp
+ * {<OpenLayers.Pixel>}
+ */
+ lastUp: null,
+
+ /**
+ * APIProperty: persist
+ * {Boolean} Leave the feature rendered until destroyFeature is called.
+ * Default is false. If set to true, the feature remains rendered until
+ * destroyFeature is called, typically by deactivating the handler or
+ * starting another drawing.
+ */
+ persist: false,
+
+ /**
+ * Property: layerOptions
+ * {Object} Any optional properties to be set on the sketch layer.
+ */
+ layerOptions: null,
+
+ /**
+ * Constructor: OpenLayers.Handler.Point
+ * Create a new point handler.
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>} The control that owns this handler
+ * callbacks - {Object} An object with a properties whose values are
+ * functions. Various callbacks described below.
+ * options - {Object} An optional object with properties to be set on the
+ * handler
+ *
+ * Named callbacks:
+ * create - Called when a sketch is first created. Callback called with
+ * the creation point geometry and sketch feature.
+ * modify - Called with each move of a vertex with the vertex (point)
+ * geometry and the sketch feature.
+ * done - Called when the point drawing is finished. The callback will
+ * recieve a single argument, the point geometry.
+ * cancel - Called when the handler is deactivated while drawing. The
+ * cancel callback will receive a geometry.
+ */
+ initialize: function(control, callbacks, options) {
+ if(!(options && options.layerOptions && options.layerOptions.styleMap)) {
+ this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {});
+ }
+
+ OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * APIMethod: activate
+ * turn on the handler
+ */
+ activate: function() {
+ if(!OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+ return false;
+ }
+ // create temporary vector layer for rendering geometry sketch
+ // TBD: this could be moved to initialize/destroy - setting visibility here
+ var options = OpenLayers.Util.extend({
+ displayInLayerSwitcher: false,
+ // indicate that the temp vector layer will never be out of range
+ // without this, resolution properties must be specified at the
+ // map-level for this temporary layer to init its resolutions
+ // correctly
+ calculateInRange: OpenLayers.Function.True
+ }, this.layerOptions);
+ this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options);
+ this.map.addLayer(this.layer);
+ return true;
+ },
+
+ /**
+ * Method: createFeature
+ * Add temporary features
+ *
+ * Parameters:
+ * pixel - {<OpenLayers.Pixel>} A pixel location on the map.
+ */
+ createFeature: function(pixel) {
+ var lonlat = this.map.getLonLatFromPixel(pixel);
+ this.point = new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
+ );
+ this.callback("create", [this.point.geometry, this.point]);
+ this.point.geometry.clearBounds();
+ this.layer.addFeatures([this.point], {silent: true});
+ },
+
+ /**
+ * APIMethod: deactivate
+ * turn off the handler
+ */
+ deactivate: function() {
+ if(!OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+ return false;
+ }
+ // call the cancel callback if mid-drawing
+ if(this.drawing) {
+ this.cancel();
+ }
+ this.destroyFeature();
+ // If a layer's map property is set to null, it means that that layer
+ // isn't added to the map. Since we ourself added the layer to the map
+ // in activate(), we can assume that if this.layer.map is null it means
+ // that the layer has been destroyed (as a result of map.destroy() for
+ // example.
+ if (this.layer.map != null) {
+ this.layer.destroy(false);
+ }
+ this.layer = null;
+ return true;
+ },
+
+ /**
+ * Method: destroyFeature
+ * Destroy the temporary geometries
+ */
+ destroyFeature: function() {
+ if(this.layer) {
+ this.layer.destroyFeatures();
+ }
+ this.point = null;
+ },
+
+ /**
+ * Method: finalize
+ * Finish the geometry and call the "done" callback.
+ *
+ * Parameters:
+ * cancel - {Boolean} Call cancel instead of done callback. Default is
+ * false.
+ */
+ finalize: function(cancel) {
+ var key = cancel ? "cancel" : "done";
+ this.drawing = false;
+ this.mouseDown = false;
+ this.lastDown = null;
+ this.lastUp = null;
+ this.callback(key, [this.geometryClone()]);
+ if(cancel || !this.persist) {
+ this.destroyFeature();
+ }
+ },
+
+ /**
+ * APIMethod: cancel
+ * Finish the geometry and call the "cancel" callback.
+ */
+ cancel: function() {
+ this.finalize(true);
+ },
+
+ /**
+ * Method: click
+ * Handle clicks. Clicks are stopped from propagating to other listeners
+ * on map.events or other dom elements.
+ *
+ * Parameters:
+ * evt - {Event} The browser event
+ *
+ * Returns:
+ * {Boolean} Allow event propagation
+ */
+ click: function(evt) {
+ OpenLayers.Event.stop(evt);
+ return false;
+ },
+
+ /**
+ * Method: dblclick
+ * Handle double-clicks. Double-clicks are stopped from propagating to other
+ * listeners on map.events or other dom elements.
+ *
+ * Parameters:
+ * evt - {Event} The browser event
+ *
+ * Returns:
+ * {Boolean} Allow event propagation
+ */
+ dblclick: function(evt) {
+ OpenLayers.Event.stop(evt);
+ return false;
+ },
+
+ /**
+ * Method: modifyFeature
+ * Modify the existing geometry given a pixel location.
+ *
+ * Parameters:
+ * pixel - {<OpenLayers.Pixel>} A pixel location on the map.
+ */
+ modifyFeature: function(pixel) {
+ var lonlat = this.map.getLonLatFromPixel(pixel);
+ this.point.geometry.x = lonlat.lon;
+ this.point.geometry.y = lonlat.lat;
+ this.callback("modify", [this.point.geometry, this.point]);
+ this.point.geometry.clearBounds();
+ this.drawFeature();
+ },
+
+ /**
+ * Method: drawFeature
+ * Render features on the temporary layer.
+ */
+ drawFeature: function() {
+ this.layer.drawFeature(this.point, this.style);
+ },
+
+ /**
+ * Method: getGeometry
+ * Return the sketch geometry. If <multi> is true, this will return
+ * a multi-part geometry.
+ *
+ * Returns:
+ * {<OpenLayers.Geometry.Point>}
+ */
+ getGeometry: function() {
+ var geometry = this.point && this.point.geometry;
+ if(geometry && this.multi) {
+ geometry = new OpenLayers.Geometry.MultiPoint([geometry]);
+ }
+ return geometry;
+ },
+
+ /**
+ * Method: geometryClone
+ * Return a clone of the relevant geometry.
+ *
+ * Returns:
+ * {<OpenLayers.Geometry>}
+ */
+ geometryClone: function() {
+ var geom = this.getGeometry();
+ return geom && geom.clone();
+ },
+
+ /**
+ * Method: mousedown
+ * Handle mouse down. Adjust the geometry and redraw.
+ * Return determines whether to propagate the event on the map.
+ *
+ * Parameters:
+ * evt - {Event} The browser event
+ *
+ * Returns:
+ * {Boolean} Allow event propagation
+ */
+ mousedown: function(evt) {
+ // check keyboard modifiers
+ if(!this.checkModifiers(evt)) {
+ return true;
+ }
+ // ignore double-clicks
+ if(this.lastDown && this.lastDown.equals(evt.xy)) {
+ return true;
+ }
+ this.drawing = true;
+ if(this.lastDown == null) {
+ if(this.persist) {
+ this.destroyFeature();
+ }
+ this.createFeature(evt.xy);
+ } else {
+ this.modifyFeature(evt.xy);
+ }
+ this.lastDown = evt.xy;
+ return false;
+ },
+
+ /**
+ * Method: mousemove
+ * Handle mouse move. Adjust the geometry and redraw.
+ * Return determines whether to propagate the event on the map.
+ *
+ * Parameters:
+ * evt - {Event} The browser event
+ *
+ * Returns:
+ * {Boolean} Allow event propagation
+ */
+ mousemove: function (evt) {
+ if(this.drawing) {
+ this.modifyFeature(evt.xy);
+ }
+ return true;
+ },
+
+ /**
+ * Method: mouseup
+ * Handle mouse up. Send the latest point in the geometry to the control.
+ * Return determines whether to propagate the event on the map.
+ *
+ * Parameters:
+ * evt - {Event} The browser event
+ *
+ * Returns:
+ * {Boolean} Allow event propagation
+ */
+ mouseup: function (evt) {
+ if(this.drawing) {
+ this.finalize();
+ return false;
+ } else {
+ return true;
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.Point"
+});
+/* ======================================================================
+ OpenLayers/Handler/Path.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Handler/Point.js
+ * @requires OpenLayers/Geometry/Point.js
+ * @requires OpenLayers/Geometry/LineString.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Path
+ * Handler to draw a path on the map. Path is displayed on mouse down,
+ * moves on mouse move, and is finished on mouse up.
+ *
+ * Inherits from:
+ * - <OpenLayers.Handler.Point>
+ */
+OpenLayers.Handler.Path = OpenLayers.Class(OpenLayers.Handler.Point, {
+
+ /**
+ * Property: line
+ * {<OpenLayers.Feature.Vector>}
+ */
+ line: null,
+
+ /**
+ * Property: freehand
+ * {Boolean} In freehand mode, the handler starts the path on mouse down,
+ * adds a point for every mouse move, and finishes the path on mouse up.
+ * Outside of freehand mode, a point is added to the path on every mouse
+ * click and double-click finishes the path.
+ */
+ freehand: false,
+
+ /**
+ * Property: freehandToggle
+ * {String} If set, freehandToggle is checked on mouse events and will set
+ * the freehand mode to the opposite of this.freehand. To disallow
+ * toggling between freehand and non-freehand mode, set freehandToggle to
+ * null. Acceptable toggle values are 'shiftKey', 'ctrlKey', and 'altKey'.
+ */
+ freehandToggle: 'shiftKey',
+
+ /**
+ * Constructor: OpenLayers.Handler.Path
+ * Create a new path hander
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>} The control that owns this handler
+ * callbacks - {Object} An object with a properties whose values are
+ * functions. Various callbacks described below.
+ * options - {Object} An optional object with properties to be set on the
+ * handler
+ *
+ * Named callbacks:
+ * create - Called when a sketch is first created. Callback called with
+ * the creation point geometry and sketch feature.
+ * modify - Called with each move of a vertex with the vertex (point)
+ * geometry and the sketch feature.
+ * point - Called as each point is added. Receives the new point geometry.
+ * done - Called when the point drawing is finished. The callback will
+ * recieve a single argument, the linestring geometry.
+ * cancel - Called when the handler is deactivated while drawing. The
+ * cancel callback will receive a geometry.
+ */
+ initialize: function(control, callbacks, options) {
+ OpenLayers.Handler.Point.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * Method: createFeature
+ * Add temporary geometries
+ *
+ * Parameters:
+ * pixel - {<OpenLayers.Pixel>} The initial pixel location for the new
+ * feature.
+ */
+ createFeature: function(pixel) {
+ var lonlat = this.control.map.getLonLatFromPixel(pixel);
+ this.point = new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
+ );
+ this.line = new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.LineString([this.point.geometry])
+ );
+ this.callback("create", [this.point.geometry, this.getSketch()]);
+ this.point.geometry.clearBounds();
+ this.layer.addFeatures([this.line, this.point], {silent: true});
+ },
+
+ /**
+ * Method: destroyFeature
+ * Destroy temporary geometries
+ */
+ destroyFeature: function() {
+ OpenLayers.Handler.Point.prototype.destroyFeature.apply(this);
+ this.line = null;
+ },
+
+ /**
+ * Method: removePoint
+ * Destroy the temporary point.
+ */
+ removePoint: function() {
+ if(this.point) {
+ this.layer.removeFeatures([this.point]);
+ }
+ },
+
+ /**
+ * Method: addPoint
+ * Add point to geometry. Send the point index to override
+ * the behavior of LinearRing that disregards adding duplicate points.
+ *
+ * Parameters:
+ * pixel - {<OpenLayers.Pixel>} The pixel location for the new point.
+ */
+ addPoint: function(pixel) {
+ this.layer.removeFeatures([this.point]);
+ var lonlat = this.control.map.getLonLatFromPixel(pixel);
+ this.point = new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
+ );
+ this.line.geometry.addComponent(
+ this.point.geometry, this.line.geometry.components.length
+ );
+ this.callback("point", [this.point.geometry, this.getGeometry()]);
+ this.callback("modify", [this.point.geometry, this.getSketch()]);
+ this.drawFeature();
+ },
+
+ /**
+ * Method: freehandMode
+ * Determine whether to behave in freehand mode or not.
+ *
+ * Returns:
+ * {Boolean}
+ */
+ freehandMode: function(evt) {
+ return (this.freehandToggle && evt[this.freehandToggle]) ?
+ !this.freehand : this.freehand;
+ },
+
+ /**
+ * Method: modifyFeature
+ * Modify the existing geometry given the new point
+ *
+ * Parameters:
+ * pixel - {<OpenLayers.Pixel>} The updated pixel location for the latest
+ * point.
+ */
+ modifyFeature: function(pixel) {
+ var lonlat = this.control.map.getLonLatFromPixel(pixel);
+ this.point.geometry.x = lonlat.lon;
+ this.point.geometry.y = lonlat.lat;
+ this.callback("modify", [this.point.geometry, this.getSketch()]);
+ this.point.geometry.clearBounds();
+ this.drawFeature();
+ },
+
+ /**
+ * Method: drawFeature
+ * Render geometries on the temporary layer.
+ */
+ drawFeature: function() {
+ this.layer.drawFeature(this.line, this.style);
+ this.layer.drawFeature(this.point, this.style);
+ },
+
+ /**
+ * Method: getSketch
+ * Return the sketch feature.
+ *
+ * Returns:
+ * {<OpenLayers.Feature.Vector>}
+ */
+ getSketch: function() {
+ return this.line;
+ },
+
+ /**
+ * Method: getGeometry
+ * Return the sketch geometry. If <multi> is true, this will return
+ * a multi-part geometry.
+ *
+ * Returns:
+ * {<OpenLayers.Geometry.LineString>}
+ */
+ getGeometry: function() {
+ var geometry = this.line && this.line.geometry;
+ if(geometry && this.multi) {
+ geometry = new OpenLayers.Geometry.MultiLineString([geometry]);
+ }
+ return geometry;
+ },
+
+ /**
+ * Method: mousedown
+ * Handle mouse down. Add a new point to the geometry and
+ * render it. Return determines whether to propagate the event on the map.
+ *
+ * Parameters:
+ * evt - {Event} The browser event
+ *
+ * Returns:
+ * {Boolean} Allow event propagation
+ */
+ mousedown: function(evt) {
+ // ignore double-clicks
+ if (this.lastDown && this.lastDown.equals(evt.xy)) {
+ return false;
+ }
+ if(this.lastDown == null) {
+ if(this.persist) {
+ this.destroyFeature();
+ }
+ this.createFeature(evt.xy);
+ } else if((this.lastUp == null) || !this.lastUp.equals(evt.xy)) {
+ this.addPoint(evt.xy);
+ }
+ this.mouseDown = true;
+ this.lastDown = evt.xy;
+ this.drawing = true;
+ return false;
+ },
+
+ /**
+ * Method: mousemove
+ * Handle mouse move. Adjust the geometry and redraw.
+ * Return determines whether to propagate the event on the map.
+ *
+ * Parameters:
+ * evt - {Event} The browser event
+ *
+ * Returns:
+ * {Boolean} Allow event propagation
+ */
+ mousemove: function (evt) {
+ if(this.drawing) {
+ if(this.mouseDown && this.freehandMode(evt)) {
+ this.addPoint(evt.xy);
+ } else {
+ this.modifyFeature(evt.xy);
+ }
+ }
+ return true;
+ },
+
+ /**
+ * Method: mouseup
+ * Handle mouse up. Send the latest point in the geometry to
+ * the control. Return determines whether to propagate the event on the map.
+ *
+ * Parameters:
+ * evt - {Event} The browser event
+ *
+ * Returns:
+ * {Boolean} Allow event propagation
+ */
+ mouseup: function (evt) {
+ this.mouseDown = false;
+ if(this.drawing) {
+ if(this.freehandMode(evt)) {
+ this.removePoint();
+ this.finalize();
+ } else {
+ if(this.lastUp == null) {
+ this.addPoint(evt.xy);
+ }
+ this.lastUp = evt.xy;
+ }
+ return false;
+ }
+ return true;
+ },
+
+ /**
+ * APIMethod: finishGeometry
+ * Finish the geometry and send it back to the control.
+ */
+ finishGeometry: function() {
+ var index = this.line.geometry.components.length - 1;
+ this.line.geometry.removeComponent(this.line.geometry.components[index]);
+ this.removePoint();
+ this.finalize();
+ },
+
+ /**
+ * Method: dblclick
+ * Handle double-clicks.
+ *
+ * Parameters:
+ * evt - {Event} The browser event
+ *
+ * Returns:
+ * {Boolean} Allow event propagation
+ */
+ dblclick: function(evt) {
+ if(!this.freehandMode(evt)) {
+ this.finishGeometry();
+ }
+ return false;
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.Path"
+});
+/* ======================================================================
+ OpenLayers/Handler/Polygon.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Handler/Path.js
+ * @requires OpenLayers/Geometry/Polygon.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Polygon
+ * Handler to draw a polygon on the map. Polygon is displayed on mouse down,
+ * moves on mouse move, and is finished on mouse up.
+ *
+ * Inherits from:
+ * - <OpenLayers.Handler.Path>
+ * - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.Polygon = OpenLayers.Class(OpenLayers.Handler.Path, {
+
+ /**
+ * APIProperty: holeModifier
+ * {String} Key modifier to trigger hole digitizing. Acceptable values are
+ * "altKey", "shiftKey", or "ctrlKey". If not set, no hole digitizing
+ * will take place. Default is null.
+ */
+ holeModifier: null,
+
+ /**
+ * Property: drawingHole
+ * {Boolean} Currently drawing an interior ring.
+ */
+ drawingHole: false,
+
+ /**
+ * Parameter: polygon
+ * {<OpenLayers.Feature.Vector>}
+ */
+ polygon: null,
+
+ /**
+ * Constructor: OpenLayers.Handler.Polygon
+ * Create a Polygon Handler.
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>} The control that owns this handler
+ * callbacks - {Object} An object with a properties whose values are
+ * functions. Various callbacks described below.
+ * options - {Object} An optional object with properties to be set on the
+ * handler
+ *
+ * Named callbacks:
+ * create - Called when a sketch is first created. Callback called with
+ * the creation point geometry and sketch feature.
+ * modify - Called with each move of a vertex with the vertex (point)
+ * geometry and the sketch feature.
+ * point - Called as each point is added. Receives the new point geometry.
+ * done - Called when the point drawing is finished. The callback will
+ * recieve a single argument, the polygon geometry.
+ * cancel - Called when the handler is deactivated while drawing. The
+ * cancel callback will receive a geometry.
+ */
+ initialize: function(control, callbacks, options) {
+ OpenLayers.Handler.Path.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * Method: createFeature
+ * Add temporary geometries
+ *
+ * Parameters:
+ * pixel - {<OpenLayers.Pixel>} The initial pixel location for the new
+ * feature.
+ */
+ createFeature: function(pixel) {
+ var lonlat = this.control.map.getLonLatFromPixel(pixel);
+ this.point = new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
+ );
+ this.line = new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.LinearRing([this.point.geometry])
+ );
+
+ // check for hole digitizing
+ var polygon;
+ if (this.holeModifier && (this.evt[this.holeModifier])) {
+ var geometry = this.point.geometry;
+ var features = this.control.layer.features;
+ var candidate;
+ // look for intersections, last drawn gets priority
+ for (var i=features.length-1; i>=0; --i) {
+ candidate = features[i].geometry;
+ if ((candidate instanceof OpenLayers.Geometry.Polygon ||
+ candidate instanceof OpenLayers.Geometry.MultiPolygon) &&
+ candidate.intersects(geometry)) {
+ polygon = features[i];
+ this.control.layer.removeFeatures([polygon], {silent: true});
+ this.control.layer.events.registerPriority(
+ "sketchcomplete", this, this.finalizeInteriorRing
+ );
+ this.control.layer.events.registerPriority(
+ "sketchmodified", this, this.enforceTopology
+ );
+ polygon.geometry.addComponent(this.line.geometry);
+ this.polygon = polygon;
+ this.drawingHole = true;
+ break;
+ }
+ }
+ }
+ if (!polygon) {
+ this.polygon = new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.Polygon([this.line.geometry])
+ );
+ }
+
+ this.callback("create", [this.point.geometry, this.getSketch()]);
+ this.point.geometry.clearBounds();
+ this.layer.addFeatures([this.polygon, this.point], {silent: true});
+ },
+
+ /**
+ * Method: enforceTopology
+ * Simple topology enforcement for drawing interior rings. Ensures vertices
+ * of interior rings are contained by exterior ring. Other topology
+ * rules are enforced in <finalizeInteriorRing> to allow drawing of
+ * rings that intersect only during the sketch (e.g. a "C" shaped ring
+ * that nearly encloses another ring).
+ */
+ enforceTopology: function(event) {
+ var point = event.vertex;
+ var components = this.line.geometry.components;
+ // ensure that vertices of interior ring are contained by exterior ring
+ if (!this.polygon.geometry.intersects(point)) {
+ var last = components[components.length-3];
+ point.x = last.x;
+ point.y = last.y;
+ }
+ },
+
+ /**
+ * Method: finalizeInteriorRing
+ * Enforces that new ring has some area and doesn't contain vertices of any
+ * other rings.
+ */
+ finalizeInteriorRing: function() {
+ var ring = this.line.geometry;
+ // ensure that ring has some area
+ var modified = (ring.getArea() !== 0);
+ if (modified) {
+ // ensure that new ring doesn't intersect any other rings
+ var rings = this.polygon.geometry.components;
+ for (var i=rings.length-2; i>=0; --i) {
+ if (ring.intersects(rings[i])) {
+ modified = false;
+ break;
+ }
+ }
+ if (modified) {
+ // ensure that new ring doesn't contain any other rings
+ var target;
+ outer: for (var i=rings.length-2; i>0; --i) {
+ var points = rings[i].components;
+ for (var j=0, jj=points.length; j<jj; ++j) {
+ if (ring.containsPoint(points[j])) {
+ modified = false;
+ break outer;
+ }
+ }
+ }
+ }
+ }
+ if (modified) {
+ if (this.polygon.state !== OpenLayers.State.INSERT) {
+ this.polygon.state = OpenLayers.State.UPDATE;
+ }
+ } else {
+ this.polygon.geometry.removeComponent(ring);
+ }
+ this.restoreFeature();
+ return false;
+ },
+
+ /**
+ * APIMethod: cancel
+ * Finish the geometry and call the "cancel" callback.
+ */
+ cancel: function() {
+ if (this.drawingHole) {
+ this.polygon.geometry.removeComponent(this.line.geometry);
+ this.restoreFeature(true);
+ }
+ return OpenLayers.Handler.Path.prototype.cancel.apply(this, arguments);
+ },
+
+ /**
+ * Method: restoreFeature
+ * Move the feature from the sketch layer to the target layer.
+ *
+ * Properties:
+ * cancel - {Boolean} Cancel drawing. If falsey, the "sketchcomplete" event
+ * will be fired.
+ */
+ restoreFeature: function(cancel) {
+ this.control.layer.events.unregister(
+ "sketchcomplete", this, this.finalizeInteriorRing
+ );
+ this.control.layer.events.unregister(
+ "sketchmodified", this, this.enforceTopology
+ );
+ this.layer.removeFeatures([this.polygon], {silent: true});
+ this.control.layer.addFeatures([this.polygon], {silent: true});
+ this.drawingHole = false;
+ if (!cancel) {
+ // Re-trigger "sketchcomplete" so other listeners can do their
+ // business. While this is somewhat sloppy (if a listener is
+ // registered with registerPriority - not common - between the start
+ // and end of a single ring drawing - very uncommon - it will be
+ // called twice).
+ // TODO: In 3.0, collapse sketch handlers into geometry specific
+ // drawing controls.
+ this.control.layer.events.triggerEvent(
+ "sketchcomplete", {feature : this.polygon}
+ );
+ }
+ },
+
+ /**
+ * Method: destroyFeature
+ * Destroy temporary geometries
+ */
+ destroyFeature: function() {
+ OpenLayers.Handler.Path.prototype.destroyFeature.apply(this);
+ this.polygon = null;
+ },
+
+ /**
+ * Method: drawFeature
+ * Render geometries on the temporary layer.
+ */
+ drawFeature: function() {
+ this.layer.drawFeature(this.polygon, this.style);
+ this.layer.drawFeature(this.point, this.style);
+ },
+
+ /**
+ * Method: getSketch
+ * Return the sketch feature.
+ *
+ * Returns:
+ * {<OpenLayers.Feature.Vector>}
+ */
+ getSketch: function() {
+ return this.polygon;
+ },
+
+ /**
+ * Method: getGeometry
+ * Return the sketch geometry. If <multi> is true, this will return
+ * a multi-part geometry.
+ *
+ * Returns:
+ * {<OpenLayers.Geometry.Polygon>}
+ */
+ getGeometry: function() {
+ var geometry = this.polygon && this.polygon.geometry;
+ if(geometry && this.multi) {
+ geometry = new OpenLayers.Geometry.MultiPolygon([geometry]);
+ }
+ return geometry;
+ },
+
+ /**
+ * Method: dblclick
+ * Handle double-clicks. Finish the geometry and send it back
+ * to the control.
+ *
+ * Parameters:
+ * evt - {Event}
+ */
+ dblclick: function(evt) {
+ if(!this.freehandMode(evt)) {
+ // remove the penultimate point
+ var index = this.line.geometry.components.length - 2;
+ this.line.geometry.removeComponent(this.line.geometry.components[index]);
+ this.removePoint();
+ this.finalize();
+ }
+ return false;
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.Polygon"
+});
+/* ======================================================================
+ OpenLayers/Renderer.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ */
+
+/**
+ * Class: OpenLayers.Renderer
+ * This is the base class for all renderers.
+ *
+ * This is based on a merger code written by Paul Spencer and Bertil Chapuis.
+ * It is largely composed of virtual functions that are to be implemented
+ * in technology-specific subclasses, but there is some generic code too.
+ *
+ * The functions that *are* implemented here merely deal with the maintenance
+ * of the size and extent variables, as well as the cached 'resolution'
+ * value.
+ *
+ * A note to the user that all subclasses should use getResolution() instead
+ * of directly accessing this.resolution in order to correctly use the
+ * cacheing system.
+ *
+ */
+OpenLayers.Renderer = OpenLayers.Class({
+
+ /**
+ * Property: container
+ * {DOMElement}
+ */
+ container: null,
+
+ /**
+ * Property: root
+ * {DOMElement}
+ */
+ root: null,
+
+ /**
+ * Property: extent
+ * {<OpenLayers.Bounds>}
+ */
+ extent: null,
+
+ /**
+ * Property: locked
+ * {Boolean} If the renderer is currently in a state where many things
+ * are changing, the 'locked' property is set to true. This means
+ * that renderers can expect at least one more drawFeature event to be
+ * called with the 'locked' property set to 'true': In some renderers,
+ * this might make sense to use as a 'only update local information'
+ * flag.
+ */
+ locked: false,
+
+ /**
+ * Property: size
+ * {<OpenLayers.Size>}
+ */
+ size: null,
+
+ /**
+ * Property: resolution
+ * {Float} cache of current map resolution
+ */
+ resolution: null,
+
+ /**
+ * Property: map
+ * {<OpenLayers.Map>} Reference to the map -- this is set in Vector's setMap()
+ */
+ map: null,
+
+ /**
+ * Constructor: OpenLayers.Renderer
+ *
+ * Parameters:
+ * containerID - {<String>}
+ * options - {Object} options for this renderer. See sublcasses for
+ * supported options.
+ */
+ initialize: function(containerID, options) {
+ this.container = OpenLayers.Util.getElement(containerID);
+ },
+
+ /**
+ * APIMethod: destroy
+ */
+ destroy: function() {
+ this.container = null;
+ this.extent = null;
+ this.size = null;
+ this.resolution = null;
+ this.map = null;
+ },
+
+ /**
+ * APIMethod: supported
+ * This should be overridden by specific subclasses
+ *
+ * Returns:
+ * {Boolean} Whether or not the browser supports the renderer class
+ */
+ supported: function() {
+ return false;
+ },
+
+ /**
+ * Method: setExtent
+ * Set the visible part of the layer.
+ *
+ * Resolution has probably changed, so we nullify the resolution
+ * cache (this.resolution) -- this way it will be re-computed when
+ * next it is needed.
+ * We nullify the resolution cache (this.resolution) if resolutionChanged
+ * is set to true - this way it will be re-computed on the next
+ * getResolution() request.
+ *
+ * Parameters:
+ * extent - {<OpenLayers.Bounds>}
+ * resolutionChanged - {Boolean}
+ */
+ setExtent: function(extent, resolutionChanged) {
+ this.extent = extent.clone();
+ if (resolutionChanged) {
+ this.resolution = null;
+ }
+ },
+
+ /**
+ * Method: setSize
+ * Sets the size of the drawing surface.
+ *
+ * Resolution has probably changed, so we nullify the resolution
+ * cache (this.resolution) -- this way it will be re-computed when
+ * next it is needed.
+ *
+ * Parameters:
+ * size - {<OpenLayers.Size>}
+ */
+ setSize: function(size) {
+ this.size = size.clone();
+ this.resolution = null;
+ },
+
+ /**
+ * Method: getResolution
+ * Uses cached copy of resolution if available to minimize computing
+ *
+ * Returns:
+ * The current map's resolution
+ */
+ getResolution: function() {
+ this.resolution = this.resolution || this.map.getResolution();
+ return this.resolution;
+ },
+
+ /**
+ * Method: drawFeature
+ * Draw the feature. The optional style argument can be used
+ * to override the feature's own style. This method should only
+ * be called from layer.drawFeature().
+ *
+ * Parameters:
+ * feature - {<OpenLayers.Feature.Vector>}
+ * style - {<Object>}
+ *
+ * Returns:
+ * {Boolean} true if the feature has been drawn completely, false if not,
+ * undefined if the feature had no geometry
+ */
+ drawFeature: function(feature, style) {
+ if(style == null) {
+ style = feature.style;
+ }
+ if (feature.geometry) {
+ var bounds = feature.geometry.getBounds();
+ if(bounds) {
+ if (!bounds.intersectsBounds(this.extent)) {
+ style = {display: "none"};
+ }
+ var rendered = this.drawGeometry(feature.geometry, style, feature.id);
+ if(style.display != "none" && style.label && rendered !== false) {
+ var location = feature.geometry.getCentroid();
+ if(style.labelXOffset || style.labelYOffset) {
+ var xOffset = isNaN(style.labelXOffset) ? 0 : style.labelXOffset;
+ var yOffset = isNaN(style.labelYOffset) ? 0 : style.labelYOffset;
+ var res = this.getResolution();
+ location.move(xOffset*res, yOffset*res);
+ }
+ this.drawText(feature.id, style, location);
+ } else {
+ this.removeText(feature.id);
+ }
+ return rendered;
+ }
+ }
+ },
+
+
+ /**
+ * Method: drawGeometry
+ *
+ * Draw a geometry. This should only be called from the renderer itself.
+ * Use layer.drawFeature() from outside the renderer.
+ * virtual function
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ * style - {Object}
+ * featureId - {<String>}
+ */
+ drawGeometry: function(geometry, style, featureId) {},
+
+ /**
+ * Method: drawText
+ * Function for drawing text labels.
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * featureId - {String}
+ * style -
+ * location - {<OpenLayers.Geometry.Point>}
+ */
+ drawText: function(featureId, style, location) {},
+
+ /**
+ * Method: removeText
+ * Function for removing text labels.
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * featureId - {String}
+ */
+ removeText: function(featureId) {},
+
+ /**
+ * Method: clear
+ * Clear all vectors from the renderer.
+ * virtual function.
+ */
+ clear: function() {},
+
+ /**
+ * Method: getFeatureIdFromEvent
+ * Returns a feature id from an event on the renderer.
+ * How this happens is specific to the renderer. This should be
+ * called from layer.getFeatureFromEvent().
+ * Virtual function.
+ *
+ * Parameters:
+ * evt - {<OpenLayers.Event>}
+ *
+ * Returns:
+ * {String} A feature id or null.
+ */
+ getFeatureIdFromEvent: function(evt) {},
+
+ /**
+ * Method: eraseFeatures
+ * This is called by the layer to erase features
+ *
+ * Parameters:
+ * features - {Array(<OpenLayers.Feature.Vector>)}
+ */
+ eraseFeatures: function(features) {
+ if(!(features instanceof Array)) {
+ features = [features];
+ }
+ for(var i=0, len=features.length; i<len; ++i) {
+ var feature = features[i];
+ this.eraseGeometry(feature.geometry, feature.id);
+ this.removeText(feature.id);
+ }
+ },
+
+ /**
+ * Method: eraseGeometry
+ * Remove a geometry from the renderer (by id).
+ * virtual function.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ * featureId - {String}
+ */
+ eraseGeometry: function(geometry, featureId) {},
+
+ /**
+ * Method: moveRoot
+ * moves this renderer's root to a (different) renderer.
+ * To be implemented by subclasses that require a common renderer root for
+ * feature selection.
+ *
+ * Parameters:
+ * renderer - {<OpenLayers.Renderer>} target renderer for the moved root
+ */
+ moveRoot: function(renderer) {},
+
+ /**
+ * Method: getRenderLayerId
+ * Gets the layer that this renderer's output appears on. If moveRoot was
+ * used, this will be different from the id of the layer containing the
+ * features rendered by this renderer.
+ *
+ * Returns:
+ * {String} the id of the output layer.
+ */
+ getRenderLayerId: function() {
+ return this.container.id;
+ },
+
+ /**
+ * Method: applyDefaultSymbolizer
+ *
+ * Parameters:
+ * symbolizer - {Object}
+ *
+ * Returns:
+ * {Object}
+ */
+ applyDefaultSymbolizer: function(symbolizer) {
+ var result = OpenLayers.Util.extend({},
+ OpenLayers.Renderer.defaultSymbolizer);
+ if(symbolizer.stroke === false) {
+ delete result.strokeWidth;
+ delete result.strokeColor;
+ }
+ if(symbolizer.fill === false) {
+ delete result.fillColor;
+ }
+ OpenLayers.Util.extend(result, symbolizer);
+ return result;
+ },
+
+ CLASS_NAME: "OpenLayers.Renderer"
+});
+
+/**
+ * Constant: OpenLayers.Renderer.defaultSymbolizer
+ * {Object} Properties from this symbolizer will be applied to symbolizers
+ * with missing properties. This can also be used to set a global
+ * symbolizer default in OpenLayers. To be SLD 1.x compliant, add the
+ * following code before rendering any vector features:
+ * (code)
+ * OpenLayers.Renderer.defaultSymbolizer = {
+ * fillColor: "#808080",
+ * fillOpacity: 1,
+ * strokeColor: "#000000",
+ * strokeOpacity: 1,
+ * strokeWidth: 1,
+ * pointRadius: 3,
+ * graphicName: "square"
+ * };
+ * (end)
+ */
+OpenLayers.Renderer.defaultSymbolizer = {
+ fillColor: "#000000",
+ strokeColor: "#000000",
+ strokeWidth: 2,
+ fillOpacity: 1,
+ strokeOpacity: 1,
+ pointRadius: 0
+};
+
+/* ======================================================================
+ OpenLayers/Renderer/Canvas.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Renderer.js
+ */
+
+/**
+ * Class: OpenLayers.Renderer.Canvas
+ * A renderer based on the 2D 'canvas' drawing element.element
+ *
+ * Inherits:
+ * - <OpenLayers.Renderer>
+ */
+OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
+
+ /**
+ * Property: canvas
+ * {Canvas} The canvas context object.
+ */
+ canvas: null,
+
+ /**
+ * Property: features
+ * {Object} Internal object of feature/style pairs for use in redrawing the layer.
+ */
+ features: null,
+
+ /**
+ * Constructor: OpenLayers.Renderer.Canvas
+ *
+ * Parameters:
+ * containerID - {<String>}
+ */
+ initialize: function(containerID) {
+ OpenLayers.Renderer.prototype.initialize.apply(this, arguments);
+ this.root = document.createElement("canvas");
+ this.container.appendChild(this.root);
+ this.canvas = this.root.getContext("2d");
+ this.features = {};
+ },
+
+ /**
+ * Method: eraseGeometry
+ * Erase a geometry from the renderer. Because the Canvas renderer has
+ * 'memory' of the features that it has drawn, we have to remove the
+ * feature so it doesn't redraw.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ * featureId - {String}
+ */
+ eraseGeometry: function(geometry, featureId) {
+ this.eraseFeatures(this.features[featureId][0]);
+ },
+
+ /**
+ * APIMethod: supported
+ *
+ * Returns:
+ * {Boolean} Whether or not the browser supports the renderer class
+ */
+ supported: function() {
+ var canvas = document.createElement("canvas");
+ return !!canvas.getContext;
+ },
+
+ /**
+ * Method: setSize
+ * Sets the size of the drawing surface.
+ *
+ * Once the size is updated, redraw the canvas.
+ *
+ * Parameters:
+ * size - {<OpenLayers.Size>}
+ */
+ setSize: function(size) {
+ this.size = size.clone();
+ this.root.style.width = size.w + "px";
+ this.root.style.height = size.h + "px";
+ this.root.width = size.w;
+ this.root.height = size.h;
+ this.resolution = null;
+ },
+
+ /**
+ * Method: drawFeature
+ * Draw the feature. Stores the feature in the features list,
+ * then redraws the layer.
+ *
+ * Parameters:
+ * feature - {<OpenLayers.Feature.Vector>}
+ * style - {<Object>}
+ */
+ drawFeature: function(feature, style) {
+ style = style || feature.style;
+ style = this.applyDefaultSymbolizer(style);
+
+ this.features[feature.id] = [feature, style];
+ this.redraw();
+ },
+
+
+ /**
+ * Method: drawGeometry
+ * Used when looping (in redraw) over the features; draws
+ * the canvas.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ * style - {Object}
+ */
+ drawGeometry: function(geometry, style) {
+ var className = geometry.CLASS_NAME;
+ if ((className == "OpenLayers.Geometry.Collection") ||
+ (className == "OpenLayers.Geometry.MultiPoint") ||
+ (className == "OpenLayers.Geometry.MultiLineString") ||
+ (className == "OpenLayers.Geometry.MultiPolygon")) {
+ for (var i = 0; i < geometry.components.length; i++) {
+ this.drawGeometry(geometry.components[i], style);
+ }
+ return;
+ }
+ switch (geometry.CLASS_NAME) {
+ case "OpenLayers.Geometry.Point":
+ this.drawPoint(geometry, style);
+ break;
+ case "OpenLayers.Geometry.LineString":
+ this.drawLineString(geometry, style);
+ break;
+ case "OpenLayers.Geometry.LinearRing":
+ this.drawLinearRing(geometry, style);
+ break;
+ case "OpenLayers.Geometry.Polygon":
+ this.drawPolygon(geometry, style);
+ break;
+ default:
+ break;
+ }
+ },
+
+ /**
+ * Method: drawExternalGraphic
+ * Called to draw External graphics.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ * style - {Object}
+ */
+ drawExternalGraphic: function(pt, style) {
+ var img = new Image();
+
+ if(style.graphicTitle) {
+ img.title=style.graphicTitle;
+ }
+
+ var width = style.graphicWidth || style.graphicHeight;
+ var height = style.graphicHeight || style.graphicWidth;
+ width = width ? width : style.pointRadius*2;
+ height = height ? height : style.pointRadius*2;
+ var xOffset = (style.graphicXOffset != undefined) ?
+ style.graphicXOffset : -(0.5 * width);
+ var yOffset = (style.graphicYOffset != undefined) ?
+ style.graphicYOffset : -(0.5 * height);
+
+ var context = { img: img,
+ x: (pt[0]+xOffset),
+ y: (pt[1]+yOffset),
+ width: width,
+ height: height,
+ opacity: style.graphicOpacity || style.fillOpacity,
+ canvas: this.canvas };
+
+ img.onload = OpenLayers.Function.bind( function() {
+ this.canvas.globalAlpha = this.opacity;
+ this.canvas.drawImage(this.img, this.x,
+ this.y, this.width, this.height);
+ }, context);
+ img.src = style.externalGraphic;
+ },
+
+ /**
+ * Method: setCanvasStyle
+ * Prepare the canvas for drawing by setting various global settings.
+ *
+ * Parameters:
+ * type - {String} one of 'stroke', 'fill', or 'reset'
+ * style - {Object} Symbolizer hash
+ */
+ setCanvasStyle: function(type, style) {
+ if (type == "fill") {
+ this.canvas.globalAlpha = style['fillOpacity'];
+ this.canvas.fillStyle = style['fillColor'];
+ } else if (type == "stroke") {
+ this.canvas.globalAlpha = style['strokeOpacity'];
+ this.canvas.strokeStyle = style['strokeColor'];
+ this.canvas.lineWidth = style['strokeWidth'];
+ } else {
+ this.canvas.globalAlpha = 0;
+ this.canvas.lineWidth = 1;
+ }
+ },
+
+ /**
+ * Method: drawPoint
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ * style - {Object}
+ */
+ drawPoint: function(geometry, style) {
+ if(style.graphic !== false) {
+ var pt = this.getLocalXY(geometry);
+
+ if (style.externalGraphic) {
+ this.drawExternalGraphic(pt, style);
+ } else {
+ if(style.fill !== false) {
+ this.setCanvasStyle("fill", style);
+ this.canvas.beginPath();
+ this.canvas.arc(pt[0], pt[1], style.pointRadius, 0, Math.PI*2, true);
+ this.canvas.fill();
+ }
+
+ if(style.stroke !== false) {
+ this.setCanvasStyle("stroke", style);
+ this.canvas.beginPath();
+ this.canvas.arc(pt[0], pt[1], style.pointRadius, 0, Math.PI*2, true);
+ this.canvas.stroke();
+ this.setCanvasStyle("reset");
+ }
+ }
+ }
+ },
+
+ /**
+ * Method: drawLineString
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ * style - {Object}
+ */
+ drawLineString: function(geometry, style) {
+ if(style.stroke !== false) {
+ this.setCanvasStyle("stroke", style);
+ this.canvas.beginPath();
+ var start = this.getLocalXY(geometry.components[0]);
+ this.canvas.moveTo(start[0], start[1]);
+ for(var i = 1; i < geometry.components.length; i++) {
+ var pt = this.getLocalXY(geometry.components[i]);
+ this.canvas.lineTo(pt[0], pt[1]);
+ }
+ this.canvas.stroke();
+ }
+ this.setCanvasStyle("reset");
+ },
+
+ /**
+ * Method: drawLinearRing
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ * style - {Object}
+ */
+ drawLinearRing: function(geometry, style) {
+ if(style.fill !== false) {
+ this.setCanvasStyle("fill", style);
+ this.canvas.beginPath();
+ var start = this.getLocalXY(geometry.components[0]);
+ this.canvas.moveTo(start[0], start[1]);
+ for(var i = 1; i < geometry.components.length - 1 ; i++) {
+ var pt = this.getLocalXY(geometry.components[i]);
+ this.canvas.lineTo(pt[0], pt[1]);
+ }
+ this.canvas.fill();
+ }
+
+ if(style.stroke !== false) {
+ this.setCanvasStyle("stroke", style);
+ this.canvas.beginPath();
+ var start = this.getLocalXY(geometry.components[0]);
+ this.canvas.moveTo(start[0], start[1]);
+ for(var i = 1; i < geometry.components.length; i++) {
+ var pt = this.getLocalXY(geometry.components[i]);
+ this.canvas.lineTo(pt[0], pt[1]);
+ }
+ this.canvas.stroke();
+ }
+ this.setCanvasStyle("reset");
+ },
+
+ /**
+ * Method: drawPolygon
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ * style - {Object}
+ */
+ drawPolygon: function(geometry, style) {
+ this.drawLinearRing(geometry.components[0], style);
+ for (var i = 1; i < geometry.components.length; i++) {
+ this.drawLinearRing(geometry.components[i], {
+ fillOpacity: 0,
+ strokeWidth: 0,
+ strokeOpacity: 0,
+ strokeColor: '#000000',
+ fillColor: '#000000'}
+ ); // inner rings are 'empty'
+ }
+ },
+
+ /**
+ * Method: drawText
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * location - {<OpenLayers.Point>}
+ * style - {Object}
+ */
+ drawText: function(location, style) {
+ style = OpenLayers.Util.extend({
+ fontColor: "#000000",
+ labelAlign: "cm"
+ }, style);
+ var pt = this.getLocalXY(location);
+
+ this.setCanvasStyle("reset");
+ this.canvas.fillStyle = style.fontColor;
+ this.canvas.globalAlpha = style.fontOpacity || 1.0;
+ var fontStyle = style.fontWeight + " " + style.fontSize + " " + style.fontFamily;
+ if (this.canvas.fillText) {
+ // HTML5
+ var labelAlign =
+ OpenLayers.Renderer.Canvas.LABEL_ALIGN[style.labelAlign[0]] ||
+ "center";
+ this.canvas.font = fontStyle;
+ this.canvas.textAlign = labelAlign;
+ this.canvas.fillText(style.label, pt[0], pt[1]);
+ } else if (this.canvas.mozDrawText) {
+ // Mozilla pre-Gecko1.9.1 (<FF3.1)
+ this.canvas.mozTextStyle = fontStyle;
+ // No built-in text alignment, so we measure and adjust the position
+ var len = this.canvas.mozMeasureText(style.label);
+ switch(style.labelAlign[0]) {
+ case "l":
+ break;
+ case "r":
+ pt[0] -= len;
+ break;
+ case "c":
+ default:
+ pt[0] -= len / 2;
+ }
+ this.canvas.translate(pt[0], pt[1]);
+
+ this.canvas.mozDrawText(style.label);
+ this.canvas.translate(-1*pt[0], -1*pt[1]);
+ }
+ this.setCanvasStyle("reset");
+ },
+
+ /**
+ * Method: getLocalXY
+ * transform geographic xy into pixel xy
+ *
+ * Parameters:
+ * point - {<OpenLayers.Geometry.Point>}
+ */
+ getLocalXY: function(point) {
+ var resolution = this.getResolution();
+ var extent = this.extent;
+ var x = (point.x / resolution + (-extent.left / resolution));
+ var y = ((extent.top / resolution) - point.y / resolution);
+ return [x, y];
+ },
+
+ /**
+ * Method: clear
+ * Clear all vectors from the renderer.
+ */
+ clear: function() {
+ this.canvas.clearRect(0, 0, this.root.width, this.root.height);
+ this.features = {};
+ },
+
+ /**
+ * Method: getFeatureIdFromEvent
+ * Returns a feature id from an event on the renderer.
+ *
+ * Parameters:
+ * evt - {<OpenLayers.Event>}
+ *
+ * Returns:
+ * {String} A feature id or null.
+ */
+ getFeatureIdFromEvent: function(evt) {
+ var loc = this.map.getLonLatFromPixel(evt.xy);
+ var resolution = this.getResolution();
+ var bounds = new OpenLayers.Bounds(loc.lon - resolution * 5,
+ loc.lat - resolution * 5,
+ loc.lon + resolution * 5,
+ loc.lat + resolution * 5);
+ var geom = bounds.toGeometry();
+ for (var feat in this.features) {
+ if (!this.features.hasOwnProperty(feat)) { continue; }
+ if (this.features[feat][0].geometry.intersects(geom)) {
+ return feat;
+ }
+ }
+ return null;
+ },
+
+ /**
+ * Method: eraseFeatures
+ * This is called by the layer to erase features; removes the feature from
+ * the list, then redraws the layer.
+ *
+ * Parameters:
+ * features - {Array(<OpenLayers.Feature.Vector>)}
+ */
+ eraseFeatures: function(features) {
+ if(!(features instanceof Array)) {
+ features = [features];
+ }
+ for(var i=0; i<features.length; ++i) {
+ delete this.features[features[i].id];
+ }
+ this.redraw();
+ },
+
+ /**
+ * Method: redraw
+ * The real 'meat' of the function: any time things have changed,
+ * redraw() can be called to loop over all the data and (you guessed
+ * it) redraw it. Unlike Elements-based Renderers, we can't interact
+ * with things once they're drawn, to remove them, for example, so
+ * instead we have to just clear everything and draw from scratch.
+ */
+ redraw: function() {
+ if (!this.locked) {
+ this.canvas.clearRect(0, 0, this.root.width, this.root.height);
+ var labelMap = [];
+ var feature, style;
+ for (var id in this.features) {
+ if (!this.features.hasOwnProperty(id)) { continue; }
+ feature = this.features[id][0];
+ style = this.features[id][1];
+ if (!feature.geometry) { continue; }
+ this.drawGeometry(feature.geometry, style);
+ if(style.label) {
+ labelMap.push([feature, style]);
+ }
+ }
+ var item;
+ for (var i=0, len=labelMap.length; i<len; ++i) {
+ item = labelMap[i];
+ this.drawText(item[0].geometry.getCentroid(), item[1]);
+ }
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Renderer.Canvas"
+});
+
+/**
+ * Constant: OpenLayers.Renderer.Canvas.LABEL_ALIGN
+ * {Object}
+ */
+OpenLayers.Renderer.Canvas.LABEL_ALIGN = {
+ "l": "left",
+ "r": "right"
+};
+/* ======================================================================
+ OpenLayers/Handler/MouseWheel.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.MouseWheel
+ * Handler for wheel up/down events.
+ *
+ * Inherits from:
+ * - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, {
+ /**
+ * Property: wheelListener
+ * {function}
+ */
+ wheelListener: null,
+
+ /**
+ * Property: mousePosition
+ * {<OpenLayers.Pixel>} mousePosition is necessary because
+ * evt.clientX/Y is buggy in Moz on wheel events, so we cache and use the
+ * value from the last mousemove.
+ */
+ mousePosition: null,
+
+ /**
+ * Property: interval
+ * {Integer} In order to increase server performance, an interval (in
+ * milliseconds) can be set to reduce the number of up/down events
+ * called. If set, a new up/down event will not be set until the
+ * interval has passed.
+ * Defaults to 0, meaning no interval.
+ */
+ interval: 0,
+
+ /**
+ * Property: delta
+ * {Integer} When interval is set, delta collects the mousewheel z-deltas
+ * of the events that occur within the interval.
+ * See also the cumulative option
+ */
+ delta: 0,
+
+ /**
+ * Property: cumulative
+ * {Boolean} When interval is set: true to collect all the mousewheel
+ * z-deltas, false to only record the delta direction (positive or
+ * negative)
+ */
+ cumulative: true,
+
+ /**
+ * Constructor: OpenLayers.Handler.MouseWheel
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>}
+ * callbacks - {Object} An object containing a single function to be
+ * called when the drag operation is finished.
+ * The callback should expect to recieve a single
+ * argument, the point geometry.
+ * options - {Object}
+ */
+ initialize: function(control, callbacks, options) {
+ OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+ this.wheelListener = OpenLayers.Function.bindAsEventListener(
+ this.onWheelEvent, this
+ );
+ },
+
+ /**
+ * Method: destroy
+ */
+ destroy: function() {
+ OpenLayers.Handler.prototype.destroy.apply(this, arguments);
+ this.wheelListener = null;
+ },
+
+ /**
+ * Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/
+ */
+
+ /**
+ * Method: onWheelEvent
+ * Catch the wheel event and handle it xbrowserly
+ *
+ * Parameters:
+ * e - {Event}
+ */
+ onWheelEvent: function(e){
+
+ // make sure we have a map and check keyboard modifiers
+ if (!this.map || !this.checkModifiers(e)) {
+ return;
+ }
+
+ // Ride up the element's DOM hierarchy to determine if it or any of
+ // its ancestors was:
+ // * specifically marked as scrollable
+ // * one of our layer divs
+ // * the map div
+ //
+ var overScrollableDiv = false;
+ var overLayerDiv = false;
+ var overMapDiv = false;
+
+ var elem = OpenLayers.Event.element(e);
+ while((elem != null) && !overMapDiv && !overScrollableDiv) {
+
+ if (!overScrollableDiv) {
+ try {
+ if (elem.currentStyle) {
+ overflow = elem.currentStyle["overflow"];
+ } else {
+ var style =
+ document.defaultView.getComputedStyle(elem, null);
+ var overflow = style.getPropertyValue("overflow");
+ }
+ overScrollableDiv = ( overflow &&
+ (overflow == "auto") || (overflow == "scroll") );
+ } catch(err) {
+ //sometimes when scrolling in a popup, this causes
+ // obscure browser error
+ }
+ }
+
+ if (!overLayerDiv) {
+ for(var i=0, len=this.map.layers.length; i<len; i++) {
+ // Are we in the layer div? Note that we have two cases
+ // here: one is to catch EventPane layers, which have a
+ // pane above the layer (layer.pane)
+ if (elem == this.map.layers[i].div
+ || elem == this.map.layers[i].pane) {
+ overLayerDiv = true;
+ break;
+ }
+ }
+ }
+ overMapDiv = (elem == this.map.div);
+
+ elem = elem.parentNode;
+ }
+
+ // Logic below is the following:
+ //
+ // If we are over a scrollable div or not over the map div:
+ // * do nothing (let the browser handle scrolling)
+ //
+ // otherwise
+ //
+ // If we are over the layer div:
+ // * zoom/in out
+ // then
+ // * kill event (so as not to also scroll the page after zooming)
+ //
+ // otherwise
+ //
+ // Kill the event (dont scroll the page if we wheel over the
+ // layerswitcher or the pan/zoom control)
+ //
+ if (!overScrollableDiv && overMapDiv) {
+ if (overLayerDiv) {
+ var delta = 0;
+ if (!e) {
+ e = window.event;
+ }
+ if (e.wheelDelta) {
+ delta = e.wheelDelta/120;
+ if (window.opera && window.opera.version() < 9.2) {
+ delta = -delta;
+ }
+ } else if (e.detail) {
+ delta = -e.detail / 3;
+ }
+ this.delta = this.delta + delta;
+
+ if(this.interval) {
+ window.clearTimeout(this._timeoutId);
+ this._timeoutId = window.setTimeout(
+ OpenLayers.Function.bind(function(){
+ this.wheelZoom(e);
+ }, this),
+ this.interval
+ );
+ } else {
+ this.wheelZoom(e);
+ }
+ }
+ OpenLayers.Event.stop(e);
+ }
+ },
+
+ /**
+ * Method: wheelZoom
+ * Given the wheel event, we carry out the appropriate zooming in or out,
+ * based on the 'wheelDelta' or 'detail' property of the event.
+ *
+ * Parameters:
+ * e - {Event}
+ */
+ wheelZoom: function(e) {
+ var delta = this.delta;
+ this.delta = 0;
+
+ if (delta) {
+ // add the mouse position to the event because mozilla has
+ // a bug with clientX and clientY (see
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=352179)
+ // getLonLatFromViewPortPx(e) returns wrong values
+ if (this.mousePosition) {
+ e.xy = this.mousePosition;
+ }
+ if (!e.xy) {
+ // If the mouse hasn't moved over the map yet, then
+ // we don't have a mouse position (in FF), so we just
+ // act as if the mouse was at the center of the map.
+ // Note that we can tell we are in the map -- and
+ // this.map is ensured to be true above.
+ e.xy = this.map.getPixelFromLonLat(
+ this.map.getCenter()
+ );
+ }
+ if (delta < 0) {
+ this.callback("down", [e, this.cumulative ? delta : -1]);
+ } else {
+ this.callback("up", [e, this.cumulative ? delta : 1]);
+ }
+ }
+ },
+
+ /**
+ * Method: mousemove
+ * Update the stored mousePosition on every move.
+ *
+ * Parameters:
+ * evt - {Event} The browser event
+ *
+ * Returns:
+ * {Boolean} Allow event propagation
+ */
+ mousemove: function (evt) {
+ this.mousePosition = evt.xy;
+ },
+
+ /**
+ * Method: activate
+ */
+ activate: function (evt) {
+ if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+ //register mousewheel events specifically on the window and document
+ var wheelListener = this.wheelListener;
+ OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener);
+ OpenLayers.Event.observe(window, "mousewheel", wheelListener);
+ OpenLayers.Event.observe(document, "mousewheel", wheelListener);
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Method: deactivate
+ */
+ deactivate: function (evt) {
+ if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+ // unregister mousewheel events specifically on the window and document
+ var wheelListener = this.wheelListener;
+ OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener);
+ OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener);
+ OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener);
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.MouseWheel"
+});
+/* ======================================================================
+ OpenLayers/Symbolizer.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ */
+
+/**
+ * Class: OpenLayers.Symbolizer
+ * Base class representing a symbolizer used for feature rendering.
+ */
+OpenLayers.Symbolizer = OpenLayers.Class({
+
+
+ /**
+ * APIProperty: zIndex
+ * {Number} The zIndex determines the rendering order for a symbolizer.
+ * Symbolizers with larger zIndex values are rendered over symbolizers
+ * with smaller zIndex values. Default is 0.
+ */
+ zIndex: 0,
+
+ /**
+ * Constructor: OpenLayers.Symbolizer
+ * Instances of this class are not useful. See one of the subclasses.
+ *
+ * Parameters:
+ * config - {Object} An object containing properties to be set on the
+ * symbolizer. Any documented symbolizer property can be set at
+ * construction.
+ *
+ * Returns:
+ * A new symbolizer.
+ */
+ initialize: function(config) {
+ OpenLayers.Util.extend(this, config);
+ },
+
+ /**
+ * APIMethod: clone
+ * Create a copy of this symbolizer.
+ *
+ * Returns a symbolizer of the same type with the same properties.
+ */
+ clone: function() {
+ var Type = eval(this.CLASS_NAME);
+ return new Type(OpenLayers.Util.extend({}, this));
+ },
+
+ CLASS_NAME: "OpenLayers.Symbolizer"
+
+});
+
+/* ======================================================================
+ OpenLayers/Symbolizer/Raster.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Symbolizer.js
+ */
+
+/**
+ * Class: OpenLayers.Symbolizer.Raster
+ * A symbolizer used to render raster images.
+ */
+OpenLayers.Symbolizer.Raster = OpenLayers.Class(OpenLayers.Symbolizer, {
+
+ /**
+ * Constructor: OpenLayers.Symbolizer.Raster
+ * Create a symbolizer for rendering rasters.
+ *
+ * Parameters:
+ * config - {Object} An object containing properties to be set on the
+ * symbolizer. Any documented symbolizer property can be set at
+ * construction.
+ *
+ * Returns:
+ * A new raster symbolizer.
+ */
+ initialize: function(config) {
+ OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
+ },
+
+ CLASS_NAME: "OpenLayers.Symbolizer.Raster"
+
+});
+/* ======================================================================
+ OpenLayers/Tile.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/*
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/Util.js
+ * @requires OpenLayers/Console.js
+ * @requires OpenLayers/Lang.js
+ */
+
+/*
+ * Class: OpenLayers.Tile
+ * This is a class designed to designate a single tile, however
+ * it is explicitly designed to do relatively little. Tiles store
+ * information about themselves -- such as the URL that they are related
+ * to, and their size - but do not add themselves to the layer div
+ * automatically, for example. Create a new tile with the
+ * <OpenLayers.Tile> constructor, or a subclass.
+ *
+ * TBD 3.0 - remove reference to url in above paragraph
+ *
+ */
+OpenLayers.Tile = OpenLayers.Class({
+
+ /**
+ * Constant: EVENT_TYPES
+ * {Array(String)} Supported application event types
+ */
+ EVENT_TYPES: [ "loadstart", "loadend", "reload", "unload"],
+
+ /**
+ * APIProperty: events
+ * {<OpenLayers.Events>} An events object that handles all
+ * events on the tile.
+ */
+ events: null,
+
+ /**
+ * Property: id
+ * {String} null
+ */
+ id: null,
+
+ /**
+ * Property: layer
+ * {<OpenLayers.Layer>} layer the tile is attached to
+ */
+ layer: null,
+
+ /**
+ * Property: url
+ * {String} url of the request.
+ *
+ * TBD 3.0
+ * Deprecated. The base tile class does not need an url. This should be
+ * handled in subclasses. Does not belong here.
+ */
+ url: null,
+
+ /**
+ * APIProperty: bounds
+ * {<OpenLayers.Bounds>} null
+ */
+ bounds: null,
+
+ /**
+ * Property: size
+ * {<OpenLayers.Size>} null
+ */
+ size: null,
+
+ /**
+ * Property: position
+ * {<OpenLayers.Pixel>} Top Left pixel of the tile
+ */
+ position: null,
+
+ /**
+ * Property: isLoading
+ * {Boolean} Is the tile loading?
+ */
+ isLoading: false,
+
+ /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor.
+ * there is no need for the base tile class to have a url.
+ *
+ * Constructor: OpenLayers.Tile
+ * Constructor for a new <OpenLayers.Tile> instance.
+ *
+ * Parameters:
+ * layer - {<OpenLayers.Layer>} layer that the tile will go in.
+ * position - {<OpenLayers.Pixel>}
+ * bounds - {<OpenLayers.Bounds>}
+ * url - {<String>}
+ * size - {<OpenLayers.Size>}
+ * options - {Object}
+ */
+ initialize: function(layer, position, bounds, url, size, options) {
+ this.layer = layer;
+ this.position = position.clone();
+ this.bounds = bounds.clone();
+ this.url = url;
+ this.size = size.clone();
+
+ //give the tile a unique id based on its BBOX.
+ this.id = OpenLayers.Util.createUniqueID("Tile_");
+
+ this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
+
+ OpenLayers.Util.extend(this, options);
+ },
+
+ /**
+ * Method: unload
+ * Call immediately before destroying if you are listening to tile
+ * events, so that counters are properly handled if tile is still
+ * loading at destroy-time. Will only fire an event if the tile is
+ * still loading.
+ */
+ unload: function() {
+ if (this.isLoading) {
+ this.isLoading = false;
+ this.events.triggerEvent("unload");
+ }
+ },
+
+ /**
+ * APIMethod: destroy
+ * Nullify references to prevent circular references and memory leaks.
+ */
+ destroy:function() {
+ this.layer = null;
+ this.bounds = null;
+ this.size = null;
+ this.position = null;
+
+ this.events.destroy();
+ this.events = null;
+ },
+
+ /**
+ * Method: clone
+ *
+ * Parameters:
+ * obj - {<OpenLayers.Tile>} The tile to be cloned
+ *
+ * Returns:
+ * {<OpenLayers.Tile>} An exact clone of this <OpenLayers.Tile>
+ */
+ clone: function (obj) {
+ if (obj == null) {
+ obj = new OpenLayers.Tile(this.layer,
+ this.position,
+ this.bounds,
+ this.url,
+ this.size);
+ }
+
+ // catch any randomly tagged-on properties
+ OpenLayers.Util.applyDefaults(obj, this);
+
+ return obj;
+ },
+
+ /**
+ * Method: draw
+ * Clear whatever is currently in the tile, then return whether or not
+ * it should actually be re-drawn.
+ *
+ * Returns:
+ * {Boolean} Whether or not the tile should actually be drawn. Note that
+ * this is not really the best way of doing things, but such is
+ * the way the code has been developed. Subclasses call this and
+ * depend on the return to know if they should draw or not.
+ */
+ draw: function() {
+ var maxExtent = this.layer.maxExtent;
+ var withinMaxExtent = (maxExtent &&
+ this.bounds.intersectsBounds(maxExtent, false));
+
+ // The only case where we *wouldn't* want to draw the tile is if the
+ // tile is outside its layer's maxExtent.
+ this.shouldDraw = (withinMaxExtent || this.layer.displayOutsideMaxExtent);
+
+ //clear tile's contents and mark as not drawn
+ this.clear();
+
+ return this.shouldDraw;
+ },
+
+ /**
+ * Method: moveTo
+ * Reposition the tile.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * position - {<OpenLayers.Pixel>}
+ * redraw - {Boolean} Call draw method on tile after moving.
+ * Default is true
+ */
+ moveTo: function (bounds, position, redraw) {
+ if (redraw == null) {
+ redraw = true;
+ }
+
+ this.bounds = bounds.clone();
+ this.position = position.clone();
+ if (redraw) {
+ this.draw();
+ }
+ },
+
+ /**
+ * Method: clear
+ * Clear the tile of any bounds/position-related data so that it can
+ * be reused in a new location. To be implemented by subclasses.
+ */
+ clear: function() {
+ // to be implemented by subclasses
+ },
+
+ /**
+ * Method: getBoundsFromBaseLayer
+ * Take the pixel locations of the corner of the tile, and pass them to
+ * the base layer and ask for the location of those pixels, so that
+ * displaying tiles over Google works fine.
+ *
+ * Parameters:
+ * position - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * bounds - {<OpenLayers.Bounds>}
+ */
+ getBoundsFromBaseLayer: function(position) {
+ var msg = OpenLayers.i18n('reprojectDeprecated',
+ {'layerName':this.layer.name});
+ OpenLayers.Console.warn(msg);
+ var topLeft = this.layer.map.getLonLatFromLayerPx(position);
+ var bottomRightPx = position.clone();
+ bottomRightPx.x += this.size.w;
+ bottomRightPx.y += this.size.h;
+ var bottomRight = this.layer.map.getLonLatFromLayerPx(bottomRightPx);
+ // Handle the case where the base layer wraps around the date line.
+ // Google does this, and it breaks WMS servers to request bounds in
+ // that fashion.
+ if (topLeft.lon > bottomRight.lon) {
+ if (topLeft.lon < 0) {
+ topLeft.lon = -180 - (topLeft.lon+180);
+ } else {
+ bottomRight.lon = 180+bottomRight.lon+180;
+ }
+ }
+ var bounds = new OpenLayers.Bounds(topLeft.lon,
+ bottomRight.lat,
+ bottomRight.lon,
+ topLeft.lat);
+ return bounds;
+ },
+
+ /**
+ * Method: showTile
+ * Show the tile only if it should be drawn.
+ */
+ showTile: function() {
+ if (this.shouldDraw) {
+ this.show();
+ }
+ },
+
+ /**
+ * Method: show
+ * Show the tile. To be implemented by subclasses.
+ */
+ show: function() { },
+
+ /**
+ * Method: hide
+ * Hide the tile. To be implemented by subclasses.
+ */
+ hide: function() { },
+
+ CLASS_NAME: "OpenLayers.Tile"
+});
+/* ======================================================================
+ OpenLayers/Tile/Image.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Tile.js
+ */
+
+/**
+ * Class: OpenLayers.Tile.Image
+ * Instances of OpenLayers.Tile.Image are used to manage the image tiles
+ * used by various layers. Create a new image tile with the
+ * <OpenLayers.Tile.Image> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Tile>
+ */
+OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
+
+ /**
+ * Property: url
+ * {String} The URL of the image being requested. No default. Filled in by
+ * layer.getURL() function.
+ */
+ url: null,
+
+ /**
+ * Property: imgDiv
+ * {DOMElement} The div element which wraps the image.
+ */
+ imgDiv: null,
+
+ /**
+ * Property: frame
+ * {DOMElement} The image element is appended to the frame. Any gutter on
+ * the image will be hidden behind the frame.
+ */
+ frame: null,
+
+ /**
+ * Property: layerAlphaHack
+ * {Boolean} True if the png alpha hack needs to be applied on the layer's div.
+ */
+ layerAlphaHack: null,
+
+ /**
+ * Property: isBackBuffer
+ * {Boolean} Is this tile a back buffer tile?
+ */
+ isBackBuffer: false,
+
+ /**
+ * Property: lastRatio
+ * {Float} Used in transition code only. This is the previous ratio
+ * of the back buffer tile resolution to the map resolution. Compared
+ * with the current ratio to determine if zooming occurred.
+ */
+ lastRatio: 1,
+
+ /**
+ * Property: isFirstDraw
+ * {Boolean} Is this the first time the tile is being drawn?
+ * This is used to force resetBackBuffer to synchronize
+ * the backBufferTile with the foreground tile the first time
+ * the foreground tile loads so that if the user zooms
+ * before the layer has fully loaded, the backBufferTile for
+ * tiles that have been loaded can be used.
+ */
+ isFirstDraw: true,
+
+ /**
+ * Property: backBufferTile
+ * {<OpenLayers.Tile>} A clone of the tile used to create transition
+ * effects when the tile is moved or changes resolution.
+ */
+ backBufferTile: null,
+
+ /**
+ * APIProperty: maxGetUrlLength
+ * {Number} If set, requests that would result in GET urls with more
+ * characters than the number provided will be made using form-encoded
+ * HTTP POST. It is good practice to avoid urls that are longer than 2048
+ * characters.
+ *
+ * Caution:
+ * Older versions of Gecko based browsers (e.g. Firefox < 3.5) and
+ * Opera < 10.0 do not fully support this option.
+ *
+ * Note:
+ * Do not use this option for layers that have a transitionEffect
+ * configured - IFrame tiles from POST requests can not be resized.
+ */
+ maxGetUrlLength: null,
+
+ /** TBD 3.0 - reorder the parameters to the init function to remove
+ * URL. the getUrl() function on the layer gets called on
+ * each draw(), so no need to specify it here.
+ *
+ * Constructor: OpenLayers.Tile.Image
+ * Constructor for a new <OpenLayers.Tile.Image> instance.
+ *
+ * Parameters:
+ * layer - {<OpenLayers.Layer>} layer that the tile will go in.
+ * position - {<OpenLayers.Pixel>}
+ * bounds - {<OpenLayers.Bounds>}
+ * url - {<String>} Deprecated. Remove me in 3.0.
+ * size - {<OpenLayers.Size>}
+ * options - {Object}
+ */
+ initialize: function(layer, position, bounds, url, size, options) {
+ OpenLayers.Tile.prototype.initialize.apply(this, arguments);
+
+ if (this.maxGetUrlLength != null) {
+ OpenLayers.Util.extend(this, OpenLayers.Tile.Image.IFrame);
+ }
+
+ this.url = url; //deprecated remove me
+
+ this.frame = document.createElement('div');
+ this.frame.style.overflow = 'hidden';
+ this.frame.style.position = 'absolute';
+
+ this.layerAlphaHack = this.layer.alpha && OpenLayers.Util.alphaHack();
+ },
+
+ /**
+ * APIMethod: destroy
+ * nullify references to prevent circular references and memory leaks
+ */
+ destroy: function() {
+ if (this.imgDiv != null) {
+ this.removeImgDiv();
+ }
+ this.imgDiv = null;
+ if ((this.frame != null) && (this.frame.parentNode == this.layer.div)) {
+ this.layer.div.removeChild(this.frame);
+ }
+ this.frame = null;
+
+ /* clean up the backBufferTile if it exists */
+ if (this.backBufferTile) {
+ this.backBufferTile.destroy();
+ this.backBufferTile = null;
+ }
+
+ this.layer.events.unregister("loadend", this, this.resetBackBuffer);
+
+ OpenLayers.Tile.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: clone
+ *
+ * Parameters:
+ * obj - {<OpenLayers.Tile.Image>} The tile to be cloned
+ *
+ * Returns:
+ * {<OpenLayers.Tile.Image>} An exact clone of this <OpenLayers.Tile.Image>
+ */
+ clone: function (obj) {
+ if (obj == null) {
+ obj = new OpenLayers.Tile.Image(this.layer,
+ this.position,
+ this.bounds,
+ this.url,
+ this.size);
+ }
+
+ //pick up properties from superclass
+ obj = OpenLayers.Tile.prototype.clone.apply(this, [obj]);
+
+ //dont want to directly copy the image div
+ obj.imgDiv = null;
+
+
+ return obj;
+ },
+
+ /**
+ * Method: draw
+ * Check that a tile should be drawn, and draw it.
+ *
+ * Returns:
+ * {Boolean} Always returns true.
+ */
+ draw: function() {
+ if (this.layer != this.layer.map.baseLayer && this.layer.reproject) {
+ this.bounds = this.getBoundsFromBaseLayer(this.position);
+ }
+ var drawTile = OpenLayers.Tile.prototype.draw.apply(this, arguments);
+
+ if ((OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS, this.layer.transitionEffect) != -1) ||
+ this.layer.singleTile) {
+ if (drawTile) {
+ //we use a clone of this tile to create a double buffer for visual
+ //continuity. The backBufferTile is used to create transition
+ //effects while the tile in the grid is repositioned and redrawn
+ if (!this.backBufferTile) {
+ this.backBufferTile = this.clone();
+ this.backBufferTile.hide();
+ // this is important. It allows the backBuffer to place itself
+ // appropriately in the DOM. The Image subclass needs to put
+ // the backBufferTile behind the main tile so the tiles can
+ // load over top and display as soon as they are loaded.
+ this.backBufferTile.isBackBuffer = true;
+
+ // potentially end any transition effects when the tile loads
+ this.events.register('loadend', this, this.resetBackBuffer);
+
+ // clear transition back buffer tile only after all tiles in
+ // this layer have loaded to avoid visual glitches
+ this.layer.events.register("loadend", this, this.resetBackBuffer);
+ }
+ // run any transition effects
+ this.startTransition();
+ } else {
+ // if we aren't going to draw the tile, then the backBuffer should
+ // be hidden too!
+ if (this.backBufferTile) {
+ this.backBufferTile.clear();
+ }
+ }
+ } else {
+ if (drawTile && this.isFirstDraw) {
+ this.events.register('loadend', this, this.showTile);
+ this.isFirstDraw = false;
+ }
+ }
+
+ if (!drawTile) {
+ return false;
+ }
+
+ if (this.isLoading) {
+ //if we're already loading, send 'reload' instead of 'loadstart'.
+ this.events.triggerEvent("reload");
+ } else {
+ this.isLoading = true;
+ this.events.triggerEvent("loadstart");
+ }
+
+ return this.renderTile();
+ },
+
+ /**
+ * Method: resetBackBuffer
+ * Triggered by two different events, layer loadend, and tile loadend.
+ * In any of these cases, we check to see if we can hide the
+ * backBufferTile yet and update its parameters to match the
+ * foreground tile.
+ *
+ * Basic logic:
+ * - If the backBufferTile hasn't been drawn yet, reset it
+ * - If layer is still loading, show foreground tile but don't hide
+ * the backBufferTile yet
+ * - If layer is done loading, reset backBuffer tile and show
+ * foreground tile
+ */
+ resetBackBuffer: function() {
+ this.showTile();
+ if (this.backBufferTile &&
+ (this.isFirstDraw || !this.layer.numLoadingTiles)) {
+ this.isFirstDraw = false;
+ // check to see if the backBufferTile is within the max extents
+ // before rendering it
+ var maxExtent = this.layer.maxExtent;
+ var withinMaxExtent = (maxExtent &&
+ this.bounds.intersectsBounds(maxExtent, false));
+ if (withinMaxExtent) {
+ this.backBufferTile.position = this.position;
+ this.backBufferTile.bounds = this.bounds;
+ this.backBufferTile.size = this.size;
+ this.backBufferTile.imageSize = this.layer.getImageSize(this.bounds) || this.size;
+ this.backBufferTile.imageOffset = this.layer.imageOffset;
+ this.backBufferTile.resolution = this.layer.getResolution();
+ this.backBufferTile.renderTile();
+ }
+
+ this.backBufferTile.hide();
+ }
+ },
+
+ /**
+ * Method: renderTile
+ * Internal function to actually initialize the image tile,
+ * position it correctly, and set its url.
+ */
+ renderTile: function() {
+ if (this.layer.async) {
+ this.initImgDiv();
+ // Asyncronous image requests call the asynchronous getURL method
+ // on the layer to fetch an image that covers 'this.bounds', in the scope of
+ // 'this', setting the 'url' property of the layer itself, and running
+ // the callback 'positionFrame' when the image request returns.
+ this.layer.getURLasync(this.bounds, this, "url", this.positionImage);
+ } else {
+ // syncronous image requests get the url and position the frame immediately,
+ // and don't wait for an image request to come back.
+
+ this.url = this.layer.getURL(this.bounds);
+
+ this.initImgDiv();
+
+ // position the frame immediately
+ this.positionImage();
+ }
+ return true;
+ },
+
+ /**
+ * Method: positionImage
+ * Using the properties currenty set on the layer, position the tile correctly.
+ * This method is used both by the async and non-async versions of the Tile.Image
+ * code.
+ */
+ positionImage: function() {
+ // if the this layer doesn't exist at the point the image is
+ // returned, do not attempt to use it for size computation
+ if (this.layer === null) {
+ return;
+ }
+ // position the frame
+ OpenLayers.Util.modifyDOMElement(this.frame,
+ null, this.position, this.size);
+
+ var imageSize = this.layer.getImageSize(this.bounds);
+ if (this.layerAlphaHack) {
+ OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,
+ null, null, imageSize, this.url);
+ } else {
+ OpenLayers.Util.modifyDOMElement(this.imgDiv,
+ null, null, imageSize) ;
+ this.imgDiv.src = this.url;
+ }
+ },
+
+ /**
+ * Method: clear
+ * Clear the tile of any bounds/position-related data so that it can
+ * be reused in a new location.
+ */
+ clear: function() {
+ if(this.imgDiv) {
+ this.hide();
+ if (OpenLayers.Tile.Image.useBlankTile) {
+ this.imgDiv.src = OpenLayers.Util.getImagesLocation() + "blank.gif";
+ }
+ }
+ },
+
+ /**
+ * Method: initImgDiv
+ * Creates the imgDiv property on the tile.
+ */
+ initImgDiv: function() {
+ if (this.imgDiv == null) {
+ var offset = this.layer.imageOffset;
+ var size = this.layer.getImageSize(this.bounds);
+
+ if (this.layerAlphaHack) {
+ this.imgDiv = OpenLayers.Util.createAlphaImageDiv(null,
+ offset,
+ size,
+ null,
+ "relative",
+ null,
+ null,
+ null,
+ true);
+ } else {
+ this.imgDiv = OpenLayers.Util.createImage(null,
+ offset,
+ size,
+ null,
+ "relative",
+ null,
+ null,
+ true);
+ }
+
+ // needed for changing to a different server for onload error
+ if (this.layer.url instanceof Array) {
+ this.imgDiv.urls = this.layer.url.slice();
+ }
+
+ this.imgDiv.className = 'olTileImage';
+
+ /* checkImgURL used to be used to called as a work around, but it
+ ended up hiding problems instead of solving them and broke things
+ like relative URLs. See discussion on the dev list:
+ http://openlayers.org/pipermail/dev/2007-January/000205.html
+
+ OpenLayers.Event.observe( this.imgDiv, "load",
+ OpenLayers.Function.bind(this.checkImgURL, this) );
+ */
+ this.frame.style.zIndex = this.isBackBuffer ? 0 : 1;
+ this.frame.appendChild(this.imgDiv);
+ this.layer.div.appendChild(this.frame);
+
+ if(this.layer.opacity != null) {
+
+ OpenLayers.Util.modifyDOMElement(this.imgDiv, null, null, null,
+ null, null, null,
+ this.layer.opacity);
+ }
+
+ // we need this reference to check back the viewRequestID
+ this.imgDiv.map = this.layer.map;
+
+ //bind a listener to the onload of the image div so that we
+ // can register when a tile has finished loading.
+ var onload = function() {
+
+ //normally isLoading should always be true here but there are some
+ // right funky conditions where loading and then reloading a tile
+ // with the same url *really*fast*. this check prevents sending
+ // a 'loadend' if the msg has already been sent
+ //
+ if (this.isLoading) {
+ this.isLoading = false;
+ this.events.triggerEvent("loadend");
+ }
+ };
+
+ if (this.layerAlphaHack) {
+ OpenLayers.Event.observe(this.imgDiv.childNodes[0], 'load',
+ OpenLayers.Function.bind(onload, this));
+ } else {
+ OpenLayers.Event.observe(this.imgDiv, 'load',
+ OpenLayers.Function.bind(onload, this));
+ }
+
+
+ // Bind a listener to the onerror of the image div so that we
+ // can registere when a tile has finished loading with errors.
+ var onerror = function() {
+
+ // If we have gone through all image reload attempts, it is time
+ // to realize that we are done with this image. Since
+ // OpenLayers.Util.onImageLoadError already has taken care about
+ // the error, we can continue as if the image was loaded
+ // successfully.
+ if (this.imgDiv._attempts > OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
+ onload.call(this);
+ }
+ };
+ OpenLayers.Event.observe(this.imgDiv, "error",
+ OpenLayers.Function.bind(onerror, this));
+ }
+
+ this.imgDiv.viewRequestID = this.layer.map.viewRequestID;
+ },
+
+ /**
+ * Method: removeImgDiv
+ * Removes the imgDiv from the DOM and stops listening to events on it.
+ */
+ removeImgDiv: function() {
+ // unregister the "load" and "error" handlers. Only the "error" handler if
+ // this.layerAlphaHack is true.
+ OpenLayers.Event.stopObservingElement(this.imgDiv);
+
+ if (this.imgDiv.parentNode == this.frame) {
+ this.frame.removeChild(this.imgDiv);
+ this.imgDiv.map = null;
+ }
+ this.imgDiv.urls = null;
+
+ var child = this.imgDiv.firstChild;
+ //check for children (alphaHack img or IFrame)
+ if (child) {
+ OpenLayers.Event.stopObservingElement(child);
+ this.imgDiv.removeChild(child);
+ delete child;
+ } else {
+ // abort any currently loading image
+ this.imgDiv.src = OpenLayers.Util.getImagesLocation() + "blank.gif";
+ }
+ },
+
+ /**
+ * Method: checkImgURL
+ * Make sure that the image that just loaded is the one this tile is meant
+ * to display, since panning/zooming might have changed the tile's URL in
+ * the meantime. If the tile URL did change before the image loaded, set
+ * the imgDiv display to 'none', as either (a) it will be reset to visible
+ * when the new URL loads in the image, or (b) we don't want to display
+ * this tile after all because its new bounds are outside our maxExtent.
+ *
+ * This function should no longer be neccesary with the improvements to
+ * Grid.js in OpenLayers 2.3. The lack of a good isEquivilantURL function
+ * caused problems in 2.2, but it's possible that with the improved
+ * isEquivilant URL function, this might be neccesary at some point.
+ *
+ * See discussion in the thread at
+ * http://openlayers.org/pipermail/dev/2007-January/000205.html
+ */
+ checkImgURL: function () {
+ // Sometimes our image will load after it has already been removed
+ // from the map, in which case this check is not needed.
+ if (this.layer) {
+ var loaded = this.layerAlphaHack ? this.imgDiv.firstChild.src : this.imgDiv.src;
+ if (!OpenLayers.Util.isEquivalentUrl(loaded, this.url)) {
+ this.hide();
+ }
+ }
+ },
+
+ /**
+ * Method: startTransition
+ * This method is invoked on tiles that are backBuffers for tiles in the
+ * grid. The grid tile is about to be cleared and a new tile source
+ * loaded. This is where the transition effect needs to be started
+ * to provide visual continuity.
+ */
+ startTransition: function() {
+ // backBufferTile has to be valid and ready to use
+ if (!this.backBufferTile || !this.backBufferTile.imgDiv) {
+ return;
+ }
+
+ // calculate the ratio of change between the current resolution of the
+ // backBufferTile and the layer. If several animations happen in a
+ // row, then the backBufferTile will scale itself appropriately for
+ // each request.
+ var ratio = 1;
+ if (this.backBufferTile.resolution) {
+ ratio = this.backBufferTile.resolution / this.layer.getResolution();
+ }
+
+ // if the ratio is not the same as it was last time (i.e. we are
+ // zooming), then we need to adjust the backBuffer tile
+ if (ratio != this.lastRatio) {
+ if (this.layer.transitionEffect == 'resize') {
+ // In this case, we can just immediately resize the
+ // backBufferTile.
+ var upperLeft = new OpenLayers.LonLat(
+ this.backBufferTile.bounds.left,
+ this.backBufferTile.bounds.top
+ );
+ var size = new OpenLayers.Size(
+ this.backBufferTile.size.w * ratio,
+ this.backBufferTile.size.h * ratio
+ );
+
+ var px = this.layer.map.getLayerPxFromLonLat(upperLeft);
+ OpenLayers.Util.modifyDOMElement(this.backBufferTile.frame,
+ null, px, size);
+ var imageSize = this.backBufferTile.imageSize;
+ imageSize = new OpenLayers.Size(imageSize.w * ratio,
+ imageSize.h * ratio);
+ var imageOffset = this.backBufferTile.imageOffset;
+ if(imageOffset) {
+ imageOffset = new OpenLayers.Pixel(
+ imageOffset.x * ratio, imageOffset.y * ratio
+ );
+ }
+
+ OpenLayers.Util.modifyDOMElement(
+ this.backBufferTile.imgDiv, null, imageOffset, imageSize
+ ) ;
+
+ this.backBufferTile.show();
+ }
+ } else {
+ // default effect is just to leave the existing tile
+ // until the new one loads if this is a singleTile and
+ // there was no change in resolution. Otherwise we
+ // don't bother to show the backBufferTile at all
+ if (this.layer.singleTile) {
+ this.backBufferTile.show();
+ } else {
+ this.backBufferTile.hide();
+ }
+ }
+ this.lastRatio = ratio;
+
+ },
+
+ /**
+ * Method: show
+ * Show the tile by showing its frame.
+ */
+ show: function() {
+ this.frame.style.display = '';
+ // Force a reflow on gecko based browsers to actually show the element
+ // before continuing execution.
+ if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS,
+ this.layer.transitionEffect) != -1) {
+ if (OpenLayers.IS_GECKO === true) {
+ this.frame.scrollLeft = this.frame.scrollLeft;
+ }
+ }
+ },
+
+ /**
+ * Method: hide
+ * Hide the tile by hiding its frame.
+ */
+ hide: function() {
+ this.frame.style.display = 'none';
+ },
+
+ CLASS_NAME: "OpenLayers.Tile.Image"
+ }
+);
+
+OpenLayers.Tile.Image.useBlankTile = (
+ OpenLayers.BROWSER_NAME == "safari" ||
+ OpenLayers.BROWSER_NAME == "opera");
+/* ======================================================================
+ OpenLayers/Format/GML/v2.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/GML/Base.js
+ */
+
+/**
+ * Class: OpenLayers.Format.GML.v2
+ * Parses GML version 2.
+ *
+ * Inherits from:
+ * - <OpenLayers.Format.GML.Base>
+ */
+OpenLayers.Format.GML.v2 = OpenLayers.Class(OpenLayers.Format.GML.Base, {
+
+ /**
+ * Property: schemaLocation
+ * {String} Schema location for a particular minor version.
+ */
+ schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd",
+
+ /**
+ * Constructor: OpenLayers.Format.GML.v2
+ * Create a parser for GML v2.
+ *
+ * Parameters:
+ * options - {Object} An optional object whose properties will be set on
+ * this instance.
+ *
+ * Valid options properties:
+ * featureType - {String} Local (without prefix) feature typeName (required).
+ * featureNS - {String} Feature namespace (required).
+ * geometryName - {String} Geometry element name.
+ */
+ initialize: function(options) {
+ OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * Property: readers
+ * Contains public functions, grouped by namespace prefix, that will
+ * be applied when a namespaced node is found matching the function
+ * name. The function will be applied in the scope of this parser
+ * with two arguments: the node being read and a context object passed
+ * from the parent.
+ */
+ readers: {
+ "gml": OpenLayers.Util.applyDefaults({
+ "outerBoundaryIs": function(node, container) {
+ var obj = {};
+ this.readChildNodes(node, obj);
+ container.outer = obj.components[0];
+ },
+ "innerBoundaryIs": function(node, container) {
+ var obj = {};
+ this.readChildNodes(node, obj);
+ container.inner.push(obj.components[0]);
+ },
+ "Box": function(node, container) {
+ var obj = {};
+ this.readChildNodes(node, obj);
+ if(!container.components) {
+ container.components = [];
+ }
+ var min = obj.points[0];
+ var max = obj.points[1];
+ container.components.push(
+ new OpenLayers.Bounds(min.x, min.y, max.x, max.y)
+ );
+ }
+ }, OpenLayers.Format.GML.Base.prototype.readers["gml"]),
+ "feature": OpenLayers.Format.GML.Base.prototype.readers["feature"],
+ "wfs": OpenLayers.Format.GML.Base.prototype.readers["wfs"]
+ },
+
+ /**
+ * Method: write
+ *
+ * Parameters:
+ * features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector}
+ * An array of features or a single feature.
+ *
+ * Returns:
+ * {String} Given an array of features, a doc with a gml:featureMembers
+ * element will be returned. Given a single feature, a doc with a
+ * gml:featureMember element will be returned.
+ */
+ write: function(features) {
+ var name;
+ if(features instanceof Array) {
+ // GML2 only has abstract feature collections
+ // wfs provides a feature collection from a well-known schema
+ name = "wfs:FeatureCollection";
+ } else {
+ name = "gml:featureMember";
+ }
+ var root = this.writeNode(name, features);
+ this.setAttributeNS(
+ root, this.namespaces["xsi"],
+ "xsi:schemaLocation", this.schemaLocation
+ );
+
+ return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
+ },
+
+ /**
+ * Property: writers
+ * As a compliment to the readers property, this structure contains public
+ * writing functions grouped by namespace alias and named like the
+ * node names they produce.
+ */
+ writers: {
+ "gml": OpenLayers.Util.applyDefaults({
+ "Point": function(geometry) {
+ var node = this.createElementNSPlus("gml:Point");
+ this.writeNode("coordinates", [geometry], node);
+ return node;
+ },
+ "coordinates": function(points) {
+ var numPoints = points.length;
+ var parts = new Array(numPoints);
+ var point;
+ for(var i=0; i<numPoints; ++i) {
+ point = points[i];
+ if(this.xy) {
+ parts[i] = point.x + "," + point.y;
+ } else {
+ parts[i] = point.y + "," + point.x;
+ }
+ if(point.z != undefined) { // allow null or undefined
+ parts[i] += "," + point.z;
+ }
+ }
+ return this.createElementNSPlus("gml:coordinates", {
+ attributes: {
+ decimal: ".", cs: ",", ts: " "
+ },
+ value: (numPoints == 1) ? parts[0] : parts.join(" ")
+ });
+ },
+ "LineString": function(geometry) {
+ var node = this.createElementNSPlus("gml:LineString");
+ this.writeNode("coordinates", geometry.components, node);
+ return node;
+ },
+ "Polygon": function(geometry) {
+ var node = this.createElementNSPlus("gml:Polygon");
+ this.writeNode("outerBoundaryIs", geometry.components[0], node);
+ for(var i=1; i<geometry.components.length; ++i) {
+ this.writeNode(
+ "innerBoundaryIs", geometry.components[i], node
+ );
+ }
+ return node;
+ },
+ "outerBoundaryIs": function(ring) {
+ var node = this.createElementNSPlus("gml:outerBoundaryIs");
+ this.writeNode("LinearRing", ring, node);
+ return node;
+ },
+ "innerBoundaryIs": function(ring) {
+ var node = this.createElementNSPlus("gml:innerBoundaryIs");
+ this.writeNode("LinearRing", ring, node);
+ return node;
+ },
+ "LinearRing": function(ring) {
+ var node = this.createElementNSPlus("gml:LinearRing");
+ this.writeNode("coordinates", ring.components, node);
+ return node;
+ },
+ "Box": function(bounds) {
+ var node = this.createElementNSPlus("gml:Box");
+ this.writeNode("coordinates", [
+ {x: bounds.left, y: bounds.bottom},
+ {x: bounds.right, y: bounds.top}
+ ], node);
+ // srsName attribute is optional for gml:Box
+ if(this.srsName) {
+ node.setAttribute("srsName", this.srsName);
+ }
+ return node;
+ }
+ }, OpenLayers.Format.GML.Base.prototype.writers["gml"]),
+ "feature": OpenLayers.Format.GML.Base.prototype.writers["feature"],
+ "wfs": OpenLayers.Format.GML.Base.prototype.writers["wfs"]
+ },
+
+ CLASS_NAME: "OpenLayers.Format.GML.v2"
+
+});
+/* ======================================================================
+ OpenLayers/Format/Filter/v1_0_0.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/GML/v2.js
+ * @requires OpenLayers/Format/Filter/v1.js
+ */
+
+/**
+ * Class: OpenLayers.Format.Filter.v1_0_0
+ * Write ogc:Filter version 1.0.0.
+ *
+ * Inherits from:
+ * - <OpenLayers.Format.GML.v2>
+ * - <OpenLayers.Format.Filter.v1>
+ */
+OpenLayers.Format.Filter.v1_0_0 = OpenLayers.Class(
+ OpenLayers.Format.GML.v2, OpenLayers.Format.Filter.v1, {
+
+ /**
+ * Constant: VERSION
+ * {String} 1.0.0
+ */
+ VERSION: "1.0.0",
+
+ /**
+ * Property: schemaLocation
+ * {String} http://www.opengis.net/ogc/filter/1.0.0/filter.xsd
+ */
+ schemaLocation: "http://www.opengis.net/ogc/filter/1.0.0/filter.xsd",
+
+ /**
+ * Constructor: OpenLayers.Format.Filter.v1_0_0
+ * Instances of this class are not created directly. Use the
+ * <OpenLayers.Format.Filter> constructor instead.
+ *
+ * Parameters:
+ * options - {Object} An optional object whose properties will be set on
+ * this instance.
+ */
+ initialize: function(options) {
+ OpenLayers.Format.GML.v2.prototype.initialize.apply(
+ this, [options]
+ );
+ },
+
+ /**
+ * Property: readers
+ * Contains public functions, grouped by namespace prefix, that will
+ * be applied when a namespaced node is found matching the function
+ * name. The function will be applied in the scope of this parser
+ * with two arguments: the node being read and a context object passed
+ * from the parent.
+ */
+ readers: {
+ "ogc": OpenLayers.Util.applyDefaults({
+ "PropertyIsEqualTo": function(node, obj) {
+ var filter = new OpenLayers.Filter.Comparison({
+ type: OpenLayers.Filter.Comparison.EQUAL_TO
+ });
+ this.readChildNodes(node, filter);
+ obj.filters.push(filter);
+ },
+ "PropertyIsNotEqualTo": function(node, obj) {
+ var filter = new OpenLayers.Filter.Comparison({
+ type: OpenLayers.Filter.Comparison.NOT_EQUAL_TO
+ });
+ this.readChildNodes(node, filter);
+ obj.filters.push(filter);
+ },
+ "PropertyIsLike": function(node, obj) {
+ var filter = new OpenLayers.Filter.Comparison({
+ type: OpenLayers.Filter.Comparison.LIKE
+ });
+ this.readChildNodes(node, filter);
+ var wildCard = node.getAttribute("wildCard");
+ var singleChar = node.getAttribute("singleChar");
+ var esc = node.getAttribute("escape");
+ filter.value2regex(wildCard, singleChar, esc);
+ obj.filters.push(filter);
+ }
+ }, OpenLayers.Format.Filter.v1.prototype.readers["ogc"]),
+ "gml": OpenLayers.Format.GML.v2.prototype.readers["gml"],
+ "feature": OpenLayers.Format.GML.v2.prototype.readers["feature"]
+ },
+
+ /**
+ * Property: writers
+ * As a compliment to the readers property, this structure contains public
+ * writing functions grouped by namespace alias and named like the
+ * node names they produce.
+ */
+ writers: {
+ "ogc": OpenLayers.Util.applyDefaults({
+ "PropertyIsEqualTo": function(filter) {
+ var node = this.createElementNSPlus("ogc:PropertyIsEqualTo");
+ // no ogc:expression handling for now
+ this.writeNode("PropertyName", filter, node);
+ this.writeNode("Literal", filter.value, node);
+ return node;
+ },
+ "PropertyIsNotEqualTo": function(filter) {
+ var node = this.createElementNSPlus("ogc:PropertyIsNotEqualTo");
+ // no ogc:expression handling for now
+ this.writeNode("PropertyName", filter, node);
+ this.writeNode("Literal", filter.value, node);
+ return node;
+ },
+ "PropertyIsLike": function(filter) {
+ var node = this.createElementNSPlus("ogc:PropertyIsLike", {
+ attributes: {
+ wildCard: "*", singleChar: ".", escape: "!"
+ }
+ });
+ // no ogc:expression handling for now
+ this.writeNode("PropertyName", filter, node);
+ // convert regex string to ogc string
+ this.writeNode("Literal", filter.regex2value(), node);
+ return node;
+ },
+ "BBOX": function(filter) {
+ var node = this.createElementNSPlus("ogc:BBOX");
+ this.writeNode("PropertyName", filter, node);
+ var box = this.writeNode("gml:Box", filter.value, node);
+ if(filter.projection) {
+ box.setAttribute("srsName", filter.projection);
+ }
+ return node;
+ }}, OpenLayers.Format.Filter.v1.prototype.writers["ogc"]),
+
+ "gml": OpenLayers.Format.GML.v2.prototype.writers["gml"],
+ "feature": OpenLayers.Format.GML.v2.prototype.writers["feature"]
+
+ },
+
+ /**
+ * Method: writeSpatial
+ *
+ * Read a {<OpenLayers.Filter.Spatial>} filter and converts it into XML.
+ *
+ * Parameters:
+ * filter - {<OpenLayers.Filter.Spatial>} The filter.
+ * name - {String} Name of the generated XML element.
+ *
+ * Returns:
+ * {DOMElement} The created XML element.
+ */
+ writeSpatial: function(filter, name) {
+ var node = this.createElementNSPlus("ogc:"+name);
+ this.writeNode("PropertyName", filter, node);
+ var child;
+ if(filter.value instanceof OpenLayers.Geometry) {
+ child = this.writeNode("feature:_geometry", filter.value).firstChild;
+ } else {
+ child = this.writeNode("gml:Box", filter.value);
+ }
+ if(filter.projection) {
+ child.setAttribute("srsName", filter.projection);
+ }
+ node.appendChild(child);
+ return node;
+ },
+
+
+ CLASS_NAME: "OpenLayers.Format.Filter.v1_0_0"
+
+});
+/* ======================================================================
+ OpenLayers/Format/WFST/v1_0_0.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/WFST/v1.js
+ * @requires OpenLayers/Format/Filter/v1_0_0.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WFST.v1_0_0
+ * A format for creating WFS v1.0.0 transactions. Create a new instance with the
+ * <OpenLayers.Format.WFST.v1_0_0> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Format.Filter.v1_0_0>
+ * - <OpenLayers.Format.WFST.v1>
+ */
+OpenLayers.Format.WFST.v1_0_0 = OpenLayers.Class(
+ OpenLayers.Format.Filter.v1_0_0, OpenLayers.Format.WFST.v1, {
+
+ /**
+ * Property: version
+ * {String} WFS version number.
+ */
+ version: "1.0.0",
+
+ /**
+ * APIProperty: srsNameInQuery
+ * {Boolean} If true the reference system is passed in Query requests
+ * via the "srsName" attribute to the "wfs:Query" element, this
+ * property defaults to false as it isn't WFS 1.0.0 compliant.
+ */
+ srsNameInQuery: false,
+
+ /**
+ * Property: schemaLocations
+ * {Object} Properties are namespace aliases, values are schema locations.
+ */
+ schemaLocations: {
+ "wfs": "http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd"
+ },
+
+ /**
+ * Constructor: OpenLayers.Format.WFST.v1_0_0
+ * A class for parsing and generating WFS v1.0.0 transactions.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ *
+ * Valid options properties:
+ * featureType - {String} Local (without prefix) feature typeName (required).
+ * featureNS - {String} Feature namespace (optional).
+ * featurePrefix - {String} Feature namespace alias (optional - only used
+ * if featureNS is provided). Default is 'feature'.
+ * geometryName - {String} Name of geometry attribute. Default is 'the_geom'.
+ */
+ initialize: function(options) {
+ OpenLayers.Format.Filter.v1_0_0.prototype.initialize.apply(this, [options]);
+ OpenLayers.Format.WFST.v1.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * Property: readers
+ * Contains public functions, grouped by namespace prefix, that will
+ * be applied when a namespaced node is found matching the function
+ * name. The function will be applied in the scope of this parser
+ * with two arguments: the node being read and a context object passed
+ * from the parent.
+ */
+ readers: {
+ "wfs": OpenLayers.Util.applyDefaults({
+ "WFS_TransactionResponse": function(node, obj) {
+ obj.insertIds = [];
+ obj.success = false;
+ this.readChildNodes(node, obj);
+ },
+ "InsertResult": function(node, container) {
+ var obj = {fids: []};
+ this.readChildNodes(node, obj);
+ container.insertIds.push(obj.fids[0]);
+ },
+ "TransactionResult": function(node, obj) {
+ this.readChildNodes(node, obj);
+ },
+ "Status": function(node, obj) {
+ this.readChildNodes(node, obj);
+ },
+ "SUCCESS": function(node, obj) {
+ obj.success = true;
+ }
+ }, OpenLayers.Format.WFST.v1.prototype.readers["wfs"]),
+ "gml": OpenLayers.Format.GML.v2.prototype.readers["gml"],
+ "feature": OpenLayers.Format.GML.v2.prototype.readers["feature"],
+ "ogc": OpenLayers.Format.Filter.v1_0_0.prototype.readers["ogc"]
+ },
+
+ /**
+ * Property: writers
+ * As a compliment to the readers property, this structure contains public
+ * writing functions grouped by namespace alias and named like the
+ * node names they produce.
+ */
+ writers: {
+ "wfs": OpenLayers.Util.applyDefaults({
+ "Query": function(options) {
+ options = OpenLayers.Util.extend({
+ featureNS: this.featureNS,
+ featurePrefix: this.featurePrefix,
+ featureType: this.featureType,
+ srsName: this.srsName,
+ srsNameInQuery: this.srsNameInQuery
+ }, options);
+ var node = this.createElementNSPlus("wfs:Query", {
+ attributes: {
+ typeName: (options.featureNS ? options.featurePrefix + ":" : "") +
+ options.featureType
+ }
+ });
+ if(options.srsNameInQuery && options.srsName) {
+ node.setAttribute("srsName", options.srsName);
+ }
+ if(options.featureNS) {
+ node.setAttribute("xmlns:" + options.featurePrefix, options.featureNS);
+ }
+ if(options.propertyNames) {
+ for(var i=0,len = options.propertyNames.length; i<len; i++) {
+ this.writeNode(
+ "ogc:PropertyName",
+ {property: options.propertyNames[i]},
+ node
+ );
+ }
+ }
+ if(options.filter) {
+ this.setFilterProperty(options.filter);
+ this.writeNode("ogc:Filter", options.filter, node);
+ }
+ return node;
+ }
+ }, OpenLayers.Format.WFST.v1.prototype.writers["wfs"]),
+ "gml": OpenLayers.Format.GML.v2.prototype.writers["gml"],
+ "feature": OpenLayers.Format.GML.v2.prototype.writers["feature"],
+ "ogc": OpenLayers.Format.Filter.v1_0_0.prototype.writers["ogc"]
+ },
+
+ CLASS_NAME: "OpenLayers.Format.WFST.v1_0_0"
+});
+/* ======================================================================
+ OpenLayers/Renderer/Elements.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Renderer.js
+ */
+
+/**
+ * Class: OpenLayers.ElementsIndexer
+ * This class takes care of figuring out which order elements should be
+ * placed in the DOM based on given indexing methods.
+ */
+OpenLayers.ElementsIndexer = OpenLayers.Class({
+
+ /**
+ * Property: maxZIndex
+ * {Integer} This is the largest-most z-index value for a node
+ * contained within the indexer.
+ */
+ maxZIndex: null,
+
+ /**
+ * Property: order
+ * {Array<String>} This is an array of node id's stored in the
+ * order that they should show up on screen. Id's higher up in the
+ * array (higher array index) represent nodes with higher z-indeces.
+ */
+ order: null,
+
+ /**
+ * Property: indices
+ * {Object} This is a hash that maps node ids to their z-index value
+ * stored in the indexer. This is done to make finding a nodes z-index
+ * value O(1).
+ */
+ indices: null,
+
+ /**
+ * Property: compare
+ * {Function} This is the function used to determine placement of
+ * of a new node within the indexer. If null, this defaults to to
+ * the Z_ORDER_DRAWING_ORDER comparison method.
+ */
+ compare: null,
+
+ /**
+ * APIMethod: initialize
+ * Create a new indexer with
+ *
+ * Parameters:
+ * yOrdering - {Boolean} Whether to use y-ordering.
+ */
+ initialize: function(yOrdering) {
+
+ this.compare = yOrdering ?
+ OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER :
+ OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER;
+
+ this.order = [];
+ this.indices = {};
+ this.maxZIndex = 0;
+ },
+
+ /**
+ * APIMethod: insert
+ * Insert a new node into the indexer. In order to find the correct
+ * positioning for the node to be inserted, this method uses a binary
+ * search. This makes inserting O(log(n)).
+ *
+ * Parameters:
+ * newNode - {DOMElement} The new node to be inserted.
+ *
+ * Returns
+ * {DOMElement} the node before which we should insert our newNode, or
+ * null if newNode can just be appended.
+ */
+ insert: function(newNode) {
+ // If the node is known to the indexer, remove it so we can
+ // recalculate where it should go.
+ if (this.exists(newNode)) {
+ this.remove(newNode);
+ }
+
+ var nodeId = newNode.id;
+
+ this.determineZIndex(newNode);
+
+ var leftIndex = -1;
+ var rightIndex = this.order.length;
+ var middle;
+
+ while (rightIndex - leftIndex > 1) {
+ middle = parseInt((leftIndex + rightIndex) / 2);
+
+ var placement = this.compare(this, newNode,
+ OpenLayers.Util.getElement(this.order[middle]));
+
+ if (placement > 0) {
+ leftIndex = middle;
+ } else {
+ rightIndex = middle;
+ }
+ }
+
+ this.order.splice(rightIndex, 0, nodeId);
+ this.indices[nodeId] = this.getZIndex(newNode);
+
+ // If the new node should be before another in the index
+ // order, return the node before which we have to insert the new one;
+ // else, return null to indicate that the new node can be appended.
+ return this.getNextElement(rightIndex);
+ },
+
+ /**
+ * APIMethod: remove
+ *
+ * Parameters:
+ * node - {DOMElement} The node to be removed.
+ */
+ remove: function(node) {
+ var nodeId = node.id;
+ var arrayIndex = OpenLayers.Util.indexOf(this.order, nodeId);
+ if (arrayIndex >= 0) {
+ // Remove it from the order array, as well as deleting the node
+ // from the indeces hash.
+ this.order.splice(arrayIndex, 1);
+ delete this.indices[nodeId];
+
+ // Reset the maxium z-index based on the last item in the
+ // order array.
+ if (this.order.length > 0) {
+ var lastId = this.order[this.order.length - 1];
+ this.maxZIndex = this.indices[lastId];
+ } else {
+ this.maxZIndex = 0;
+ }
+ }
+ },
+
+ /**
+ * APIMethod: clear
+ */
+ clear: function() {
+ this.order = [];
+ this.indices = {};
+ this.maxZIndex = 0;
+ },
+
+ /**
+ * APIMethod: exists
+ *
+ * Parameters:
+ * node- {DOMElement} The node to test for existence.
+ *
+ * Returns:
+ * {Boolean} Whether or not the node exists in the indexer?
+ */
+ exists: function(node) {
+ return (this.indices[node.id] != null);
+ },
+
+ /**
+ * APIMethod: getZIndex
+ * Get the z-index value for the current node from the node data itself.
+ *
+ * Parameters:
+ * node - {DOMElement} The node whose z-index to get.
+ *
+ * Returns:
+ * {Integer} The z-index value for the specified node (from the node
+ * data itself).
+ */
+ getZIndex: function(node) {
+ return node._style.graphicZIndex;
+ },
+
+ /**
+ * Method: determineZIndex
+ * Determine the z-index for the current node if there isn't one,
+ * and set the maximum value if we've found a new maximum.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ */
+ determineZIndex: function(node) {
+ var zIndex = node._style.graphicZIndex;
+
+ // Everything must have a zIndex. If none is specified,
+ // this means the user *must* (hint: assumption) want this
+ // node to succomb to drawing order. To enforce drawing order
+ // over all indexing methods, we'll create a new z-index that's
+ // greater than any currently in the indexer.
+ if (zIndex == null) {
+ zIndex = this.maxZIndex;
+ node._style.graphicZIndex = zIndex;
+ } else if (zIndex > this.maxZIndex) {
+ this.maxZIndex = zIndex;
+ }
+ },
+
+ /**
+ * APIMethod: getNextElement
+ * Get the next element in the order stack.
+ *
+ * Parameters:
+ * index - {Integer} The index of the current node in this.order.
+ *
+ * Returns:
+ * {DOMElement} the node following the index passed in, or
+ * null.
+ */
+ getNextElement: function(index) {
+ var nextIndex = index + 1;
+ if (nextIndex < this.order.length) {
+ var nextElement = OpenLayers.Util.getElement(this.order[nextIndex]);
+ if (nextElement == undefined) {
+ nextElement = this.getNextElement(nextIndex);
+ }
+ return nextElement;
+ } else {
+ return null;
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.ElementsIndexer"
+});
+
+/**
+ * Namespace: OpenLayers.ElementsIndexer.IndexingMethods
+ * These are the compare methods for figuring out where a new node should be
+ * placed within the indexer. These methods are very similar to general
+ * sorting methods in that they return -1, 0, and 1 to specify the
+ * direction in which new nodes fall in the ordering.
+ */
+OpenLayers.ElementsIndexer.IndexingMethods = {
+
+ /**
+ * Method: Z_ORDER
+ * This compare method is used by other comparison methods.
+ * It can be used individually for ordering, but is not recommended,
+ * because it doesn't subscribe to drawing order.
+ *
+ * Parameters:
+ * indexer - {<OpenLayers.ElementsIndexer>}
+ * newNode - {DOMElement}
+ * nextNode - {DOMElement}
+ *
+ * Returns:
+ * {Integer}
+ */
+ Z_ORDER: function(indexer, newNode, nextNode) {
+ var newZIndex = indexer.getZIndex(newNode);
+
+ var returnVal = 0;
+ if (nextNode) {
+ var nextZIndex = indexer.getZIndex(nextNode);
+ returnVal = newZIndex - nextZIndex;
+ }
+
+ return returnVal;
+ },
+
+ /**
+ * APIMethod: Z_ORDER_DRAWING_ORDER
+ * This method orders nodes by their z-index, but does so in a way
+ * that, if there are other nodes with the same z-index, the newest
+ * drawn will be the front most within that z-index. This is the
+ * default indexing method.
+ *
+ * Parameters:
+ * indexer - {<OpenLayers.ElementsIndexer>}
+ * newNode - {DOMElement}
+ * nextNode - {DOMElement}
+ *
+ * Returns:
+ * {Integer}
+ */
+ Z_ORDER_DRAWING_ORDER: function(indexer, newNode, nextNode) {
+ var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(
+ indexer,
+ newNode,
+ nextNode
+ );
+
+ // Make Z_ORDER subscribe to drawing order by pushing it above
+ // all of the other nodes with the same z-index.
+ if (nextNode && returnVal == 0) {
+ returnVal = 1;
+ }
+
+ return returnVal;
+ },
+
+ /**
+ * APIMethod: Z_ORDER_Y_ORDER
+ * This one should really be called Z_ORDER_Y_ORDER_DRAWING_ORDER, as it
+ * best describes which ordering methods have precedence (though, the
+ * name would be too long). This method orders nodes by their z-index,
+ * but does so in a way that, if there are other nodes with the same
+ * z-index, the nodes with the lower y position will be "closer" than
+ * those with a higher y position. If two nodes have the exact same y
+ * position, however, then this method will revert to using drawing
+ * order to decide placement.
+ *
+ * Parameters:
+ * indexer - {<OpenLayers.ElementsIndexer>}
+ * newNode - {DOMElement}
+ * nextNode - {DOMElement}
+ *
+ * Returns:
+ * {Integer}
+ */
+ Z_ORDER_Y_ORDER: function(indexer, newNode, nextNode) {
+ var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(
+ indexer,
+ newNode,
+ nextNode
+ );
+
+ if (nextNode && returnVal === 0) {
+ var result = nextNode._boundsBottom - newNode._boundsBottom;
+ returnVal = (result === 0) ? 1 : result;
+ }
+
+ return returnVal;
+ }
+};
+
+/**
+ * Class: OpenLayers.Renderer.Elements
+ * This is another virtual class in that it should never be instantiated by
+ * itself as a Renderer. It exists because there is *tons* of shared
+ * functionality between different vector libraries which use nodes/elements
+ * as a base for rendering vectors.
+ *
+ * The highlevel bits of code that are implemented here are the adding and
+ * removing of geometries, which is essentially the same for any
+ * element-based renderer. The details of creating each node and drawing the
+ * paths are of course different, but the machinery is the same.
+ *
+ * Inherits:
+ * - <OpenLayers.Renderer>
+ */
+OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
+
+ /**
+ * Property: rendererRoot
+ * {DOMElement}
+ */
+ rendererRoot: null,
+
+ /**
+ * Property: root
+ * {DOMElement}
+ */
+ root: null,
+
+ /**
+ * Property: vectorRoot
+ * {DOMElement}
+ */
+ vectorRoot: null,
+
+ /**
+ * Property: textRoot
+ * {DOMElement}
+ */
+ textRoot: null,
+
+ /**
+ * Property: xmlns
+ * {String}
+ */
+ xmlns: null,
+
+ /**
+ * Property: Indexer
+ * {<OpenLayers.ElementIndexer>} An instance of OpenLayers.ElementsIndexer
+ * created upon initialization if the zIndexing or yOrdering options
+ * passed to this renderer's constructor are set to true.
+ */
+ indexer: null,
+
+ /**
+ * Constant: BACKGROUND_ID_SUFFIX
+ * {String}
+ */
+ BACKGROUND_ID_SUFFIX: "_background",
+
+ /**
+ * Constant: BACKGROUND_ID_SUFFIX
+ * {String}
+ */
+ LABEL_ID_SUFFIX: "_label",
+
+ /**
+ * Constructor: OpenLayers.Renderer.Elements
+ *
+ * Parameters:
+ * containerID - {String}
+ * options - {Object} options for this renderer. Supported options are:
+ * * yOrdering - {Boolean} Whether to use y-ordering
+ * * zIndexing - {Boolean} Whether to use z-indexing. Will be ignored
+ * if yOrdering is set to true.
+ */
+ initialize: function(containerID, options) {
+ OpenLayers.Renderer.prototype.initialize.apply(this, arguments);
+
+ this.rendererRoot = this.createRenderRoot();
+ this.root = this.createRoot("_root");
+ this.vectorRoot = this.createRoot("_vroot");
+ this.textRoot = this.createRoot("_troot");
+
+ this.root.appendChild(this.vectorRoot);
+ this.root.appendChild(this.textRoot);
+
+ this.rendererRoot.appendChild(this.root);
+ this.container.appendChild(this.rendererRoot);
+
+ if(options && (options.zIndexing || options.yOrdering)) {
+ this.indexer = new OpenLayers.ElementsIndexer(options.yOrdering);
+ }
+ },
+
+ /**
+ * Method: destroy
+ */
+ destroy: function() {
+
+ this.clear();
+
+ this.rendererRoot = null;
+ this.root = null;
+ this.xmlns = null;
+
+ OpenLayers.Renderer.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: clear
+ * Remove all the elements from the root
+ */
+ clear: function() {
+ var child;
+ var root = this.vectorRoot;
+ if (root) {
+ while (child = root.firstChild) {
+ root.removeChild(child);
+ }
+ }
+ root = this.textRoot;
+ if (root) {
+ while (child = root.firstChild) {
+ root.removeChild(child);
+ }
+ }
+ if (this.indexer) {
+ this.indexer.clear();
+ }
+ },
+
+ /**
+ * Method: getNodeType
+ * This function is in charge of asking the specific renderer which type
+ * of node to create for the given geometry and style. All geometries
+ * in an Elements-based renderer consist of one node and some
+ * attributes. We have the nodeFactory() function which creates a node
+ * for us, but it takes a 'type' as input, and that is precisely what
+ * this function tells us.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ * style - {Object}
+ *
+ * Returns:
+ * {String} The corresponding node type for the specified geometry
+ */
+ getNodeType: function(geometry, style) { },
+
+ /**
+ * Method: drawGeometry
+ * Draw the geometry, creating new nodes, setting paths, setting style,
+ * setting featureId on the node. This method should only be called
+ * by the renderer itself.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ * style - {Object}
+ * featureId - {String}
+ *
+ * Returns:
+ * {Boolean} true if the geometry has been drawn completely; null if
+ * incomplete; false otherwise
+ */
+ drawGeometry: function(geometry, style, featureId) {
+ var className = geometry.CLASS_NAME;
+ var rendered = true;
+ if ((className == "OpenLayers.Geometry.Collection") ||
+ (className == "OpenLayers.Geometry.MultiPoint") ||
+ (className == "OpenLayers.Geometry.MultiLineString") ||
+ (className == "OpenLayers.Geometry.MultiPolygon")) {
+ for (var i = 0, len=geometry.components.length; i<len; i++) {
+ rendered = this.drawGeometry(
+ geometry.components[i], style, featureId) && rendered;
+ }
+ return rendered;
+ };
+
+ rendered = false;
+ var removeBackground = false;
+ if (style.display != "none") {
+ if (style.backgroundGraphic) {
+ this.redrawBackgroundNode(geometry.id, geometry, style,
+ featureId);
+ } else {
+ removeBackground = true;
+ }
+ rendered = this.redrawNode(geometry.id, geometry, style,
+ featureId);
+ }
+ if (rendered == false) {
+ var node = document.getElementById(geometry.id);
+ if (node) {
+ if (node._style.backgroundGraphic) {
+ removeBackground = true;
+ }
+ node.parentNode.removeChild(node);
+ }
+ }
+ if (removeBackground) {
+ var node = document.getElementById(
+ geometry.id + this.BACKGROUND_ID_SUFFIX);
+ if (node) {
+ node.parentNode.removeChild(node);
+ }
+ }
+ return rendered;
+ },
+
+ /**
+ * Method: redrawNode
+ *
+ * Parameters:
+ * id - {String}
+ * geometry - {<OpenLayers.Geometry>}
+ * style - {Object}
+ * featureId - {String}
+ *
+ * Returns:
+ * {Boolean} true if the complete geometry could be drawn, null if parts of
+ * the geometry could not be drawn, false otherwise
+ */
+ redrawNode: function(id, geometry, style, featureId) {
+ style = this.applyDefaultSymbolizer(style);
+ // Get the node if it's already on the map.
+ var node = this.nodeFactory(id, this.getNodeType(geometry, style));
+
+ // Set the data for the node, then draw it.
+ node._featureId = featureId;
+ node._boundsBottom = geometry.getBounds().bottom;
+ node._geometryClass = geometry.CLASS_NAME;
+ node._style = style;
+
+ var drawResult = this.drawGeometryNode(node, geometry, style);
+ if(drawResult === false) {
+ return false;
+ }
+
+ node = drawResult.node;
+
+ // Insert the node into the indexer so it can show us where to
+ // place it. Note that this operation is O(log(n)). If there's a
+ // performance problem (when dragging, for instance) this is
+ // likely where it would be.
+ if (this.indexer) {
+ var insert = this.indexer.insert(node);
+ if (insert) {
+ this.vectorRoot.insertBefore(node, insert);
+ } else {
+ this.vectorRoot.appendChild(node);
+ }
+ } else {
+ // if there's no indexer, simply append the node to root,
+ // but only if the node is a new one
+ if (node.parentNode !== this.vectorRoot){
+ this.vectorRoot.appendChild(node);
+ }
+ }
+
+ this.postDraw(node);
+
+ return drawResult.complete;
+ },
+
+ /**
+ * Method: redrawBackgroundNode
+ * Redraws the node using special 'background' style properties. Basically
+ * just calls redrawNode(), but instead of directly using the
+ * 'externalGraphic', 'graphicXOffset', 'graphicYOffset', and
+ * 'graphicZIndex' properties directly from the specified 'style'
+ * parameter, we create a new style object and set those properties
+ * from the corresponding 'background'-prefixed properties from
+ * specified 'style' parameter.
+ *
+ * Parameters:
+ * id - {String}
+ * geometry - {<OpenLayers.Geometry>}
+ * style - {Object}
+ * featureId - {String}
+ *
+ * Returns:
+ * {Boolean} true if the complete geometry could be drawn, null if parts of
+ * the geometry could not be drawn, false otherwise
+ */
+ redrawBackgroundNode: function(id, geometry, style, featureId) {
+ var backgroundStyle = OpenLayers.Util.extend({}, style);
+
+ // Set regular style attributes to apply to the background styles.
+ backgroundStyle.externalGraphic = backgroundStyle.backgroundGraphic;
+ backgroundStyle.graphicXOffset = backgroundStyle.backgroundXOffset;
+ backgroundStyle.graphicYOffset = backgroundStyle.backgroundYOffset;
+ backgroundStyle.graphicZIndex = backgroundStyle.backgroundGraphicZIndex;
+ backgroundStyle.graphicWidth = backgroundStyle.backgroundWidth || backgroundStyle.graphicWidth;
+ backgroundStyle.graphicHeight = backgroundStyle.backgroundHeight || backgroundStyle.graphicHeight;
+
+ // Erase background styles.
+ backgroundStyle.backgroundGraphic = null;
+ backgroundStyle.backgroundXOffset = null;
+ backgroundStyle.backgroundYOffset = null;
+ backgroundStyle.backgroundGraphicZIndex = null;
+
+ return this.redrawNode(
+ id + this.BACKGROUND_ID_SUFFIX,
+ geometry,
+ backgroundStyle,
+ null
+ );
+ },
+
+ /**
+ * Method: drawGeometryNode
+ * Given a node, draw a geometry on the specified layer.
+ * node and geometry are required arguments, style is optional.
+ * This method is only called by the render itself.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ * style - {Object}
+ *
+ * Returns:
+ * {Object} a hash with properties "node" (the drawn node) and "complete"
+ * (null if parts of the geometry could not be drawn, false if nothing
+ * could be drawn)
+ */
+ drawGeometryNode: function(node, geometry, style) {
+ style = style || node._style;
+
+ var options = {
+ 'isFilled': style.fill === undefined ?
+ true :
+ style.fill,
+ 'isStroked': style.stroke === undefined ?
+ !!style.strokeWidth :
+ style.stroke
+ };
+ var drawn;
+ switch (geometry.CLASS_NAME) {
+ case "OpenLayers.Geometry.Point":
+ if(style.graphic === false) {
+ options.isFilled = false;
+ options.isStroked = false;
+ }
+ drawn = this.drawPoint(node, geometry);
+ break;
+ case "OpenLayers.Geometry.LineString":
+ options.isFilled = false;
+ drawn = this.drawLineString(node, geometry);
+ break;
+ case "OpenLayers.Geometry.LinearRing":
+ drawn = this.drawLinearRing(node, geometry);
+ break;
+ case "OpenLayers.Geometry.Polygon":
+ drawn = this.drawPolygon(node, geometry);
+ break;
+ case "OpenLayers.Geometry.Surface":
+ drawn = this.drawSurface(node, geometry);
+ break;
+ case "OpenLayers.Geometry.Rectangle":
+ drawn = this.drawRectangle(node, geometry);
+ break;
+ default:
+ break;
+ }
+
+ node._options = options;
+
+ //set style
+ //TBD simplify this
+ if (drawn != false) {
+ return {
+ node: this.setStyle(node, style, options, geometry),
+ complete: drawn
+ };
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Method: postDraw
+ * Things that have do be done after the geometry node is appended
+ * to its parent node. To be overridden by subclasses.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ */
+ postDraw: function(node) {},
+
+ /**
+ * Method: drawPoint
+ * Virtual function for drawing Point Geometry.
+ * Should be implemented by subclasses.
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement} or false if the renderer could not draw the point
+ */
+ drawPoint: function(node, geometry) {},
+
+ /**
+ * Method: drawLineString
+ * Virtual function for drawing LineString Geometry.
+ * Should be implemented by subclasses.
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement} or null if the renderer could not draw all components of
+ * the linestring, or false if nothing could be drawn
+ */
+ drawLineString: function(node, geometry) {},
+
+ /**
+ * Method: drawLinearRing
+ * Virtual function for drawing LinearRing Geometry.
+ * Should be implemented by subclasses.
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement} or null if the renderer could not draw all components
+ * of the linear ring, or false if nothing could be drawn
+ */
+ drawLinearRing: function(node, geometry) {},
+
+ /**
+ * Method: drawPolygon
+ * Virtual function for drawing Polygon Geometry.
+ * Should be implemented by subclasses.
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement} or null if the renderer could not draw all components
+ * of the polygon, or false if nothing could be drawn
+ */
+ drawPolygon: function(node, geometry) {},
+
+ /**
+ * Method: drawRectangle
+ * Virtual function for drawing Rectangle Geometry.
+ * Should be implemented by subclasses.
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement} or false if the renderer could not draw the rectangle
+ */
+ drawRectangle: function(node, geometry) {},
+
+ /**
+ * Method: drawCircle
+ * Virtual function for drawing Circle Geometry.
+ * Should be implemented by subclasses.
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement} or false if the renderer could not draw the circle
+ */
+ drawCircle: function(node, geometry) {},
+
+ /**
+ * Method: drawSurface
+ * Virtual function for drawing Surface Geometry.
+ * Should be implemented by subclasses.
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement} or false if the renderer could not draw the surface
+ */
+ drawSurface: function(node, geometry) {},
+
+ /**
+ * Method: removeText
+ * Removes a label
+ *
+ * Parameters:
+ * featureId - {String}
+ */
+ removeText: function(featureId) {
+ var label = document.getElementById(featureId + this.LABEL_ID_SUFFIX);
+ if (label) {
+ this.textRoot.removeChild(label);
+ }
+ },
+
+ /**
+ * Method: getFeatureIdFromEvent
+ *
+ * Parameters:
+ * evt - {Object} An <OpenLayers.Event> object
+ *
+ * Returns:
+ * {<OpenLayers.Geometry>} A geometry from an event that
+ * happened on a layer.
+ */
+ getFeatureIdFromEvent: function(evt) {
+ var target = evt.target;
+ var useElement = target && target.correspondingUseElement;
+ var node = useElement ? useElement : (target || evt.srcElement);
+ var featureId = node._featureId;
+ return featureId;
+ },
+
+ /**
+ * Method: eraseGeometry
+ * Erase a geometry from the renderer. In the case of a multi-geometry,
+ * we cycle through and recurse on ourselves. Otherwise, we look for a
+ * node with the geometry.id, destroy its geometry, and remove it from
+ * the DOM.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ * featureId - {String}
+ */
+ eraseGeometry: function(geometry, featureId) {
+ if ((geometry.CLASS_NAME == "OpenLayers.Geometry.MultiPoint") ||
+ (geometry.CLASS_NAME == "OpenLayers.Geometry.MultiLineString") ||
+ (geometry.CLASS_NAME == "OpenLayers.Geometry.MultiPolygon") ||
+ (geometry.CLASS_NAME == "OpenLayers.Geometry.Collection")) {
+ for (var i=0, len=geometry.components.length; i<len; i++) {
+ this.eraseGeometry(geometry.components[i], featureId);
+ }
+ } else {
+ var element = OpenLayers.Util.getElement(geometry.id);
+ if (element && element.parentNode) {
+ if (element.geometry) {
+ element.geometry.destroy();
+ element.geometry = null;
+ }
+ element.parentNode.removeChild(element);
+
+ if (this.indexer) {
+ this.indexer.remove(element);
+ }
+
+ if (element._style.backgroundGraphic) {
+ var backgroundId = geometry.id + this.BACKGROUND_ID_SUFFIX;
+ var bElem = OpenLayers.Util.getElement(backgroundId);
+ if (bElem && bElem.parentNode) {
+ // No need to destroy the geometry since the element and the background
+ // node share the same geometry.
+ bElem.parentNode.removeChild(bElem);
+ }
+ }
+ }
+ }
+ },
+
+ /**
+ * Method: nodeFactory
+ * Create new node of the specified type, with the (optional) specified id.
+ *
+ * If node already exists with same ID and a different type, we remove it
+ * and then call ourselves again to recreate it.
+ *
+ * Parameters:
+ * id - {String}
+ * type - {String} type Kind of node to draw.
+ *
+ * Returns:
+ * {DOMElement} A new node of the given type and id.
+ */
+ nodeFactory: function(id, type) {
+ var node = OpenLayers.Util.getElement(id);
+ if (node) {
+ if (!this.nodeTypeCompare(node, type)) {
+ node.parentNode.removeChild(node);
+ node = this.nodeFactory(id, type);
+ }
+ } else {
+ node = this.createNode(type, id);
+ }
+ return node;
+ },
+
+ /**
+ * Method: nodeTypeCompare
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * type - {String} Kind of node
+ *
+ * Returns:
+ * {Boolean} Whether or not the specified node is of the specified type
+ * This function must be overridden by subclasses.
+ */
+ nodeTypeCompare: function(node, type) {},
+
+ /**
+ * Method: createNode
+ *
+ * Parameters:
+ * type - {String} Kind of node to draw.
+ * id - {String} Id for node.
+ *
+ * Returns:
+ * {DOMElement} A new node of the given type and id.
+ * This function must be overridden by subclasses.
+ */
+ createNode: function(type, id) {},
+
+ /**
+ * Method: moveRoot
+ * moves this renderer's root to a different renderer.
+ *
+ * Parameters:
+ * renderer - {<OpenLayers.Renderer>} target renderer for the moved root
+ */
+ moveRoot: function(renderer) {
+ var root = this.root;
+ if(renderer.root.parentNode == this.rendererRoot) {
+ root = renderer.root;
+ }
+ root.parentNode.removeChild(root);
+ renderer.rendererRoot.appendChild(root);
+ },
+
+ /**
+ * Method: getRenderLayerId
+ * Gets the layer that this renderer's output appears on. If moveRoot was
+ * used, this will be different from the id of the layer containing the
+ * features rendered by this renderer.
+ *
+ * Returns:
+ * {String} the id of the output layer.
+ */
+ getRenderLayerId: function() {
+ return this.root.parentNode.parentNode.id;
+ },
+
+ /**
+ * Method: isComplexSymbol
+ * Determines if a symbol cannot be rendered using drawCircle
+ *
+ * Parameters:
+ * graphicName - {String}
+ *
+ * Returns
+ * {Boolean} true if the symbol is complex, false if not
+ */
+ isComplexSymbol: function(graphicName) {
+ return (graphicName != "circle") && !!graphicName;
+ },
+
+ CLASS_NAME: "OpenLayers.Renderer.Elements"
+});
+
+
+/**
+ * Constant: OpenLayers.Renderer.symbol
+ * Coordinate arrays for well known (named) symbols.
+ */
+OpenLayers.Renderer.symbol = {
+ "star": [350,75, 379,161, 469,161, 397,215, 423,301, 350,250, 277,301,
+ 303,215, 231,161, 321,161, 350,75],
+ "cross": [4,0, 6,0, 6,4, 10,4, 10,6, 6,6, 6,10, 4,10, 4,6, 0,6, 0,4, 4,4,
+ 4,0],
+ "x": [0,0, 25,0, 50,35, 75,0, 100,0, 65,50, 100,100, 75,100, 50,65, 25,100, 0,100, 35,50, 0,0],
+ "square": [0,0, 0,1, 1,1, 1,0, 0,0],
+ "triangle": [0,10, 10,10, 5,0, 0,10]
+};
+/* ======================================================================
+ OpenLayers/Strategy/Fixed.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Strategy.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.Fixed
+ * A simple strategy that requests features once and never requests new data.
+ *
+ * Inherits from:
+ * - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, {
+
+ /**
+ * APIProperty: preload
+ * {Boolean} Load data before layer made visible. Enabling this may result
+ * in considerable overhead if your application loads many data layers
+ * that are not visible by default. Default is false.
+ */
+ preload: false,
+
+ /**
+ * Constructor: OpenLayers.Strategy.Fixed
+ * Create a new Fixed strategy.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ */
+ initialize: function(options) {
+ OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * APIMethod: destroy
+ * Clean up the strategy.
+ */
+ destroy: function() {
+ OpenLayers.Strategy.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: activate
+ * Activate the strategy: load data or add listener to load when visible
+ *
+ * Returns:
+ * {Boolean} True if the strategy was successfully activated or false if
+ * the strategy was already active.
+ */
+ activate: function() {
+ if(OpenLayers.Strategy.prototype.activate.apply(this, arguments)) {
+ this.layer.events.on({
+ "refresh": this.load,
+ scope: this
+ });
+ if(this.layer.visibility == true || this.preload) {
+ this.load();
+ } else {
+ this.layer.events.on({
+ "visibilitychanged": this.load,
+ scope: this
+ });
+ }
+ return true;
+ }
+ return false;
+ },
+
+ /**
+ * Method: deactivate
+ * Deactivate the strategy. Undo what is done in <activate>.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
+ if(deactivated) {
+ this.layer.events.un({
+ "refresh": this.load,
+ "visibilitychanged": this.load,
+ scope: this
+ });
+ }
+ return deactivated;
+ },
+
+ /**
+ * Method: load
+ * Tells protocol to load data and unhooks the visibilitychanged event
+ *
+ * Parameters:
+ * options - {Object} options to pass to protocol read.
+ */
+ load: function(options) {
+ var layer = this.layer;
+ layer.events.triggerEvent("loadstart");
+ layer.protocol.read(OpenLayers.Util.applyDefaults({
+ callback: OpenLayers.Function.bind(this.merge, this,
+ layer.map.getProjectionObject()),
+ filter: layer.filter
+ }, options));
+ layer.events.un({
+ "visibilitychanged": this.load,
+ scope: this
+ });
+ },
+
+ /**
+ * Method: merge
+ * Add all features to the layer.
+ *
+ * Parameters:
+ * mapProjection - {OpenLayers.Projection} the map projection
+ * resp - {Object} options to pass to protocol read.
+ */
+ merge: function(mapProjection, resp) {
+ var layer = this.layer;
+ layer.destroyFeatures();
+ var features = resp.features;
+ if (features && features.length > 0) {
+ if(!mapProjection.equals(layer.projection)) {
+ var geom;
+ for(var i=0, len=features.length; i<len; ++i) {
+ geom = features[i].geometry;
+ if(geom) {
+ geom.transform(layer.projection, mapProjection);
+ }
+ }
+ }
+ layer.addFeatures(features);
+ }
+ layer.events.triggerEvent("loadend");
+ },
+
+ CLASS_NAME: "OpenLayers.Strategy.Fixed"
+});
+/* ======================================================================
+ OpenLayers/Protocol.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ */
+
+/**
+ * Class: OpenLayers.Protocol
+ * Abstract vector layer protocol class. Not to be instantiated directly. Use
+ * one of the protocol subclasses instead.
+ */
+OpenLayers.Protocol = OpenLayers.Class({
+
+ /**
+ * Property: format
+ * {<OpenLayers.Format>} The format used by this protocol.
+ */
+ format: null,
+
+ /**
+ * Property: options
+ * {Object} Any options sent to the constructor.
+ */
+ options: null,
+
+ /**
+ * Property: autoDestroy
+ * {Boolean} The creator of the protocol can set autoDestroy to false
+ * to fully control when the protocol is destroyed. Defaults to
+ * true.
+ */
+ autoDestroy: true,
+
+ /**
+ * Property: defaultFilter
+ * {OpenLayers.Filter} Optional default filter to read requests
+ */
+ defaultFilter: null,
+
+ /**
+ * Constructor: OpenLayers.Protocol
+ * Abstract class for vector protocols. Create instances of a subclass.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ */
+ initialize: function(options) {
+ options = options || {};
+ OpenLayers.Util.extend(this, options);
+ this.options = options;
+ },
+
+ /**
+ * Method: mergeWithDefaultFilter
+ * Merge filter passed to the read method with the default one
+ *
+ * Parameters:
+ * filter - {OpenLayers.Filter}
+ */
+ mergeWithDefaultFilter: function(filter) {
+ var merged;
+ if (filter && this.defaultFilter) {
+ merged = new OpenLayers.Filter.Logical({
+ type: OpenLayers.Filter.Logical.AND,
+ filters: [this.defaultFilter, filter]
+ });
+ } else {
+ merged = filter || this.defaultFilter || undefined;
+ }
+ return merged;
+ },
+
+ /**
+ * APIMethod: destroy
+ * Clean up the protocol.
+ */
+ destroy: function() {
+ this.options = null;
+ this.format = null;
+ },
+
+ /**
+ * APIMethod: read
+ * Construct a request for reading new features.
+ *
+ * Parameters:
+ * options - {Object} Optional object for configuring the request.
+ *
+ * Returns:
+ * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+ * object, the same object will be passed to the callback function passed
+ * if one exists in the options object.
+ */
+ read: function(options) {
+ options = options || {};
+ options.filter = this.mergeWithDefaultFilter(options.filter);
+ },
+
+
+ /**
+ * APIMethod: create
+ * Construct a request for writing newly created features.
+ *
+ * Parameters:
+ * features - {Array({<OpenLayers.Feature.Vector>})} or
+ * {<OpenLayers.Feature.Vector>}
+ * options - {Object} Optional object for configuring the request.
+ *
+ * Returns:
+ * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+ * object, the same object will be passed to the callback function passed
+ * if one exists in the options object.
+ */
+ create: function() {
+ },
+
+ /**
+ * APIMethod: update
+ * Construct a request updating modified features.
+ *
+ * Parameters:
+ * features - {Array({<OpenLayers.Feature.Vector>})} or
+ * {<OpenLayers.Feature.Vector>}
+ * options - {Object} Optional object for configuring the request.
+ *
+ * Returns:
+ * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+ * object, the same object will be passed to the callback function passed
+ * if one exists in the options object.
+ */
+ update: function() {
+ },
+
+ /**
+ * APIMethod: delete
+ * Construct a request deleting a removed feature.
+ *
+ * Parameters:
+ * feature - {<OpenLayers.Feature.Vector>}
+ * options - {Object} Optional object for configuring the request.
+ *
+ * Returns:
+ * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+ * object, the same object will be passed to the callback function passed
+ * if one exists in the options object.
+ */
+ "delete": function() {
+ },
+
+ /**
+ * APIMethod: commit
+ * Go over the features and for each take action
+ * based on the feature state. Possible actions are create,
+ * update and delete.
+ *
+ * Parameters:
+ * features - {Array({<OpenLayers.Feature.Vector>})}
+ * options - {Object} Object whose possible keys are "create", "update",
+ * "delete", "callback" and "scope", the values referenced by the
+ * first three are objects as passed to the "create", "update", and
+ * "delete" methods, the value referenced by the "callback" key is
+ * a function which is called when the commit operation is complete
+ * using the scope referenced by the "scope" key.
+ *
+ * Returns:
+ * {Array({<OpenLayers.Protocol.Response>})} An array of
+ * <OpenLayers.Protocol.Response> objects.
+ */
+ commit: function() {
+ },
+
+ /**
+ * Method: abort
+ * Abort an ongoing request.
+ *
+ * Parameters:
+ * response - {<OpenLayers.Protocol.Response>}
+ */
+ abort: function(response) {
+ },
+
+ /**
+ * Method: createCallback
+ * Returns a function that applies the given public method with resp and
+ * options arguments.
+ *
+ * Parameters:
+ * method - {Function} The method to be applied by the callback.
+ * response - {<OpenLayers.Protocol.Response>} The protocol response object.
+ * options - {Object} Options sent to the protocol method
+ */
+ createCallback: function(method, response, options) {
+ return OpenLayers.Function.bind(function() {
+ method.apply(this, [response, options]);
+ }, this);
+ },
+
+ CLASS_NAME: "OpenLayers.Protocol"
+});
+
+/**
+ * Class: OpenLayers.Protocol.Response
+ * Protocols return Response objects to their users.
+ */
+OpenLayers.Protocol.Response = OpenLayers.Class({
+ /**
+ * Property: code
+ * {Number} - OpenLayers.Protocol.Response.SUCCESS or
+ * OpenLayers.Protocol.Response.FAILURE
+ */
+ code: null,
+
+ /**
+ * Property: requestType
+ * {String} The type of request this response corresponds to. Either
+ * "create", "read", "update" or "delete".
+ */
+ requestType: null,
+
+ /**
+ * Property: last
+ * {Boolean} - true if this is the last response expected in a commit,
+ * false otherwise, defaults to true.
+ */
+ last: true,
+
+ /**
+ * Property: features
+ * {Array({<OpenLayers.Feature.Vector>})} or {<OpenLayers.Feature.Vector>}
+ * The features returned in the response by the server.
+ */
+ features: null,
+
+ /**
+ * Property: reqFeatures
+ * {Array({<OpenLayers.Feature.Vector>})} or {<OpenLayers.Feature.Vector>}
+ * The features provided by the user and placed in the request by the
+ * protocol.
+ */
+ reqFeatures: null,
+
+ /**
+ * Property: priv
+ */
+ priv: null,
+
+ /**
+ * Constructor: OpenLayers.Protocol.Response
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ */
+ initialize: function(options) {
+ OpenLayers.Util.extend(this, options);
+ },
+
+ /**
+ * Method: success
+ *
+ * Returns:
+ * {Boolean} - true on success, false otherwise
+ */
+ success: function() {
+ return this.code > 0;
+ },
+
+ CLASS_NAME: "OpenLayers.Protocol.Response"
+});
+
+OpenLayers.Protocol.Response.SUCCESS = 1;
+OpenLayers.Protocol.Response.FAILURE = 0;
+/* ======================================================================
+ OpenLayers/Protocol/WFS.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Protocol.js
+ */
+
+/**
+ * Function: OpenLayers.Protocol.WFS
+ * Used to create a versioned WFS protocol. Default version is 1.0.0.
+ *
+ * Returns:
+ * {<OpenLayers.Protocol>} A WFS protocol of the given version.
+ */
+OpenLayers.Protocol.WFS = function(options) {
+ options = OpenLayers.Util.applyDefaults(
+ options, OpenLayers.Protocol.WFS.DEFAULTS
+ );
+ var cls = OpenLayers.Protocol.WFS["v"+options.version.replace(/\./g, "_")];
+ if(!cls) {
+ throw "Unsupported WFS version: " + options.version;
+ }
+ return new cls(options);
+};
+
+/**
+ * Function: OpenLayers.Protocol.WFS.fromWMSLayer
+ * Convenience function to create a WFS protocol from a WMS layer. This makes
+ * the assumption that a WFS requests can be issued at the same URL as
+ * WMS requests and that a WFS featureType exists with the same name as the
+ * WMS layer.
+ *
+ * This function is designed to auto-configure <url>, <featureType>,
+ * <featurePrefix> and <srsName> for WFS <version> 1.1.0. Note that
+ * srsName matching with the WMS layer will not work with WFS 1.0.0..
+ *
+ * Parameters:
+ * layer - {<OpenLayers.Layer.WMS>} WMS layer that has a matching WFS
+ * FeatureType at the same server url with the same typename.
+ * options - {Object} Default properties to be set on the protocol.
+ *
+ */
+OpenLayers.Protocol.WFS.fromWMSLayer = function(layer, options) {
+ var typeName, featurePrefix;
+ var param = layer.params["LAYERS"];
+ var parts = (param instanceof Array ? param[0] : param).split(":");
+ if(parts.length > 1) {
+ featurePrefix = parts[0];
+ }
+ typeName = parts.pop();
+ var protocolOptions = {
+ url: layer.url,
+ featureType: typeName,
+ featurePrefix: featurePrefix,
+ srsName: layer.projection && layer.projection.getCode() ||
+ layer.map && layer.map.getProjectionObject().getCode(),
+ version: "1.1.0"
+ };
+ return new OpenLayers.Protocol.WFS(OpenLayers.Util.applyDefaults(
+ options, protocolOptions
+ ));
+};
+
+/**
+ * Constant: OpenLayers.Protocol.WFS.DEFAULTS
+ */
+OpenLayers.Protocol.WFS.DEFAULTS = {
+ "version": "1.0.0"
+};
+/* ======================================================================
+ OpenLayers/Layer/Markers.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.Markers
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer>
+ */
+OpenLayers.Layer.Markers = OpenLayers.Class(OpenLayers.Layer, {
+
+ /**
+ * APIProperty: isBaseLayer
+ * {Boolean} Markers layer is never a base layer.
+ */
+ isBaseLayer: false,
+
+ /**
+ * APIProperty: markers
+ * {Array(<OpenLayers.Marker>)} internal marker list
+ */
+ markers: null,
+
+
+ /**
+ * Property: drawn
+ * {Boolean} internal state of drawing. This is a workaround for the fact
+ * that the map does not call moveTo with a zoomChanged when the map is
+ * first starting up. This lets us catch the case where we have *never*
+ * drawn the layer, and draw it even if the zoom hasn't changed.
+ */
+ drawn: false,
+
+ /**
+ * Constructor: OpenLayers.Layer.Markers
+ * Create a Markers layer.
+ *
+ * Parameters:
+ * name - {String}
+ * options - {Object} Hashtable of extra options to tag onto the layer
+ */
+ initialize: function(name, options) {
+ OpenLayers.Layer.prototype.initialize.apply(this, arguments);
+ this.markers = [];
+ },
+
+ /**
+ * APIMethod: destroy
+ */
+ destroy: function() {
+ this.clearMarkers();
+ this.markers = null;
+ OpenLayers.Layer.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * APIMethod: setOpacity
+ * Sets the opacity for all the markers.
+ *
+ * Parameter:
+ * opacity - {Float}
+ */
+ setOpacity: function(opacity) {
+ if (opacity != this.opacity) {
+ this.opacity = opacity;
+ for (var i=0, len=this.markers.length; i<len; i++) {
+ this.markers[i].setOpacity(this.opacity);
+ }
+ }
+ },
+
+ /**
+ * Method: moveTo
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * zoomChanged - {Boolean}
+ * dragging - {Boolean}
+ */
+ moveTo:function(bounds, zoomChanged, dragging) {
+ OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
+
+ if (zoomChanged || !this.drawn) {
+ for(var i=0, len=this.markers.length; i<len; i++) {
+ this.drawMarker(this.markers[i]);
+ }
+ this.drawn = true;
+ }
+ },
+
+ /**
+ * APIMethod: addMarker
+ *
+ * Parameters:
+ * marker - {<OpenLayers.Marker>}
+ */
+ addMarker: function(marker) {
+ this.markers.push(marker);
+
+ if (this.opacity != null) {
+ marker.setOpacity(this.opacity);
+ }
+
+ if (this.map && this.map.getExtent()) {
+ marker.map = this.map;
+ this.drawMarker(marker);
+ }
+ },
+
+ /**
+ * APIMethod: removeMarker
+ *
+ * Parameters:
+ * marker - {<OpenLayers.Marker>}
+ */
+ removeMarker: function(marker) {
+ if (this.markers && this.markers.length) {
+ OpenLayers.Util.removeItem(this.markers, marker);
+ marker.erase();
+ }
+ },
+
+ /**
+ * Method: clearMarkers
+ * This method removes all markers from a layer. The markers are not
+ * destroyed by this function, but are removed from the list of markers.
+ */
+ clearMarkers: function() {
+ if (this.markers != null) {
+ while(this.markers.length > 0) {
+ this.removeMarker(this.markers[0]);
+ }
+ }
+ },
+
+ /**
+ * Method: drawMarker
+ * Calculate the pixel location for the marker, create it, and
+ * add it to the layer's div
+ *
+ * Parameters:
+ * marker - {<OpenLayers.Marker>}
+ */
+ drawMarker: function(marker) {
+ var px = this.map.getLayerPxFromLonLat(marker.lonlat);
+ if (px == null) {
+ marker.display(false);
+ } else {
+ if (!marker.isDrawn()) {
+ var markerImg = marker.draw(px);
+ this.div.appendChild(markerImg);
+ } else if(marker.icon) {
+ marker.icon.moveTo(px);
+ }
+ }
+ },
+
+ /**
+ * APIMethod: getDataExtent
+ * Calculates the max extent which includes all of the markers.
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>}
+ */
+ getDataExtent: function () {
+ var maxExtent = null;
+
+ if ( this.markers && (this.markers.length > 0)) {
+ var maxExtent = new OpenLayers.Bounds();
+ for(var i=0, len=this.markers.length; i<len; i++) {
+ var marker = this.markers[i];
+ maxExtent.extend(marker.lonlat);
+ }
+ }
+
+ return maxExtent;
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.Markers"
+});
+/* ======================================================================
+ OpenLayers/Protocol/WFS/v1.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Protocol/WFS.js
+ */
+
+/**
+ * Class: OpenLayers.Protocol.WFS.v1
+ * Abstract class for for v1.0.0 and v1.1.0 protocol.
+ *
+ * Inherits from:
+ * - <OpenLayers.Protocol>
+ */
+OpenLayers.Protocol.WFS.v1 = OpenLayers.Class(OpenLayers.Protocol, {
+
+ /**
+ * Property: version
+ * {String} WFS version number.
+ */
+ version: null,
+
+ /**
+ * Property: srsName
+ * {String} Name of spatial reference system. Default is "EPSG:4326".
+ */
+ srsName: "EPSG:4326",
+
+ /**
+ * Property: featureType
+ * {String} Local feature typeName.
+ */
+ featureType: null,
+
+ /**
+ * Property: featureNS
+ * {String} Feature namespace.
+ */
+ featureNS: null,
+
+ /**
+ * Property: geometryName
+ * {String} Name of the geometry attribute for features. Default is
+ * "the_geom".
+ */
+ geometryName: "the_geom",
+
+ /**
+ * Property: schema
+ * {String} Optional schema location that will be included in the
+ * schemaLocation attribute value. Note that the feature type schema
+ * is required for a strict XML validator (on transactions with an
+ * insert for example), but is *not* required by the WFS specification
+ * (since the server is supposed to know about feature type schemas).
+ */
+ schema: null,
+
+ /**
+ * Property: featurePrefix
+ * {String} Namespace alias for feature type. Default is "feature".
+ */
+ featurePrefix: "feature",
+
+ /**
+ * Property: formatOptions
+ * {Object} Optional options for the format. If a format is not provided,
+ * this property can be used to extend the default format options.
+ */
+ formatOptions: null,
+
+ /**
+ * Property: readFormat
+ * {<OpenLayers.Format>} For WFS requests it is possible to get a
+ * different output format than GML. In that case, we cannot parse
+ * the response with the default format (WFST) and we need a different
+ * format for reading.
+ */
+ readFormat: null,
+
+ /**
+ * Property: readOptions
+ * {Object} Optional object to pass to format's read.
+ */
+ readOptions: null,
+
+ /**
+ * Constructor: OpenLayers.Protocol.WFS
+ * A class for giving layers WFS protocol.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ *
+ * Valid options properties:
+ * url - {String} URL to send requests to (required).
+ * featureType - {String} Local (without prefix) feature typeName (required).
+ * featureNS - {String} Feature namespace (required, but can be autodetected
+ * for reading if featurePrefix is provided and identical to the prefix
+ * in the server response).
+ * featurePrefix - {String} Feature namespace alias (optional - only used
+ * for writing if featureNS is provided). Default is 'feature'.
+ * geometryName - {String} Name of geometry attribute. Default is 'the_geom'.
+ */
+ initialize: function(options) {
+ OpenLayers.Protocol.prototype.initialize.apply(this, [options]);
+ if(!options.format) {
+ this.format = OpenLayers.Format.WFST(OpenLayers.Util.extend({
+ version: this.version,
+ featureType: this.featureType,
+ featureNS: this.featureNS,
+ featurePrefix: this.featurePrefix,
+ geometryName: this.geometryName,
+ srsName: this.srsName,
+ schema: this.schema
+ }, this.formatOptions));
+ }
+ if(!this.featureNS && this.featurePrefix) {
+ // featureNS autodetection
+ var readNode = this.format.readNode;
+ this.format.readNode = function(node, obj) {
+ if(!this.featureNS && node.prefix == this.featurePrefix) {
+ this.featureNS = node.namespaceURI;
+ this.setNamespace("feature", this.featureNS);
+ }
+ return readNode.apply(this, arguments);
+ };
+ }
+ },
+
+ /**
+ * APIMethod: destroy
+ * Clean up the protocol.
+ */
+ destroy: function() {
+ if(this.options && !this.options.format) {
+ this.format.destroy();
+ }
+ this.format = null;
+ OpenLayers.Protocol.prototype.destroy.apply(this);
+ },
+
+ /**
+ * APIMethod: read
+ * Construct a request for reading new features. Since WFS splits the
+ * basic CRUD operations into GetFeature requests (for read) and
+ * Transactions (for all others), this method does not make use of the
+ * format's read method (that is only about reading transaction
+ * responses).
+ *
+ * To use a configured protocol to get e.g. a WFS hit count, applications
+ * could do the following:
+ *
+ * (code)
+ * protocol.read({
+ * readOptions: {output: "object"},
+ * resultType: "hits",
+ * maxFeatures: null,
+ * callback: function(resp) {
+ * // process resp.numberOfFeatures here
+ * }
+ * });
+ * (end)
+ */
+ read: function(options) {
+ OpenLayers.Protocol.prototype.read.apply(this, arguments);
+ options = OpenLayers.Util.extend({}, options);
+ OpenLayers.Util.applyDefaults(options, this.options || {});
+ var response = new OpenLayers.Protocol.Response({requestType: "read"});
+
+ var data = OpenLayers.Format.XML.prototype.write.apply(
+ this.format, [this.format.writeNode("wfs:GetFeature", options)]
+ );
+
+ response.priv = OpenLayers.Request.POST({
+ url: options.url,
+ callback: this.createCallback(this.handleRead, response, options),
+ params: options.params,
+ headers: options.headers,
+ data: data
+ });
+
+ return response;
+ },
+
+ /**
+ * Method: handleRead
+ * Deal with response from the read request.
+ *
+ * Parameters:
+ * response - {<OpenLayers.Protocol.Response>} The response object to pass
+ * to the user callback.
+ * options - {Object} The user options passed to the read call.
+ */
+ handleRead: function(response, options) {
+ options = OpenLayers.Util.extend({}, options);
+ OpenLayers.Util.applyDefaults(options, this.options);
+
+ if(options.callback) {
+ var request = response.priv;
+ if(request.status >= 200 && request.status < 300) {
+ // success
+ if (options.readOptions && options.readOptions.output == "object") {
+ OpenLayers.Util.extend(response,
+ this.parseResponse(request, options.readOptions));
+ } else {
+ response.features = this.parseResponse(request, options.readOptions);
+ }
+ response.code = OpenLayers.Protocol.Response.SUCCESS;
+ } else {
+ // failure
+ response.code = OpenLayers.Protocol.Response.FAILURE;
+ }
+ options.callback.call(options.scope, response);
+ }
+ },
+
+ /**
+ * Method: parseResponse
+ * Read HTTP response body and return features
+ *
+ * Parameters:
+ * request - {XMLHttpRequest} The request object
+ * options - {Object} Optional object to pass to format's read
+ *
+ * Returns:
+ * {Object} or {Array({<OpenLayers.Feature.Vector>})} or
+ * {<OpenLayers.Feature.Vector>}
+ * An object with a features property, an array of features or a single
+ * feature.
+ */
+ parseResponse: function(request, options) {
+ var doc = request.responseXML;
+ if(!doc || !doc.documentElement) {
+ doc = request.responseText;
+ }
+ if(!doc || doc.length <= 0) {
+ return null;
+ }
+ return (this.readFormat !== null) ? this.readFormat.read(doc) :
+ this.format.read(doc, options);
+ },
+
+ /**
+ * Method: commit
+ * Given a list of feature, assemble a batch request for update, create,
+ * and delete transactions. A commit call on the prototype amounts
+ * to writing a WFS transaction - so the write method on the format
+ * is used.
+ *
+ * Parameters:
+ * features - {Array(<OpenLayers.Feature.Vector>}
+ *
+ * Returns:
+ * {<OpenLayers.Protocol.Response>} A response object with a features
+ * property containing any insertIds and a priv property referencing
+ * the XMLHttpRequest object.
+ */
+ commit: function(features, options) {
+
+ options = OpenLayers.Util.extend({}, options);
+ OpenLayers.Util.applyDefaults(options, this.options);
+
+ var response = new OpenLayers.Protocol.Response({
+ requestType: "commit",
+ reqFeatures: features
+ });
+ response.priv = OpenLayers.Request.POST({
+ url: options.url,
+ data: this.format.write(features, options),
+ callback: this.createCallback(this.handleCommit, response, options)
+ });
+
+ return response;
+ },
+
+ /**
+ * Method: handleCommit
+ * Called when the commit request returns.
+ *
+ * Parameters:
+ * response - {<OpenLayers.Protocol.Response>} The response object to pass
+ * to the user callback.
+ * options - {Object} The user options passed to the commit call.
+ */
+ handleCommit: function(response, options) {
+ if(options.callback) {
+ var request = response.priv;
+
+ // ensure that we have an xml doc
+ var data = request.responseXML;
+ if(!data || !data.documentElement) {
+ data = request.responseText;
+ }
+
+ var obj = this.format.read(data) || {};
+
+ response.insertIds = obj.insertIds || [];
+ response.code = (obj.success) ?
+ OpenLayers.Protocol.Response.SUCCESS :
+ OpenLayers.Protocol.Response.FAILURE;
+ options.callback.call(options.scope, response);
+ }
+ },
+
+ /**
+ * Method: filterDelete
+ * Send a request that deletes all features by their filter.
+ *
+ * Parameters:
+ * filter - {OpenLayers.Filter} filter
+ */
+ filterDelete: function(filter, options) {
+ options = OpenLayers.Util.extend({}, options);
+ OpenLayers.Util.applyDefaults(options, this.options);
+
+ var response = new OpenLayers.Protocol.Response({
+ requestType: "commit"
+ });
+
+ var root = this.format.createElementNSPlus("wfs:Transaction", {
+ attributes: {
+ service: "WFS",
+ version: this.version
+ }
+ });
+
+ var deleteNode = this.format.createElementNSPlus("wfs:Delete", {
+ attributes: {
+ typeName: (options.featureNS ? this.featurePrefix + ":" : "") +
+ options.featureType
+ }
+ });
+
+ if(options.featureNS) {
+ deleteNode.setAttribute("xmlns:" + this.featurePrefix, options.featureNS);
+ }
+ var filterNode = this.format.writeNode("ogc:Filter", filter);
+
+ deleteNode.appendChild(filterNode);
+
+ root.appendChild(deleteNode);
+
+ var data = OpenLayers.Format.XML.prototype.write.apply(
+ this.format, [root]
+ );
+
+ return OpenLayers.Request.POST({
+ url: this.url,
+ callback : options.callback || function(){},
+ data: data
+ });
+
+ },
+
+ /**
+ * Method: abort
+ * Abort an ongoing request, the response object passed to
+ * this method must come from this protocol (as a result
+ * of a read, or commit operation).
+ *
+ * Parameters:
+ * response - {<OpenLayers.Protocol.Response>}
+ */
+ abort: function(response) {
+ if (response) {
+ response.priv.abort();
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Protocol.WFS.v1"
+});
+/* ======================================================================
+ OpenLayers/Filter/Spatial.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Filter.js
+ * @requires OpenLayers/Console.js
+ * @requires OpenLayers/Lang.js
+ */
+
+/**
+ * Class: OpenLayers.Filter.Spatial
+ * This class represents a spatial filter.
+ * Currently implemented: BBOX, DWithin and Intersects
+ *
+ * Inherits from
+ * - <OpenLayers.Filter>
+ */
+OpenLayers.Filter.Spatial = OpenLayers.Class(OpenLayers.Filter, {
+
+ /**
+ * APIProperty: type
+ * {String} Type of spatial filter.
+ *
+ * The type should be one of:
+ * - OpenLayers.Filter.Spatial.BBOX
+ * - OpenLayers.Filter.Spatial.INTERSECTS
+ * - OpenLayers.Filter.Spatial.DWITHIN
+ * - OpenLayers.Filter.Spatial.WITHIN
+ * - OpenLayers.Filter.Spatial.CONTAINS
+ */
+ type: null,
+
+ /**
+ * APIProperty: property
+ * {String} Name of the context property to compare.
+ */
+ property: null,
+
+ /**
+ * APIProperty: value
+ * {<OpenLayers.Bounds> || <OpenLayers.Geometry>} The bounds or geometry
+ * to be used by the filter. Use bounds for BBOX filters and geometry
+ * for INTERSECTS or DWITHIN filters.
+ */
+ value: null,
+
+ /**
+ * APIProperty: distance
+ * {Number} The distance to use in a DWithin spatial filter.
+ */
+ distance: null,
+
+ /**
+ * APIProperty: distanceUnits
+ * {String} The units to use for the distance, e.g. 'm'.
+ */
+ distanceUnits: null,
+
+ /**
+ * Constructor: OpenLayers.Filter.Spatial
+ * Creates a spatial filter.
+ *
+ * Parameters:
+ * options - {Object} An optional object with properties to set on the
+ * filter.
+ *
+ * Returns:
+ * {<OpenLayers.Filter.Spatial>}
+ */
+ initialize: function(options) {
+ OpenLayers.Filter.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * Method: evaluate
+ * Evaluates this filter for a specific feature.
+ *
+ * Parameters:
+ * feature - {<OpenLayers.Feature.Vector>} feature to apply the filter to.
+ *
+ * Returns:
+ * {Boolean} The feature meets filter criteria.
+ */
+ evaluate: function(feature) {
+ var intersect = false;
+ switch(this.type) {
+ case OpenLayers.Filter.Spatial.BBOX:
+ case OpenLayers.Filter.Spatial.INTERSECTS:
+ if(feature.geometry) {
+ var geom = this.value;
+ if(this.value.CLASS_NAME == "OpenLayers.Bounds") {
+ geom = this.value.toGeometry();
+ }
+ if(feature.geometry.intersects(geom)) {
+ intersect = true;
+ }
+ }
+ break;
+ default:
+ OpenLayers.Console.error(
+ OpenLayers.i18n("filterEvaluateNotImplemented"));
+ break;
+ }
+ return intersect;
+ },
+
+ /**
+ * APIMethod: clone
+ * Clones this filter.
+ *
+ * Returns:
+ * {<OpenLayers.Filter.Spatial>} Clone of this filter.
+ */
+ clone: function() {
+ var options = OpenLayers.Util.applyDefaults({
+ value: this.value && this.value.clone && this.value.clone()
+ }, this);
+ return new OpenLayers.Filter.Spatial(options);
+ },
+ CLASS_NAME: "OpenLayers.Filter.Spatial"
+});
+
+OpenLayers.Filter.Spatial.BBOX = "BBOX";
+OpenLayers.Filter.Spatial.INTERSECTS = "INTERSECTS";
+OpenLayers.Filter.Spatial.DWITHIN = "DWITHIN";
+OpenLayers.Filter.Spatial.WITHIN = "WITHIN";
+OpenLayers.Filter.Spatial.CONTAINS = "CONTAINS";
+/* ======================================================================
+ OpenLayers/Control.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Control
+ * Controls affect the display or behavior of the map. They allow everything
+ * from panning and zooming to displaying a scale indicator. Controls by
+ * default are added to the map they are contained within however it is
+ * possible to add a control to an external div by passing the div in the
+ * options parameter.
+ *
+ * Example:
+ * The following example shows how to add many of the common controls
+ * to a map.
+ *
+ * > var map = new OpenLayers.Map('map', { controls: [] });
+ * >
+ * > map.addControl(new OpenLayers.Control.PanZoomBar());
+ * > map.addControl(new OpenLayers.Control.MouseToolbar());
+ * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
+ * > map.addControl(new OpenLayers.Control.Permalink());
+ * > map.addControl(new OpenLayers.Control.Permalink('permalink'));
+ * > map.addControl(new OpenLayers.Control.MousePosition());
+ * > map.addControl(new OpenLayers.Control.OverviewMap());
+ * > map.addControl(new OpenLayers.Control.KeyboardDefaults());
+ *
+ * The next code fragment is a quick example of how to intercept
+ * shift-mouse click to display the extent of the bounding box
+ * dragged out by the user. Usually controls are not created
+ * in exactly this manner. See the source for a more complete
+ * example:
+ *
+ * > var control = new OpenLayers.Control();
+ * > OpenLayers.Util.extend(control, {
+ * > draw: function () {
+ * > // this Handler.Box will intercept the shift-mousedown
+ * > // before Control.MouseDefault gets to see it
+ * > this.box = new OpenLayers.Handler.Box( control,
+ * > {"done": this.notice},
+ * > {keyMask: OpenLayers.Handler.MOD_SHIFT});
+ * > this.box.activate();
+ * > },
+ * >
+ * > notice: function (bounds) {
+ * > OpenLayers.Console.userError(bounds);
+ * > }
+ * > });
+ * > map.addControl(control);
+ *
+ */
+OpenLayers.Control = OpenLayers.Class({
+
+ /**
+ * Property: id
+ * {String}
+ */
+ id: null,
+
+ /**
+ * Property: map
+ * {<OpenLayers.Map>} this gets set in the addControl() function in
+ * OpenLayers.Map
+ */
+ map: null,
+
+ /**
+ * Property: div
+ * {DOMElement}
+ */
+ div: null,
+
+ /**
+ * Property: type
+ * {Number} Controls can have a 'type'. The type determines the type of
+ * interactions which are possible with them when they are placed in an
+ * <OpenLayers.Control.Panel>.
+ */
+ type: null,
+
+ /**
+ * Property: allowSelection
+ * {Boolean} By deafault, controls do not allow selection, because
+ * it may interfere with map dragging. If this is true, OpenLayers
+ * will not prevent selection of the control.
+ * Default is false.
+ */
+ allowSelection: false,
+
+ /**
+ * Property: displayClass
+ * {string} This property is used for CSS related to the drawing of the
+ * Control.
+ */
+ displayClass: "",
+
+ /**
+ * Property: title
+ * {string} This property is used for showing a tooltip over the
+ * Control.
+ */
+ title: "",
+
+ /**
+ * APIProperty: autoActivate
+ * {Boolean} Activate the control when it is added to a map. Default is
+ * false.
+ */
+ autoActivate: false,
+
+ /**
+ * Property: active
+ * {Boolean} The control is active.
+ */
+ active: null,
+
+ /**
+ * Property: handler
+ * {<OpenLayers.Handler>} null
+ */
+ handler: null,
+
+ /**
+ * APIProperty: eventListeners
+ * {Object} If set as an option at construction, the eventListeners
+ * object will be registered with <OpenLayers.Events.on>. Object
+ * structure must be a listeners object as shown in the example for
+ * the events.on method.
+ */
+ eventListeners: null,
+
+ /**
+ * Property: events
+ * {<OpenLayers.Events>} Events instance for triggering control specific
+ * events.
+ */
+ events: null,
+
+ /**
+ * Constant: EVENT_TYPES
+ * {Array(String)} Supported application event types. Register a listener
+ * for a particular event with the following syntax:
+ * (code)
+ * control.events.register(type, obj, listener);
+ * (end)
+ *
+ * Listeners will be called with a reference to an event object. The
+ * properties of this event depends on exactly what happened.
+ *
+ * All event objects have at least the following properties:
+ * object - {Object} A reference to control.events.object (a reference
+ * to the control).
+ * element - {DOMElement} A reference to control.events.element (which
+ * will be null unless documented otherwise).
+ *
+ * Supported map event types:
+ * activate - Triggered when activated.
+ * deactivate - Triggered when deactivated.
+ */
+ EVENT_TYPES: ["activate", "deactivate"],
+
+ /**
+ * Constructor: OpenLayers.Control
+ * Create an OpenLayers Control. The options passed as a parameter
+ * directly extend the control. For example passing the following:
+ *
+ * > var control = new OpenLayers.Control({div: myDiv});
+ *
+ * Overrides the default div attribute value of null.
+ *
+ * Parameters:
+ * options - {Object}
+ */
+ initialize: function (options) {
+ // We do this before the extend so that instances can override
+ // className in options.
+ this.displayClass =
+ this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, "");
+
+ OpenLayers.Util.extend(this, options);
+
+ this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
+ if(this.eventListeners instanceof Object) {
+ this.events.on(this.eventListeners);
+ }
+ if (this.id == null) {
+ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+ }
+ },
+
+ /**
+ * Method: destroy
+ * The destroy method is used to perform any clean up before the control
+ * is dereferenced. Typically this is where event listeners are removed
+ * to prevent memory leaks.
+ */
+ destroy: function () {
+ if(this.events) {
+ if(this.eventListeners) {
+ this.events.un(this.eventListeners);
+ }
+ this.events.destroy();
+ this.events = null;
+ }
+ this.eventListeners = null;
+
+ // eliminate circular references
+ if (this.handler) {
+ this.handler.destroy();
+ this.handler = null;
+ }
+ if(this.handlers) {
+ for(var key in this.handlers) {
+ if(this.handlers.hasOwnProperty(key) &&
+ typeof this.handlers[key].destroy == "function") {
+ this.handlers[key].destroy();
+ }
+ }
+ this.handlers = null;
+ }
+ if (this.map) {
+ this.map.removeControl(this);
+ this.map = null;
+ }
+ },
+
+ /**
+ * Method: setMap
+ * Set the map property for the control. This is done through an accessor
+ * so that subclasses can override this and take special action once
+ * they have their map variable set.
+ *
+ * Parameters:
+ * map - {<OpenLayers.Map>}
+ */
+ setMap: function(map) {
+ this.map = map;
+ if (this.handler) {
+ this.handler.setMap(map);
+ }
+ },
+
+ /**
+ * Method: draw
+ * The draw method is called when the control is ready to be displayed
+ * on the page. If a div has not been created one is created. Controls
+ * with a visual component will almost always want to override this method
+ * to customize the look of control.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>} The top-left pixel position of the control
+ * or null.
+ *
+ * Returns:
+ * {DOMElement} A reference to the DIV DOMElement containing the control
+ */
+ draw: function (px) {
+ if (this.div == null) {
+ this.div = OpenLayers.Util.createDiv(this.id);
+ this.div.className = this.displayClass;
+ if (!this.allowSelection) {
+ this.div.className += " olControlNoSelect";
+ this.div.setAttribute("unselectable", "on", 0);
+ this.div.onselectstart = OpenLayers.Function.False;
+ }
+ if (this.title != "") {
+ this.div.title = this.title;
+ }
+ }
+ if (px != null) {
+ this.position = px.clone();
+ }
+ this.moveTo(this.position);
+ return this.div;
+ },
+
+ /**
+ * Method: moveTo
+ * Sets the left and top style attributes to the passed in pixel
+ * coordinates.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ */
+ moveTo: function (px) {
+ if ((px != null) && (this.div != null)) {
+ this.div.style.left = px.x + "px";
+ this.div.style.top = px.y + "px";
+ }
+ },
+
+ /**
+ * Method: activate
+ * Explicitly activates a control and it's associated
+ * handler if one has been set. Controls can be
+ * deactivated by calling the deactivate() method.
+ *
+ * Returns:
+ * {Boolean} True if the control was successfully activated or
+ * false if the control was already active.
+ */
+ activate: function () {
+ if (this.active) {
+ return false;
+ }
+ if (this.handler) {
+ this.handler.activate();
+ }
+ this.active = true;
+ if(this.map) {
+ OpenLayers.Element.addClass(
+ this.map.viewPortDiv,
+ this.displayClass.replace(/ /g, "") + "Active"
+ );
+ }
+ this.events.triggerEvent("activate");
+ return true;
+ },
+
+ /**
+ * Method: deactivate
+ * Deactivates a control and it's associated handler if any. The exact
+ * effect of this depends on the control itself.
+ *
+ * Returns:
+ * {Boolean} True if the control was effectively deactivated or false
+ * if the control was already inactive.
+ */
+ deactivate: function () {
+ if (this.active) {
+ if (this.handler) {
+ this.handler.deactivate();
+ }
+ this.active = false;
+ if(this.map) {
+ OpenLayers.Element.removeClass(
+ this.map.viewPortDiv,
+ this.displayClass.replace(/ /g, "") + "Active"
+ );
+ }
+ this.events.triggerEvent("deactivate");
+ return true;
+ }
+ return false;
+ },
+
+ CLASS_NAME: "OpenLayers.Control"
+});
+
+/**
+ * Constant: OpenLayers.Control.TYPE_BUTTON
+ */
+OpenLayers.Control.TYPE_BUTTON = 1;
+
+/**
+ * Constant: OpenLayers.Control.TYPE_TOGGLE
+ */
+OpenLayers.Control.TYPE_TOGGLE = 2;
+
+/**
+ * Constant: OpenLayers.Control.TYPE_TOOL
+ */
+OpenLayers.Control.TYPE_TOOL = 3;
+/* ======================================================================
+ OpenLayers/Request.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Events.js
+ */
+
+/**
+ * Namespace: OpenLayers.Request
+ * The OpenLayers.Request namespace contains convenience methods for working
+ * with XMLHttpRequests. These methods work with a cross-browser
+ * W3C compliant <OpenLayers.Request.XMLHttpRequest> class.
+ */
+OpenLayers.Request = {
+
+ /**
+ * Constant: DEFAULT_CONFIG
+ * {Object} Default configuration for all requests.
+ */
+ DEFAULT_CONFIG: {
+ method: "GET",
+ url: window.location.href,
+ async: true,
+ user: undefined,
+ password: undefined,
+ params: null,
+ proxy: OpenLayers.ProxyHost,
+ headers: {},
+ data: null,
+ callback: function() {},
+ success: null,
+ failure: null,
+ scope: null
+ },
+
+ /**
+ * Constant: URL_SPLIT_REGEX
+ */
+ URL_SPLIT_REGEX: /([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/,
+
+ /**
+ * APIProperty: events
+ * {<OpenLayers.Events>} An events object that handles all
+ * events on the {<OpenLayers.Request>} object.
+ *
+ * All event listeners will receive an event object with three properties:
+ * request - {<OpenLayers.Request.XMLHttpRequest>} The request object.
+ * config - {Object} The config object sent to the specific request method.
+ * requestUrl - {String} The request url.
+ *
+ * Supported event types:
+ * complete - Triggered when we have a response from the request, if a
+ * listener returns false, no further response processing will take
+ * place.
+ * success - Triggered when the HTTP response has a success code (200-299).
+ * failure - Triggered when the HTTP response does not have a success code.
+ */
+ events: new OpenLayers.Events(this, null, ["complete", "success", "failure"]),
+
+ /**
+ * APIMethod: issue
+ * Create a new XMLHttpRequest object, open it, set any headers, bind
+ * a callback to done state, and send any data. It is recommended that
+ * you use one <GET>, <POST>, <PUT>, <DELETE>, <OPTIONS>, or <HEAD>.
+ * This method is only documented to provide detail on the configuration
+ * options available to all request methods.
+ *
+ * Parameters:
+ * config - {Object} Object containing properties for configuring the
+ * request. Allowed configuration properties are described below.
+ * This object is modified and should not be reused.
+ *
+ * Allowed config properties:
+ * method - {String} One of GET, POST, PUT, DELETE, HEAD, or
+ * OPTIONS. Default is GET.
+ * url - {String} URL for the request.
+ * async - {Boolean} Open an asynchronous request. Default is true.
+ * user - {String} User for relevant authentication scheme. Set
+ * to null to clear current user.
+ * password - {String} Password for relevant authentication scheme.
+ * Set to null to clear current password.
+ * proxy - {String} Optional proxy. Defaults to
+ * <OpenLayers.ProxyHost>.
+ * params - {Object} Any key:value pairs to be appended to the
+ * url as a query string. Assumes url doesn't already include a query
+ * string or hash. Typically, this is only appropriate for <GET>
+ * requests where the query string will be appended to the url.
+ * Parameter values that are arrays will be
+ * concatenated with a comma (note that this goes against form-encoding)
+ * as is done with <OpenLayers.Util.getParameterString>.
+ * headers - {Object} Object with header:value pairs to be set on
+ * the request.
+ * data - {String | Document} Optional data to send with the request.
+ * Typically, this is only used with <POST> and <PUT> requests.
+ * Make sure to provide the appropriate "Content-Type" header for your
+ * data. For <POST> and <PUT> requests, the content type defaults to
+ * "application-xml". If your data is a different content type, or
+ * if you are using a different HTTP method, set the "Content-Type"
+ * header to match your data type.
+ * callback - {Function} Function to call when request is done.
+ * To determine if the request failed, check request.status (200
+ * indicates success).
+ * success - {Function} Optional function to call if request status is in
+ * the 200s. This will be called in addition to callback above and
+ * would typically only be used as an alternative.
+ * failure - {Function} Optional function to call if request status is not
+ * in the 200s. This will be called in addition to callback above and
+ * would typically only be used as an alternative.
+ * scope - {Object} If callback is a public method on some object,
+ * set the scope to that object.
+ *
+ * Returns:
+ * {XMLHttpRequest} Request object. To abort the request before a response
+ * is received, call abort() on the request object.
+ */
+ issue: function(config) {
+ // apply default config - proxy host may have changed
+ var defaultConfig = OpenLayers.Util.extend(
+ this.DEFAULT_CONFIG,
+ {proxy: OpenLayers.ProxyHost}
+ );
+ config = OpenLayers.Util.applyDefaults(config, defaultConfig);
+
+ // create request, open, and set headers
+ var request = new OpenLayers.Request.XMLHttpRequest();
+ var url = config.url;
+ if(config.params) {
+ var paramString = OpenLayers.Util.getParameterString(config.params);
+ if(paramString.length > 0) {
+ var separator = (url.indexOf('?') > -1) ? '&' : '?';
+ url += separator + paramString;
+ }
+ }
+ var sameOrigin = !(url.indexOf("http") == 0);
+ var urlParts = !sameOrigin && url.match(this.URL_SPLIT_REGEX);
+ if (urlParts) {
+ var location = window.location;
+ sameOrigin =
+ urlParts[1] == location.protocol &&
+ urlParts[3] == location.hostname;
+ var uPort = urlParts[4], lPort = location.port;
+ if (uPort != 80 && uPort != "" || lPort != "80" && lPort != "") {
+ sameOrigin = sameOrigin && uPort == lPort;
+ }
+ }
+ if (!sameOrigin) {
+ if (config.proxy) {
+ if (typeof config.proxy == "function") {
+ url = config.proxy(url);
+ } else {
+ url = config.proxy + encodeURIComponent(url);
+ }
+ } else {
+ OpenLayers.Console.warn(
+ OpenLayers.i18n("proxyNeeded"), {url: url});
+ }
+ }
+ request.open(
+ config.method, url, config.async, config.user, config.password
+ );
+ for(var header in config.headers) {
+ request.setRequestHeader(header, config.headers[header]);
+ }
+
+ var events = this.events;
+
+ // we want to execute runCallbacks with "this" as the
+ // execution scope
+ var self = this;
+
+ request.onreadystatechange = function() {
+ if(request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {
+ var proceed = events.triggerEvent(
+ "complete",
+ {request: request, config: config, requestUrl: url}
+ );
+ if(proceed !== false) {
+ self.runCallbacks(
+ {request: request, config: config, requestUrl: url}
+ );
+ }
+ }
+ };
+
+ // send request (optionally with data) and return
+ // call in a timeout for asynchronous requests so the return is
+ // available before readyState == 4 for cached docs
+ if(config.async === false) {
+ request.send(config.data);
+ } else {
+ window.setTimeout(function(){
+ if (request.readyState !== 0) { // W3C: 0-UNSENT
+ request.send(config.data);
+ }
+ }, 0);
+ }
+ return request;
+ },
+
+ /**
+ * Method: runCallbacks
+ * Calls the complete, success and failure callbacks. Application
+ * can listen to the "complete" event, have the listener
+ * display a confirm window and always return false, and
+ * execute OpenLayers.Request.runCallbacks if the user
+ * hits "yes" in the confirm window.
+ *
+ * Parameters:
+ * options - {Object} Hash containing request, config and requestUrl keys
+ */
+ runCallbacks: function(options) {
+ var request = options.request;
+ var config = options.config;
+
+ // bind callbacks to readyState 4 (done)
+ var complete = (config.scope) ?
+ OpenLayers.Function.bind(config.callback, config.scope) :
+ config.callback;
+
+ // optional success callback
+ var success;
+ if(config.success) {
+ success = (config.scope) ?
+ OpenLayers.Function.bind(config.success, config.scope) :
+ config.success;
+ }
+
+ // optional failure callback
+ var failure;
+ if(config.failure) {
+ failure = (config.scope) ?
+ OpenLayers.Function.bind(config.failure, config.scope) :
+ config.failure;
+ }
+
+ complete(request);
+
+ if (!request.status || (request.status >= 200 && request.status < 300)) {
+ this.events.triggerEvent("success", options);
+ if(success) {
+ success(request);
+ }
+ }
+ if(request.status && (request.status < 200 || request.status >= 300)) {
+ this.events.triggerEvent("failure", options);
+ if(failure) {
+ failure(request);
+ }
+ }
+ },
+
+ /**
+ * APIMethod: GET
+ * Send an HTTP GET request. Additional configuration properties are
+ * documented in the <issue> method, with the method property set
+ * to GET.
+ *
+ * Parameters:
+ * config - {Object} Object with properties for configuring the request.
+ * See the <issue> method for documentation of allowed properties.
+ * This object is modified and should not be reused.
+ *
+ * Returns:
+ * {XMLHttpRequest} Request object.
+ */
+ GET: function(config) {
+ config = OpenLayers.Util.extend(config, {method: "GET"});
+ return OpenLayers.Request.issue(config);
+ },
+
+ /**
+ * APIMethod: POST
+ * Send a POST request. Additional configuration properties are
+ * documented in the <issue> method, with the method property set
+ * to POST and "Content-Type" header set to "application/xml".
+ *
+ * Parameters:
+ * config - {Object} Object with properties for configuring the request.
+ * See the <issue> method for documentation of allowed properties. The
+ * default "Content-Type" header will be set to "application-xml" if
+ * none is provided. This object is modified and should not be reused.
+ *
+ * Returns:
+ * {XMLHttpRequest} Request object.
+ */
+ POST: function(config) {
+ config = OpenLayers.Util.extend(config, {method: "POST"});
+ // set content type to application/xml if it isn't already set
+ config.headers = config.headers ? config.headers : {};
+ if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
+ config.headers["Content-Type"] = "application/xml";
+ }
+ return OpenLayers.Request.issue(config);
+ },
+
+ /**
+ * APIMethod: PUT
+ * Send an HTTP PUT request. Additional configuration properties are
+ * documented in the <issue> method, with the method property set
+ * to PUT and "Content-Type" header set to "application/xml".
+ *
+ * Parameters:
+ * config - {Object} Object with properties for configuring the request.
+ * See the <issue> method for documentation of allowed properties. The
+ * default "Content-Type" header will be set to "application-xml" if
+ * none is provided. This object is modified and should not be reused.
+ *
+ * Returns:
+ * {XMLHttpRequest} Request object.
+ */
+ PUT: function(config) {
+ config = OpenLayers.Util.extend(config, {method: "PUT"});
+ // set content type to application/xml if it isn't already set
+ config.headers = config.headers ? config.headers : {};
+ if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
+ config.headers["Content-Type"] = "application/xml";
+ }
+ return OpenLayers.Request.issue(config);
+ },
+
+ /**
+ * APIMethod: DELETE
+ * Send an HTTP DELETE request. Additional configuration properties are
+ * documented in the <issue> method, with the method property set
+ * to DELETE.
+ *
+ * Parameters:
+ * config - {Object} Object with properties for configuring the request.
+ * See the <issue> method for documentation of allowed properties.
+ * This object is modified and should not be reused.
+ *
+ * Returns:
+ * {XMLHttpRequest} Request object.
+ */
+ DELETE: function(config) {
+ config = OpenLayers.Util.extend(config, {method: "DELETE"});
+ return OpenLayers.Request.issue(config);
+ },
+
+ /**
+ * APIMethod: HEAD
+ * Send an HTTP HEAD request. Additional configuration properties are
+ * documented in the <issue> method, with the method property set
+ * to HEAD.
+ *
+ * Parameters:
+ * config - {Object} Object with properties for configuring the request.
+ * See the <issue> method for documentation of allowed properties.
+ * This object is modified and should not be reused.
+ *
+ * Returns:
+ * {XMLHttpRequest} Request object.
+ */
+ HEAD: function(config) {
+ config = OpenLayers.Util.extend(config, {method: "HEAD"});
+ return OpenLayers.Request.issue(config);
+ },
+
+ /**
+ * APIMethod: OPTIONS
+ * Send an HTTP OPTIONS request. Additional configuration properties are
+ * documented in the <issue> method, with the method property set
+ * to OPTIONS.
+ *
+ * Parameters:
+ * config - {Object} Object with properties for configuring the request.
+ * See the <issue> method for documentation of allowed properties.
+ * This object is modified and should not be reused.
+ *
+ * Returns:
+ * {XMLHttpRequest} Request object.
+ */
+ OPTIONS: function(config) {
+ config = OpenLayers.Util.extend(config, {method: "OPTIONS"});
+ return OpenLayers.Request.issue(config);
+ }
+
+};
+/* ======================================================================
+ OpenLayers/Request/XMLHttpRequest.js
+ ====================================================================== */
+
+// XMLHttpRequest.js Copyright (C) 2010 Sergey Ilinsky (http://www.ilinsky.com)
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @requires OpenLayers/Request.js
+ */
+
+(function () {
+
+ // Save reference to earlier defined object implementation (if any)
+ var oXMLHttpRequest = window.XMLHttpRequest;
+
+ // Define on browser type
+ var bGecko = !!window.controllers,
+ bIE = window.document.all && !window.opera,
+ bIE7 = bIE && window.navigator.userAgent.match(/MSIE 7.0/);
+
+ // Enables "XMLHttpRequest()" call next to "new XMLHttpReques()"
+ function fXMLHttpRequest() {
+ this._object = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP");
+ this._listeners = [];
+ };
+
+ // Constructor
+ function cXMLHttpRequest() {
+ return new fXMLHttpRequest;
+ };
+ cXMLHttpRequest.prototype = fXMLHttpRequest.prototype;
+
+ // BUGFIX: Firefox with Firebug installed would break pages if not executed
+ if (bGecko && oXMLHttpRequest.wrapped)
+ cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped;
+
+ // Constants
+ cXMLHttpRequest.UNSENT = 0;
+ cXMLHttpRequest.OPENED = 1;
+ cXMLHttpRequest.HEADERS_RECEIVED = 2;
+ cXMLHttpRequest.LOADING = 3;
+ cXMLHttpRequest.DONE = 4;
+
+ // Public Properties
+ cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT;
+ cXMLHttpRequest.prototype.responseText = '';
+ cXMLHttpRequest.prototype.responseXML = null;
+ cXMLHttpRequest.prototype.status = 0;
+ cXMLHttpRequest.prototype.statusText = '';
+
+ // Priority proposal
+ cXMLHttpRequest.prototype.priority = "NORMAL";
+
+ // Instance-level Events Handlers
+ cXMLHttpRequest.prototype.onreadystatechange = null;
+
+ // Class-level Events Handlers
+ cXMLHttpRequest.onreadystatechange = null;
+ cXMLHttpRequest.onopen = null;
+ cXMLHttpRequest.onsend = null;
+ cXMLHttpRequest.onabort = null;
+
+ // Public Methods
+ cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) {
+ // Delete headers, required when object is reused
+ delete this._headers;
+
+ // When bAsync parameter value is omitted, use true as default
+ if (arguments.length < 3)
+ bAsync = true;
+
+ // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests
+ this._async = bAsync;
+
+ // Set the onreadystatechange handler
+ var oRequest = this,
+ nState = this.readyState,
+ fOnUnload;
+
+ // BUGFIX: IE - memory leak on page unload (inter-page leak)
+ if (bIE && bAsync) {
+ fOnUnload = function() {
+ if (nState != cXMLHttpRequest.DONE) {
+ fCleanTransport(oRequest);
+ // Safe to abort here since onreadystatechange handler removed
+ oRequest.abort();
+ }
+ };
+ window.attachEvent("onunload", fOnUnload);
+ }
+
+ // Add method sniffer
+ if (cXMLHttpRequest.onopen)
+ cXMLHttpRequest.onopen.apply(this, arguments);
+
+ if (arguments.length > 4)
+ this._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
+ else
+ if (arguments.length > 3)
+ this._object.open(sMethod, sUrl, bAsync, sUser);
+ else
+ this._object.open(sMethod, sUrl, bAsync);
+
+ this.readyState = cXMLHttpRequest.OPENED;
+ fReadyStateChange(this);
+
+ this._object.onreadystatechange = function() {
+ if (bGecko && !bAsync)
+ return;
+
+ // Synchronize state
+ oRequest.readyState = oRequest._object.readyState;
+
+ //
+ fSynchronizeValues(oRequest);
+
+ // BUGFIX: Firefox fires unnecessary DONE when aborting
+ if (oRequest._aborted) {
+ // Reset readyState to UNSENT
+ oRequest.readyState = cXMLHttpRequest.UNSENT;
+
+ // Return now
+ return;
+ }
+
+ if (oRequest.readyState == cXMLHttpRequest.DONE) {
+ // Free up queue
+ delete oRequest._data;
+/* if (bAsync)
+ fQueue_remove(oRequest);*/
+ //
+ fCleanTransport(oRequest);
+// Uncomment this block if you need a fix for IE cache
+/*
+ // BUGFIX: IE - cache issue
+ if (!oRequest._object.getResponseHeader("Date")) {
+ // Save object to cache
+ oRequest._cached = oRequest._object;
+
+ // Instantiate a new transport object
+ cXMLHttpRequest.call(oRequest);
+
+ // Re-send request
+ if (sUser) {
+ if (sPassword)
+ oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
+ else
+ oRequest._object.open(sMethod, sUrl, bAsync, sUser);
+ }
+ else
+ oRequest._object.open(sMethod, sUrl, bAsync);
+ oRequest._object.setRequestHeader("If-Modified-Since", oRequest._cached.getResponseHeader("Last-Modified") || new window.Date(0));
+ // Copy headers set
+ if (oRequest._headers)
+ for (var sHeader in oRequest._headers)
+ if (typeof oRequest._headers[sHeader] == "string") // Some frameworks prototype objects with functions
+ oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]);
+
+ oRequest._object.onreadystatechange = function() {
+ // Synchronize state
+ oRequest.readyState = oRequest._object.readyState;
+
+ if (oRequest._aborted) {
+ //
+ oRequest.readyState = cXMLHttpRequest.UNSENT;
+
+ // Return
+ return;
+ }
+
+ if (oRequest.readyState == cXMLHttpRequest.DONE) {
+ // Clean Object
+ fCleanTransport(oRequest);
+
+ // get cached request
+ if (oRequest.status == 304)
+ oRequest._object = oRequest._cached;
+
+ //
+ delete oRequest._cached;
+
+ //
+ fSynchronizeValues(oRequest);
+
+ //
+ fReadyStateChange(oRequest);
+
+ // BUGFIX: IE - memory leak in interrupted
+ if (bIE && bAsync)
+ window.detachEvent("onunload", fOnUnload);
+ }
+ };
+ oRequest._object.send(null);
+
+ // Return now - wait until re-sent request is finished
+ return;
+ };
+*/
+ // BUGFIX: IE - memory leak in interrupted
+ if (bIE && bAsync)
+ window.detachEvent("onunload", fOnUnload);
+ }
+
+ // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice
+ if (nState != oRequest.readyState)
+ fReadyStateChange(oRequest);
+
+ nState = oRequest.readyState;
+ }
+ };
+ function fXMLHttpRequest_send(oRequest) {
+ oRequest._object.send(oRequest._data);
+
+ // BUGFIX: Gecko - missing readystatechange calls in synchronous requests
+ if (bGecko && !oRequest._async) {
+ oRequest.readyState = cXMLHttpRequest.OPENED;
+
+ // Synchronize state
+ fSynchronizeValues(oRequest);
+
+ // Simulate missing states
+ while (oRequest.readyState < cXMLHttpRequest.DONE) {
+ oRequest.readyState++;
+ fReadyStateChange(oRequest);
+ // Check if we are aborted
+ if (oRequest._aborted)
+ return;
+ }
+ }
+ };
+ cXMLHttpRequest.prototype.send = function(vData) {
+ // Add method sniffer
+ if (cXMLHttpRequest.onsend)
+ cXMLHttpRequest.onsend.apply(this, arguments);
+
+ if (!arguments.length)
+ vData = null;
+
+ // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required
+ // BUGFIX: IE - rewrites any custom mime-type to "text/xml" in case an XMLNode is sent
+ // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard)
+ if (vData && vData.nodeType) {
+ vData = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml;
+ if (!oRequest._headers["Content-Type"])
+ oRequest._object.setRequestHeader("Content-Type", "application/xml");
+ }
+
+ this._data = vData;
+/*
+ // Add to queue
+ if (this._async)
+ fQueue_add(this);
+ else*/
+ fXMLHttpRequest_send(this);
+ };
+ cXMLHttpRequest.prototype.abort = function() {
+ // Add method sniffer
+ if (cXMLHttpRequest.onabort)
+ cXMLHttpRequest.onabort.apply(this, arguments);
+
+ // BUGFIX: Gecko - unnecessary DONE when aborting
+ if (this.readyState > cXMLHttpRequest.UNSENT)
+ this._aborted = true;
+
+ this._object.abort();
+
+ // BUGFIX: IE - memory leak
+ fCleanTransport(this);
+
+ this.readyState = cXMLHttpRequest.UNSENT;
+
+ delete this._data;
+/* if (this._async)
+ fQueue_remove(this);*/
+ };
+ cXMLHttpRequest.prototype.getAllResponseHeaders = function() {
+ return this._object.getAllResponseHeaders();
+ };
+ cXMLHttpRequest.prototype.getResponseHeader = function(sName) {
+ return this._object.getResponseHeader(sName);
+ };
+ cXMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) {
+ // BUGFIX: IE - cache issue
+ if (!this._headers)
+ this._headers = {};
+ this._headers[sName] = sValue;
+
+ return this._object.setRequestHeader(sName, sValue);
+ };
+
+ // EventTarget interface implementation
+ cXMLHttpRequest.prototype.addEventListener = function(sName, fHandler, bUseCapture) {
+ for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)
+ if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)
+ return;
+ // Add listener
+ this._listeners.push([sName, fHandler, bUseCapture]);
+ };
+
+ cXMLHttpRequest.prototype.removeEventListener = function(sName, fHandler, bUseCapture) {
+ for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)
+ if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)
+ break;
+ // Remove listener
+ if (oListener)
+ this._listeners.splice(nIndex, 1);
+ };
+
+ cXMLHttpRequest.prototype.dispatchEvent = function(oEvent) {
+ var oEventPseudo = {
+ 'type': oEvent.type,
+ 'target': this,
+ 'currentTarget':this,
+ 'eventPhase': 2,
+ 'bubbles': oEvent.bubbles,
+ 'cancelable': oEvent.cancelable,
+ 'timeStamp': oEvent.timeStamp,
+ 'stopPropagation': function() {}, // There is no flow
+ 'preventDefault': function() {}, // There is no default action
+ 'initEvent': function() {} // Original event object should be initialized
+ };
+
+ // Execute onreadystatechange
+ if (oEventPseudo.type == "readystatechange" && this.onreadystatechange)
+ (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]);
+
+ // Execute listeners
+ for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)
+ if (oListener[0] == oEventPseudo.type && !oListener[2])
+ (oListener[1].handleEvent || oListener[1]).apply(this, [oEventPseudo]);
+ };
+
+ //
+ cXMLHttpRequest.prototype.toString = function() {
+ return '[' + "object" + ' ' + "XMLHttpRequest" + ']';
+ };
+
+ cXMLHttpRequest.toString = function() {
+ return '[' + "XMLHttpRequest" + ']';
+ };
+
+ // Helper function
+ function fReadyStateChange(oRequest) {
+ // Sniffing code
+ if (cXMLHttpRequest.onreadystatechange)
+ cXMLHttpRequest.onreadystatechange.apply(oRequest);
+
+ // Fake event
+ oRequest.dispatchEvent({
+ 'type': "readystatechange",
+ 'bubbles': false,
+ 'cancelable': false,
+ 'timeStamp': new Date + 0
+ });
+ };
+
+ function fGetDocument(oRequest) {
+ var oDocument = oRequest.responseXML,
+ sResponse = oRequest.responseText;
+ // Try parsing responseText
+ if (bIE && sResponse && oDocument && !oDocument.documentElement && oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)) {
+ oDocument = new window.ActiveXObject("Microsoft.XMLDOM");
+ oDocument.async = false;
+ oDocument.validateOnParse = false;
+ oDocument.loadXML(sResponse);
+ }
+ // Check if there is no error in document
+ if (oDocument)
+ if ((bIE && oDocument.parseError != 0) || !oDocument.documentElement || (oDocument.documentElement && oDocument.documentElement.tagName == "parsererror"))
+ return null;
+ return oDocument;
+ };
+
+ function fSynchronizeValues(oRequest) {
+ try { oRequest.responseText = oRequest._object.responseText; } catch (e) {}
+ try { oRequest.responseXML = fGetDocument(oRequest._object); } catch (e) {}
+ try { oRequest.status = oRequest._object.status; } catch (e) {}
+ try { oRequest.statusText = oRequest._object.statusText; } catch (e) {}
+ };
+
+ function fCleanTransport(oRequest) {
+ // BUGFIX: IE - memory leak (on-page leak)
+ oRequest._object.onreadystatechange = new window.Function;
+ };
+/*
+ // Queue manager
+ var oQueuePending = {"CRITICAL":[],"HIGH":[],"NORMAL":[],"LOW":[],"LOWEST":[]},
+ aQueueRunning = [];
+ function fQueue_add(oRequest) {
+ oQueuePending[oRequest.priority in oQueuePending ? oRequest.priority : "NORMAL"].push(oRequest);
+ //
+ setTimeout(fQueue_process);
+ };
+
+ function fQueue_remove(oRequest) {
+ for (var nIndex = 0, bFound = false; nIndex < aQueueRunning.length; nIndex++)
+ if (bFound)
+ aQueueRunning[nIndex - 1] = aQueueRunning[nIndex];
+ else
+ if (aQueueRunning[nIndex] == oRequest)
+ bFound = true;
+ if (bFound)
+ aQueueRunning.length--;
+ //
+ setTimeout(fQueue_process);
+ };
+
+ function fQueue_process() {
+ if (aQueueRunning.length < 6) {
+ for (var sPriority in oQueuePending) {
+ if (oQueuePending[sPriority].length) {
+ var oRequest = oQueuePending[sPriority][0];
+ oQueuePending[sPriority] = oQueuePending[sPriority].slice(1);
+ //
+ aQueueRunning.push(oRequest);
+ // Send request
+ fXMLHttpRequest_send(oRequest);
+ break;
+ }
+ }
+ }
+ };
+*/
+ // Internet Explorer 5.0 (missing apply)
+ if (!window.Function.prototype.apply) {
+ window.Function.prototype.apply = function(oRequest, oArguments) {
+ if (!oArguments)
+ oArguments = [];
+ oRequest.__func = this;
+ oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]);
+ delete oRequest.__func;
+ };
+ };
+
+ // Register new object with window
+ /**
+ * Class: OpenLayers.Request.XMLHttpRequest
+ * Standard-compliant (W3C) cross-browser implementation of the
+ * XMLHttpRequest object. From
+ * http://code.google.com/p/xmlhttprequest/.
+ */
+ OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest;
+})();
+/* ======================================================================
+ OpenLayers/Ajax.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Request/XMLHttpRequest.js
+ * @requires OpenLayers/Console.js
+ * @requires OpenLayers/Lang.js
+ */
+
+OpenLayers.ProxyHost = "";
+//OpenLayers.ProxyHost = "examples/proxy.cgi?url=";
+
+/**
+ * Ajax reader for OpenLayers
+ *
+ * @uri url to do remote XML http get
+ * @param {String} 'get' format params (x=y&a=b...)
+ * @who object to handle callbacks for this request
+ * @complete the function to be called on success
+ * @failure the function to be called on failure
+ *
+ * example usage from a caller:
+ *
+ * caps: function(request) {
+ * -blah-
+ * },
+ *
+ * OpenLayers.loadURL(url,params,this,caps);
+ *
+ * Notice the above example does not provide an error handler; a default empty
+ * handler is provided which merely logs the error if a failure handler is not
+ * supplied
+ *
+ */
+
+
+/**
+ * Function: OpenLayers.nullHandler
+ * @param {} request
+ */
+OpenLayers.nullHandler = function(request) {
+ OpenLayers.Console.userError(OpenLayers.i18n("unhandledRequest", {'statusText':request.statusText}));
+};
+
+/**
+ * APIFunction: OpenLayers.loadURL
+ * Background load a document. For more flexibility in using XMLHttpRequest,
+ * see the <OpenLayers.Request> methods.
+ *
+ * Parameters:
+ * uri - {String} URI of source doc
+ * params - {String} or {Object} GET params. Either a string in the form
+ * "?hello=world&foo=bar" (do not forget the leading question mark)
+ * or an object in the form {'hello': 'world', 'foo': 'bar}
+ * caller - {Object} object which gets callbacks
+ * onComplete - {Function} Optional callback for success. The callback
+ * will be called with this set to caller and will receive the request
+ * object as an argument. Note that if you do not specify an onComplete
+ * function, <OpenLayers.nullHandler> will be called (which pops up a
+ * user friendly error message dialog).
+ * onFailure - {Function} Optional callback for failure. In the event of
+ * a failure, the callback will be called with this set to caller and will
+ * receive the request object as an argument. Note that if you do not
+ * specify an onComplete function, <OpenLayers.nullHandler> will be called
+ * (which pops up a user friendly error message dialog).
+ *
+ * Returns:
+ * {<OpenLayers.Request.XMLHttpRequest>} The request object. To abort loading,
+ * call request.abort().
+ */
+OpenLayers.loadURL = function(uri, params, caller,
+ onComplete, onFailure) {
+
+ if(typeof params == 'string') {
+ params = OpenLayers.Util.getParameters(params);
+ }
+ var success = (onComplete) ? onComplete : OpenLayers.nullHandler;
+ var failure = (onFailure) ? onFailure : OpenLayers.nullHandler;
+
+ return OpenLayers.Request.GET({
+ url: uri, params: params,
+ success: success, failure: failure, scope: caller
+ });
+};
+
+/**
+ * Function: OpenLayers.parseXMLString
+ * Parse XML into a doc structure
+ *
+ * Parameters:
+ * text - {String}
+ *
+ * Returns:
+ * {?} Parsed AJAX Responsev
+ */
+OpenLayers.parseXMLString = function(text) {
+
+ //MS sucks, if the server is bad it dies
+ var index = text.indexOf('<');
+ if (index > 0) {
+ text = text.substring(index);
+ }
+
+ var ajaxResponse = OpenLayers.Util.Try(
+ function() {
+ var xmldom = new ActiveXObject('Microsoft.XMLDOM');
+ xmldom.loadXML(text);
+ return xmldom;
+ },
+ function() {
+ return new DOMParser().parseFromString(text, 'text/xml');
+ },
+ function() {
+ var req = new XMLHttpRequest();
+ req.open("GET", "data:" + "text/xml" +
+ ";charset=utf-8," + encodeURIComponent(text), false);
+ if (req.overrideMimeType) {
+ req.overrideMimeType("text/xml");
+ }
+ req.send(null);
+ return req.responseXML;
+ }
+ );
+
+ return ajaxResponse;
+};
+
+
+/**
+ * Namespace: OpenLayers.Ajax
+ */
+OpenLayers.Ajax = {
+
+ /**
+ * Method: emptyFunction
+ */
+ emptyFunction: function () {},
+
+ /**
+ * Method: getTransport
+ *
+ * Returns:
+ * {Object} Transport mechanism for whichever browser we're in, or false if
+ * none available.
+ */
+ getTransport: function() {
+ return OpenLayers.Util.Try(
+ function() {return new XMLHttpRequest();},
+ function() {return new ActiveXObject('Msxml2.XMLHTTP');},
+ function() {return new ActiveXObject('Microsoft.XMLHTTP');}
+ ) || false;
+ },
+
+ /**
+ * Property: activeRequestCount
+ * {Integer}
+ */
+ activeRequestCount: 0
+};
+
+/**
+ * Namespace: OpenLayers.Ajax.Responders
+ * {Object}
+ */
+OpenLayers.Ajax.Responders = {
+
+ /**
+ * Property: responders
+ * {Array}
+ */
+ responders: [],
+
+ /**
+ * Method: register
+ *
+ * Parameters:
+ * responderToAdd - {?}
+ */
+ register: function(responderToAdd) {
+ for (var i = 0; i < this.responders.length; i++){
+ if (responderToAdd == this.responders[i]){
+ return;
+ }
+ }
+ this.responders.push(responderToAdd);
+ },
+
+ /**
+ * Method: unregister
+ *
+ * Parameters:
+ * responderToRemove - {?}
+ */
+ unregister: function(responderToRemove) {
+ OpenLayers.Util.removeItem(this.reponders, responderToRemove);
+ },
+
+ /**
+ * Method: dispatch
+ *
+ * Parameters:
+ * callback - {?}
+ * request - {?}
+ * transport - {?}
+ */
+ dispatch: function(callback, request, transport) {
+ var responder;
+ for (var i = 0; i < this.responders.length; i++) {
+ responder = this.responders[i];
+
+ if (responder[callback] &&
+ typeof responder[callback] == 'function') {
+ try {
+ responder[callback].apply(responder,
+ [request, transport]);
+ } catch (e) {}
+ }
+ }
+ }
+};
+
+OpenLayers.Ajax.Responders.register({
+ /**
+ * Function: onCreate
+ */
+ onCreate: function() {
+ OpenLayers.Ajax.activeRequestCount++;
+ },
+
+ /**
+ * Function: onComplete
+ */
+ onComplete: function() {
+ OpenLayers.Ajax.activeRequestCount--;
+ }
+});
+
+/**
+ * Class: OpenLayers.Ajax.Base
+ */
+OpenLayers.Ajax.Base = OpenLayers.Class({
+
+ /**
+ * Constructor: OpenLayers.Ajax.Base
+ *
+ * Parameters:
+ * options - {Object}
+ */
+ initialize: function(options) {
+ this.options = {
+ method: 'post',
+ asynchronous: true,
+ contentType: 'application/xml',
+ parameters: ''
+ };
+ OpenLayers.Util.extend(this.options, options || {});
+
+ this.options.method = this.options.method.toLowerCase();
+
+ if (typeof this.options.parameters == 'string') {
+ this.options.parameters =
+ OpenLayers.Util.getParameters(this.options.parameters);
+ }
+ }
+});
+
+/**
+ * Class: OpenLayers.Ajax.Request
+ * *Deprecated*. Use <OpenLayers.Request> method instead.
+ *
+ * Inherit:
+ * - <OpenLayers.Ajax.Base>
+ */
+OpenLayers.Ajax.Request = OpenLayers.Class(OpenLayers.Ajax.Base, {
+
+ /**
+ * Property: _complete
+ *
+ * {Boolean}
+ */
+ _complete: false,
+
+ /**
+ * Constructor: OpenLayers.Ajax.Request
+ *
+ * Parameters:
+ * url - {String}
+ * options - {Object}
+ */
+ initialize: function(url, options) {
+ OpenLayers.Ajax.Base.prototype.initialize.apply(this, [options]);
+
+ if (OpenLayers.ProxyHost && OpenLayers.String.startsWith(url, "http")) {
+ url = OpenLayers.ProxyHost + encodeURIComponent(url);
+ }
+
+ this.transport = OpenLayers.Ajax.getTransport();
+ this.request(url);
+ },
+
+ /**
+ * Method: request
+ *
+ * Parameters:
+ * url - {String}
+ */
+ request: function(url) {
+ this.url = url;
+ this.method = this.options.method;
+ var params = OpenLayers.Util.extend({}, this.options.parameters);
+
+ if (this.method != 'get' && this.method != 'post') {
+ // simulate other verbs over post
+ params['_method'] = this.method;
+ this.method = 'post';
+ }
+
+ this.parameters = params;
+
+ if (params = OpenLayers.Util.getParameterString(params)) {
+ // when GET, append parameters to URL
+ if (this.method == 'get') {
+ this.url += ((this.url.indexOf('?') > -1) ? '&' : '?') + params;
+ } else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+ params += '&_=';
+ }
+ }
+ try {
+ var response = new OpenLayers.Ajax.Response(this);
+ if (this.options.onCreate) {
+ this.options.onCreate(response);
+ }
+
+ OpenLayers.Ajax.Responders.dispatch('onCreate',
+ this,
+ response);
+
+ this.transport.open(this.method.toUpperCase(),
+ this.url,
+ this.options.asynchronous);
+
+ if (this.options.asynchronous) {
+ window.setTimeout(
+ OpenLayers.Function.bind(this.respondToReadyState, this, 1),
+ 10);
+ }
+
+ this.transport.onreadystatechange =
+ OpenLayers.Function.bind(this.onStateChange, this);
+ this.setRequestHeaders();
+
+ this.body = this.method == 'post' ?
+ (this.options.postBody || params) : null;
+ this.transport.send(this.body);
+
+ // Force Firefox to handle ready state 4 for synchronous requests
+ if (!this.options.asynchronous &&
+ this.transport.overrideMimeType) {
+ this.onStateChange();
+ }
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ /**
+ * Method: onStateChange
+ */
+ onStateChange: function() {
+ var readyState = this.transport.readyState;
+ if (readyState > 1 && !((readyState == 4) && this._complete)) {
+ this.respondToReadyState(this.transport.readyState);
+ }
+ },
+
+ /**
+ * Method: setRequestHeaders
+ */
+ setRequestHeaders: function() {
+ var headers = {
+ 'X-Requested-With': 'XMLHttpRequest',
+ 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*',
+ 'OpenLayers': true
+ };
+
+ if (this.method == 'post') {
+ headers['Content-type'] = this.options.contentType +
+ (this.options.encoding ? '; charset=' + this.options.encoding : '');
+
+ /* Force "Connection: close" for older Mozilla browsers to work
+ * around a bug where XMLHttpRequest sends an incorrect
+ * Content-length header. See Mozilla Bugzilla #246651.
+ */
+ if (this.transport.overrideMimeType &&
+ (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) {
+ headers['Connection'] = 'close';
+ }
+ }
+ // user-defined headers
+ if (typeof this.options.requestHeaders == 'object') {
+ var extras = this.options.requestHeaders;
+
+ if (typeof extras.push == 'function') {
+ for (var i = 0, length = extras.length; i < length; i += 2) {
+ headers[extras[i]] = extras[i+1];
+ }
+ } else {
+ for (var i in extras) {
+ headers[i] = extras[i];
+ }
+ }
+ }
+
+ for (var name in headers) {
+ this.transport.setRequestHeader(name, headers[name]);
+ }
+ },
+
+ /**
+ * Method: success
+ *
+ * Returns:
+ * {Boolean} -
+ */
+ success: function() {
+ var status = this.getStatus();
+ return !status || (status >=200 && status < 300);
+ },
+
+ /**
+ * Method: getStatus
+ *
+ * Returns:
+ * {Integer} - Status
+ */
+ getStatus: function() {
+ try {
+ return this.transport.status || 0;
+ } catch (e) {
+ return 0;
+ }
+ },
+
+ /**
+ * Method: respondToReadyState
+ *
+ * Parameters:
+ * readyState - {?}
+ */
+ respondToReadyState: function(readyState) {
+ var state = OpenLayers.Ajax.Request.Events[readyState];
+ var response = new OpenLayers.Ajax.Response(this);
+
+ if (state == 'Complete') {
+ try {
+ this._complete = true;
+ (this.options['on' + response.status] ||
+ this.options['on' + (this.success() ? 'Success' : 'Failure')] ||
+ OpenLayers.Ajax.emptyFunction)(response);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ var contentType = response.getHeader('Content-type');
+ }
+
+ try {
+ (this.options['on' + state] ||
+ OpenLayers.Ajax.emptyFunction)(response);
+ OpenLayers.Ajax.Responders.dispatch('on' + state,
+ this,
+ response);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ if (state == 'Complete') {
+ // avoid memory leak in MSIE: clean up
+ this.transport.onreadystatechange = OpenLayers.Ajax.emptyFunction;
+ }
+ },
+
+ /**
+ * Method: getHeader
+ *
+ * Parameters:
+ * name - {String} Header name
+ *
+ * Returns:
+ * {?} - response header for the given name
+ */
+ getHeader: function(name) {
+ try {
+ return this.transport.getResponseHeader(name);
+ } catch (e) {
+ return null;
+ }
+ },
+
+ /**
+ * Method: dispatchException
+ * If the optional onException function is set, execute it
+ * and then dispatch the call to any other listener registered
+ * for onException.
+ *
+ * If no optional onException function is set, we suspect that
+ * the user may have also not used
+ * OpenLayers.Ajax.Responders.register to register a listener
+ * for the onException call. To make sure that something
+ * gets done with this exception, only dispatch the call if there
+ * are listeners.
+ *
+ * If you explicitly want to swallow exceptions, set
+ * request.options.onException to an empty function (function(){})
+ * or register an empty function with <OpenLayers.Ajax.Responders>
+ * for onException.
+ *
+ * Parameters:
+ * exception - {?}
+ */
+ dispatchException: function(exception) {
+ var handler = this.options.onException;
+ if(handler) {
+ // call options.onException and alert any other listeners
+ handler(this, exception);
+ OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
+ } else {
+ // check if there are any other listeners
+ var listener = false;
+ var responders = OpenLayers.Ajax.Responders.responders;
+ for (var i = 0; i < responders.length; i++) {
+ if(responders[i].onException) {
+ listener = true;
+ break;
+ }
+ }
+ if(listener) {
+ // call all listeners
+ OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
+ } else {
+ // let the exception through
+ throw exception;
+ }
+ }
+ }
+});
+
+/**
+ * Property: Events
+ * {Array(String)}
+ */
+OpenLayers.Ajax.Request.Events =
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+/**
+ * Class: OpenLayers.Ajax.Response
+ */
+OpenLayers.Ajax.Response = OpenLayers.Class({
+
+ /**
+ * Property: status
+ *
+ * {Integer}
+ */
+ status: 0,
+
+
+ /**
+ * Property: statusText
+ *
+ * {String}
+ */
+ statusText: '',
+
+ /**
+ * Constructor: OpenLayers.Ajax.Response
+ *
+ * Parameters:
+ * request - {Object}
+ */
+ initialize: function(request) {
+ this.request = request;
+ var transport = this.transport = request.transport,
+ readyState = this.readyState = transport.readyState;
+
+ if ((readyState > 2 &&
+ !(!!(window.attachEvent && !window.opera))) ||
+ readyState == 4) {
+ this.status = this.getStatus();
+ this.statusText = this.getStatusText();
+ this.responseText = transport.responseText == null ?
+ '' : String(transport.responseText);
+ }
+
+ if(readyState == 4) {
+ var xml = transport.responseXML;
+ this.responseXML = xml === undefined ? null : xml;
+ }
+ },
+
+ /**
+ * Method: getStatus
+ */
+ getStatus: OpenLayers.Ajax.Request.prototype.getStatus,
+
+ /**
+ * Method: getStatustext
+ *
+ * Returns:
+ * {String} - statusText
+ */
+ getStatusText: function() {
+ try {
+ return this.transport.statusText || '';
+ } catch (e) {
+ return '';
+ }
+ },
+
+ /**
+ * Method: getHeader
+ */
+ getHeader: OpenLayers.Ajax.Request.prototype.getHeader,
+
+ /**
+ * Method: getResponseHeader
+ *
+ * Returns:
+ * {?} - response header for given name
+ */
+ getResponseHeader: function(name) {
+ return this.transport.getResponseHeader(name);
+ }
+});
+
+
+/**
+ * Function: getElementsByTagNameNS
+ *
+ * Parameters:
+ * parentnode - {?}
+ * nsuri - {?}
+ * nsprefix - {?}
+ * tagname - {?}
+ *
+ * Returns:
+ * {?}
+ */
+OpenLayers.Ajax.getElementsByTagNameNS = function(parentnode, nsuri,
+ nsprefix, tagname) {
+ var elem = null;
+ if (parentnode.getElementsByTagNameNS) {
+ elem = parentnode.getElementsByTagNameNS(nsuri, tagname);
+ } else {
+ elem = parentnode.getElementsByTagName(nsprefix + ':' + tagname);
+ }
+ return elem;
+};
+
+
+/**
+ * Function: serializeXMLToString
+ * Wrapper function around XMLSerializer, which doesn't exist/work in
+ * IE/Safari. We need to come up with a way to serialize in those browser:
+ * for now, these browsers will just fail. #535, #536
+ *
+ * Parameters:
+ * xmldom {XMLNode} xml dom to serialize
+ *
+ * Returns:
+ * {?}
+ */
+OpenLayers.Ajax.serializeXMLToString = function(xmldom) {
+ var serializer = new XMLSerializer();
+ var data = serializer.serializeToString(xmldom);
+ return data;
+};
+/* ======================================================================
+ OpenLayers/Handler/Drag.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Drag
+ * The drag handler is used to deal with sequences of browser events related
+ * to dragging. The handler is used by controls that want to know when
+ * a drag sequence begins, when a drag is happening, and when it has
+ * finished.
+ *
+ * Controls that use the drag handler typically construct it with callbacks
+ * for 'down', 'move', and 'done'. Callbacks for these keys are called
+ * when the drag begins, with each move, and when the drag is done. In
+ * addition, controls can have callbacks keyed to 'up' and 'out' if they
+ * care to differentiate between the types of events that correspond with
+ * the end of a drag sequence. If no drag actually occurs (no mouse move)
+ * the 'down' and 'up' callbacks will be called, but not the 'done'
+ * callback.
+ *
+ * Create a new drag handler with the <OpenLayers.Handler.Drag> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, {
+
+ /**
+ * Property: started
+ * {Boolean} When a mousedown event is received, we want to record it, but
+ * not set 'dragging' until the mouse moves after starting.
+ */
+ started: false,
+
+ /**
+ * Property: stopDown
+ * {Boolean} Stop propagation of mousedown events from getting to listeners
+ * on the same element. Default is true.
+ */
+ stopDown: true,
+
+ /**
+ * Property: dragging
+ * {Boolean}
+ */
+ dragging: false,
+
+ /**
+ * Property: last
+ * {<OpenLayers.Pixel>} The last pixel location of the drag.
+ */
+ last: null,
+
+ /**
+ * Property: start
+ * {<OpenLayers.Pixel>} The first pixel location of the drag.
+ */
+ start: null,
+
+ /**
+ * Property: oldOnselectstart
+ * {Function}
+ */
+ oldOnselectstart: null,
+
+ /**
+ * Property: interval
+ * {Integer} In order to increase performance, an interval (in
+ * milliseconds) can be set to reduce the number of drag events
+ * called. If set, a new drag event will not be set until the
+ * interval has passed.
+ * Defaults to 0, meaning no interval.
+ */
+ interval: 0,
+
+ /**
+ * Property: timeoutId
+ * {String} The id of the timeout used for the mousedown interval.
+ * This is "private", and should be left alone.
+ */
+ timeoutId: null,
+
+ /**
+ * APIProperty: documentDrag
+ * {Boolean} If set to true, the handler will also handle mouse moves when
+ * the cursor has moved out of the map viewport. Default is false.
+ */
+ documentDrag: false,
+
+ /**
+ * Property: documentEvents
+ * {Boolean} Are we currently observing document events?
+ */
+ documentEvents: null,
+
+ /**
+ * Constructor: OpenLayers.Handler.Drag
+ * Returns OpenLayers.Handler.Drag
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>} The control that is making use of
+ * this handler. If a handler is being used without a control, the
+ * handlers setMap method must be overridden to deal properly with
+ * the map.
+ * callbacks - {Object} An object containing a single function to be
+ * called when the drag operation is finished. The callback should
+ * expect to recieve a single argument, the pixel location of the event.
+ * Callbacks for 'move' and 'done' are supported. You can also speficy
+ * callbacks for 'down', 'up', and 'out' to respond to those events.
+ * options - {Object}
+ */
+ initialize: function(control, callbacks, options) {
+ OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+
+ if (this.documentDrag === true) {
+ var me = this;
+ this._docMove = function(evt) {
+ me.mousemove({
+ xy: {x: evt.clientX, y: evt.clientY},
+ element: document
+ });
+ };
+ this._docUp = function(evt) {
+ me.mouseup({xy: {x: evt.clientX, y: evt.clientY}});
+ };
+ }
+ },
+
+ /**
+ * The four methods below (down, move, up, and out) are used by subclasses
+ * to do their own processing related to these mouse events.
+ */
+
+ /**
+ * Method: down
+ * This method is called during the handling of the mouse down event.
+ * Subclasses can do their own processing here.
+ *
+ * Parameters:
+ * evt - {Event} The mouse down event
+ */
+ down: function(evt) {
+ },
+
+ /**
+ * Method: move
+ * This method is called during the handling of the mouse move event.
+ * Subclasses can do their own processing here.
+ *
+ * Parameters:
+ * evt - {Event} The mouse move event
+ *
+ */
+ move: function(evt) {
+ },
+
+ /**
+ * Method: up
+ * This method is called during the handling of the mouse up event.
+ * Subclasses can do their own processing here.
+ *
+ * Parameters:
+ * evt - {Event} The mouse up event
+ */
+ up: function(evt) {
+ },
+
+ /**
+ * Method: out
+ * This method is called during the handling of the mouse out event.
+ * Subclasses can do their own processing here.
+ *
+ * Parameters:
+ * evt - {Event} The mouse out event
+ */
+ out: function(evt) {
+ },
+
+ /**
+ * The methods below are part of the magic of event handling. Because
+ * they are named like browser events, they are registered as listeners
+ * for the events they represent.
+ */
+
+ /**
+ * Method: mousedown
+ * Handle mousedown events
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} Let the event propagate.
+ */
+ mousedown: function (evt) {
+ var propagate = true;
+ this.dragging = false;
+ if (this.checkModifiers(evt) && OpenLayers.Event.isLeftClick(evt)) {
+ this.started = true;
+ this.start = evt.xy;
+ this.last = evt.xy;
+ OpenLayers.Element.addClass(
+ this.map.viewPortDiv, "olDragDown"
+ );
+ this.down(evt);
+ this.callback("down", [evt.xy]);
+ OpenLayers.Event.stop(evt);
+
+ if(!this.oldOnselectstart) {
+ this.oldOnselectstart = (document.onselectstart) ? document.onselectstart : OpenLayers.Function.True;
+ }
+ document.onselectstart = OpenLayers.Function.False;
+
+ propagate = !this.stopDown;
+ } else {
+ this.started = false;
+ this.start = null;
+ this.last = null;
+ }
+ return propagate;
+ },
+
+ /**
+ * Method: mousemove
+ * Handle mousemove events
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} Let the event propagate.
+ */
+ mousemove: function (evt) {
+ if (this.started && !this.timeoutId && (evt.xy.x != this.last.x || evt.xy.y != this.last.y)) {
+ if(this.documentDrag === true && this.documentEvents) {
+ if(evt.element === document) {
+ this.adjustXY(evt);
+ // do setEvent manually because the documentEvents are not
+ // registered with the map
+ this.setEvent(evt);
+ } else {
+ this.removeDocumentEvents();
+ }
+ }
+ if (this.interval > 0) {
+ this.timeoutId = setTimeout(OpenLayers.Function.bind(this.removeTimeout, this), this.interval);
+ }
+ this.dragging = true;
+ this.move(evt);
+ this.callback("move", [evt.xy]);
+ if(!this.oldOnselectstart) {
+ this.oldOnselectstart = document.onselectstart;
+ document.onselectstart = OpenLayers.Function.False;
+ }
+ this.last = this.evt.xy;
+ }
+ return true;
+ },
+
+ /**
+ * Method: removeTimeout
+ * Private. Called by mousemove() to remove the drag timeout.
+ */
+ removeTimeout: function() {
+ this.timeoutId = null;
+ },
+
+ /**
+ * Method: mouseup
+ * Handle mouseup events
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} Let the event propagate.
+ */
+ mouseup: function (evt) {
+ if (this.started) {
+ if(this.documentDrag === true && this.documentEvents) {
+ this.adjustXY(evt);
+ this.removeDocumentEvents();
+ }
+ var dragged = (this.start != this.last);
+ this.started = false;
+ this.dragging = false;
+ OpenLayers.Element.removeClass(
+ this.map.viewPortDiv, "olDragDown"
+ );
+ this.up(evt);
+ this.callback("up", [evt.xy]);
+ if(dragged) {
+ this.callback("done", [evt.xy]);
+ }
+ document.onselectstart = this.oldOnselectstart;
+ }
+ return true;
+ },
+
+ /**
+ * Method: mouseout
+ * Handle mouseout events
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} Let the event propagate.
+ */
+ mouseout: function (evt) {
+ if (this.started && OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) {
+ if(this.documentDrag === true) {
+ this.addDocumentEvents();
+ } else {
+ var dragged = (this.start != this.last);
+ this.started = false;
+ this.dragging = false;
+ OpenLayers.Element.removeClass(
+ this.map.viewPortDiv, "olDragDown"
+ );
+ this.out(evt);
+ this.callback("out", []);
+ if(dragged) {
+ this.callback("done", [evt.xy]);
+ }
+ if(document.onselectstart) {
+ document.onselectstart = this.oldOnselectstart;
+ }
+ }
+ }
+ return true;
+ },
+
+ /**
+ * Method: click
+ * The drag handler captures the click event. If something else registers
+ * for clicks on the same element, its listener will not be called
+ * after a drag.
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} Let the event propagate.
+ */
+ click: function (evt) {
+ // let the click event propagate only if the mouse moved
+ return (this.start == this.last);
+ },
+
+ /**
+ * Method: activate
+ * Activate the handler.
+ *
+ * Returns:
+ * {Boolean} The handler was successfully activated.
+ */
+ activate: function() {
+ var activated = false;
+ if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+ this.dragging = false;
+ activated = true;
+ }
+ return activated;
+ },
+
+ /**
+ * Method: deactivate
+ * Deactivate the handler.
+ *
+ * Returns:
+ * {Boolean} The handler was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = false;
+ if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+ this.started = false;
+ this.dragging = false;
+ this.start = null;
+ this.last = null;
+ deactivated = true;
+ OpenLayers.Element.removeClass(
+ this.map.viewPortDiv, "olDragDown"
+ );
+ }
+ return deactivated;
+ },
+
+ /**
+ * Method: adjustXY
+ * Converts event coordinates that are relative to the document body to
+ * ones that are relative to the map viewport. The latter is the default in
+ * OpenLayers.
+ *
+ * Parameters:
+ * evt - {Object}
+ */
+ adjustXY: function(evt) {
+ var pos = OpenLayers.Util.pagePosition(this.map.viewPortDiv);
+ evt.xy.x -= pos[0];
+ evt.xy.y -= pos[1];
+ },
+
+ /**
+ * Method: addDocumentEvents
+ * Start observing document events when documentDrag is true and the mouse
+ * cursor leaves the map viewport while dragging.
+ */
+ addDocumentEvents: function() {
+ OpenLayers.Element.addClass(document.body, "olDragDown");
+ this.documentEvents = true;
+ OpenLayers.Event.observe(document, "mousemove", this._docMove);
+ OpenLayers.Event.observe(document, "mouseup", this._docUp);
+ },
+
+ /**
+ * Method: removeDocumentEvents
+ * Stops observing document events when documentDrag is true and the mouse
+ * cursor re-enters the map viewport while dragging.
+ */
+ removeDocumentEvents: function() {
+ OpenLayers.Element.removeClass(document.body, "olDragDown");
+ this.documentEvents = false;
+ OpenLayers.Event.stopObserving(document, "mousemove", this._docMove);
+ OpenLayers.Event.stopObserving(document, "mouseup", this._docUp);
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.Drag"
+});
+/* ======================================================================
+ OpenLayers/Handler/Box.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ * @requires OpenLayers/Handler/Drag.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Box
+ * Handler for dragging a rectangle across the map. Box is displayed
+ * on mouse down, moves on mouse move, and is finished on mouse up.
+ *
+ * Inherits from:
+ * - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, {
+
+ /**
+ * Property: dragHandler
+ * {<OpenLayers.Handler.Drag>}
+ */
+ dragHandler: null,
+
+ /**
+ * APIProperty: boxDivClassName
+ * {String} The CSS class to use for drawing the box. Default is
+ * olHandlerBoxZoomBox
+ */
+ boxDivClassName: 'olHandlerBoxZoomBox',
+
+ /**
+ * Property: boxCharacteristics
+ * {Object} Caches some box characteristics from css. This is used
+ * by the getBoxCharacteristics method.
+ */
+ boxCharacteristics: null,
+
+ /**
+ * Constructor: OpenLayers.Handler.Box
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>}
+ * callbacks - {Object} An object with a "done" property whose value is a
+ * callback to be called when the box drag operation is finished.
+ * The callback should expect to recieve a single argument, the box
+ * bounds or a pixel. If the box dragging didn't span more than a 5
+ * pixel distance, a pixel will be returned instead of a bounds object.
+ * options - {Object}
+ */
+ initialize: function(control, callbacks, options) {
+ OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+ this.dragHandler = new OpenLayers.Handler.Drag(
+ this,
+ {
+ down: this.startBox,
+ move: this.moveBox,
+ out: this.removeBox,
+ up: this.endBox
+ },
+ {keyMask: this.keyMask}
+ );
+ },
+
+ /**
+ * Method: destroy
+ */
+ destroy: function() {
+ if (this.dragHandler) {
+ this.dragHandler.destroy();
+ this.dragHandler = null;
+ }
+ OpenLayers.Handler.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: setMap
+ */
+ setMap: function (map) {
+ OpenLayers.Handler.prototype.setMap.apply(this, arguments);
+ if (this.dragHandler) {
+ this.dragHandler.setMap(map);
+ }
+ },
+
+ /**
+ * Method: startBox
+ *
+ * Parameters:
+ * evt - {Event}
+ */
+ startBox: function (xy) {
+ this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
+ new OpenLayers.Pixel(-9999, -9999));
+ this.zoomBox.className = this.boxDivClassName;
+ this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
+ this.map.viewPortDiv.appendChild(this.zoomBox);
+
+ OpenLayers.Element.addClass(
+ this.map.viewPortDiv, "olDrawBox"
+ );
+ },
+
+ /**
+ * Method: moveBox
+ */
+ moveBox: function (xy) {
+ var startX = this.dragHandler.start.x;
+ var startY = this.dragHandler.start.y;
+ var deltaX = Math.abs(startX - xy.x);
+ var deltaY = Math.abs(startY - xy.y);
+ this.zoomBox.style.width = Math.max(1, deltaX) + "px";
+ this.zoomBox.style.height = Math.max(1, deltaY) + "px";
+ this.zoomBox.style.left = xy.x < startX ? xy.x+"px" : startX+"px";
+ this.zoomBox.style.top = xy.y < startY ? xy.y+"px" : startY+"px";
+
+ // depending on the box model, modify width and height to take borders
+ // of the box into account
+ var box = this.getBoxCharacteristics();
+ if (box.newBoxModel) {
+ if (xy.x > startX) {
+ this.zoomBox.style.width =
+ Math.max(1, deltaX - box.xOffset) + "px";
+ }
+ if (xy.y > startY) {
+ this.zoomBox.style.height =
+ Math.max(1, deltaY - box.yOffset) + "px";
+ }
+ }
+ },
+
+ /**
+ * Method: endBox
+ */
+ endBox: function(end) {
+ var result;
+ if (Math.abs(this.dragHandler.start.x - end.x) > 5 ||
+ Math.abs(this.dragHandler.start.y - end.y) > 5) {
+ var start = this.dragHandler.start;
+ var top = Math.min(start.y, end.y);
+ var bottom = Math.max(start.y, end.y);
+ var left = Math.min(start.x, end.x);
+ var right = Math.max(start.x, end.x);
+ result = new OpenLayers.Bounds(left, bottom, right, top);
+ } else {
+ result = this.dragHandler.start.clone(); // i.e. OL.Pixel
+ }
+ this.removeBox();
+
+ this.callback("done", [result]);
+ },
+
+ /**
+ * Method: removeBox
+ * Remove the zoombox from the screen and nullify our reference to it.
+ */
+ removeBox: function() {
+ this.map.viewPortDiv.removeChild(this.zoomBox);
+ this.zoomBox = null;
+ this.boxCharacteristics = null;
+ OpenLayers.Element.removeClass(
+ this.map.viewPortDiv, "olDrawBox"
+ );
+
+ },
+
+ /**
+ * Method: activate
+ */
+ activate: function () {
+ if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+ this.dragHandler.activate();
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Method: deactivate
+ */
+ deactivate: function () {
+ if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+ this.dragHandler.deactivate();
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Method: getCharacteristics
+ * Determines offset and box model for a box.
+ *
+ * Returns:
+ * {Object} a hash with the following properties:
+ * - xOffset - Corner offset in x-direction
+ * - yOffset - Corner offset in y-direction
+ * - newBoxModel - true for all browsers except IE in quirks mode
+ */
+ getBoxCharacteristics: function() {
+ if (!this.boxCharacteristics) {
+ var xOffset = parseInt(OpenLayers.Element.getStyle(this.zoomBox,
+ "border-left-width")) + parseInt(OpenLayers.Element.getStyle(
+ this.zoomBox, "border-right-width")) + 1;
+ var yOffset = parseInt(OpenLayers.Element.getStyle(this.zoomBox,
+ "border-top-width")) + parseInt(OpenLayers.Element.getStyle(
+ this.zoomBox, "border-bottom-width")) + 1;
+ // all browsers use the new box model, except IE in quirks mode
+ var newBoxModel = OpenLayers.BROWSER_NAME == "msie" ?
+ document.compatMode != "BackCompat" : true;
+ this.boxCharacteristics = {
+ xOffset: xOffset,
+ yOffset: yOffset,
+ newBoxModel: newBoxModel
+ };
+ }
+ return this.boxCharacteristics;
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.Box"
+});
+/* ======================================================================
+ OpenLayers/Control/ZoomBox.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Handler/Box.js
+ */
+
+/**
+ * Class: OpenLayers.Control.ZoomBox
+ * The ZoomBox control enables zooming directly to a given extent, by drawing
+ * a box on the map. The box is drawn by holding down shift, whilst dragging
+ * the mouse.
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, {
+ /**
+ * Property: type
+ * {OpenLayers.Control.TYPE}
+ */
+ type: OpenLayers.Control.TYPE_TOOL,
+
+ /**
+ * Property: out
+ * {Boolean} Should the control be used for zooming out?
+ */
+ out: false,
+
+ /**
+ * Property: alwaysZoom
+ * {Boolean} Always zoom in/out, when box drawed
+ */
+ alwaysZoom: false,
+
+ /**
+ * Method: draw
+ */
+ draw: function() {
+ this.handler = new OpenLayers.Handler.Box( this,
+ {done: this.zoomBox}, {keyMask: this.keyMask} );
+ },
+
+ /**
+ * Method: zoomBox
+ *
+ * Parameters:
+ * position - {<OpenLayers.Bounds>} or {<OpenLayers.Pixel>}
+ */
+ zoomBox: function (position) {
+ if (position instanceof OpenLayers.Bounds) {
+ var bounds;
+ if (!this.out) {
+ var minXY = this.map.getLonLatFromPixel(
+ new OpenLayers.Pixel(position.left, position.bottom));
+ var maxXY = this.map.getLonLatFromPixel(
+ new OpenLayers.Pixel(position.right, position.top));
+ bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat,
+ maxXY.lon, maxXY.lat);
+ } else {
+ var pixWidth = Math.abs(position.right-position.left);
+ var pixHeight = Math.abs(position.top-position.bottom);
+ var zoomFactor = Math.min((this.map.size.h / pixHeight),
+ (this.map.size.w / pixWidth));
+ var extent = this.map.getExtent();
+ var center = this.map.getLonLatFromPixel(
+ position.getCenterPixel());
+ var xmin = center.lon - (extent.getWidth()/2)*zoomFactor;
+ var xmax = center.lon + (extent.getWidth()/2)*zoomFactor;
+ var ymin = center.lat - (extent.getHeight()/2)*zoomFactor;
+ var ymax = center.lat + (extent.getHeight()/2)*zoomFactor;
+ bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax);
+ }
+ // always zoom in/out
+ var lastZoom = this.map.getZoom();
+ this.map.zoomToExtent(bounds);
+ if (lastZoom == this.map.getZoom() && this.alwaysZoom == true){
+ this.map.zoomTo(lastZoom + (this.out ? -1 : 1));
+ }
+ } else { // it's a pixel
+ if (!this.out) {
+ this.map.setCenter(this.map.getLonLatFromPixel(position),
+ this.map.getZoom() + 1);
+ } else {
+ this.map.setCenter(this.map.getLonLatFromPixel(position),
+ this.map.getZoom() - 1);
+ }
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Control.ZoomBox"
+});
+/* ======================================================================
+ OpenLayers/Control/DragPan.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Handler/Drag.js
+ */
+
+/**
+ * Class: OpenLayers.Control.DragPan
+ * The DragPan control pans the map with a drag of the mouse.
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Property: type
+ * {OpenLayers.Control.TYPES}
+ */
+ type: OpenLayers.Control.TYPE_TOOL,
+
+ /**
+ * Property: panned
+ * {Boolean} The map moved.
+ */
+ panned: false,
+
+ /**
+ * Property: interval
+ * {Integer} The number of milliseconds that should ellapse before
+ * panning the map again. Set this to increase dragging performance.
+ * Defaults to 25 milliseconds.
+ */
+ interval: 25,
+
+ /**
+ * APIProperty: documentDrag
+ * {Boolean} If set to true, mouse dragging will continue even if the
+ * mouse cursor leaves the map viewport. Default is false.
+ */
+ documentDrag: false,
+
+ /**
+ * Method: draw
+ * Creates a Drag handler, using <panMap> and
+ * <panMapDone> as callbacks.
+ */
+ draw: function() {
+ this.handler = new OpenLayers.Handler.Drag(this, {
+ "move": this.panMap,
+ "done": this.panMapDone
+ }, {
+ interval: this.interval,
+ documentDrag: this.documentDrag
+ }
+ );
+ },
+
+ /**
+ * Method: panMap
+ *
+ * Parameters:
+ * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
+ */
+ panMap: function(xy) {
+ this.panned = true;
+ this.map.pan(
+ this.handler.last.x - xy.x,
+ this.handler.last.y - xy.y,
+ {dragging: this.handler.dragging, animate: false}
+ );
+ },
+
+ /**
+ * Method: panMapDone
+ * Finish the panning operation. Only call setCenter (through <panMap>)
+ * if the map has actually been moved.
+ *
+ * Parameters:
+ * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
+ */
+ panMapDone: function(xy) {
+ if(this.panned) {
+ this.panMap(xy);
+ this.panned = false;
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Control.DragPan"
+});
+/* ======================================================================
+ OpenLayers/Handler/Click.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Click
+ * A handler for mouse clicks. The intention of this handler is to give
+ * controls more flexibility with handling clicks. Browsers trigger
+ * click events twice for a double-click. In addition, the mousedown,
+ * mousemove, mouseup sequence fires a click event. With this handler,
+ * controls can decide whether to ignore clicks associated with a double
+ * click. By setting a <pixelTolerance>, controls can also ignore clicks
+ * that include a drag. Create a new instance with the
+ * <OpenLayers.Handler.Click> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
+
+ /**
+ * APIProperty: delay
+ * {Number} Number of milliseconds between clicks before the event is
+ * considered a double-click.
+ */
+ delay: 300,
+
+ /**
+ * APIProperty: single
+ * {Boolean} Handle single clicks. Default is true. If false, clicks
+ * will not be reported. If true, single-clicks will be reported.
+ */
+ single: true,
+
+ /**
+ * APIProperty: double
+ * {Boolean} Handle double-clicks. Default is false.
+ */
+ 'double': false,
+
+ /**
+ * APIProperty: pixelTolerance
+ * {Number} Maximum number of pixels between mouseup and mousedown for an
+ * event to be considered a click. Default is 0. If set to an
+ * integer value, clicks with a drag greater than the value will be
+ * ignored. This property can only be set when the handler is
+ * constructed.
+ */
+ pixelTolerance: 0,
+
+ /**
+ * APIProperty: stopSingle
+ * {Boolean} Stop other listeners from being notified of clicks. Default
+ * is false. If true, any click listeners registered before this one
+ * will not be notified of *any* click event (associated with double
+ * or single clicks).
+ */
+ stopSingle: false,
+
+ /**
+ * APIProperty: stopDouble
+ * {Boolean} Stop other listeners from being notified of double-clicks.
+ * Default is false. If true, any click listeners registered before
+ * this one will not be notified of *any* double-click events.
+ *
+ * The one caveat with stopDouble is that given a map with two click
+ * handlers, one with stopDouble true and the other with stopSingle
+ * true, the stopSingle handler should be activated last to get
+ * uniform cross-browser performance. Since IE triggers one click
+ * with a dblclick and FF triggers two, if a stopSingle handler is
+ * activated first, all it gets in IE is a single click when the
+ * second handler stops propagation on the dblclick.
+ */
+ stopDouble: false,
+
+ /**
+ * Property: timerId
+ * {Number} The id of the timeout waiting to clear the <delayedCall>.
+ */
+ timerId: null,
+
+ /**
+ * Property: down
+ * {<OpenLayers.Pixel>} The pixel location of the last mousedown.
+ */
+ down: null,
+
+ /**
+ * Property: rightclickTimerId
+ * {Number} The id of the right mouse timeout waiting to clear the
+ * <delayedEvent>.
+ */
+ rightclickTimerId: null,
+
+ /**
+ * Constructor: OpenLayers.Handler.Click
+ * Create a new click handler.
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>} The control that is making use of
+ * this handler. If a handler is being used without a control, the
+ * handler's setMap method must be overridden to deal properly with
+ * the map.
+ * callbacks - {Object} An object with keys corresponding to callbacks
+ * that will be called by the handler. The callbacks should
+ * expect to recieve a single argument, the click event.
+ * Callbacks for 'click' and 'dblclick' are supported.
+ * options - {Object} Optional object whose properties will be set on the
+ * handler.
+ */
+ initialize: function(control, callbacks, options) {
+ OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+ // optionally register for mouseup and mousedown
+ if(this.pixelTolerance != null) {
+ this.mousedown = function(evt) {
+ this.down = evt.xy;
+ return true;
+ };
+ }
+ },
+
+ /**
+ * Method: mousedown
+ * Handle mousedown. Only registered as a listener if pixelTolerance is
+ * a non-zero value at construction.
+ *
+ * Returns:
+ * {Boolean} Continue propagating this event.
+ */
+ mousedown: null,
+
+ /**
+ * Method: mouseup
+ * Handle mouseup. Installed to support collection of right mouse events.
+ *
+ * Returns:
+ * {Boolean} Continue propagating this event.
+ */
+ mouseup: function (evt) {
+ var propagate = true;
+
+ // Collect right mouse clicks from the mouseup
+ // IE - ignores the second right click in mousedown so using
+ // mouseup instead
+ if (this.checkModifiers(evt) &&
+ this.control.handleRightClicks &&
+ OpenLayers.Event.isRightClick(evt)) {
+ propagate = this.rightclick(evt);
+ }
+
+ return propagate;
+ },
+
+ /**
+ * Method: rightclick
+ * Handle rightclick. For a dblrightclick, we get two clicks so we need
+ * to always register for dblrightclick to properly handle single
+ * clicks.
+ *
+ * Returns:
+ * {Boolean} Continue propagating this event.
+ */
+ rightclick: function(evt) {
+ if(this.passesTolerance(evt)) {
+ if(this.rightclickTimerId != null) {
+ //Second click received before timeout this must be
+ // a double click
+ this.clearTimer();
+ this.callback('dblrightclick', [evt]);
+ return !this.stopDouble;
+ } else {
+ //Set the rightclickTimerId, send evt only if double is
+ // true else trigger single
+ var clickEvent = this['double'] ?
+ OpenLayers.Util.extend({}, evt) :
+ this.callback('rightclick', [evt]);
+
+ var delayedRightCall = OpenLayers.Function.bind(
+ this.delayedRightCall,
+ this,
+ clickEvent
+ );
+ this.rightclickTimerId = window.setTimeout(
+ delayedRightCall, this.delay
+ );
+ }
+ }
+ return !this.stopSingle;
+ },
+
+ /**
+ * Method: delayedRightCall
+ * Sets <rightclickTimerId> to null. And optionally triggers the
+ * rightclick callback if evt is set.
+ */
+ delayedRightCall: function(evt) {
+ this.rightclickTimerId = null;
+ if (evt) {
+ this.callback('rightclick', [evt]);
+ }
+ return !this.stopSingle;
+ },
+
+ /**
+ * Method: dblclick
+ * Handle dblclick. For a dblclick, we get two clicks in some browsers
+ * (FF) and one in others (IE). So we need to always register for
+ * dblclick to properly handle single clicks.
+ *
+ * Returns:
+ * {Boolean} Continue propagating this event.
+ */
+ dblclick: function(evt) {
+ if(this.passesTolerance(evt)) {
+ if(this["double"]) {
+ this.callback('dblclick', [evt]);
+ }
+ this.clearTimer();
+ }
+ return !this.stopDouble;
+ },
+
+ /**
+ * Method: click
+ * Handle click.
+ *
+ * Returns:
+ * {Boolean} Continue propagating this event.
+ */
+ click: function(evt) {
+ if(this.passesTolerance(evt)) {
+ if(this.timerId != null) {
+ // already received a click
+ this.clearTimer();
+ } else {
+ // set the timer, send evt only if single is true
+ //use a clone of the event object because it will no longer
+ //be a valid event object in IE in the timer callback
+ var clickEvent = this.single ?
+ OpenLayers.Util.extend({}, evt) : null;
+ this.timerId = window.setTimeout(
+ OpenLayers.Function.bind(this.delayedCall, this, clickEvent),
+ this.delay
+ );
+ }
+ }
+ return !this.stopSingle;
+ },
+
+ /**
+ * Method: passesTolerance
+ * Determine whether the event is within the optional pixel tolerance. Note
+ * that the pixel tolerance check only works if mousedown events get to
+ * the listeners registered here. If they are stopped by other elements,
+ * the <pixelTolerance> will have no effect here (this method will always
+ * return true).
+ *
+ * Returns:
+ * {Boolean} The click is within the pixel tolerance (if specified).
+ */
+ passesTolerance: function(evt) {
+ var passes = true;
+ if(this.pixelTolerance != null && this.down) {
+ var dpx = Math.sqrt(
+ Math.pow(this.down.x - evt.xy.x, 2) +
+ Math.pow(this.down.y - evt.xy.y, 2)
+ );
+ if(dpx > this.pixelTolerance) {
+ passes = false;
+ }
+ }
+ return passes;
+ },
+
+ /**
+ * Method: clearTimer
+ * Clear the timer and set <timerId> to null.
+ */
+ clearTimer: function() {
+ if(this.timerId != null) {
+ window.clearTimeout(this.timerId);
+ this.timerId = null;
+ }
+ if(this.rightclickTimerId != null) {
+ window.clearTimeout(this.rightclickTimerId);
+ this.rightclickTimerId = null;
+ }
+ },
+
+ /**
+ * Method: delayedCall
+ * Sets <timerId> to null. And optionally triggers the click callback if
+ * evt is set.
+ */
+ delayedCall: function(evt) {
+ this.timerId = null;
+ if(evt) {
+ this.callback('click', [evt]);
+ }
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Deactivate the handler.
+ *
+ * Returns:
+ * {Boolean} The handler was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = false;
+ if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+ this.clearTimer();
+ this.down = null;
+ deactivated = true;
+ }
+ return deactivated;
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.Click"
+});
+/* ======================================================================
+ OpenLayers/Control/Navigation.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control/ZoomBox.js
+ * @requires OpenLayers/Control/DragPan.js
+ * @requires OpenLayers/Handler/MouseWheel.js
+ * @requires OpenLayers/Handler/Click.js
+ */
+
+/**
+ * Class: OpenLayers.Control.Navigation
+ * The navigation control handles map browsing with mouse events (dragging,
+ * double-clicking, and scrolling the wheel). Create a new navigation
+ * control with the <OpenLayers.Control.Navigation> control.
+ *
+ * Note that this control is added to the map by default (if no controls
+ * array is sent in the options object to the <OpenLayers.Map>
+ * constructor).
+ *
+ * Inherits:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Property: dragPan
+ * {<OpenLayers.Control.DragPan>}
+ */
+ dragPan: null,
+
+ /**
+ * APIProprety: dragPanOptions
+ * {Object} Options passed to the DragPan control.
+ */
+ dragPanOptions: null,
+
+ /**
+ * APIProperty: documentDrag
+ * {Boolean} Allow panning of the map by dragging outside map viewport.
+ * Default is false.
+ */
+ documentDrag: false,
+
+ /**
+ * Property: zoomBox
+ * {<OpenLayers.Control.ZoomBox>}
+ */
+ zoomBox: null,
+
+ /**
+ * APIProperty: zoomBoxEnabled
+ * {Boolean} Whether the user can draw a box to zoom
+ */
+ zoomBoxEnabled: true,
+
+ /**
+ * APIProperty: zoomWheelEnabled
+ * {Boolean} Whether the mousewheel should zoom the map
+ */
+ zoomWheelEnabled: true,
+
+ /**
+ * Property: mouseWheelOptions
+ * {Object} Options passed to the MouseWheel control (only useful if
+ * <zoomWheelEnabled> is set to true)
+ */
+ mouseWheelOptions: null,
+
+ /**
+ * APIProperty: handleRightClicks
+ * {Boolean} Whether or not to handle right clicks. Default is false.
+ */
+ handleRightClicks: false,
+
+ /**
+ * APIProperty: zoomBoxKeyMask
+ * {Integer} <OpenLayers.Handler> key code of the key, which has to be
+ * pressed, while drawing the zoom box with the mouse on the screen.
+ * You should probably set handleRightClicks to true if you use this
+ * with MOD_CTRL, to disable the context menu for machines which use
+ * CTRL-Click as a right click.
+ * Default: <OpenLayers.Handler.MOD_SHIFT
+ */
+ zoomBoxKeyMask: OpenLayers.Handler.MOD_SHIFT,
+
+ /**
+ * APIProperty: autoActivate
+ * {Boolean} Activate the control when it is added to a map. Default is
+ * true.
+ */
+ autoActivate: true,
+
+ /**
+ * Constructor: OpenLayers.Control.Navigation
+ * Create a new navigation control
+ *
+ * Parameters:
+ * options - {Object} An optional object whose properties will be set on
+ * the control
+ */
+ initialize: function(options) {
+ this.handlers = {};
+ OpenLayers.Control.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * Method: destroy
+ * The destroy method is used to perform any clean up before the control
+ * is dereferenced. Typically this is where event listeners are removed
+ * to prevent memory leaks.
+ */
+ destroy: function() {
+ this.deactivate();
+
+ if (this.dragPan) {
+ this.dragPan.destroy();
+ }
+ this.dragPan = null;
+
+ if (this.zoomBox) {
+ this.zoomBox.destroy();
+ }
+ this.zoomBox = null;
+ OpenLayers.Control.prototype.destroy.apply(this,arguments);
+ },
+
+ /**
+ * Method: activate
+ */
+ activate: function() {
+ this.dragPan.activate();
+ if (this.zoomWheelEnabled) {
+ this.handlers.wheel.activate();
+ }
+ this.handlers.click.activate();
+ if (this.zoomBoxEnabled) {
+ this.zoomBox.activate();
+ }
+ return OpenLayers.Control.prototype.activate.apply(this,arguments);
+ },
+
+ /**
+ * Method: deactivate
+ */
+ deactivate: function() {
+ this.zoomBox.deactivate();
+ this.dragPan.deactivate();
+ this.handlers.click.deactivate();
+ this.handlers.wheel.deactivate();
+ return OpenLayers.Control.prototype.deactivate.apply(this,arguments);
+ },
+
+ /**
+ * Method: draw
+ */
+ draw: function() {
+ // disable right mouse context menu for support of right click events
+ if (this.handleRightClicks) {
+ this.map.viewPortDiv.oncontextmenu = OpenLayers.Function.False;
+ }
+
+ var clickCallbacks = {
+ 'dblclick': this.defaultDblClick,
+ 'dblrightclick': this.defaultDblRightClick
+ };
+ var clickOptions = {
+ 'double': true,
+ 'stopDouble': true
+ };
+ this.handlers.click = new OpenLayers.Handler.Click(
+ this, clickCallbacks, clickOptions
+ );
+ this.dragPan = new OpenLayers.Control.DragPan(
+ OpenLayers.Util.extend({
+ map: this.map,
+ documentDrag: this.documentDrag
+ }, this.dragPanOptions)
+ );
+ this.zoomBox = new OpenLayers.Control.ZoomBox(
+ {map: this.map, keyMask: this.zoomBoxKeyMask});
+ this.dragPan.draw();
+ this.zoomBox.draw();
+ this.handlers.wheel = new OpenLayers.Handler.MouseWheel(
+ this, {"up" : this.wheelUp,
+ "down": this.wheelDown},
+ this.mouseWheelOptions );
+ },
+
+ /**
+ * Method: defaultDblClick
+ *
+ * Parameters:
+ * evt - {Event}
+ */
+ defaultDblClick: function (evt) {
+ var newCenter = this.map.getLonLatFromViewPortPx( evt.xy );
+ this.map.setCenter(newCenter, this.map.zoom + 1);
+ },
+
+ /**
+ * Method: defaultDblRightClick
+ *
+ * Parameters:
+ * evt - {Event}
+ */
+ defaultDblRightClick: function (evt) {
+ var newCenter = this.map.getLonLatFromViewPortPx( evt.xy );
+ this.map.setCenter(newCenter, this.map.zoom - 1);
+ },
+
+ /**
+ * Method: wheelChange
+ *
+ * Parameters:
+ * evt - {Event}
+ * deltaZ - {Integer}
+ */
+ wheelChange: function(evt, deltaZ) {
+ var currentZoom = this.map.getZoom();
+ var newZoom = this.map.getZoom() + Math.round(deltaZ);
+ newZoom = Math.max(newZoom, 0);
+ newZoom = Math.min(newZoom, this.map.getNumZoomLevels());
+ if (newZoom === currentZoom) {
+ return;
+ }
+ var size = this.map.getSize();
+ var deltaX = size.w/2 - evt.xy.x;
+ var deltaY = evt.xy.y - size.h/2;
+ var newRes = this.map.baseLayer.getResolutionForZoom(newZoom);
+ var zoomPoint = this.map.getLonLatFromPixel(evt.xy);
+ var newCenter = new OpenLayers.LonLat(
+ zoomPoint.lon + deltaX * newRes,
+ zoomPoint.lat + deltaY * newRes );
+ this.map.setCenter( newCenter, newZoom );
+ },
+
+ /**
+ * Method: wheelUp
+ * User spun scroll wheel up
+ *
+ * Parameters:
+ * evt - {Event}
+ * delta - {Integer}
+ */
+ wheelUp: function(evt, delta) {
+ this.wheelChange(evt, delta || 1);
+ },
+
+ /**
+ * Method: wheelDown
+ * User spun scroll wheel down
+ *
+ * Parameters:
+ * evt - {Event}
+ * delta - {Integer}
+ */
+ wheelDown: function(evt, delta) {
+ this.wheelChange(evt, delta || -1);
+ },
+
+ /**
+ * Method: disableZoomBox
+ */
+ disableZoomBox : function() {
+ this.zoomBoxEnabled = false;
+ this.zoomBox.deactivate();
+ },
+
+ /**
+ * Method: enableZoomBox
+ */
+ enableZoomBox : function() {
+ this.zoomBoxEnabled = true;
+ if (this.active) {
+ this.zoomBox.activate();
+ }
+ },
+
+ /**
+ * Method: disableZoomWheel
+ */
+
+ disableZoomWheel : function() {
+ this.zoomWheelEnabled = false;
+ this.handlers.wheel.deactivate();
+ },
+
+ /**
+ * Method: enableZoomWheel
+ */
+
+ enableZoomWheel : function() {
+ this.zoomWheelEnabled = true;
+ if (this.active) {
+ this.handlers.wheel.activate();
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Control.Navigation"
+});
+/* ======================================================================
+ OpenLayers/Layer/HTTPRequest.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.HTTPRequest
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer>
+ */
+OpenLayers.Layer.HTTPRequest = OpenLayers.Class(OpenLayers.Layer, {
+
+ /**
+ * Constant: URL_HASH_FACTOR
+ * {Float} Used to hash URL param strings for multi-WMS server selection.
+ * Set to the Golden Ratio per Knuth's recommendation.
+ */
+ URL_HASH_FACTOR: (Math.sqrt(5) - 1) / 2,
+
+ /**
+ * Property: url
+ * {Array(String) or String} This is either an array of url strings or
+ * a single url string.
+ */
+ url: null,
+
+ /**
+ * Property: params
+ * {Object} Hashtable of key/value parameters
+ */
+ params: null,
+
+ /**
+ * APIProperty: reproject
+ * *Deprecated*. See http://trac.openlayers.org/wiki/SpatialMercator
+ * for information on the replacement for this functionality.
+ * {Boolean} Whether layer should reproject itself based on base layer
+ * locations. This allows reprojection onto commercial layers.
+ * Default is false: Most layers can't reproject, but layers
+ * which can create non-square geographic pixels can, like WMS.
+ *
+ */
+ reproject: false,
+
+ /**
+ * Constructor: OpenLayers.Layer.HTTPRequest
+ *
+ * Parameters:
+ * name - {String}
+ * url - {Array(String) or String}
+ * params - {Object}
+ * options - {Object} Hashtable of extra options to tag onto the layer
+ */
+ initialize: function(name, url, params, options) {
+ var newArguments = arguments;
+ newArguments = [name, options];
+ OpenLayers.Layer.prototype.initialize.apply(this, newArguments);
+ this.url = url;
+ this.params = OpenLayers.Util.extend( {}, params);
+ },
+
+ /**
+ * APIMethod: destroy
+ */
+ destroy: function() {
+ this.url = null;
+ this.params = null;
+ OpenLayers.Layer.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * APIMethod: clone
+ *
+ * Parameters:
+ * obj - {Object}
+ *
+ * Returns:
+ * {<OpenLayers.Layer.HTTPRequest>} An exact clone of this
+ * <OpenLayers.Layer.HTTPRequest>
+ */
+ clone: function (obj) {
+
+ if (obj == null) {
+ obj = new OpenLayers.Layer.HTTPRequest(this.name,
+ this.url,
+ this.params,
+ this.getOptions());
+ }
+
+ //get all additions from superclasses
+ obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]);
+
+ // copy/set any non-init, non-simple values here
+
+ return obj;
+ },
+
+ /**
+ * APIMethod: setUrl
+ *
+ * Parameters:
+ * newUrl - {String}
+ */
+ setUrl: function(newUrl) {
+ this.url = newUrl;
+ },
+
+ /**
+ * APIMethod: mergeNewParams
+ *
+ * Parameters:
+ * newParams - {Object}
+ *
+ * Returns:
+ * redrawn: {Boolean} whether the layer was actually redrawn.
+ */
+ mergeNewParams:function(newParams) {
+ this.params = OpenLayers.Util.extend(this.params, newParams);
+ var ret = this.redraw();
+ if(this.map != null) {
+ this.map.events.triggerEvent("changelayer", {
+ layer: this,
+ property: "params"
+ });
+ }
+ return ret;
+ },
+
+ /**
+ * APIMethod: redraw
+ * Redraws the layer. Returns true if the layer was redrawn, false if not.
+ *
+ * Parameters:
+ * force - {Boolean} Force redraw by adding random parameter.
+ *
+ * Returns:
+ * {Boolean} The layer was redrawn.
+ */
+ redraw: function(force) {
+ if (force) {
+ return this.mergeNewParams({"_olSalt": Math.random()});
+ } else {
+ return OpenLayers.Layer.prototype.redraw.apply(this, []);
+ }
+ },
+
+ /**
+ * Method: selectUrl
+ * selectUrl() implements the standard floating-point multiplicative
+ * hash function described by Knuth, and hashes the contents of the
+ * given param string into a float between 0 and 1. This float is then
+ * scaled to the size of the provided urls array, and used to select
+ * a URL.
+ *
+ * Parameters:
+ * paramString - {String}
+ * urls - {Array(String)}
+ *
+ * Returns:
+ * {String} An entry from the urls array, deterministically selected based
+ * on the paramString.
+ */
+ selectUrl: function(paramString, urls) {
+ var product = 1;
+ for (var i=0, len=paramString.length; i<len; i++) {
+ product *= paramString.charCodeAt(i) * this.URL_HASH_FACTOR;
+ product -= Math.floor(product);
+ }
+ return urls[Math.floor(product * urls.length)];
+ },
+
+ /**
+ * Method: getFullRequestString
+ * Combine url with layer's params and these newParams.
+ *
+ * does checking on the serverPath variable, allowing for cases when it
+ * is supplied with trailing ? or &, as well as cases where not.
+ *
+ * return in formatted string like this:
+ * "server?key1=value1&key2=value2&key3=value3"
+ *
+ * WARNING: The altUrl parameter is deprecated and will be removed in 3.0.
+ *
+ * Parameters:
+ * newParams - {Object}
+ * altUrl - {String} Use this as the url instead of the layer's url
+ *
+ * Returns:
+ * {String}
+ */
+ getFullRequestString:function(newParams, altUrl) {
+
+ // if not altUrl passed in, use layer's url
+ var url = altUrl || this.url;
+
+ // create a new params hashtable with all the layer params and the
+ // new params together. then convert to string
+ var allParams = OpenLayers.Util.extend({}, this.params);
+ allParams = OpenLayers.Util.extend(allParams, newParams);
+ var paramsString = OpenLayers.Util.getParameterString(allParams);
+
+ // if url is not a string, it should be an array of strings,
+ // in which case we will deterministically select one of them in
+ // order to evenly distribute requests to different urls.
+ //
+ if (url instanceof Array) {
+ url = this.selectUrl(paramsString, url);
+ }
+
+ // ignore parameters that are already in the url search string
+ var urlParams =
+ OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));
+ for(var key in allParams) {
+ if(key.toUpperCase() in urlParams) {
+ delete allParams[key];
+ }
+ }
+ paramsString = OpenLayers.Util.getParameterString(allParams);
+
+ return OpenLayers.Util.urlAppend(url, paramsString);
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.HTTPRequest"
+});
+/* ======================================================================
+ OpenLayers/Layer/Grid.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/HTTPRequest.js
+ * @requires OpenLayers/Console.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.Grid
+ * Base class for layers that use a lattice of tiles. Create a new grid
+ * layer with the <OpenLayers.Layer.Grid> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer.HTTPRequest>
+ */
+OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
+
+ /**
+ * APIProperty: tileSize
+ * {<OpenLayers.Size>}
+ */
+ tileSize: null,
+
+ /**
+ * Property: tileOriginCorner
+ * {String} If the <tileOrigin> property is not provided, the tile origin
+ * will be derived from the layer's <maxExtent>. The corner of the
+ * <maxExtent> used is determined by this property. Acceptable values
+ * are "tl" (top left), "tr" (top right), "bl" (bottom left), and "br"
+ * (bottom right). Default is "bl".
+ */
+ tileOriginCorner: "bl",
+
+ /**
+ * APIProperty: tileOrigin
+ * {<OpenLayers.LonLat>} Optional origin for aligning the grid of tiles.
+ * If provided, requests for tiles at all resolutions will be aligned
+ * with this location (no tiles shall overlap this location). If
+ * not provided, the grid of tiles will be aligned with the layer's
+ * <maxExtent>. Default is ``null``.
+ */
+ tileOrigin: null,
+
+ /** APIProperty: tileOptions
+ * {Object} optional configuration options for <OpenLayers.Tile> instances
+ * created by this Layer, if supported by the tile class.
+ */
+ tileOptions: null,
+
+ /**
+ * Property: grid
+ * {Array(Array(<OpenLayers.Tile>))} This is an array of rows, each row is
+ * an array of tiles.
+ */
+ grid: null,
+
+ /**
+ * APIProperty: singleTile
+ * {Boolean} Moves the layer into single-tile mode, meaning that one tile
+ * will be loaded. The tile's size will be determined by the 'ratio'
+ * property. When the tile is dragged such that it does not cover the
+ * entire viewport, it is reloaded.
+ */
+ singleTile: false,
+
+ /** APIProperty: ratio
+ * {Float} Used only when in single-tile mode, this specifies the
+ * ratio of the size of the single tile to the size of the map.
+ */
+ ratio: 1.5,
+
+ /**
+ * APIProperty: buffer
+ * {Integer} Used only when in gridded mode, this specifies the number of
+ * extra rows and colums of tiles on each side which will
+ * surround the minimum grid tiles to cover the map.
+ */
+ buffer: 2,
+
+ /**
+ * APIProperty: numLoadingTiles
+ * {Integer} How many tiles are still loading?
+ */
+ numLoadingTiles: 0,
+
+ /**
+ * Constructor: OpenLayers.Layer.Grid
+ * Create a new grid layer
+ *
+ * Parameters:
+ * name - {String}
+ * url - {String}
+ * params - {Object}
+ * options - {Object} Hashtable of extra options to tag onto the layer
+ */
+ initialize: function(name, url, params, options) {
+ OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,
+ arguments);
+
+ //grid layers will trigger 'tileloaded' when each new tile is
+ // loaded, as a means of progress update to listeners.
+ // listeners can access 'numLoadingTiles' if they wish to keep track
+ // of the loading progress
+ //
+ this.events.addEventType("tileloaded");
+
+ this.grid = [];
+ },
+
+ /**
+ * APIMethod: destroy
+ * Deconstruct the layer and clear the grid.
+ */
+ destroy: function() {
+ this.clearGrid();
+ this.grid = null;
+ this.tileSize = null;
+ OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: clearGrid
+ * Go through and remove all tiles from the grid, calling
+ * destroy() on each of them to kill circular references
+ */
+ clearGrid:function() {
+ if (this.grid) {
+ for(var iRow=0, len=this.grid.length; iRow<len; iRow++) {
+ var row = this.grid[iRow];
+ for(var iCol=0, clen=row.length; iCol<clen; iCol++) {
+ var tile = row[iCol];
+ this.removeTileMonitoringHooks(tile);
+ tile.destroy();
+ }
+ }
+ this.grid = [];
+ }
+ },
+
+ /**
+ * APIMethod: clone
+ * Create a clone of this layer
+ *
+ * Parameters:
+ * obj - {Object} Is this ever used?
+ *
+ * Returns:
+ * {<OpenLayers.Layer.Grid>} An exact clone of this OpenLayers.Layer.Grid
+ */
+ clone: function (obj) {
+
+ if (obj == null) {
+ obj = new OpenLayers.Layer.Grid(this.name,
+ this.url,
+ this.params,
+ this.getOptions());
+ }
+
+ //get all additions from superclasses
+ obj = OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this, [obj]);
+
+ // copy/set any non-init, non-simple values here
+ if (this.tileSize != null) {
+ obj.tileSize = this.tileSize.clone();
+ }
+
+ // we do not want to copy reference to grid, so we make a new array
+ obj.grid = [];
+
+ return obj;
+ },
+
+ /**
+ * Method: moveTo
+ * This function is called whenever the map is moved. All the moving
+ * of actual 'tiles' is done by the map, but moveTo's role is to accept
+ * a bounds and make sure the data that that bounds requires is pre-loaded.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * zoomChanged - {Boolean}
+ * dragging - {Boolean}
+ */
+ moveTo:function(bounds, zoomChanged, dragging) {
+ OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this, arguments);
+
+ bounds = bounds || this.map.getExtent();
+
+ if (bounds != null) {
+
+ // if grid is empty or zoom has changed, we *must* re-tile
+ var forceReTile = !this.grid.length || zoomChanged;
+
+ // total bounds of the tiles
+ var tilesBounds = this.getTilesBounds();
+
+ if (this.singleTile) {
+
+ // We want to redraw whenever even the slightest part of the
+ // current bounds is not contained by our tile.
+ // (thus, we do not specify partial -- its default is false)
+ if ( forceReTile ||
+ (!dragging && !tilesBounds.containsBounds(bounds))) {
+ this.initSingleTile(bounds);
+ }
+ } else {
+
+ // if the bounds have changed such that they are not even
+ // *partially* contained by our tiles (IE user has
+ // programmatically panned to the other side of the earth)
+ // then we want to reTile (thus, partial true).
+ //
+ if (forceReTile || !tilesBounds.containsBounds(bounds, true)) {
+ this.initGriddedTiles(bounds);
+ } else {
+ //we might have to shift our buffer tiles
+ this.moveGriddedTiles(bounds);
+ }
+ }
+ }
+ },
+
+ /**
+ * APIMethod: setTileSize
+ * Check if we are in singleTile mode and if so, set the size as a ratio
+ * of the map size (as specified by the layer's 'ratio' property).
+ *
+ * Parameters:
+ * size - {<OpenLayers.Size>}
+ */
+ setTileSize: function(size) {
+ if (this.singleTile) {
+ size = this.map.getSize();
+ size.h = parseInt(size.h * this.ratio);
+ size.w = parseInt(size.w * this.ratio);
+ }
+ OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this, [size]);
+ },
+
+ /**
+ * Method: getGridBounds
+ * Deprecated. This function will be removed in 3.0. Please use
+ * getTilesBounds() instead.
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
+ * currently loaded tiles (including those partially or not at all seen
+ * onscreen)
+ */
+ getGridBounds: function() {
+ var msg = "The getGridBounds() function is deprecated. It will be " +
+ "removed in 3.0. Please use getTilesBounds() instead.";
+ OpenLayers.Console.warn(msg);
+ return this.getTilesBounds();
+ },
+
+ /**
+ * APIMethod: getTilesBounds
+ * Return the bounds of the tile grid.
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
+ * currently loaded tiles (including those partially or not at all seen
+ * onscreen).
+ */
+ getTilesBounds: function() {
+ var bounds = null;
+
+ if (this.grid.length) {
+ var bottom = this.grid.length - 1;
+ var bottomLeftTile = this.grid[bottom][0];
+
+ var right = this.grid[0].length - 1;
+ var topRightTile = this.grid[0][right];
+
+ bounds = new OpenLayers.Bounds(bottomLeftTile.bounds.left,
+ bottomLeftTile.bounds.bottom,
+ topRightTile.bounds.right,
+ topRightTile.bounds.top);
+
+ }
+ return bounds;
+ },
+
+ /**
+ * Method: initSingleTile
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ */
+ initSingleTile: function(bounds) {
+
+ //determine new tile bounds
+ var center = bounds.getCenterLonLat();
+ var tileWidth = bounds.getWidth() * this.ratio;
+ var tileHeight = bounds.getHeight() * this.ratio;
+
+ var tileBounds =
+ new OpenLayers.Bounds(center.lon - (tileWidth/2),
+ center.lat - (tileHeight/2),
+ center.lon + (tileWidth/2),
+ center.lat + (tileHeight/2));
+
+ var ul = new OpenLayers.LonLat(tileBounds.left, tileBounds.top);
+ var px = this.map.getLayerPxFromLonLat(ul);
+
+ if (!this.grid.length) {
+ this.grid[0] = [];
+ }
+
+ var tile = this.grid[0][0];
+ if (!tile) {
+ tile = this.addTile(tileBounds, px);
+
+ this.addTileMonitoringHooks(tile);
+ tile.draw();
+ this.grid[0][0] = tile;
+ } else {
+ tile.moveTo(tileBounds, px);
+ }
+
+ //remove all but our single tile
+ this.removeExcessTiles(1,1);
+ },
+
+ /**
+ * Method: calculateGridLayout
+ * Generate parameters for the grid layout.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bound>}
+ * origin - {<OpenLayers.LonLat>}
+ * resolution - {Number}
+ *
+ * Returns:
+ * Object containing properties tilelon, tilelat, tileoffsetlat,
+ * tileoffsetlat, tileoffsetx, tileoffsety
+ */
+ calculateGridLayout: function(bounds, origin, resolution) {
+ var tilelon = resolution * this.tileSize.w;
+ var tilelat = resolution * this.tileSize.h;
+
+ var offsetlon = bounds.left - origin.lon;
+ var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
+ var tilecolremain = offsetlon/tilelon - tilecol;
+ var tileoffsetx = -tilecolremain * this.tileSize.w;
+ var tileoffsetlon = origin.lon + tilecol * tilelon;
+
+ var offsetlat = bounds.top - (origin.lat + tilelat);
+ var tilerow = Math.ceil(offsetlat/tilelat) + this.buffer;
+ var tilerowremain = tilerow - offsetlat/tilelat;
+ var tileoffsety = -tilerowremain * this.tileSize.h;
+ var tileoffsetlat = origin.lat + tilerow * tilelat;
+
+ return {
+ tilelon: tilelon, tilelat: tilelat,
+ tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
+ tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
+ };
+
+ },
+
+ /**
+ * Method: getTileOrigin
+ * Determine the origin for aligning the grid of tiles. If a <tileOrigin>
+ * property is supplied, that will be returned. Otherwise, the origin
+ * will be derived from the layer's <maxExtent> property. In this case,
+ * the tile origin will be the corner of the <maxExtent> given by the
+ * <tileOriginCorner> property.
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} The tile origin.
+ */
+ getTileOrigin: function() {
+ var origin = this.tileOrigin;
+ if (!origin) {
+ var extent = this.getMaxExtent();
+ var edges = ({
+ "tl": ["left", "top"],
+ "tr": ["right", "top"],
+ "bl": ["left", "bottom"],
+ "br": ["right", "bottom"]
+ })[this.tileOriginCorner];
+ origin = new OpenLayers.LonLat(extent[edges[0]], extent[edges[1]]);
+ }
+ return origin;
+ },
+
+ /**
+ * Method: initGriddedTiles
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ */
+ initGriddedTiles:function(bounds) {
+
+ // work out mininum number of rows and columns; this is the number of
+ // tiles required to cover the viewport plus at least one for panning
+
+ var viewSize = this.map.getSize();
+ var minRows = Math.ceil(viewSize.h/this.tileSize.h) +
+ Math.max(1, 2 * this.buffer);
+ var minCols = Math.ceil(viewSize.w/this.tileSize.w) +
+ Math.max(1, 2 * this.buffer);
+
+ var origin = this.getTileOrigin();
+ var resolution = this.map.getResolution();
+
+ var tileLayout = this.calculateGridLayout(bounds, origin, resolution);
+
+ var tileoffsetx = Math.round(tileLayout.tileoffsetx); // heaven help us
+ var tileoffsety = Math.round(tileLayout.tileoffsety);
+
+ var tileoffsetlon = tileLayout.tileoffsetlon;
+ var tileoffsetlat = tileLayout.tileoffsetlat;
+
+ var tilelon = tileLayout.tilelon;
+ var tilelat = tileLayout.tilelat;
+
+ this.origin = new OpenLayers.Pixel(tileoffsetx, tileoffsety);
+
+ var startX = tileoffsetx;
+ var startLon = tileoffsetlon;
+
+ var rowidx = 0;
+
+ var layerContainerDivLeft = parseInt(this.map.layerContainerDiv.style.left);
+ var layerContainerDivTop = parseInt(this.map.layerContainerDiv.style.top);
+
+
+ do {
+ var row = this.grid[rowidx++];
+ if (!row) {
+ row = [];
+ this.grid.push(row);
+ }
+
+ tileoffsetlon = startLon;
+ tileoffsetx = startX;
+ var colidx = 0;
+
+ do {
+ var tileBounds =
+ new OpenLayers.Bounds(tileoffsetlon,
+ tileoffsetlat,
+ tileoffsetlon + tilelon,
+ tileoffsetlat + tilelat);
+
+ var x = tileoffsetx;
+ x -= layerContainerDivLeft;
+
+ var y = tileoffsety;
+ y -= layerContainerDivTop;
+
+ var px = new OpenLayers.Pixel(x, y);
+ var tile = row[colidx++];
+ if (!tile) {
+ tile = this.addTile(tileBounds, px);
+ this.addTileMonitoringHooks(tile);
+ row.push(tile);
+ } else {
+ tile.moveTo(tileBounds, px, false);
+ }
+
+ tileoffsetlon += tilelon;
+ tileoffsetx += this.tileSize.w;
+ } while ((tileoffsetlon <= bounds.right + tilelon * this.buffer)
+ || colidx < minCols);
+
+ tileoffsetlat -= tilelat;
+ tileoffsety += this.tileSize.h;
+ } while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer)
+ || rowidx < minRows);
+
+ //shave off exceess rows and colums
+ this.removeExcessTiles(rowidx, colidx);
+
+ //now actually draw the tiles
+ this.spiralTileLoad();
+ },
+
+ /**
+ * Method: getMaxExtent
+ * Get this layer's maximum extent. (Implemented as a getter for
+ * potential specific implementations in sub-classes.)
+ *
+ * Returns:
+ * {OpenLayers.Bounds}
+ */
+ getMaxExtent: function() {
+ return this.maxExtent;
+ },
+
+ /**
+ * Method: spiralTileLoad
+ * Starts at the top right corner of the grid and proceeds in a spiral
+ * towards the center, adding tiles one at a time to the beginning of a
+ * queue.
+ *
+ * Once all the grid's tiles have been added to the queue, we go back
+ * and iterate through the queue (thus reversing the spiral order from
+ * outside-in to inside-out), calling draw() on each tile.
+ */
+ spiralTileLoad: function() {
+ var tileQueue = [];
+
+ var directions = ["right", "down", "left", "up"];
+
+ var iRow = 0;
+ var iCell = -1;
+ var direction = OpenLayers.Util.indexOf(directions, "right");
+ var directionsTried = 0;
+
+ while( directionsTried < directions.length) {
+
+ var testRow = iRow;
+ var testCell = iCell;
+
+ switch (directions[direction]) {
+ case "right":
+ testCell++;
+ break;
+ case "down":
+ testRow++;
+ break;
+ case "left":
+ testCell--;
+ break;
+ case "up":
+ testRow--;
+ break;
+ }
+
+ // if the test grid coordinates are within the bounds of the
+ // grid, get a reference to the tile.
+ var tile = null;
+ if ((testRow < this.grid.length) && (testRow >= 0) &&
+ (testCell < this.grid[0].length) && (testCell >= 0)) {
+ tile = this.grid[testRow][testCell];
+ }
+
+ if ((tile != null) && (!tile.queued)) {
+ //add tile to beginning of queue, mark it as queued.
+ tileQueue.unshift(tile);
+ tile.queued = true;
+
+ //restart the directions counter and take on the new coords
+ directionsTried = 0;
+ iRow = testRow;
+ iCell = testCell;
+ } else {
+ //need to try to load a tile in a different direction
+ direction = (direction + 1) % 4;
+ directionsTried++;
+ }
+ }
+
+ // now we go through and draw the tiles in forward order
+ for(var i=0, len=tileQueue.length; i<len; i++) {
+ var tile = tileQueue[i];
+ tile.draw();
+ //mark tile as unqueued for the next time (since tiles are reused)
+ tile.queued = false;
+ }
+ },
+
+ /**
+ * APIMethod: addTile
+ * Gives subclasses of Grid the opportunity to create an
+ * OpenLayer.Tile of their choosing. The implementer should initialize
+ * the new tile and take whatever steps necessary to display it.
+ *
+ * Parameters
+ * bounds - {<OpenLayers.Bounds>}
+ * position - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Tile>} The added OpenLayers.Tile
+ */
+ addTile:function(bounds, position) {
+ // Should be implemented by subclasses
+ },
+
+ /**
+ * Method: addTileMonitoringHooks
+ * This function takes a tile as input and adds the appropriate hooks to
+ * the tile so that the layer can keep track of the loading tiles.
+ *
+ * Parameters:
+ * tile - {<OpenLayers.Tile>}
+ */
+ addTileMonitoringHooks: function(tile) {
+
+ tile.onLoadStart = function() {
+ //if that was first tile then trigger a 'loadstart' on the layer
+ if (this.numLoadingTiles == 0) {
+ this.events.triggerEvent("loadstart");
+ }
+ this.numLoadingTiles++;
+ };
+ tile.events.register("loadstart", this, tile.onLoadStart);
+
+ tile.onLoadEnd = function() {
+ this.numLoadingTiles--;
+ this.events.triggerEvent("tileloaded");
+ //if that was the last tile, then trigger a 'loadend' on the layer
+ if (this.numLoadingTiles == 0) {
+ this.events.triggerEvent("loadend");
+ }
+ };
+ tile.events.register("loadend", this, tile.onLoadEnd);
+ tile.events.register("unload", this, tile.onLoadEnd);
+ },
+
+ /**
+ * Method: removeTileMonitoringHooks
+ * This function takes a tile as input and removes the tile hooks
+ * that were added in addTileMonitoringHooks()
+ *
+ * Parameters:
+ * tile - {<OpenLayers.Tile>}
+ */
+ removeTileMonitoringHooks: function(tile) {
+ tile.unload();
+ tile.events.un({
+ "loadstart": tile.onLoadStart,
+ "loadend": tile.onLoadEnd,
+ "unload": tile.onLoadEnd,
+ scope: this
+ });
+ },
+
+ /**
+ * Method: moveGriddedTiles
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ */
+ moveGriddedTiles: function(bounds) {
+ var buffer = this.buffer || 1;
+ while (true) {
+ var tlLayer = this.grid[0][0].position;
+ var tlViewPort =
+ this.map.getViewPortPxFromLayerPx(tlLayer);
+ if (tlViewPort.x > -this.tileSize.w * (buffer - 1)) {
+ this.shiftColumn(true);
+ } else if (tlViewPort.x < -this.tileSize.w * buffer) {
+ this.shiftColumn(false);
+ } else if (tlViewPort.y > -this.tileSize.h * (buffer - 1)) {
+ this.shiftRow(true);
+ } else if (tlViewPort.y < -this.tileSize.h * buffer) {
+ this.shiftRow(false);
+ } else {
+ break;
+ }
+ };
+ },
+
+ /**
+ * Method: shiftRow
+ * Shifty grid work
+ *
+ * Parameters:
+ * prepend - {Boolean} if true, prepend to beginning.
+ * if false, then append to end
+ */
+ shiftRow:function(prepend) {
+ var modelRowIndex = (prepend) ? 0 : (this.grid.length - 1);
+ var grid = this.grid;
+ var modelRow = grid[modelRowIndex];
+
+ var resolution = this.map.getResolution();
+ var deltaY = (prepend) ? -this.tileSize.h : this.tileSize.h;
+ var deltaLat = resolution * -deltaY;
+
+ var row = (prepend) ? grid.pop() : grid.shift();
+
+ for (var i=0, len=modelRow.length; i<len; i++) {
+ var modelTile = modelRow[i];
+ var bounds = modelTile.bounds.clone();
+ var position = modelTile.position.clone();
+ bounds.bottom = bounds.bottom + deltaLat;
+ bounds.top = bounds.top + deltaLat;
+ position.y = position.y + deltaY;
+ row[i].moveTo(bounds, position);
+ }
+
+ if (prepend) {
+ grid.unshift(row);
+ } else {
+ grid.push(row);
+ }
+ },
+
+ /**
+ * Method: shiftColumn
+ * Shift grid work in the other dimension
+ *
+ * Parameters:
+ * prepend - {Boolean} if true, prepend to beginning.
+ * if false, then append to end
+ */
+ shiftColumn: function(prepend) {
+ var deltaX = (prepend) ? -this.tileSize.w : this.tileSize.w;
+ var resolution = this.map.getResolution();
+ var deltaLon = resolution * deltaX;
+
+ for (var i=0, len=this.grid.length; i<len; i++) {
+ var row = this.grid[i];
+ var modelTileIndex = (prepend) ? 0 : (row.length - 1);
+ var modelTile = row[modelTileIndex];
+
+ var bounds = modelTile.bounds.clone();
+ var position = modelTile.position.clone();
+ bounds.left = bounds.left + deltaLon;
+ bounds.right = bounds.right + deltaLon;
+ position.x = position.x + deltaX;
+
+ var tile = prepend ? this.grid[i].pop() : this.grid[i].shift();
+ tile.moveTo(bounds, position);
+ if (prepend) {
+ row.unshift(tile);
+ } else {
+ row.push(tile);
+ }
+ }
+ },
+
+ /**
+ * Method: removeExcessTiles
+ * When the size of the map or the buffer changes, we may need to
+ * remove some excess rows and columns.
+ *
+ * Parameters:
+ * rows - {Integer} Maximum number of rows we want our grid to have.
+ * colums - {Integer} Maximum number of columns we want our grid to have.
+ */
+ removeExcessTiles: function(rows, columns) {
+
+ // remove extra rows
+ while (this.grid.length > rows) {
+ var row = this.grid.pop();
+ for (var i=0, l=row.length; i<l; i++) {
+ var tile = row[i];
+ this.removeTileMonitoringHooks(tile);
+ tile.destroy();
+ }
+ }
+
+ // remove extra columns
+ while (this.grid[0].length > columns) {
+ for (var i=0, l=this.grid.length; i<l; i++) {
+ var row = this.grid[i];
+ var tile = row.pop();
+ this.removeTileMonitoringHooks(tile);
+ tile.destroy();
+ }
+ }
+ },
+
+ /**
+ * Method: onMapResize
+ * For singleTile layers, this will set a new tile size according to the
+ * dimensions of the map pane.
+ */
+ onMapResize: function() {
+ if (this.singleTile) {
+ this.clearGrid();
+ this.setTileSize();
+ }
+ },
+
+ /**
+ * APIMethod: getTileBounds
+ * Returns The tile bounds for a layer given a pixel location.
+ *
+ * Parameters:
+ * viewPortPx - {<OpenLayers.Pixel>} The location in the viewport.
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} Bounds of the tile at the given pixel location.
+ */
+ getTileBounds: function(viewPortPx) {
+ var maxExtent = this.maxExtent;
+ var resolution = this.getResolution();
+ var tileMapWidth = resolution * this.tileSize.w;
+ var tileMapHeight = resolution * this.tileSize.h;
+ var mapPoint = this.getLonLatFromViewPortPx(viewPortPx);
+ var tileLeft = maxExtent.left + (tileMapWidth *
+ Math.floor((mapPoint.lon -
+ maxExtent.left) /
+ tileMapWidth));
+ var tileBottom = maxExtent.bottom + (tileMapHeight *
+ Math.floor((mapPoint.lat -
+ maxExtent.bottom) /
+ tileMapHeight));
+ return new OpenLayers.Bounds(tileLeft, tileBottom,
+ tileLeft + tileMapWidth,
+ tileBottom + tileMapHeight);
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.Grid"
+});
+/* ======================================================================
+ OpenLayers/Layer/WMS.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ * @requires OpenLayers/Tile/Image.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.WMS
+ * Instances of OpenLayers.Layer.WMS are used to display data from OGC Web
+ * Mapping Services. Create a new WMS layer with the <OpenLayers.Layer.WMS>
+ * constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.WMS = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+ /**
+ * Constant: DEFAULT_PARAMS
+ * {Object} Hashtable of default parameter key/value pairs
+ */
+ DEFAULT_PARAMS: { service: "WMS",
+ version: "1.1.1",
+ request: "GetMap",
+ styles: "",
+ exceptions: "application/vnd.ogc.se_inimage",
+ format: "image/jpeg"
+ },
+
+ /**
+ * Property: reproject
+ * *Deprecated*. See http://trac.openlayers.org/wiki/SphericalMercator
+ * for information on the replacement for this functionality.
+ * {Boolean} Try to reproject this layer if its coordinate reference system
+ * is different than that of the base layer. Default is true.
+ * Set this in the layer options. Should be set to false in
+ * most cases.
+ */
+ reproject: false,
+
+ /**
+ * APIProperty: isBaseLayer
+ * {Boolean} Default is true for WMS layer
+ */
+ isBaseLayer: true,
+
+ /**
+ * APIProperty: encodeBBOX
+ * {Boolean} Should the BBOX commas be encoded? The WMS spec says 'no',
+ * but some services want it that way. Default false.
+ */
+ encodeBBOX: false,
+
+ /**
+ * APIProperty: noMagic
+ * {Boolean} If true, the image format will not be automagicaly switched
+ * from image/jpeg to image/png or image/gif when using
+ * TRANSPARENT=TRUE. Also isBaseLayer will not changed by the
+ * constructor. Default false.
+ */
+ noMagic: false,
+
+ /**
+ * Property: yx
+ * {Object} Keys in this object are EPSG codes for which the axis order
+ * is to be reversed (yx instead of xy, LatLon instead of LonLat), with
+ * true as value. This is only relevant for WMS versions >= 1.3.0.
+ */
+ yx: {'EPSG:4326': true},
+
+ /**
+ * Constructor: OpenLayers.Layer.WMS
+ * Create a new WMS layer object
+ *
+ * Example:
+ * (code)
+ * var wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
+ * "http://wms.jpl.nasa.gov/wms.cgi",
+ * {layers: "modis,global_mosaic"});
+ * (end)
+ *
+ * Parameters:
+ * name - {String} A name for the layer
+ * url - {String} Base url for the WMS
+ * (e.g. http://wms.jpl.nasa.gov/wms.cgi)
+ * params - {Object} An object with key/value pairs representing the
+ * GetMap query string parameters and parameter values.
+ * options - {Ojbect} Hashtable of extra options to tag onto the layer
+ */
+ initialize: function(name, url, params, options) {
+ var newArguments = [];
+ //uppercase params
+ params = OpenLayers.Util.upperCaseObject(params);
+ if (parseFloat(params.VERSION) >= 1.3 && !params.EXCEPTIONS) {
+ params.EXCEPTIONS = "INIMAGE";
+ }
+ newArguments.push(name, url, params, options);
+ OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
+ OpenLayers.Util.applyDefaults(
+ this.params,
+ OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)
+ );
+
+
+ //layer is transparent
+ if (!this.noMagic && this.params.TRANSPARENT &&
+ this.params.TRANSPARENT.toString().toLowerCase() == "true") {
+
+ // unless explicitly set in options, make layer an overlay
+ if ( (options == null) || (!options.isBaseLayer) ) {
+ this.isBaseLayer = false;
+ }
+
+ // jpegs can never be transparent, so intelligently switch the
+ // format, depending on teh browser's capabilities
+ if (this.params.FORMAT == "image/jpeg") {
+ this.params.FORMAT = OpenLayers.Util.alphaHack() ? "image/gif"
+ : "image/png";
+ }
+ }
+
+ },
+
+ /**
+ * Method: destroy
+ * Destroy this layer
+ */
+ destroy: function() {
+ // for now, nothing special to do here.
+ OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);
+ },
+
+
+ /**
+ * Method: clone
+ * Create a clone of this layer
+ *
+ * Returns:
+ * {<OpenLayers.Layer.WMS>} An exact clone of this layer
+ */
+ clone: function (obj) {
+
+ if (obj == null) {
+ obj = new OpenLayers.Layer.WMS(this.name,
+ this.url,
+ this.params,
+ this.getOptions());
+ }
+
+ //get all additions from superclasses
+ obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+ // copy/set any non-init, non-simple values here
+
+ return obj;
+ },
+
+ /**
+ * APIMethod: reverseAxisOrder
+ * Returns true if the axis order is reversed for the WMS version and
+ * projection of the layer.
+ *
+ * Returns:
+ * {Boolean} true if the axis order is reversed, false otherwise.
+ */
+ reverseAxisOrder: function() {
+ return (parseFloat(this.params.VERSION) >= 1.3 &&
+ !!this.yx[this.map.getProjectionObject().getCode()]);
+ },
+
+ /**
+ * Method: getURL
+ * Return a GetMap query string for this layer
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the
+ * request.
+ *
+ * Returns:
+ * {String} A string with the layer's url and parameters and also the
+ * passed-in bounds and appropriate tile size specified as
+ * parameters.
+ */
+ getURL: function (bounds) {
+ bounds = this.adjustBounds(bounds);
+
+ var imageSize = this.getImageSize();
+ var newParams = {};
+ // WMS 1.3 introduced axis order
+ var reverseAxisOrder = this.reverseAxisOrder();
+ newParams.BBOX = this.encodeBBOX ?
+ bounds.toBBOX(null, reverseAxisOrder) :
+ bounds.toArray(reverseAxisOrder);
+ newParams.WIDTH = imageSize.w;
+ newParams.HEIGHT = imageSize.h;
+ var requestString = this.getFullRequestString(newParams);
+ return requestString;
+ },
+
+ /**
+ * Method: addTile
+ * addTile creates a tile, initializes it, and adds it to the layer div.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * position - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+ */
+ addTile:function(bounds,position) {
+ return new OpenLayers.Tile.Image(this, position, bounds,
+ null, this.tileSize, this.tileOptions);
+ },
+
+ /**
+ * APIMethod: mergeNewParams
+ * Catch changeParams and uppercase the new params to be merged in
+ * before calling changeParams on the super class.
+ *
+ * Once params have been changed, the tiles will be reloaded with
+ * the new parameters.
+ *
+ * Parameters:
+ * newParams - {Object} Hashtable of new params to use
+ */
+ mergeNewParams:function(newParams) {
+ var upperParams = OpenLayers.Util.upperCaseObject(newParams);
+ var newArguments = [upperParams];
+ return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,
+ newArguments);
+ },
+
+ /**
+ * APIMethod: getFullRequestString
+ * Combine the layer's url with its params and these newParams.
+ *
+ * Add the SRS parameter from projection -- this is probably
+ * more eloquently done via a setProjection() method, but this
+ * works for now and always.
+ *
+ * Parameters:
+ * newParams - {Object}
+ * altUrl - {String} Use this as the url instead of the layer's url
+ *
+ * Returns:
+ * {String}
+ */
+ getFullRequestString:function(newParams, altUrl) {
+ var mapProjection = this.map.getProjectionObject();
+ var projectionCode = this.projection.equals(mapProjection) ?
+ this.projection.getCode() :
+ mapProjection.getCode();
+ var value = (projectionCode == "none") ? null : projectionCode
+ if (parseFloat(this.params.VERSION) >= 1.3) {
+ this.params.CRS = value;
+ } else {
+ this.params.SRS = value;
+ }
+
+ return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(
+ this, arguments);
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.WMS"
+});
+/* ======================================================================
+ OpenLayers/StyleMap.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/Style.js
+ * @requires OpenLayers/Feature/Vector.js
+ */
+
+/**
+ * Class: OpenLayers.StyleMap
+ */
+OpenLayers.StyleMap = OpenLayers.Class({
+
+ /**
+ * Property: styles
+ * Hash of {<OpenLayers.Style>}, keyed by names of well known
+ * rendering intents (e.g. "default", "temporary", "select", "delete").
+ */
+ styles: null,
+
+ /**
+ * Property: extendDefault
+ * {Boolean} if true, every render intent will extend the symbolizers
+ * specified for the "default" intent at rendering time. Otherwise, every
+ * rendering intent will be treated as a completely independent style.
+ */
+ extendDefault: true,
+
+ /**
+ * Constructor: OpenLayers.StyleMap
+ *
+ * Parameters:
+ * style - {Object} Optional. Either a style hash, or a style object, or
+ * a hash of style objects (style hashes) keyed by rendering
+ * intent. If just one style hash or style object is passed,
+ * this will be used for all known render intents (default,
+ * select, temporary)
+ * options - {Object} optional hash of additional options for this
+ * instance
+ */
+ initialize: function (style, options) {
+ this.styles = {
+ "default": new OpenLayers.Style(
+ OpenLayers.Feature.Vector.style["default"]),
+ "select": new OpenLayers.Style(
+ OpenLayers.Feature.Vector.style["select"]),
+ "temporary": new OpenLayers.Style(
+ OpenLayers.Feature.Vector.style["temporary"]),
+ "delete": new OpenLayers.Style(
+ OpenLayers.Feature.Vector.style["delete"])
+ };
+
+ // take whatever the user passed as style parameter and convert it
+ // into parts of stylemap.
+ if(style instanceof OpenLayers.Style) {
+ // user passed a style object
+ this.styles["default"] = style;
+ this.styles["select"] = style;
+ this.styles["temporary"] = style;
+ this.styles["delete"] = style;
+ } else if(typeof style == "object") {
+ for(var key in style) {
+ if(style[key] instanceof OpenLayers.Style) {
+ // user passed a hash of style objects
+ this.styles[key] = style[key];
+ } else if(typeof style[key] == "object") {
+ // user passsed a hash of style hashes
+ this.styles[key] = new OpenLayers.Style(style[key]);
+ } else {
+ // user passed a style hash (i.e. symbolizer)
+ this.styles["default"] = new OpenLayers.Style(style);
+ this.styles["select"] = new OpenLayers.Style(style);
+ this.styles["temporary"] = new OpenLayers.Style(style);
+ this.styles["delete"] = new OpenLayers.Style(style);
+ break;
+ }
+ }
+ }
+ OpenLayers.Util.extend(this, options);
+ },
+
+ /**
+ * Method: destroy
+ */
+ destroy: function() {
+ for(var key in this.styles) {
+ this.styles[key].destroy();
+ }
+ this.styles = null;
+ },
+
+ /**
+ * Method: createSymbolizer
+ * Creates the symbolizer for a feature for a render intent.
+ *
+ * Parameters:
+ * feature - {<OpenLayers.Feature>} The feature to evaluate the rules
+ * of the intended style against.
+ * intent - {String} The intent determines the symbolizer that will be
+ * used to draw the feature. Well known intents are "default"
+ * (for just drawing the features), "select" (for selected
+ * features) and "temporary" (for drawing features).
+ *
+ * Returns:
+ * {Object} symbolizer hash
+ */
+ createSymbolizer: function(feature, intent) {
+ if(!feature) {
+ feature = new OpenLayers.Feature.Vector();
+ }
+ if(!this.styles[intent]) {
+ intent = "default";
+ }
+ feature.renderIntent = intent;
+ var defaultSymbolizer = {};
+ if(this.extendDefault && intent != "default") {
+ defaultSymbolizer = this.styles["default"].createSymbolizer(feature);
+ }
+ return OpenLayers.Util.extend(defaultSymbolizer,
+ this.styles[intent].createSymbolizer(feature));
+ },
+
+ /**
+ * Method: addUniqueValueRules
+ * Convenience method to create comparison rules for unique values of a
+ * property. The rules will be added to the style object for a specified
+ * rendering intent. This method is a shortcut for creating something like
+ * the "unique value legends" familiar from well known desktop GIS systems
+ *
+ * Parameters:
+ * renderIntent - {String} rendering intent to add the rules to
+ * property - {String} values of feature attributes to create the
+ * rules for
+ * symbolizers - {Object} Hash of symbolizers, keyed by the desired
+ * property values
+ * context - {Object} An optional object with properties that
+ * symbolizers' property values should be evaluated
+ * against. If no context is specified, feature.attributes
+ * will be used
+ */
+ addUniqueValueRules: function(renderIntent, property, symbolizers, context) {
+ var rules = [];
+ for (var value in symbolizers) {
+ rules.push(new OpenLayers.Rule({
+ symbolizer: symbolizers[value],
+ context: context,
+ filter: new OpenLayers.Filter.Comparison({
+ type: OpenLayers.Filter.Comparison.EQUAL_TO,
+ property: property,
+ value: value
+ })
+ }));
+ }
+ this.styles[renderIntent].addRules(rules);
+ },
+
+ CLASS_NAME: "OpenLayers.StyleMap"
+});
+/* ======================================================================
+ OpenLayers/Layer/Vector.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Layer.js
+ * @requires OpenLayers/Renderer.js
+ * @requires OpenLayers/StyleMap.js
+ * @requires OpenLayers/Feature/Vector.js
+ * @requires OpenLayers/Console.js
+ * @requires OpenLayers/Lang.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.Vector
+ * Instances of OpenLayers.Layer.Vector are used to render vector data from
+ * a variety of sources. Create a new vector layer with the
+ * <OpenLayers.Layer.Vector> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer>
+ */
+OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
+
+ /**
+ * Constant: EVENT_TYPES
+ * {Array(String)} Supported application event types. Register a listener
+ * for a particular event with the following syntax:
+ * (code)
+ * layer.events.register(type, obj, listener);
+ * (end)
+ *
+ * Listeners will be called with a reference to an event object. The
+ * properties of this event depends on exactly what happened.
+ *
+ * All event objects have at least the following properties:
+ * object - {Object} A reference to layer.events.object.
+ * element - {DOMElement} A reference to layer.events.element.
+ *
+ * Supported map event types (in addition to those from <OpenLayers.Layer>):
+ * beforefeatureadded - Triggered before a feature is added. Listeners
+ * will receive an object with a *feature* property referencing the
+ * feature to be added. To stop the feature from being added, a
+ * listener should return false.
+ * beforefeaturesadded - Triggered before an array of features is added.
+ * Listeners will receive an object with a *features* property
+ * referencing the feature to be added. To stop the features from
+ * being added, a listener should return false.
+ * featureadded - Triggered after a feature is added. The event
+ * object passed to listeners will have a *feature* property with a
+ * reference to the added feature.
+ * featuresadded - Triggered after features are added. The event
+ * object passed to listeners will have a *features* property with a
+ * reference to an array of added features.
+ * beforefeatureremoved - Triggered before a feature is removed. Listeners
+ * will receive an object with a *feature* property referencing the
+ * feature to be removed.
+ * beforefeaturesremoved - Triggered before multiple features are removed.
+ * Listeners will receive an object with a *features* property
+ * referencing the features to be removed.
+ * featureremoved - Triggerd after a feature is removed. The event
+ * object passed to listeners will have a *feature* property with a
+ * reference to the removed feature.
+ * featuresremoved - Triggered after features are removed. The event
+ * object passed to listeners will have a *features* property with a
+ * reference to an array of removed features.
+ * beforefeatureselected - Triggered after a feature is selected. Listeners
+ * will receive an object with a *feature* property referencing the
+ * feature to be selected. To stop the feature from being selectd, a
+ * listener should return false.
+ * featureselected - Triggered after a feature is selected. Listeners
+ * will receive an object with a *feature* property referencing the
+ * selected feature.
+ * featureunselected - Triggered after a feature is unselected.
+ * Listeners will receive an object with a *feature* property
+ * referencing the unselected feature.
+ * beforefeaturemodified - Triggered when a feature is selected to
+ * be modified. Listeners will receive an object with a *feature*
+ * property referencing the selected feature.
+ * featuremodified - Triggered when a feature has been modified.
+ * Listeners will receive an object with a *feature* property referencing
+ * the modified feature.
+ * afterfeaturemodified - Triggered when a feature is finished being modified.
+ * Listeners will receive an object with a *feature* property referencing
+ * the modified feature.
+ * vertexmodified - Triggered when a vertex within any feature geometry
+ * has been modified. Listeners will receive an object with a
+ * *feature* property referencing the modified feature, a *vertex*
+ * property referencing the vertex modified (always a point geometry),
+ * and a *pixel* property referencing the pixel location of the
+ * modification.
+ * vertexremoved - Triggered when a vertex within any feature geometry
+ * has been deleted. Listeners will receive an object with a
+ * *feature* property referencing the modified feature, a *vertex*
+ * property referencing the vertex modified (always a point geometry),
+ * and a *pixel* property referencing the pixel location of the
+ * removal.
+ * sketchstarted - Triggered when a feature sketch bound for this layer
+ * is started. Listeners will receive an object with a *feature*
+ * property referencing the new sketch feature and a *vertex* property
+ * referencing the creation point.
+ * sketchmodified - Triggered when a feature sketch bound for this layer
+ * is modified. Listeners will receive an object with a *vertex*
+ * property referencing the modified vertex and a *feature* property
+ * referencing the sketch feature.
+ * sketchcomplete - Triggered when a feature sketch bound for this layer
+ * is complete. Listeners will receive an object with a *feature*
+ * property referencing the sketch feature. By returning false, a
+ * listener can stop the sketch feature from being added to the layer.
+ * refresh - Triggered when something wants a strategy to ask the protocol
+ * for a new set of features.
+ */
+ EVENT_TYPES: ["beforefeatureadded", "beforefeaturesadded",
+ "featureadded", "featuresadded", "beforefeatureremoved",
+ "beforefeaturesremoved", "featureremoved", "featuresremoved",
+ "beforefeatureselected", "featureselected", "featureunselected",
+ "beforefeaturemodified", "featuremodified", "afterfeaturemodified",
+ "vertexmodified", "vertexremoved", "sketchstarted",
+ "sketchmodified", "sketchcomplete", "refresh"],
+
+ /**
+ * APIProperty: isBaseLayer
+ * {Boolean} The layer is a base layer. Default is false. Set this property
+ * in the layer options.
+ */
+ isBaseLayer: false,
+
+ /**
+ * APIProperty: isFixed
+ * {Boolean} Whether the layer remains in one place while dragging the
+ * map.
+ */
+ isFixed: false,
+
+ /**
+ * APIProperty: features
+ * {Array(<OpenLayers.Feature.Vector>)}
+ */
+ features: null,
+
+ /**
+ * Property: filter
+ * {<OpenLayers.Filter>} The filter set in this layer,
+ * a strategy launching read requests can combined
+ * this filter with its own filter.
+ */
+ filter: null,
+
+ /**
+ * Property: selectedFeatures
+ * {Array(<OpenLayers.Feature.Vector>)}
+ */
+ selectedFeatures: null,
+
+ /**
+ * Property: unrenderedFeatures
+ * {Object} hash of features, keyed by feature.id, that the renderer
+ * failed to draw
+ */
+ unrenderedFeatures: null,
+
+ /**
+ * APIProperty: reportError
+ * {Boolean} report friendly error message when loading of renderer
+ * fails.
+ */
+ reportError: true,
+
+ /**
+ * APIProperty: style
+ * {Object} Default style for the layer
+ */
+ style: null,
+
+ /**
+ * Property: styleMap
+ * {<OpenLayers.StyleMap>}
+ */
+ styleMap: null,
+
+ /**
+ * Property: strategies
+ * {Array(<OpenLayers.Strategy>})} Optional list of strategies for the layer.
+ */
+ strategies: null,
+
+ /**
+ * Property: protocol
+ * {<OpenLayers.Protocol>} Optional protocol for the layer.
+ */
+ protocol: null,
+
+ /**
+ * Property: renderers
+ * {Array(String)} List of supported Renderer classes. Add to this list to
+ * add support for additional renderers. This list is ordered:
+ * the first renderer which returns true for the 'supported()'
+ * method will be used, if not defined in the 'renderer' option.
+ */
+ renderers: ['SVG', 'VML', 'Canvas'],
+
+ /**
+ * Property: renderer
+ * {<OpenLayers.Renderer>}
+ */
+ renderer: null,
+
+ /**
+ * APIProperty: rendererOptions
+ * {Object} Options for the renderer. See {<OpenLayers.Renderer>} for
+ * supported options.
+ */
+ rendererOptions: null,
+
+ /**
+ * APIProperty: geometryType
+ * {String} geometryType allows you to limit the types of geometries this
+ * layer supports. This should be set to something like
+ * "OpenLayers.Geometry.Point" to limit types.
+ */
+ geometryType: null,
+
+ /**
+ * Property: drawn
+ * {Boolean} Whether the Vector Layer features have been drawn yet.
+ */
+ drawn: false,
+
+ /**
+ * Constructor: OpenLayers.Layer.Vector
+ * Create a new vector layer
+ *
+ * Parameters:
+ * name - {String} A name for the layer
+ * options - {Object} Optional object with non-default properties to set on
+ * the layer.
+ *
+ * Returns:
+ * {<OpenLayers.Layer.Vector>} A new vector layer
+ */
+ initialize: function(name, options) {
+
+ // concatenate events specific to vector with those from the base
+ this.EVENT_TYPES =
+ OpenLayers.Layer.Vector.prototype.EVENT_TYPES.concat(
+ OpenLayers.Layer.prototype.EVENT_TYPES
+ );
+
+ OpenLayers.Layer.prototype.initialize.apply(this, arguments);
+
+ // allow user-set renderer, otherwise assign one
+ if (!this.renderer || !this.renderer.supported()) {
+ this.assignRenderer();
+ }
+
+ // if no valid renderer found, display error
+ if (!this.renderer || !this.renderer.supported()) {
+ this.renderer = null;
+ this.displayError();
+ }
+
+ if (!this.styleMap) {
+ this.styleMap = new OpenLayers.StyleMap();
+ }
+
+ this.features = [];
+ this.selectedFeatures = [];
+ this.unrenderedFeatures = {};
+
+ // Allow for custom layer behavior
+ if(this.strategies){
+ for(var i=0, len=this.strategies.length; i<len; i++) {
+ this.strategies[i].setLayer(this);
+ }
+ }
+
+ },
+
+ /**
+ * APIMethod: destroy
+ * Destroy this layer
+ */
+ destroy: function() {
+ if (this.strategies) {
+ var strategy, i, len;
+ for(i=0, len=this.strategies.length; i<len; i++) {
+ strategy = this.strategies[i];
+ if(strategy.autoDestroy) {
+ strategy.destroy();
+ }
+ }
+ this.strategies = null;
+ }
+ if (this.protocol) {
+ if(this.protocol.autoDestroy) {
+ this.protocol.destroy();
+ }
+ this.protocol = null;
+ }
+ this.destroyFeatures();
+ this.features = null;
+ this.selectedFeatures = null;
+ this.unrenderedFeatures = null;
+ if (this.renderer) {
+ this.renderer.destroy();
+ }
+ this.renderer = null;
+ this.geometryType = null;
+ this.drawn = null;
+ OpenLayers.Layer.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: clone
+ * Create a clone of this layer.
+ *
+ * Note: Features of the layer are also cloned.
+ *
+ * Returns:
+ * {<OpenLayers.Layer.Vector>} An exact clone of this layer
+ */
+ clone: function (obj) {
+
+ if (obj == null) {
+ obj = new OpenLayers.Layer.Vector(this.name, this.getOptions());
+ }
+
+ //get all additions from superclasses
+ obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]);
+
+ // copy/set any non-init, non-simple values here
+ var features = this.features;
+ var len = features.length;
+ var clonedFeatures = new Array(len);
+ for(var i=0; i<len; ++i) {
+ clonedFeatures[i] = features[i].clone();
+ }
+ obj.features = clonedFeatures;
+
+ return obj;
+ },
+
+ /**
+ * Method: refresh
+ * Ask the layer to request features again and redraw them. Triggers
+ * the refresh event if the layer is in range and visible.
+ *
+ * Parameters:
+ * obj - {Object} Optional object with properties for any listener of
+ * the refresh event.
+ */
+ refresh: function(obj) {
+ if(this.calculateInRange() && this.visibility) {
+ this.events.triggerEvent("refresh", obj);
+ }
+ },
+
+ /**
+ * Method: assignRenderer
+ * Iterates through the available renderer implementations and selects
+ * and assigns the first one whose "supported()" function returns true.
+ */
+ assignRenderer: function() {
+ for (var i=0, len=this.renderers.length; i<len; i++) {
+ var rendererClass = this.renderers[i];
+ var renderer = (typeof rendererClass == "function") ?
+ rendererClass :
+ OpenLayers.Renderer[rendererClass];
+ if (renderer && renderer.prototype.supported()) {
+ this.renderer = new renderer(this.div, this.rendererOptions);
+ break;
+ }
+ }
+ },
+
+ /**
+ * Method: displayError
+ * Let the user know their browser isn't supported.
+ */
+ displayError: function() {
+ if (this.reportError) {
+ OpenLayers.Console.userError(OpenLayers.i18n("browserNotSupported",
+ {'renderers':this.renderers.join("\n")}));
+ }
+ },
+
+ /**
+ * Method: setMap
+ * The layer has been added to the map.
+ *
+ * If there is no renderer set, the layer can't be used. Remove it.
+ * Otherwise, give the renderer a reference to the map and set its size.
+ *
+ * Parameters:
+ * map - {<OpenLayers.Map>}
+ */
+ setMap: function(map) {
+ OpenLayers.Layer.prototype.setMap.apply(this, arguments);
+
+ if (!this.renderer) {
+ this.map.removeLayer(this);
+ } else {
+ this.renderer.map = this.map;
+ this.renderer.setSize(this.map.getSize());
+ }
+ },
+
+ /**
+ * Method: afterAdd
+ * Called at the end of the map.addLayer sequence. At this point, the map
+ * will have a base layer. Any autoActivate strategies will be
+ * activated here.
+ */
+ afterAdd: function() {
+ if(this.strategies) {
+ var strategy, i, len;
+ for(i=0, len=this.strategies.length; i<len; i++) {
+ strategy = this.strategies[i];
+ if(strategy.autoActivate) {
+ strategy.activate();
+ }
+ }
+ }
+ },
+
+ /**
+ * Method: removeMap
+ * The layer has been removed from the map.
+ *
+ * Parameters:
+ * map - {<OpenLayers.Map>}
+ */
+ removeMap: function(map) {
+ this.drawn = false;
+ if(this.strategies) {
+ var strategy, i, len;
+ for(i=0, len=this.strategies.length; i<len; i++) {
+ strategy = this.strategies[i];
+ if(strategy.autoActivate) {
+ strategy.deactivate();
+ }
+ }
+ }
+ },
+
+ /**
+ * Method: onMapResize
+ * Notify the renderer of the change in size.
+ *
+ */
+ onMapResize: function() {
+ OpenLayers.Layer.prototype.onMapResize.apply(this, arguments);
+ this.renderer.setSize(this.map.getSize());
+ },
+
+ /**
+ * Method: moveTo
+ * Reset the vector layer's div so that it once again is lined up with
+ * the map. Notify the renderer of the change of extent, and in the
+ * case of a change of zoom level (resolution), have the
+ * renderer redraw features.
+ *
+ * If the layer has not yet been drawn, cycle through the layer's
+ * features and draw each one.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * zoomChanged - {Boolean}
+ * dragging - {Boolean}
+ */
+ moveTo: function(bounds, zoomChanged, dragging) {
+ OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
+
+ var coordSysUnchanged = true;
+
+ if (!dragging) {
+ this.renderer.root.style.visibility = "hidden";
+
+ this.div.style.left = -parseInt(this.map.layerContainerDiv.style.left) + "px";
+ this.div.style.top = -parseInt(this.map.layerContainerDiv.style.top) + "px";
+ var extent = this.map.getExtent();
+ coordSysUnchanged = this.renderer.setExtent(extent, zoomChanged);
+
+ this.renderer.root.style.visibility = "visible";
+
+ // Force a reflow on gecko based browsers to prevent jump/flicker.
+ // This seems to happen on only certain configurations; it was originally
+ // noticed in FF 2.0 and Linux.
+ if (OpenLayers.IS_GECKO === true) {
+ this.div.scrollLeft = this.div.scrollLeft;
+ }
+
+ if(!zoomChanged && coordSysUnchanged) {
+ for(var i in this.unrenderedFeatures) {
+ var feature = this.unrenderedFeatures[i];
+ this.drawFeature(feature);
+ }
+ }
+ }
+
+ if (!this.drawn || zoomChanged || !coordSysUnchanged) {
+ this.drawn = true;
+ var feature;
+ for(var i=0, len=this.features.length; i<len; i++) {
+ this.renderer.locked = (i !== (len - 1));
+ feature = this.features[i];
+ this.drawFeature(feature);
+ }
+ }
+ },
+
+ /**
+ * APIMethod: display
+ * Hide or show the Layer
+ *
+ * Parameters:
+ * display - {Boolean}
+ */
+ display: function(display) {
+ OpenLayers.Layer.prototype.display.apply(this, arguments);
+ // we need to set the display style of the root in case it is attached
+ // to a foreign layer
+ var currentDisplay = this.div.style.display;
+ if(currentDisplay != this.renderer.root.style.display) {
+ this.renderer.root.style.display = currentDisplay;
+ }
+ },
+
+ /**
+ * APIMethod: addFeatures
+ * Add Features to the layer.
+ *
+ * Parameters:
+ * features - {Array(<OpenLayers.Feature.Vector>)}
+ * options - {Object}
+ */
+ addFeatures: function(features, options) {
+ if (!(features instanceof Array)) {
+ features = [features];
+ }
+
+ var notify = !options || !options.silent;
+ if(notify) {
+ var event = {features: features};
+ var ret = this.events.triggerEvent("beforefeaturesadded", event);
+ if(ret === false) {
+ return;
+ }
+ features = event.features;
+ }
+
+ // Track successfully added features for featuresadded event, since
+ // beforefeatureadded can veto single features.
+ var featuresAdded = [];
+ for (var i=0, len=features.length; i<len; i++) {
+ if (i != (features.length - 1)) {
+ this.renderer.locked = true;
+ } else {
+ this.renderer.locked = false;
+ }
+ var feature = features[i];
+
+ if (this.geometryType &&
+ !(feature.geometry instanceof this.geometryType)) {
+ var throwStr = OpenLayers.i18n('componentShouldBe',
+ {'geomType':this.geometryType.prototype.CLASS_NAME});
+ throw throwStr;
+ }
+
+ //give feature reference to its layer
+ feature.layer = this;
+
+ if (!feature.style && this.style) {
+ feature.style = OpenLayers.Util.extend({}, this.style);
+ }
+
+ if (notify) {
+ if(this.events.triggerEvent("beforefeatureadded",
+ {feature: feature}) === false) {
+ continue;
+ };
+ this.preFeatureInsert(feature);
+ }
+
+ featuresAdded.push(feature);
+ this.features.push(feature);
+ this.drawFeature(feature);
+
+ if (notify) {
+ this.events.triggerEvent("featureadded", {
+ feature: feature
+ });
+ this.onFeatureInsert(feature);
+ }
+ }
+
+ if(notify) {
+ this.events.triggerEvent("featuresadded", {features: featuresAdded});
+ }
+ },
+
+
+ /**
+ * APIMethod: removeFeatures
+ * Remove features from the layer. This erases any drawn features and
+ * removes them from the layer's control. The beforefeatureremoved
+ * and featureremoved events will be triggered for each feature. The
+ * featuresremoved event will be triggered after all features have
+ * been removed. To supress event triggering, use the silent option.
+ *
+ * Parameters:
+ * features - {Array(<OpenLayers.Feature.Vector>)} List of features to be
+ * removed.
+ * options - {Object} Optional properties for changing behavior of the
+ * removal.
+ *
+ * Valid options:
+ * silent - {Boolean} Supress event triggering. Default is false.
+ */
+ removeFeatures: function(features, options) {
+ if(!features || features.length === 0) {
+ return;
+ }
+ if (features === this.features) {
+ return this.removeAllFeatures(options);
+ }
+ if (!(features instanceof Array)) {
+ features = [features];
+ }
+ if (features === this.selectedFeatures) {
+ features = features.slice();
+ }
+
+ var notify = !options || !options.silent;
+
+ if (notify) {
+ this.events.triggerEvent(
+ "beforefeaturesremoved", {features: features}
+ );
+ }
+
+ for (var i = features.length - 1; i >= 0; i--) {
+ // We remain locked so long as we're not at 0
+ // and the 'next' feature has a geometry. We do the geometry check
+ // because if all the features after the current one are 'null', we
+ // won't call eraseGeometry, so we break the 'renderer functions
+ // will always be called with locked=false *last*' rule. The end result
+ // is a possible gratiutious unlocking to save a loop through the rest
+ // of the list checking the remaining features every time. So long as
+ // null geoms are rare, this is probably okay.
+ if (i != 0 && features[i-1].geometry) {
+ this.renderer.locked = true;
+ } else {
+ this.renderer.locked = false;
+ }
+
+ var feature = features[i];
+ delete this.unrenderedFeatures[feature.id];
+
+ if (notify) {
+ this.events.triggerEvent("beforefeatureremoved", {
+ feature: feature
+ });
+ }
+
+ this.features = OpenLayers.Util.removeItem(this.features, feature);
+ // feature has no layer at this point
+ feature.layer = null;
+
+ if (feature.geometry) {
+ this.renderer.eraseFeatures(feature);
+ }
+
+ //in the case that this feature is one of the selected features,
+ // remove it from that array as well.
+ if (OpenLayers.Util.indexOf(this.selectedFeatures, feature) != -1){
+ OpenLayers.Util.removeItem(this.selectedFeatures, feature);
+ }
+
+ if (notify) {
+ this.events.triggerEvent("featureremoved", {
+ feature: feature
+ });
+ }
+ }
+
+ if (notify) {
+ this.events.triggerEvent("featuresremoved", {features: features});
+ }
+ },
+
+ /**
+ * APIMethod: removeAllFeatures
+ * Remove all features from the layer.
+ *
+ * Parameters:
+ * options - {Object} Optional properties for changing behavior of the
+ * removal.
+ *
+ * Valid options:
+ * silent - {Boolean} Supress event triggering. Default is false.
+ */
+ removeAllFeatures: function(options) {
+ var notify = !options || !options.silent;
+ var features = this.features;
+ if (notify) {
+ this.events.triggerEvent(
+ "beforefeaturesremoved", {features: features}
+ );
+ }
+ var feature;
+ for (var i = features.length-1; i >= 0; i--) {
+ feature = features[i];
+ if (notify) {
+ this.events.triggerEvent("beforefeatureremoved", {
+ feature: feature
+ });
+ }
+ feature.layer = null;
+ if (notify) {
+ this.events.triggerEvent("featureremoved", {
+ feature: feature
+ });
+ }
+ }
+ this.renderer.clear();
+ this.features = [];
+ this.unrenderedFeatures = {};
+ this.selectedFeatures = [];
+ if (notify) {
+ this.events.triggerEvent("featuresremoved", {features: features});
+ }
+ },
+
+ /**
+ * APIMethod: destroyFeatures
+ * Erase and destroy features on the layer.
+ *
+ * Parameters:
+ * features - {Array(<OpenLayers.Feature.Vector>)} An optional array of
+ * features to destroy. If not supplied, all features on the layer
+ * will be destroyed.
+ * options - {Object}
+ */
+ destroyFeatures: function(features, options) {
+ var all = (features == undefined); // evaluates to true if
+ // features is null
+ if(all) {
+ features = this.features;
+ }
+ if(features) {
+ this.removeFeatures(features, options);
+ for(var i=features.length-1; i>=0; i--) {
+ features[i].destroy();
+ }
+ }
+ },
+
+ /**
+ * APIMethod: drawFeature
+ * Draw (or redraw) a feature on the layer. If the optional style argument
+ * is included, this style will be used. If no style is included, the
+ * feature's style will be used. If the feature doesn't have a style,
+ * the layer's style will be used.
+ *
+ * This function is not designed to be used when adding features to
+ * the layer (use addFeatures instead). It is meant to be used when
+ * the style of a feature has changed, or in some other way needs to
+ * visually updated *after* it has already been added to a layer. You
+ * must add the feature to the layer for most layer-related events to
+ * happen.
+ *
+ * Parameters:
+ * feature - {<OpenLayers.Feature.Vector>}
+ * style - {String | Object} Named render intent or full symbolizer object.
+ */
+ drawFeature: function(feature, style) {
+ // don't try to draw the feature with the renderer if the layer is not
+ // drawn itself
+ if (!this.drawn) {
+ return
+ }
+ if (typeof style != "object") {
+ if(!style && feature.state === OpenLayers.State.DELETE) {
+ style = "delete";
+ }
+ var renderIntent = style || feature.renderIntent;
+ style = feature.style || this.style;
+ if (!style) {
+ style = this.styleMap.createSymbolizer(feature, renderIntent);
+ }
+ }
+
+ if (!this.renderer.drawFeature(feature, style)) {
+ this.unrenderedFeatures[feature.id] = feature;
+ } else {
+ delete this.unrenderedFeatures[feature.id];
+ };
+ },
+
+ /**
+ * Method: eraseFeatures
+ * Erase features from the layer.
+ *
+ * Parameters:
+ * features - {Array(<OpenLayers.Feature.Vector>)}
+ */
+ eraseFeatures: function(features) {
+ this.renderer.eraseFeatures(features);
+ },
+
+ /**
+ * Method: getFeatureFromEvent
+ * Given an event, return a feature if the event occurred over one.
+ * Otherwise, return null.
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {<OpenLayers.Feature.Vector>} A feature if one was under the event.
+ */
+ getFeatureFromEvent: function(evt) {
+ if (!this.renderer) {
+ OpenLayers.Console.error(OpenLayers.i18n("getFeatureError"));
+ return null;
+ }
+ var featureId = this.renderer.getFeatureIdFromEvent(evt);
+ return this.getFeatureById(featureId);
+ },
+
+ /**
+ * APIMethod: getFeatureBy
+ * Given a property value, return the feature if it exists in the features array
+ *
+ * Parameters:
+ * property - {String}
+ * value - {String}
+ *
+ * Returns:
+ * {<OpenLayers.Feature.Vector>} A feature corresponding to the given
+ * property value or null if there is no such feature.
+ */
+ getFeatureBy: function(property, value) {
+ //TBD - would it be more efficient to use a hash for this.features?
+ var feature = null;
+ for(var i=0, len=this.features.length; i<len; ++i) {
+ if(this.features[i][property] == value) {
+ feature = this.features[i];
+ break;
+ }
+ }
+ return feature;
+ },
+
+ /**
+ * APIMethod: getFeatureById
+ * Given a feature id, return the feature if it exists in the features array
+ *
+ * Parameters:
+ * featureId - {String}
+ *
+ * Returns:
+ * {<OpenLayers.Feature.Vector>} A feature corresponding to the given
+ * featureId or null if there is no such feature.
+ */
+ getFeatureById: function(featureId) {
+ return this.getFeatureBy('id', featureId);
+ },
+
+ /**
+ * APIMethod: getFeatureByFid
+ * Given a feature fid, return the feature if it exists in the features array
+ *
+ * Parameters:
+ * featureFid - {String}
+ *
+ * Returns:
+ * {<OpenLayers.Feature.Vector>} A feature corresponding to the given
+ * featureFid or null if there is no such feature.
+ */
+ getFeatureByFid: function(featureFid) {
+ return this.getFeatureBy('fid', featureFid);
+ },
+
+ /**
+ * APIMethod: getFeaturesByAttribute
+ * Returns an array of features that have the given attribute key set to the
+ * given value. Comparison of attribute values takes care of datatypes, e.g.
+ * the string '1234' is not equal to the number 1234.
+ *
+ * Parameters:
+ * attrName - {String}
+ * attrValue - {Mixed}
+ *
+ * Returns:
+ * Array(<OpenLayers.Feature.Vector>) An array of features that have the
+ * passed named attribute set to the given value.
+ */
+ getFeaturesByAttribute: function(attrName, attrValue) {
+ var i,
+ feature,
+ len = this.features.length,
+ foundFeatures = [];
+ for(i = 0; i < len; i++) {
+ feature = this.features[i];
+ if(feature && feature.attributes) {
+ if (feature.attributes[attrName] === attrValue) {
+ foundFeatures.push(feature);
+ }
+ }
+ }
+ return foundFeatures;
+ },
+
+ /**
+ * Unselect the selected features
+ * i.e. clears the featureSelection array
+ * change the style back
+ clearSelection: function() {
+
+ var vectorLayer = this.map.vectorLayer;
+ for (var i = 0; i < this.map.featureSelection.length; i++) {
+ var featureSelection = this.map.featureSelection[i];
+ vectorLayer.drawFeature(featureSelection, vectorLayer.style);
+ }
+ this.map.featureSelection = [];
+ },
+ */
+
+
+ /**
+ * APIMethod: onFeatureInsert
+ * method called after a feature is inserted.
+ * Does nothing by default. Override this if you
+ * need to do something on feature updates.
+ *
+ * Paarameters:
+ * feature - {<OpenLayers.Feature.Vector>}
+ */
+ onFeatureInsert: function(feature) {
+ },
+
+ /**
+ * APIMethod: preFeatureInsert
+ * method called before a feature is inserted.
+ * Does nothing by default. Override this if you
+ * need to do something when features are first added to the
+ * layer, but before they are drawn, such as adjust the style.
+ *
+ * Parameters:
+ * feature - {<OpenLayers.Feature.Vector>}
+ */
+ preFeatureInsert: function(feature) {
+ },
+
+ /**
+ * APIMethod: getDataExtent
+ * Calculates the max extent which includes all of the features.
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>}
+ */
+ getDataExtent: function () {
+ var maxExtent = null;
+ var features = this.features;
+ if(features && (features.length > 0)) {
+ maxExtent = new OpenLayers.Bounds();
+ var geometry = null;
+ for(var i=0, len=features.length; i<len; i++) {
+ geometry = features[i].geometry;
+ if (geometry) {
+ maxExtent.extend(geometry.getBounds());
+ }
+ }
+ }
+ return maxExtent;
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.Vector"
+});
+/* ======================================================================
+ OpenLayers/Layer/XYZ.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ * @requires OpenLayers/Tile/Image.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.XYZ
+ * The XYZ class is designed to make it easier for people who have tiles
+ * arranged by a standard XYZ grid.
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.XYZ = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+ /**
+ * APIProperty: isBaseLayer
+ * Default is true, as this is designed to be a base tile source.
+ */
+ isBaseLayer: true,
+
+ /**
+ * APIProperty: sphericalMecator
+ * Whether the tile extents should be set to the defaults for
+ * spherical mercator. Useful for things like OpenStreetMap.
+ * Default is false, except for the OSM subclass.
+ */
+ sphericalMercator: false,
+
+ /**
+ * APIProperty: zoomOffset
+ * {Number} If your cache has more zoom levels than you want to provide
+ * access to with this layer, supply a zoomOffset. This zoom offset
+ * is added to the current map zoom level to determine the level
+ * for a requested tile. For example, if you supply a zoomOffset
+ * of 3, when the map is at the zoom 0, tiles will be requested from
+ * level 3 of your cache. Default is 0 (assumes cache level and map
+ * zoom are equivalent). Using <zoomOffset> is an alternative to
+ * setting <serverResolutions> if you only want to expose a subset
+ * of the server resolutions.
+ */
+ zoomOffset: 0,
+
+ /**
+ * APIProperty: serverResolutions
+ * {Array} A list of all resolutions available on the server. Only set this
+ * property if the map resolutions differs from the server.
+ */
+ serverResolutions: null,
+
+ /**
+ * Constructor: OpenLayers.Layer.XYZ
+ *
+ * Parameters:
+ * name - {String}
+ * url - {String}
+ * options - {Object} Hashtable of extra options to tag onto the layer
+ */
+ initialize: function(name, url, options) {
+ if (options && options.sphericalMercator || this.sphericalMercator) {
+ options = OpenLayers.Util.extend({
+ maxExtent: new OpenLayers.Bounds(
+ -128 * 156543.0339,
+ -128 * 156543.0339,
+ 128 * 156543.0339,
+ 128 * 156543.0339
+ ),
+ maxResolution: 156543.0339,
+ numZoomLevels: 19,
+ units: "m",
+ projection: "EPSG:900913"
+ }, options);
+ }
+ url = url || this.url;
+ name = name || this.name;
+ var newArguments = [name, url, {}, options];
+ OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
+ },
+
+ /**
+ * APIMethod: clone
+ * Create a clone of this layer
+ *
+ * Parameters:
+ * obj - {Object} Is this ever used?
+ *
+ * Returns:
+ * {<OpenLayers.Layer.XYZ>} An exact clone of this OpenLayers.Layer.XYZ
+ */
+ clone: function (obj) {
+
+ if (obj == null) {
+ obj = new OpenLayers.Layer.XYZ(this.name,
+ this.url,
+ this.getOptions());
+ }
+
+ //get all additions from superclasses
+ obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+ return obj;
+ },
+
+ /**
+ * Method: getURL
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ *
+ * Returns:
+ * {String} A string with the layer's url and parameters and also the
+ * passed-in bounds and appropriate tile size specified as
+ * parameters
+ */
+ getURL: function (bounds) {
+ var xyz = this.getXYZ(bounds);
+ var url = this.url;
+ if (url instanceof Array) {
+ var s = '' + xyz.x + xyz.y + xyz.z;
+ url = this.selectUrl(s, url);
+ }
+
+ return OpenLayers.String.format(url, xyz);
+ },
+
+ /**
+ * Method: getXYZ
+ * Calculates x, y and z for the given bounds.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ *
+ * Returns:
+ * {Object} - an object with x, y and z properties.
+ */
+ getXYZ: function(bounds) {
+ var res = this.map.getResolution();
+ var x = Math.round((bounds.left - this.maxExtent.left)
+ / (res * this.tileSize.w));
+ var y = Math.round((this.maxExtent.top - bounds.top)
+ / (res * this.tileSize.h));
+ var z = this.serverResolutions != null ?
+ OpenLayers.Util.indexOf(this.serverResolutions, res) :
+ this.map.getZoom() + this.zoomOffset;
+
+ return {'x': x, 'y': y, 'z': z};
+ },
+
+ /**
+ * Method: addTile
+ * addTile creates a tile, initializes it, and adds it to the layer div.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * position - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+ */
+ addTile:function(bounds,position) {
+ return new OpenLayers.Tile.Image(this, position, bounds,
+ null, this.tileSize);
+ },
+
+ /* APIMethod: setMap
+ * When the layer is added to a map, then we can fetch our origin
+ * (if we don't have one.)
+ *
+ * Parameters:
+ * map - {<OpenLayers.Map>}
+ */
+ setMap: function(map) {
+ OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments);
+ if (!this.tileOrigin) {
+ this.tileOrigin = new OpenLayers.LonLat(this.maxExtent.left,
+ this.maxExtent.bottom);
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.XYZ"
+});
+
+
+/**
+ * Class: OpenLayers.Layer.OSM
+ * A class to access OpenStreetMap tiles. By default, uses the OpenStreetMap
+ * hosted tile.openstreetmap.org 'Mapnik' tileset. If you wish to use
+ * tiles at home / osmarender layer instead, you can pass a layer like:
+ *
+ * (code)
+ * new OpenLayers.Layer.OSM("t at h",
+ * "http://tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png");
+ * (end)
+ *
+ * This layer defaults to Spherical Mercator.
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer.XYZ>
+ */
+OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
+ name: "OpenStreetMap",
+ attribution: "Data CC-By-SA by <a href='http://openstreetmap.org/'>OpenStreetMap</a>",
+ sphericalMercator: true,
+ url: 'http://tile.openstreetmap.org/${z}/${x}/${y}.png',
+ clone: function(obj) {
+ if (obj == null) {
+ obj = new OpenLayers.Layer.OSM(
+ this.name, this.url, this.getOptions());
+ }
+ obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]);
+ return obj;
+ },
+ CLASS_NAME: "OpenLayers.Layer.OSM"
+});
+/* ======================================================================
+ OpenLayers/Renderer/SVG.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Renderer/Elements.js
+ */
+
+/**
+ * Class: OpenLayers.Renderer.SVG
+ *
+ * Inherits:
+ * - <OpenLayers.Renderer.Elements>
+ */
+OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
+
+ /**
+ * Property: xmlns
+ * {String}
+ */
+ xmlns: "http://www.w3.org/2000/svg",
+
+ /**
+ * Property: xlinkns
+ * {String}
+ */
+ xlinkns: "http://www.w3.org/1999/xlink",
+
+ /**
+ * Constant: MAX_PIXEL
+ * {Integer} Firefox has a limitation where values larger or smaller than
+ * about 15000 in an SVG document lock the browser up. This
+ * works around it.
+ */
+ MAX_PIXEL: 15000,
+
+ /**
+ * Property: translationParameters
+ * {Object} Hash with "x" and "y" properties
+ */
+ translationParameters: null,
+
+ /**
+ * Property: symbolMetrics
+ * {Object} Cache for symbol metrics according to their svg coordinate
+ * space. This is an object keyed by the symbol's id, and values are
+ * an array of [width, centerX, centerY].
+ */
+ symbolMetrics: null,
+
+ /**
+ * Constructor: OpenLayers.Renderer.SVG
+ *
+ * Parameters:
+ * containerID - {String}
+ */
+ initialize: function(containerID) {
+ if (!this.supported()) {
+ return;
+ }
+ OpenLayers.Renderer.Elements.prototype.initialize.apply(this,
+ arguments);
+ this.translationParameters = {x: 0, y: 0};
+
+ this.symbolMetrics = {};
+ },
+
+ /**
+ * APIMethod: destroy
+ */
+ destroy: function() {
+ OpenLayers.Renderer.Elements.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * APIMethod: supported
+ *
+ * Returns:
+ * {Boolean} Whether or not the browser supports the SVG renderer
+ */
+ supported: function() {
+ var svgFeature = "http://www.w3.org/TR/SVG11/feature#";
+ return (document.implementation &&
+ (document.implementation.hasFeature("org.w3c.svg", "1.0") ||
+ document.implementation.hasFeature(svgFeature + "SVG", "1.1") ||
+ document.implementation.hasFeature(svgFeature + "BasicStructure", "1.1") ));
+ },
+
+ /**
+ * Method: inValidRange
+ * See #669 for more information
+ *
+ * Parameters:
+ * x - {Integer}
+ * y - {Integer}
+ * xyOnly - {Boolean} whether or not to just check for x and y, which means
+ * to not take the current translation parameters into account if true.
+ *
+ * Returns:
+ * {Boolean} Whether or not the 'x' and 'y' coordinates are in the
+ * valid range.
+ */
+ inValidRange: function(x, y, xyOnly) {
+ var left = x + (xyOnly ? 0 : this.translationParameters.x);
+ var top = y + (xyOnly ? 0 : this.translationParameters.y);
+ return (left >= -this.MAX_PIXEL && left <= this.MAX_PIXEL &&
+ top >= -this.MAX_PIXEL && top <= this.MAX_PIXEL);
+ },
+
+ /**
+ * Method: setExtent
+ *
+ * Parameters:
+ * extent - {<OpenLayers.Bounds>}
+ * resolutionChanged - {Boolean}
+ *
+ * Returns:
+ * {Boolean} true to notify the layer that the new extent does not exceed
+ * the coordinate range, and the features will not need to be redrawn.
+ * False otherwise.
+ */
+ setExtent: function(extent, resolutionChanged) {
+ OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,
+ arguments);
+
+ var resolution = this.getResolution();
+ var left = -extent.left / resolution;
+ var top = extent.top / resolution;
+
+ // If the resolution has changed, start over changing the corner, because
+ // the features will redraw.
+ if (resolutionChanged) {
+ this.left = left;
+ this.top = top;
+ // Set the viewbox
+ var extentString = "0 0 " + this.size.w + " " + this.size.h;
+
+ this.rendererRoot.setAttributeNS(null, "viewBox", extentString);
+ this.translate(0, 0);
+ return true;
+ } else {
+ var inRange = this.translate(left - this.left, top - this.top);
+ if (!inRange) {
+ // recenter the coordinate system
+ this.setExtent(extent, true);
+ }
+ return inRange;
+ }
+ },
+
+ /**
+ * Method: translate
+ * Transforms the SVG coordinate system
+ *
+ * Parameters:
+ * x - {Float}
+ * y - {Float}
+ *
+ * Returns:
+ * {Boolean} true if the translation parameters are in the valid coordinates
+ * range, false otherwise.
+ */
+ translate: function(x, y) {
+ if (!this.inValidRange(x, y, true)) {
+ return false;
+ } else {
+ var transformString = "";
+ if (x || y) {
+ transformString = "translate(" + x + "," + y + ")";
+ }
+ this.root.setAttributeNS(null, "transform", transformString);
+ this.translationParameters = {x: x, y: y};
+ return true;
+ }
+ },
+
+ /**
+ * Method: setSize
+ * Sets the size of the drawing surface.
+ *
+ * Parameters:
+ * size - {<OpenLayers.Size>} The size of the drawing surface
+ */
+ setSize: function(size) {
+ OpenLayers.Renderer.prototype.setSize.apply(this, arguments);
+
+ this.rendererRoot.setAttributeNS(null, "width", this.size.w);
+ this.rendererRoot.setAttributeNS(null, "height", this.size.h);
+ },
+
+ /**
+ * Method: getNodeType
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ * style - {Object}
+ *
+ * Returns:
+ * {String} The corresponding node type for the specified geometry
+ */
+ getNodeType: function(geometry, style) {
+ var nodeType = null;
+ switch (geometry.CLASS_NAME) {
+ case "OpenLayers.Geometry.Point":
+ if (style.externalGraphic) {
+ nodeType = "image";
+ } else if (this.isComplexSymbol(style.graphicName)) {
+ nodeType = "svg";
+ } else {
+ nodeType = "circle";
+ }
+ break;
+ case "OpenLayers.Geometry.Rectangle":
+ nodeType = "rect";
+ break;
+ case "OpenLayers.Geometry.LineString":
+ nodeType = "polyline";
+ break;
+ case "OpenLayers.Geometry.LinearRing":
+ nodeType = "polygon";
+ break;
+ case "OpenLayers.Geometry.Polygon":
+ case "OpenLayers.Geometry.Curve":
+ case "OpenLayers.Geometry.Surface":
+ nodeType = "path";
+ break;
+ default:
+ break;
+ }
+ return nodeType;
+ },
+
+ /**
+ * Method: setStyle
+ * Use to set all the style attributes to a SVG node.
+ *
+ * Takes care to adjust stroke width and point radius to be
+ * resolution-relative
+ *
+ * Parameters:
+ * node - {SVGDomElement} An SVG element to decorate
+ * style - {Object}
+ * options - {Object} Currently supported options include
+ * 'isFilled' {Boolean} and
+ * 'isStroked' {Boolean}
+ */
+ setStyle: function(node, style, options) {
+ style = style || node._style;
+ options = options || node._options;
+ var r = parseFloat(node.getAttributeNS(null, "r"));
+ var widthFactor = 1;
+ var pos;
+ if (node._geometryClass == "OpenLayers.Geometry.Point" && r) {
+ node.style.visibility = "";
+ if (style.graphic === false) {
+ node.style.visibility = "hidden";
+ } else if (style.externalGraphic) {
+ pos = this.getPosition(node);
+
+ if (style.graphicTitle) {
+ node.setAttributeNS(null, "title", style.graphicTitle);
+ }
+ if (style.graphicWidth && style.graphicHeight) {
+ node.setAttributeNS(null, "preserveAspectRatio", "none");
+ }
+ var width = style.graphicWidth || style.graphicHeight;
+ var height = style.graphicHeight || style.graphicWidth;
+ width = width ? width : style.pointRadius*2;
+ height = height ? height : style.pointRadius*2;
+ var xOffset = (style.graphicXOffset != undefined) ?
+ style.graphicXOffset : -(0.5 * width);
+ var yOffset = (style.graphicYOffset != undefined) ?
+ style.graphicYOffset : -(0.5 * height);
+
+ var opacity = style.graphicOpacity || style.fillOpacity;
+
+ node.setAttributeNS(null, "x", (pos.x + xOffset).toFixed());
+ node.setAttributeNS(null, "y", (pos.y + yOffset).toFixed());
+ node.setAttributeNS(null, "width", width);
+ node.setAttributeNS(null, "height", height);
+ node.setAttributeNS(this.xlinkns, "href", style.externalGraphic);
+ node.setAttributeNS(null, "style", "opacity: "+opacity);
+ } else if (this.isComplexSymbol(style.graphicName)) {
+ // the symbol viewBox is three times as large as the symbol
+ var offset = style.pointRadius * 3;
+ var size = offset * 2;
+ var id = this.importSymbol(style.graphicName);
+ pos = this.getPosition(node);
+ widthFactor = this.symbolMetrics[id][0] * 3 / size;
+
+ // remove the node from the dom before we modify it. This
+ // prevents various rendering issues in Safari and FF
+ var parent = node.parentNode;
+ var nextSibling = node.nextSibling;
+ if(parent) {
+ parent.removeChild(node);
+ }
+
+ // The more appropriate way to implement this would be use/defs,
+ // but due to various issues in several browsers, it is safer to
+ // copy the symbols instead of referencing them.
+ // See e.g. ticket http://trac.osgeo.org/openlayers/ticket/2985
+ // and this email thread
+ // http://osgeo-org.1803224.n2.nabble.com/Select-Control-Ctrl-click-on-Feature-with-a-graphicName-opens-new-browser-window-tc5846039.html
+ var src = document.getElementById(id);
+ node.firstChild && node.removeChild(node.firstChild);
+ node.appendChild(src.firstChild.cloneNode(true));
+ node.setAttributeNS(null, "viewBox", src.getAttributeNS(null, "viewBox"));
+
+ node.setAttributeNS(null, "width", size);
+ node.setAttributeNS(null, "height", size);
+ node.setAttributeNS(null, "x", pos.x - offset);
+ node.setAttributeNS(null, "y", pos.y - offset);
+
+ // now that the node has all its new properties, insert it
+ // back into the dom where it was
+ if(nextSibling) {
+ parent.insertBefore(node, nextSibling);
+ } else if(parent) {
+ parent.appendChild(node);
+ }
+ } else {
+ node.setAttributeNS(null, "r", style.pointRadius);
+ }
+
+ var rotation = style.rotation;
+
+ if ((rotation !== undefined || node._rotation !== undefined) && pos) {
+ node._rotation = rotation;
+ rotation |= 0;
+ if (node.nodeName !== "svg") {
+ node.setAttributeNS(null, "transform",
+ "rotate(" + rotation + " " + pos.x + " " +
+ pos.y + ")");
+ } else {
+ var metrics = this.symbolMetrics[id];
+ node.firstChild.setAttributeNS(null, "transform", "rotate("
+ + rotation + " "
+ + metrics[1] + " "
+ + metrics[2] + ")");
+ }
+ }
+ }
+
+ if (options.isFilled) {
+ node.setAttributeNS(null, "fill", style.fillColor);
+ node.setAttributeNS(null, "fill-opacity", style.fillOpacity);
+ } else {
+ node.setAttributeNS(null, "fill", "none");
+ }
+
+ if (options.isStroked) {
+ node.setAttributeNS(null, "stroke", style.strokeColor);
+ node.setAttributeNS(null, "stroke-opacity", style.strokeOpacity);
+ node.setAttributeNS(null, "stroke-width", style.strokeWidth * widthFactor);
+ node.setAttributeNS(null, "stroke-linecap", style.strokeLinecap || "round");
+ // Hard-coded linejoin for now, to make it look the same as in VML.
+ // There is no strokeLinejoin property yet for symbolizers.
+ node.setAttributeNS(null, "stroke-linejoin", "round");
+ style.strokeDashstyle && node.setAttributeNS(null,
+ "stroke-dasharray", this.dashStyle(style, widthFactor));
+ } else {
+ node.setAttributeNS(null, "stroke", "none");
+ }
+
+ if (style.pointerEvents) {
+ node.setAttributeNS(null, "pointer-events", style.pointerEvents);
+ }
+
+ if (style.cursor != null) {
+ node.setAttributeNS(null, "cursor", style.cursor);
+ }
+
+ return node;
+ },
+
+ /**
+ * Method: dashStyle
+ *
+ * Parameters:
+ * style - {Object}
+ * widthFactor - {Number}
+ *
+ * Returns:
+ * {String} A SVG compliant 'stroke-dasharray' value
+ */
+ dashStyle: function(style, widthFactor) {
+ var w = style.strokeWidth * widthFactor;
+ var str = style.strokeDashstyle;
+ switch (str) {
+ case 'solid':
+ return 'none';
+ case 'dot':
+ return [1, 4 * w].join();
+ case 'dash':
+ return [4 * w, 4 * w].join();
+ case 'dashdot':
+ return [4 * w, 4 * w, 1, 4 * w].join();
+ case 'longdash':
+ return [8 * w, 4 * w].join();
+ case 'longdashdot':
+ return [8 * w, 4 * w, 1, 4 * w].join();
+ default:
+ return OpenLayers.String.trim(str).replace(/\s+/g, ",");
+ }
+ },
+
+ /**
+ * Method: createNode
+ *
+ * Parameters:
+ * type - {String} Kind of node to draw
+ * id - {String} Id for node
+ *
+ * Returns:
+ * {DOMElement} A new node of the given type and id
+ */
+ createNode: function(type, id) {
+ var node = document.createElementNS(this.xmlns, type);
+ if (id) {
+ node.setAttributeNS(null, "id", id);
+ }
+ return node;
+ },
+
+ /**
+ * Method: nodeTypeCompare
+ *
+ * Parameters:
+ * node - {SVGDomElement} An SVG element
+ * type - {String} Kind of node
+ *
+ * Returns:
+ * {Boolean} Whether or not the specified node is of the specified type
+ */
+ nodeTypeCompare: function(node, type) {
+ return (type == node.nodeName);
+ },
+
+ /**
+ * Method: createRenderRoot
+ *
+ * Returns:
+ * {DOMElement} The specific render engine's root element
+ */
+ createRenderRoot: function() {
+ return this.nodeFactory(this.container.id + "_svgRoot", "svg");
+ },
+
+ /**
+ * Method: createRoot
+ *
+ * Parameter:
+ * suffix - {String} suffix to append to the id
+ *
+ * Returns:
+ * {DOMElement}
+ */
+ createRoot: function(suffix) {
+ return this.nodeFactory(this.container.id + suffix, "g");
+ },
+
+ /**
+ * Method: createDefs
+ *
+ * Returns:
+ * {DOMElement} The element to which we'll add the symbol definitions
+ */
+ createDefs: function() {
+ var defs = this.nodeFactory(this.container.id + "_defs", "defs");
+ this.rendererRoot.appendChild(defs);
+ return defs;
+ },
+
+ /**************************************
+ * *
+ * GEOMETRY DRAWING FUNCTIONS *
+ * *
+ **************************************/
+
+ /**
+ * Method: drawPoint
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement} or false if the renderer could not draw the point
+ */
+ drawPoint: function(node, geometry) {
+ return this.drawCircle(node, geometry, 1);
+ },
+
+ /**
+ * Method: drawCircle
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ * radius - {Float}
+ *
+ * Returns:
+ * {DOMElement} or false if the renderer could not draw the circle
+ */
+ drawCircle: function(node, geometry, radius) {
+ var resolution = this.getResolution();
+ var x = (geometry.x / resolution + this.left);
+ var y = (this.top - geometry.y / resolution);
+
+ if (this.inValidRange(x, y)) {
+ node.setAttributeNS(null, "cx", x);
+ node.setAttributeNS(null, "cy", y);
+ node.setAttributeNS(null, "r", radius);
+ return node;
+ } else {
+ return false;
+ }
+
+ },
+
+ /**
+ * Method: drawLineString
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement} or null if the renderer could not draw all components of
+ * the linestring, or false if nothing could be drawn
+ */
+ drawLineString: function(node, geometry) {
+ var componentsResult = this.getComponentsString(geometry.components);
+ if (componentsResult.path) {
+ node.setAttributeNS(null, "points", componentsResult.path);
+ return (componentsResult.complete ? node : null);
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Method: drawLinearRing
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement} or null if the renderer could not draw all components
+ * of the linear ring, or false if nothing could be drawn
+ */
+ drawLinearRing: function(node, geometry) {
+ var componentsResult = this.getComponentsString(geometry.components);
+ if (componentsResult.path) {
+ node.setAttributeNS(null, "points", componentsResult.path);
+ return (componentsResult.complete ? node : null);
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Method: drawPolygon
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement} or null if the renderer could not draw all components
+ * of the polygon, or false if nothing could be drawn
+ */
+ drawPolygon: function(node, geometry) {
+ var d = "";
+ var draw = true;
+ var complete = true;
+ var linearRingResult, path;
+ for (var j=0, len=geometry.components.length; j<len; j++) {
+ d += " M";
+ linearRingResult = this.getComponentsString(
+ geometry.components[j].components, " ");
+ path = linearRingResult.path;
+ if (path) {
+ d += " " + path;
+ complete = linearRingResult.complete && complete;
+ } else {
+ draw = false;
+ }
+ }
+ d += " z";
+ if (draw) {
+ node.setAttributeNS(null, "d", d);
+ node.setAttributeNS(null, "fill-rule", "evenodd");
+ return complete ? node : null;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Method: drawRectangle
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement} or false if the renderer could not draw the rectangle
+ */
+ drawRectangle: function(node, geometry) {
+ var resolution = this.getResolution();
+ var x = (geometry.x / resolution + this.left);
+ var y = (this.top - geometry.y / resolution);
+
+ if (this.inValidRange(x, y)) {
+ node.setAttributeNS(null, "x", x);
+ node.setAttributeNS(null, "y", y);
+ node.setAttributeNS(null, "width", geometry.width / resolution);
+ node.setAttributeNS(null, "height", geometry.height / resolution);
+ return node;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Method: drawSurface
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement} or false if the renderer could not draw the surface
+ */
+ drawSurface: function(node, geometry) {
+
+ // create the svg path string representation
+ var d = null;
+ var draw = true;
+ for (var i=0, len=geometry.components.length; i<len; i++) {
+ if ((i%3) == 0 && (i/3) == 0) {
+ var component = this.getShortString(geometry.components[i]);
+ if (!component) { draw = false; }
+ d = "M " + component;
+ } else if ((i%3) == 1) {
+ var component = this.getShortString(geometry.components[i]);
+ if (!component) { draw = false; }
+ d += " C " + component;
+ } else {
+ var component = this.getShortString(geometry.components[i]);
+ if (!component) { draw = false; }
+ d += " " + component;
+ }
+ }
+ d += " Z";
+ if (draw) {
+ node.setAttributeNS(null, "d", d);
+ return node;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Method: drawText
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * featureId - {String}
+ * style -
+ * location - {<OpenLayers.Geometry.Point>}
+ */
+ drawText: function(featureId, style, location) {
+ var resolution = this.getResolution();
+
+ var x = (location.x / resolution + this.left);
+ var y = (location.y / resolution - this.top);
+
+ var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "text");
+ var tspan = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_tspan", "tspan");
+
+ label.setAttributeNS(null, "x", x);
+ label.setAttributeNS(null, "y", -y);
+
+ if (style.fontColor) {
+ label.setAttributeNS(null, "fill", style.fontColor);
+ }
+ if (style.fontOpacity) {
+ label.setAttributeNS(null, "opacity", style.fontOpacity);
+ }
+ if (style.fontFamily) {
+ label.setAttributeNS(null, "font-family", style.fontFamily);
+ }
+ if (style.fontSize) {
+ label.setAttributeNS(null, "font-size", style.fontSize);
+ }
+ if (style.fontWeight) {
+ label.setAttributeNS(null, "font-weight", style.fontWeight);
+ }
+ if(style.labelSelect === true) {
+ label.setAttributeNS(null, "pointer-events", "visible");
+ label._featureId = featureId;
+ tspan._featureId = featureId;
+ tspan._geometry = location;
+ tspan._geometryClass = location.CLASS_NAME;
+ } else {
+ label.setAttributeNS(null, "pointer-events", "none");
+ }
+ var align = style.labelAlign || "cm";
+ label.setAttributeNS(null, "text-anchor",
+ OpenLayers.Renderer.SVG.LABEL_ALIGN[align[0]] || "middle");
+
+ if (OpenLayers.IS_GECKO === true) {
+ label.setAttributeNS(null, "dominant-baseline",
+ OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]] || "central");
+ } else {
+ tspan.setAttributeNS(null, "baseline-shift",
+ OpenLayers.Renderer.SVG.LABEL_VSHIFT[align[1]] || "-35%");
+ }
+
+ tspan.textContent = style.label;
+
+ if(!label.parentNode) {
+ label.appendChild(tspan);
+ this.textRoot.appendChild(label);
+ }
+ },
+
+ /**
+ * Method: getComponentString
+ *
+ * Parameters:
+ * components - {Array(<OpenLayers.Geometry.Point>)} Array of points
+ * separator - {String} character between coordinate pairs. Defaults to ","
+ *
+ * Returns:
+ * {Object} hash with properties "path" (the string created from the
+ * components and "complete" (false if the renderer was unable to
+ * draw all components)
+ */
+ getComponentsString: function(components, separator) {
+ var renderCmp = [];
+ var complete = true;
+ var len = components.length;
+ var strings = [];
+ var str, component;
+ for(var i=0; i<len; i++) {
+ component = components[i];
+ renderCmp.push(component);
+ str = this.getShortString(component);
+ if (str) {
+ strings.push(str);
+ } else {
+ // The current component is outside the valid range. Let's
+ // see if the previous or next component is inside the range.
+ // If so, add the coordinate of the intersection with the
+ // valid range bounds.
+ if (i > 0) {
+ if (this.getShortString(components[i - 1])) {
+ strings.push(this.clipLine(components[i],
+ components[i-1]));
+ }
+ }
+ if (i < len - 1) {
+ if (this.getShortString(components[i + 1])) {
+ strings.push(this.clipLine(components[i],
+ components[i+1]));
+ }
+ }
+ complete = false;
+ }
+ }
+
+ return {
+ path: strings.join(separator || ","),
+ complete: complete
+ };
+ },
+
+ /**
+ * Method: clipLine
+ * Given two points (one inside the valid range, and one outside),
+ * clips the line betweeen the two points so that the new points are both
+ * inside the valid range.
+ *
+ * Parameters:
+ * badComponent - {<OpenLayers.Geometry.Point>)} original geometry of the
+ * invalid point
+ * goodComponent - {<OpenLayers.Geometry.Point>)} original geometry of the
+ * valid point
+ * Returns
+ * {String} the SVG coordinate pair of the clipped point (like
+ * getShortString), or an empty string if both passed componets are at
+ * the same point.
+ */
+ clipLine: function(badComponent, goodComponent) {
+ if (goodComponent.equals(badComponent)) {
+ return "";
+ }
+ var resolution = this.getResolution();
+ var maxX = this.MAX_PIXEL - this.translationParameters.x;
+ var maxY = this.MAX_PIXEL - this.translationParameters.y;
+ var x1 = goodComponent.x / resolution + this.left;
+ var y1 = this.top - goodComponent.y / resolution;
+ var x2 = badComponent.x / resolution + this.left;
+ var y2 = this.top - badComponent.y / resolution;
+ var k;
+ if (x2 < -maxX || x2 > maxX) {
+ k = (y2 - y1) / (x2 - x1);
+ x2 = x2 < 0 ? -maxX : maxX;
+ y2 = y1 + (x2 - x1) * k;
+ }
+ if (y2 < -maxY || y2 > maxY) {
+ k = (x2 - x1) / (y2 - y1);
+ y2 = y2 < 0 ? -maxY : maxY;
+ x2 = x1 + (y2 - y1) * k;
+ }
+ return x2 + "," + y2;
+ },
+
+ /**
+ * Method: getShortString
+ *
+ * Parameters:
+ * point - {<OpenLayers.Geometry.Point>}
+ *
+ * Returns:
+ * {String} or false if point is outside the valid range
+ */
+ getShortString: function(point) {
+ var resolution = this.getResolution();
+ var x = (point.x / resolution + this.left);
+ var y = (this.top - point.y / resolution);
+
+ if (this.inValidRange(x, y)) {
+ return x + "," + y;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Method: getPosition
+ * Finds the position of an svg node.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ *
+ * Returns:
+ * {Object} hash with x and y properties, representing the coordinates
+ * within the svg coordinate system
+ */
+ getPosition: function(node) {
+ return({
+ x: parseFloat(node.getAttributeNS(null, "cx")),
+ y: parseFloat(node.getAttributeNS(null, "cy"))
+ });
+ },
+
+ /**
+ * Method: importSymbol
+ * add a new symbol definition from the rendererer's symbol hash
+ *
+ * Parameters:
+ * graphicName - {String} name of the symbol to import
+ *
+ * Returns:
+ * {String} - id of the imported symbol
+ */
+ importSymbol: function (graphicName) {
+ if (!this.defs) {
+ // create svg defs tag
+ this.defs = this.createDefs();
+ }
+ var id = this.container.id + "-" + graphicName;
+
+ // check if symbol already exists in the defs
+ if (document.getElementById(id) != null) {
+ return id;
+ }
+
+ var symbol = OpenLayers.Renderer.symbol[graphicName];
+ if (!symbol) {
+ throw new Error(graphicName + ' is not a valid symbol name');
+ }
+
+ var symbolNode = this.nodeFactory(id, "symbol");
+ var node = this.nodeFactory(null, "polygon");
+ symbolNode.appendChild(node);
+ var symbolExtent = new OpenLayers.Bounds(
+ Number.MAX_VALUE, Number.MAX_VALUE, 0, 0);
+
+ var points = [];
+ var x,y;
+ for (var i=0; i<symbol.length; i=i+2) {
+ x = symbol[i];
+ y = symbol[i+1];
+ symbolExtent.left = Math.min(symbolExtent.left, x);
+ symbolExtent.bottom = Math.min(symbolExtent.bottom, y);
+ symbolExtent.right = Math.max(symbolExtent.right, x);
+ symbolExtent.top = Math.max(symbolExtent.top, y);
+ points.push(x, ",", y);
+ }
+
+ node.setAttributeNS(null, "points", points.join(" "));
+
+ var width = symbolExtent.getWidth();
+ var height = symbolExtent.getHeight();
+ // create a viewBox three times as large as the symbol itself,
+ // to allow for strokeWidth being displayed correctly at the corners.
+ var viewBox = [symbolExtent.left - width,
+ symbolExtent.bottom - height, width * 3, height * 3];
+ symbolNode.setAttributeNS(null, "viewBox", viewBox.join(" "));
+ this.symbolMetrics[id] = [
+ Math.max(width, height),
+ symbolExtent.getCenterLonLat().lon,
+ symbolExtent.getCenterLonLat().lat
+ ];
+
+ this.defs.appendChild(symbolNode);
+ return symbolNode.id;
+ },
+
+ /**
+ * Method: getFeatureIdFromEvent
+ *
+ * Parameters:
+ * evt - {Object} An <OpenLayers.Event> object
+ *
+ * Returns:
+ * {<OpenLayers.Geometry>} A geometry from an event that
+ * happened on a layer.
+ */
+ getFeatureIdFromEvent: function(evt) {
+ var featureId = OpenLayers.Renderer.Elements.prototype.getFeatureIdFromEvent.apply(this, arguments);
+ if(!featureId) {
+ var target = evt.target;
+ featureId = target.parentNode && target != this.rendererRoot &&
+ target.parentNode._featureId;
+ }
+ return featureId;
+ },
+
+ CLASS_NAME: "OpenLayers.Renderer.SVG"
+});
+
+/**
+ * Constant: OpenLayers.Renderer.SVG.LABEL_ALIGN
+ * {Object}
+ */
+OpenLayers.Renderer.SVG.LABEL_ALIGN = {
+ "l": "start",
+ "r": "end",
+ "b": "bottom",
+ "t": "hanging"
+};
+
+/**
+ * Constant: OpenLayers.Renderer.SVG.LABEL_VSHIFT
+ * {Object}
+ */
+OpenLayers.Renderer.SVG.LABEL_VSHIFT = {
+ // according to
+ // http://www.w3.org/Graphics/SVG/Test/20061213/htmlObjectHarness/full-text-align-02-b.html
+ // a baseline-shift of -70% shifts the text exactly from the
+ // bottom to the top of the baseline, so -35% moves the text to
+ // the center of the baseline.
+ "t": "-70%",
+ "b": "0"
+};
+/* ======================================================================
+ OpenLayers/Control/ScaleLine.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.ScaleLine
+ * The ScaleLine displays a small line indicator representing the current
+ * map scale on the map. By default it is drawn in the lower left corner of
+ * the map.
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ *
+ * Is a very close copy of:
+ * - <OpenLayers.Control.Scale>
+ */
+OpenLayers.Control.ScaleLine = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Property: maxWidth
+ * {Integer} Maximum width of the scale line in pixels. Default is 100.
+ */
+ maxWidth: 100,
+
+ /**
+ * Property: topOutUnits
+ * {String} Units for zoomed out on top bar. Default is km.
+ */
+ topOutUnits: "km",
+
+ /**
+ * Property: topInUnits
+ * {String} Units for zoomed in on top bar. Default is m.
+ */
+ topInUnits: "m",
+
+ /**
+ * Property: bottomOutUnits
+ * {String} Units for zoomed out on bottom bar. Default is mi.
+ */
+ bottomOutUnits: "mi",
+
+ /**
+ * Property: bottomInUnits
+ * {String} Units for zoomed in on bottom bar. Default is ft.
+ */
+ bottomInUnits: "ft",
+
+ /**
+ * Property: eTop
+ * {DOMElement}
+ */
+ eTop: null,
+
+ /**
+ * Property: eBottom
+ * {DOMElement}
+ */
+ eBottom:null,
+
+ /**
+ * APIProperty: geodesic
+ * {Boolean} Use geodesic measurement. Default is false. The recommended
+ * setting for maps in EPSG:4326 is false, and true EPSG:900913. If set to
+ * true, the scale will be calculated based on the horizontal size of the
+ * pixel in the center of the map viewport.
+ */
+ geodesic: false,
+
+ /**
+ * Constructor: OpenLayers.Control.ScaleLine
+ * Create a new scale line control.
+ *
+ * Parameters:
+ * options - {Object} An optional object whose properties will be used
+ * to extend the control.
+ */
+ initialize: function(options) {
+ OpenLayers.Control.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * Method: draw
+ *
+ * Returns:
+ * {DOMElement}
+ */
+ draw: function() {
+ OpenLayers.Control.prototype.draw.apply(this, arguments);
+ if (!this.eTop) {
+ // stick in the top bar
+ this.eTop = document.createElement("div");
+ this.eTop.className = this.displayClass + "Top";
+ var theLen = this.topInUnits.length;
+ this.div.appendChild(this.eTop);
+ if((this.topOutUnits == "") || (this.topInUnits == "")) {
+ this.eTop.style.visibility = "hidden";
+ } else {
+ this.eTop.style.visibility = "visible";
+ }
+
+ // and the bottom bar
+ this.eBottom = document.createElement("div");
+ this.eBottom.className = this.displayClass + "Bottom";
+ this.div.appendChild(this.eBottom);
+ if((this.bottomOutUnits == "") || (this.bottomInUnits == "")) {
+ this.eBottom.style.visibility = "hidden";
+ } else {
+ this.eBottom.style.visibility = "visible";
+ }
+ }
+ this.map.events.register('moveend', this, this.update);
+ this.update();
+ return this.div;
+ },
+
+ /**
+ * Method: getBarLen
+ * Given a number, round it down to the nearest 1,2,5 times a power of 10.
+ * That seems a fairly useful set of number groups to use.
+ *
+ * Parameters:
+ * maxLen - {float} the number we're rounding down from
+ *
+ * Returns:
+ * {Float} the rounded number (less than or equal to maxLen)
+ */
+ getBarLen: function(maxLen) {
+ // nearest power of 10 lower than maxLen
+ var digits = parseInt(Math.log(maxLen) / Math.log(10));
+ var pow10 = Math.pow(10, digits);
+
+ // ok, find first character
+ var firstChar = parseInt(maxLen / pow10);
+
+ // right, put it into the correct bracket
+ var barLen;
+ if(firstChar > 5) {
+ barLen = 5;
+ } else if(firstChar > 2) {
+ barLen = 2;
+ } else {
+ barLen = 1;
+ }
+
+ // scale it up the correct power of 10
+ return barLen * pow10;
+ },
+
+ /**
+ * Method: update
+ * Update the size of the bars, and the labels they contain.
+ */
+ update: function() {
+ var res = this.map.getResolution();
+ if (!res) {
+ return;
+ }
+
+ var curMapUnits = this.map.getUnits();
+ var inches = OpenLayers.INCHES_PER_UNIT;
+
+ // convert maxWidth to map units
+ var maxSizeData = this.maxWidth * res * inches[curMapUnits];
+ var geodesicRatio = 1;
+ if(this.geodesic === true) {
+ var maxSizeGeodesic = (this.map.getGeodesicPixelSize().w ||
+ 0.000001) * this.maxWidth;
+ var maxSizeKilometers = maxSizeData / inches["km"];
+ geodesicRatio = maxSizeGeodesic / maxSizeKilometers;
+ maxSizeData *= geodesicRatio;
+ }
+
+ // decide whether to use large or small scale units
+ var topUnits;
+ var bottomUnits;
+ if(maxSizeData > 100000) {
+ topUnits = this.topOutUnits;
+ bottomUnits = this.bottomOutUnits;
+ } else {
+ topUnits = this.topInUnits;
+ bottomUnits = this.bottomInUnits;
+ }
+
+ // and to map units units
+ var topMax = maxSizeData / inches[topUnits];
+ var bottomMax = maxSizeData / inches[bottomUnits];
+
+ // now trim this down to useful block length
+ var topRounded = this.getBarLen(topMax);
+ var bottomRounded = this.getBarLen(bottomMax);
+
+ // and back to display units
+ topMax = topRounded / inches[curMapUnits] * inches[topUnits];
+ bottomMax = bottomRounded / inches[curMapUnits] * inches[bottomUnits];
+
+ // and to pixel units
+ var topPx = topMax / res / geodesicRatio;
+ var bottomPx = bottomMax / res / geodesicRatio;
+
+ // now set the pixel widths
+ // and the values inside them
+
+ if (this.eBottom.style.visibility == "visible"){
+ this.eBottom.style.width = Math.round(bottomPx) + "px";
+ this.eBottom.innerHTML = bottomRounded + " " + bottomUnits ;
+ }
+
+ if (this.eTop.style.visibility == "visible"){
+ this.eTop.style.width = Math.round(topPx) + "px";
+ this.eTop.innerHTML = topRounded + " " + topUnits;
+ }
+
+ },
+
+ CLASS_NAME: "OpenLayers.Control.ScaleLine"
+});
+
+/* ======================================================================
+ OpenLayers/Control/PanZoom.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.PanZoom
+ * The PanZoom is a visible control, composed of a
+ * <OpenLayers.Control.PanPanel> and a <OpenLayers.Control.ZoomPanel>. By
+ * default it is drawn in the upper left corner of the map.
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * APIProperty: slideFactor
+ * {Integer} Number of pixels by which we'll pan the map in any direction
+ * on clicking the arrow buttons. If you want to pan by some ratio
+ * of the map dimensions, use <slideRatio> instead.
+ */
+ slideFactor: 50,
+
+ /**
+ * APIProperty: slideRatio
+ * {Number} The fraction of map width/height by which we'll pan the map
+ * on clicking the arrow buttons. Default is null. If set, will
+ * override <slideFactor>. E.g. if slideRatio is .5, then the Pan Up
+ * button will pan up half the map height.
+ */
+ slideRatio: null,
+
+ /**
+ * Property: buttons
+ * {Array(DOMElement)} Array of Button Divs
+ */
+ buttons: null,
+
+ /**
+ * Property: position
+ * {<OpenLayers.Pixel>}
+ */
+ position: null,
+
+ /**
+ * Constructor: OpenLayers.Control.PanZoom
+ *
+ * Parameters:
+ * options - {Object}
+ */
+ initialize: function(options) {
+ this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,
+ OpenLayers.Control.PanZoom.Y);
+ OpenLayers.Control.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * APIMethod: destroy
+ */
+ destroy: function() {
+ OpenLayers.Control.prototype.destroy.apply(this, arguments);
+ this.removeButtons();
+ this.buttons = null;
+ this.position = null;
+ },
+
+ /**
+ * Method: draw
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {DOMElement} A reference to the container div for the PanZoom control.
+ */
+ draw: function(px) {
+ // initialize our internal div
+ OpenLayers.Control.prototype.draw.apply(this, arguments);
+ px = this.position;
+
+ // place the controls
+ this.buttons = [];
+
+ var sz = new OpenLayers.Size(18,18);
+ var centered = new OpenLayers.Pixel(px.x+sz.w/2, px.y);
+
+ this._addButton("panup", "north-mini.png", centered, sz);
+ px.y = centered.y+sz.h;
+ this._addButton("panleft", "west-mini.png", px, sz);
+ this._addButton("panright", "east-mini.png", px.add(sz.w, 0), sz);
+ this._addButton("pandown", "south-mini.png",
+ centered.add(0, sz.h*2), sz);
+ this._addButton("zoomin", "zoom-plus-mini.png",
+ centered.add(0, sz.h*3+5), sz);
+ this._addButton("zoomworld", "zoom-world-mini.png",
+ centered.add(0, sz.h*4+5), sz);
+ this._addButton("zoomout", "zoom-minus-mini.png",
+ centered.add(0, sz.h*5+5), sz);
+ return this.div;
+ },
+
+ /**
+ * Method: _addButton
+ *
+ * Parameters:
+ * id - {String}
+ * img - {String}
+ * xy - {<OpenLayers.Pixel>}
+ * sz - {<OpenLayers.Size>}
+ *
+ * Returns:
+ * {DOMElement} A Div (an alphaImageDiv, to be precise) that contains the
+ * image of the button, and has all the proper event handlers set.
+ */
+ _addButton:function(id, img, xy, sz) {
+ var imgLocation = OpenLayers.Util.getImagesLocation() + img;
+ var btn = OpenLayers.Util.createAlphaImageDiv(
+ this.id + "_" + id,
+ xy, sz, imgLocation, "absolute");
+
+ //we want to add the outer div
+ this.div.appendChild(btn);
+
+ OpenLayers.Event.observe(btn, "mousedown",
+ OpenLayers.Function.bindAsEventListener(this.buttonDown, btn));
+ OpenLayers.Event.observe(btn, "dblclick",
+ OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
+ OpenLayers.Event.observe(btn, "click",
+ OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
+ btn.action = id;
+ btn.map = this.map;
+
+ if(!this.slideRatio){
+ var slideFactorPixels = this.slideFactor;
+ var getSlideFactor = function() {
+ return slideFactorPixels;
+ };
+ } else {
+ var slideRatio = this.slideRatio;
+ var getSlideFactor = function(dim) {
+ return this.map.getSize()[dim] * slideRatio;
+ };
+ }
+
+ btn.getSlideFactor = getSlideFactor;
+
+ //we want to remember/reference the outer div
+ this.buttons.push(btn);
+ return btn;
+ },
+
+ /**
+ * Method: _removeButton
+ *
+ * Parameters:
+ * btn - {Object}
+ */
+ _removeButton: function(btn) {
+ OpenLayers.Event.stopObservingElement(btn);
+ btn.map = null;
+ btn.getSlideFactor = null;
+ this.div.removeChild(btn);
+ OpenLayers.Util.removeItem(this.buttons, btn);
+ },
+
+ /**
+ * Method: removeButtons
+ */
+ removeButtons: function() {
+ for(var i=this.buttons.length-1; i>=0; --i) {
+ this._removeButton(this.buttons[i]);
+ }
+ },
+
+ /**
+ * Method: doubleClick
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean}
+ */
+ doubleClick: function (evt) {
+ OpenLayers.Event.stop(evt);
+ return false;
+ },
+
+ /**
+ * Method: buttonDown
+ *
+ * Parameters:
+ * evt - {Event}
+ */
+ buttonDown: function (evt) {
+ if (!OpenLayers.Event.isLeftClick(evt)) {
+ return;
+ }
+
+ switch (this.action) {
+ case "panup":
+ this.map.pan(0, -this.getSlideFactor("h"));
+ break;
+ case "pandown":
+ this.map.pan(0, this.getSlideFactor("h"));
+ break;
+ case "panleft":
+ this.map.pan(-this.getSlideFactor("w"), 0);
+ break;
+ case "panright":
+ this.map.pan(this.getSlideFactor("w"), 0);
+ break;
+ case "zoomin":
+ this.map.zoomIn();
+ break;
+ case "zoomout":
+ this.map.zoomOut();
+ break;
+ case "zoomworld":
+ this.map.zoomToMaxExtent();
+ break;
+ }
+
+ OpenLayers.Event.stop(evt);
+ },
+
+ CLASS_NAME: "OpenLayers.Control.PanZoom"
+});
+
+/**
+ * Constant: X
+ * {Integer}
+ */
+OpenLayers.Control.PanZoom.X = 4;
+
+/**
+ * Constant: Y
+ * {Integer}
+ */
+OpenLayers.Control.PanZoom.Y = 4;
+/* ======================================================================
+ OpenLayers/Strategy/Paging.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Strategy.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.Paging
+ * Strategy for vector feature paging
+ *
+ * Inherits from:
+ * - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, {
+
+ /**
+ * Property: features
+ * {Array(<OpenLayers.Feature.Vector>)} Cached features.
+ */
+ features: null,
+
+ /**
+ * Property: length
+ * {Integer} Number of features per page. Default is 10.
+ */
+ length: 10,
+
+ /**
+ * Property: num
+ * {Integer} The currently displayed page number.
+ */
+ num: null,
+
+ /**
+ * Property: paging
+ * {Boolean} The strategy is currently changing pages.
+ */
+ paging: false,
+
+ /**
+ * Constructor: OpenLayers.Strategy.Paging
+ * Create a new paging strategy.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ */
+ initialize: function(options) {
+ OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * APIMethod: activate
+ * Activate the strategy. Register any listeners, do appropriate setup.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully activated.
+ */
+ activate: function() {
+ var activated = OpenLayers.Strategy.prototype.activate.call(this);
+ if(activated) {
+ this.layer.events.on({
+ "beforefeaturesadded": this.cacheFeatures,
+ scope: this
+ });
+ }
+ return activated;
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Deactivate the strategy. Unregister any listeners, do appropriate
+ * tear-down.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
+ if(deactivated) {
+ this.clearCache();
+ this.layer.events.un({
+ "beforefeaturesadded": this.cacheFeatures,
+ scope: this
+ });
+ }
+ return deactivated;
+ },
+
+ /**
+ * Method: cacheFeatures
+ * Cache features before they are added to the layer.
+ *
+ * Parameters:
+ * event - {Object} The event that this was listening for. This will come
+ * with a batch of features to be paged.
+ */
+ cacheFeatures: function(event) {
+ if(!this.paging) {
+ this.clearCache();
+ this.features = event.features;
+ this.pageNext(event);
+ }
+ },
+
+ /**
+ * Method: clearCache
+ * Clear out the cached features. This destroys features, assuming
+ * nothing else has a reference.
+ */
+ clearCache: function() {
+ if(this.features) {
+ for(var i=0; i<this.features.length; ++i) {
+ this.features[i].destroy();
+ }
+ }
+ this.features = null;
+ this.num = null;
+ },
+
+ /**
+ * APIMethod: pageCount
+ * Get the total count of pages given the current cache of features.
+ *
+ * Returns:
+ * {Integer} The page count.
+ */
+ pageCount: function() {
+ var numFeatures = this.features ? this.features.length : 0;
+ return Math.ceil(numFeatures / this.length);
+ },
+
+ /**
+ * APIMethod: pageNum
+ * Get the zero based page number.
+ *
+ * Returns:
+ * {Integer} The current page number being displayed.
+ */
+ pageNum: function() {
+ return this.num;
+ },
+
+ /**
+ * APIMethod: pageLength
+ * Gets or sets page length.
+ *
+ * Parameters:
+ * newLength: {Integer} Optional length to be set.
+ *
+ * Returns:
+ * {Integer} The length of a page (number of features per page).
+ */
+ pageLength: function(newLength) {
+ if(newLength && newLength > 0) {
+ this.length = newLength;
+ }
+ return this.length;
+ },
+
+ /**
+ * APIMethod: pageNext
+ * Display the next page of features.
+ *
+ * Returns:
+ * {Boolean} A new page was displayed.
+ */
+ pageNext: function(event) {
+ var changed = false;
+ if(this.features) {
+ if(this.num === null) {
+ this.num = -1;
+ }
+ var start = (this.num + 1) * this.length;
+ changed = this.page(start, event);
+ }
+ return changed;
+ },
+
+ /**
+ * APIMethod: pagePrevious
+ * Display the previous page of features.
+ *
+ * Returns:
+ * {Boolean} A new page was displayed.
+ */
+ pagePrevious: function() {
+ var changed = false;
+ if(this.features) {
+ if(this.num === null) {
+ this.num = this.pageCount();
+ }
+ var start = (this.num - 1) * this.length;
+ changed = this.page(start);
+ }
+ return changed;
+ },
+
+ /**
+ * Method: page
+ * Display the page starting at the given index from the cache.
+ *
+ * Returns:
+ * {Boolean} A new page was displayed.
+ */
+ page: function(start, event) {
+ var changed = false;
+ if(this.features) {
+ if(start >= 0 && start < this.features.length) {
+ var num = Math.floor(start / this.length);
+ if(num != this.num) {
+ this.paging = true;
+ var features = this.features.slice(start, start + this.length);
+ this.layer.removeFeatures(this.layer.features);
+ this.num = num;
+ // modify the event if any
+ if(event && event.features) {
+ // this.was called by an event listener
+ event.features = features;
+ } else {
+ // this was called directly on the strategy
+ this.layer.addFeatures(features);
+ }
+ this.paging = false;
+ changed = true;
+ }
+ }
+ }
+ return changed;
+ },
+
+ CLASS_NAME: "OpenLayers.Strategy.Paging"
+});
+/* ======================================================================
+ OpenLayers/Strategy/BBOX.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Strategy.js
+ * @requires OpenLayers/Filter/Spatial.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.BBOX
+ * A simple strategy that reads new features when the viewport invalidates
+ * some bounds.
+ *
+ * Inherits from:
+ * - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, {
+
+ /**
+ * Property: bounds
+ * {<OpenLayers.Bounds>} The current data bounds (in the same projection
+ * as the layer - not always the same projection as the map).
+ */
+ bounds: null,
+
+ /**
+ * Property: resolution
+ * {Float} The current data resolution.
+ */
+ resolution: null,
+
+ /**
+ * APIProperty: ratio
+ * {Float} The ratio of the data bounds to the viewport bounds (in each
+ * dimension). Default is 2.
+ */
+ ratio: 2,
+
+ /**
+ * Property: resFactor
+ * {Float} Optional factor used to determine when previously requested
+ * features are invalid. If set, the resFactor will be compared to the
+ * resolution of the previous request to the current map resolution.
+ * If resFactor > (old / new) and 1/resFactor < (old / new). If you
+ * set a resFactor of 1, data will be requested every time the
+ * resolution changes. If you set a resFactor of 3, data will be
+ * requested if the old resolution is 3 times the new, or if the new is
+ * 3 times the old. If the old bounds do not contain the new bounds
+ * new data will always be requested (with or without considering
+ * resFactor).
+ */
+ resFactor: null,
+
+ /**
+ * Property: response
+ * {<OpenLayers.Protocol.Response>} The protocol response object returned
+ * by the layer protocol.
+ */
+ response: null,
+
+ /**
+ * Constructor: OpenLayers.Strategy.BBOX
+ * Create a new BBOX strategy.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ */
+ initialize: function(options) {
+ OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * Method: activate
+ * Set up strategy with regard to reading new batches of remote data.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully activated.
+ */
+ activate: function() {
+ var activated = OpenLayers.Strategy.prototype.activate.call(this);
+ if(activated) {
+ this.layer.events.on({
+ "moveend": this.update,
+ scope: this
+ });
+ this.layer.events.on({
+ "refresh": this.update,
+ scope: this
+ });
+ }
+ return activated;
+ },
+
+ /**
+ * Method: deactivate
+ * Tear down strategy with regard to reading new batches of remote data.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
+ if(deactivated) {
+ this.layer.events.un({
+ "moveend": this.update,
+ scope: this
+ });
+ this.layer.events.un({
+ "refresh": this.update,
+ scope: this
+ });
+ }
+ return deactivated;
+ },
+
+ /**
+ * Method: update
+ * Callback function called on "moveend" or "refresh" layer events.
+ *
+ * Parameters:
+ * options - {Object} An object with a property named "force", this
+ * property references a boolean value indicating if new data
+ * must be incondtionally read.
+ */
+ update: function(options) {
+ var mapBounds = this.getMapBounds();
+ if ((options && options.force) || this.invalidBounds(mapBounds)) {
+ this.calculateBounds(mapBounds);
+ this.resolution = this.layer.map.getResolution();
+ this.triggerRead();
+ }
+ },
+
+ /**
+ * Method: getMapBounds
+ * Get the map bounds expressed in the same projection as this layer.
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} Map bounds in the projection of the layer.
+ */
+ getMapBounds: function() {
+ var bounds = this.layer.map.getExtent();
+ if(!this.layer.projection.equals(this.layer.map.getProjectionObject())) {
+ bounds = bounds.clone().transform(
+ this.layer.map.getProjectionObject(), this.layer.projection
+ );
+ }
+ return bounds;
+ },
+
+ /**
+ * Method: invalidBounds
+ * Determine whether the previously requested set of features is invalid.
+ * This occurs when the new map bounds do not contain the previously
+ * requested bounds. In addition, if <resFactor> is set, it will be
+ * considered.
+ *
+ * Parameters:
+ * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be
+ * retrieved from the map object if not provided
+ *
+ * Returns:
+ * {Boolean}
+ */
+ invalidBounds: function(mapBounds) {
+ if(!mapBounds) {
+ mapBounds = this.getMapBounds();
+ }
+ var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds);
+ if(!invalid && this.resFactor) {
+ var ratio = this.resolution / this.layer.map.getResolution();
+ invalid = (ratio >= this.resFactor || ratio <= (1 / this.resFactor));
+ }
+ return invalid;
+ },
+
+ /**
+ * Method: calculateBounds
+ *
+ * Parameters:
+ * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be
+ * retrieved from the map object if not provided
+ */
+ calculateBounds: function(mapBounds) {
+ if(!mapBounds) {
+ mapBounds = this.getMapBounds();
+ }
+ var center = mapBounds.getCenterLonLat();
+ var dataWidth = mapBounds.getWidth() * this.ratio;
+ var dataHeight = mapBounds.getHeight() * this.ratio;
+ this.bounds = new OpenLayers.Bounds(
+ center.lon - (dataWidth / 2),
+ center.lat - (dataHeight / 2),
+ center.lon + (dataWidth / 2),
+ center.lat + (dataHeight / 2)
+ );
+ },
+
+ /**
+ * Method: triggerRead
+ *
+ * Returns:
+ * {<OpenLayers.Protocol.Response>} The protocol response object
+ * returned by the layer protocol.
+ */
+ triggerRead: function() {
+ if (this.response) {
+ this.layer.protocol.abort(this.response);
+ this.layer.events.triggerEvent("loadend");
+ }
+ this.layer.events.triggerEvent("loadstart");
+ this.response = this.layer.protocol.read({
+ filter: this.createFilter(),
+ callback: this.merge,
+ scope: this
+ });
+ },
+
+ /**
+ * Method: createFilter
+ * Creates a spatial BBOX filter. If the layer that this strategy belongs
+ * to has a filter property, this filter will be combined with the BBOX
+ * filter.
+ *
+ * Returns
+ * {<OpenLayers.Filter>} The filter object.
+ */
+ createFilter: function() {
+ var filter = new OpenLayers.Filter.Spatial({
+ type: OpenLayers.Filter.Spatial.BBOX,
+ value: this.bounds,
+ projection: this.layer.projection
+ });
+ if (this.layer.filter) {
+ filter = new OpenLayers.Filter.Logical({
+ type: OpenLayers.Filter.Logical.AND,
+ filters: [this.layer.filter, filter]
+ });
+ }
+ return filter;
+ },
+
+ /**
+ * Method: merge
+ * Given a list of features, determine which ones to add to the layer.
+ * If the layer projection differs from the map projection, features
+ * will be transformed from the layer projection to the map projection.
+ *
+ * Parameters:
+ * resp - {<OpenLayers.Protocol.Response>} The response object passed
+ * by the protocol.
+ */
+ merge: function(resp) {
+ this.layer.destroyFeatures();
+ var features = resp.features;
+ if(features && features.length > 0) {
+ var remote = this.layer.projection;
+ var local = this.layer.map.getProjectionObject();
+ if(!local.equals(remote)) {
+ var geom;
+ for(var i=0, len=features.length; i<len; ++i) {
+ geom = features[i].geometry;
+ if(geom) {
+ geom.transform(remote, local);
+ }
+ }
+ }
+ this.layer.addFeatures(features);
+ }
+ this.response = null;
+ this.layer.events.triggerEvent("loadend");
+ },
+
+ CLASS_NAME: "OpenLayers.Strategy.BBOX"
+});
+/* ======================================================================
+ OpenLayers/Layer/Google/v3.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/Google.js
+ */
+
+/**
+ * Constant: OpenLayers.Layer.Google.v3
+ *
+ * Mixin providing functionality specific to the Google Maps API v3. Note that
+ * this layer configures the google.maps.map object with the "disableDefaultUI"
+ * option set to true. Using UI controls that the Google Maps API provides is
+ * not supported by the OpenLayers API.
+ */
+OpenLayers.Layer.Google.v3 = {
+
+ /**
+ * Constant: DEFAULTS
+ * {Object} It is not recommended to change the properties set here. Note
+ * that Google.v3 layers only work when sphericalMercator is set to true.
+ *
+ * (code)
+ * {
+ * maxExtent: new OpenLayers.Bounds(
+ * -128 * 156543.0339,
+ * -128 * 156543.0339,
+ * 128 * 156543.0339,
+ * 128 * 156543.0339
+ * ),
+ * sphericalMercator: true,
+ * maxResolution: 156543.0339,
+ * units: "m",
+ * projection: "EPSG:900913"
+ * }
+ * (end)
+ */
+ DEFAULTS: {
+ maxExtent: new OpenLayers.Bounds(
+ -128 * 156543.0339,
+ -128 * 156543.0339,
+ 128 * 156543.0339,
+ 128 * 156543.0339
+ ),
+ sphericalMercator: true,
+ maxResolution: 156543.0339,
+ units: "m",
+ projection: "EPSG:900913"
+ },
+
+ /**
+ * APIProperty: animationEnabled
+ * {Boolean} If set to true, the transition between zoom levels will be
+ * animated (if supported by the GMaps API for the device used). Set to
+ * false to match the zooming experience of other layer types. Default
+ * is true. Note that the GMaps API does not give us control over zoom
+ * animation, so if set to false, when zooming, this will make the
+ * layer temporarily invisible, wait until GMaps reports the map being
+ * idle, and make it visible again. The result will be a blank layer
+ * for a few moments while zooming.
+ */
+ animationEnabled: true,
+
+ /**
+ * Method: loadMapObject
+ * Load the GMap and register appropriate event listeners. If we can't
+ * load GMap2, then display a warning message.
+ */
+ loadMapObject:function() {
+ if (!this.type) {
+ this.type = google.maps.MapTypeId.ROADMAP;
+ }
+ var mapObject;
+ var cache = OpenLayers.Layer.Google.cache[this.map.id];
+ if (cache) {
+ // there are already Google layers added to this map
+ mapObject = cache.mapObject;
+ // increment the layer count
+ ++cache.count;
+ } else {
+ // this is the first Google layer for this map
+
+ var container = this.map.viewPortDiv;
+ var div = document.createElement("div");
+ div.id = this.map.id + "_GMapContainer";
+ div.style.position = "absolute";
+ div.style.width = "100%";
+ div.style.height = "100%";
+ container.appendChild(div);
+
+ // create GMap and shuffle elements
+ var center = this.map.getCenter();
+ mapObject = new google.maps.Map(div, {
+ center: center ?
+ new google.maps.LatLng(center.lat, center.lon) :
+ new google.maps.LatLng(0, 0),
+ zoom: this.map.getZoom() || 0,
+ mapTypeId: this.type,
+ disableDefaultUI: true,
+ keyboardShortcuts: false,
+ draggable: false,
+ disableDoubleClickZoom: true,
+ scrollwheel: false,
+ streetViewControl: false
+ });
+
+ // cache elements for use by any other google layers added to
+ // this same map
+ cache = {
+ mapObject: mapObject,
+ count: 1
+ };
+ OpenLayers.Layer.Google.cache[this.map.id] = cache;
+ this.repositionListener = google.maps.event.addListenerOnce(
+ mapObject,
+ "center_changed",
+ OpenLayers.Function.bind(this.repositionMapElements, this)
+ );
+ }
+ this.mapObject = mapObject;
+ this.setGMapVisibility(this.visibility);
+ },
+
+ /**
+ * Method: repositionMapElements
+ *
+ * Waits until powered by and terms of use elements are available and then
+ * moves them so they are clickable.
+ */
+ repositionMapElements: function() {
+
+ // This is the first time any Google layer in this mapObject has been
+ // made visible. The mapObject needs to know the container size.
+ google.maps.event.trigger(this.mapObject, "resize");
+
+ var div = this.mapObject.getDiv().firstChild;
+ if (!div || div.childNodes.length < 3) {
+ this.repositionTimer = window.setTimeout(
+ OpenLayers.Function.bind(this.repositionMapElements, this),
+ 250
+ );
+ return false;
+ }
+
+ var cache = OpenLayers.Layer.Google.cache[this.map.id];
+ var container = this.map.viewPortDiv;
+
+ // move the Map Data popup to the container, if any
+ while (div.lastChild.style.display == "none") {
+ container.appendChild(div.lastChild);
+ }
+
+ // move the ToS and branding stuff up to the container div
+ var termsOfUse = div.lastChild;
+ container.appendChild(termsOfUse);
+ termsOfUse.style.zIndex = "1100";
+ termsOfUse.style.bottom = "";
+ termsOfUse.className = "olLayerGoogleCopyright olLayerGoogleV3";
+ termsOfUse.style.display = "";
+ cache.termsOfUse = termsOfUse;
+
+ var poweredBy = div.lastChild;
+ container.appendChild(poweredBy);
+ poweredBy.style.zIndex = "1100";
+ poweredBy.style.bottom = "";
+ poweredBy.className = "olLayerGooglePoweredBy olLayerGoogleV3 gmnoprint";
+ poweredBy.style.display = "";
+ cache.poweredBy = poweredBy;
+
+ this.setGMapVisibility(this.visibility);
+
+ },
+
+ /**
+ * APIMethod: onMapResize
+ */
+ onMapResize: function() {
+ if (this.visibility) {
+ google.maps.event.trigger(this.mapObject, "resize");
+ } else {
+ if (!this._resized) {
+ var layer = this;
+ google.maps.event.addListenerOnce(this.mapObject, "tilesloaded", function() {
+ delete layer._resized;
+ google.maps.event.trigger(layer.mapObject, "resize");
+ layer.moveTo(layer.map.getCenter(), layer.map.getZoom());
+ });
+ }
+ this._resized = true;
+ }
+ },
+
+ /**
+ * Method: setGMapVisibility
+ * Display the GMap container and associated elements.
+ *
+ * Parameters:
+ * visible - {Boolean} Display the GMap elements.
+ */
+ setGMapVisibility: function(visible) {
+ var cache = OpenLayers.Layer.Google.cache[this.map.id];
+ if (cache) {
+ var type = this.type;
+ var layers = this.map.layers;
+ var layer;
+ for (var i=layers.length-1; i>=0; --i) {
+ layer = layers[i];
+ if (layer instanceof OpenLayers.Layer.Google &&
+ layer.visibility === true && layer.inRange === true) {
+ type = layer.type;
+ visible = true;
+ break;
+ }
+ }
+ var container = this.mapObject.getDiv();
+ if (visible === true) {
+ this.mapObject.setMapTypeId(type);
+ container.style.left = "";
+ if (cache.termsOfUse && cache.termsOfUse.style) {
+ cache.termsOfUse.style.left = "";
+ cache.termsOfUse.style.display = "";
+ cache.poweredBy.style.display = "";
+ }
+ cache.displayed = this.id;
+ } else {
+ delete cache.displayed;
+ container.style.left = "-9999px";
+ if (cache.termsOfUse && cache.termsOfUse.style) {
+ cache.termsOfUse.style.display = "none";
+ // move ToU far to the left in addition to setting
+ // display to "none", because at the end of the GMap
+ // load sequence, display: none will be unset and ToU
+ // would be visible after loading a map with a google
+ // layer that is initially hidden.
+ cache.termsOfUse.style.left = "-9999px";
+ cache.poweredBy.style.display = "none";
+ }
+ }
+ }
+ },
+
+ /**
+ * Method: getMapContainer
+ *
+ * Returns:
+ * {DOMElement} the GMap container's div
+ */
+ getMapContainer: function() {
+ return this.mapObject.getDiv();
+ },
+
+ //
+ // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds
+ //
+
+ /**
+ * APIMethod: getMapObjectBoundsFromOLBounds
+ *
+ * Parameters:
+ * olBounds - {<OpenLayers.Bounds>}
+ *
+ * Returns:
+ * {Object} A MapObject Bounds, translated from olBounds
+ * Returns null if null value is passed in
+ */
+ getMapObjectBoundsFromOLBounds: function(olBounds) {
+ var moBounds = null;
+ if (olBounds != null) {
+ var sw = this.sphericalMercator ?
+ this.inverseMercator(olBounds.bottom, olBounds.left) :
+ new OpenLayers.LonLat(olBounds.bottom, olBounds.left);
+ var ne = this.sphericalMercator ?
+ this.inverseMercator(olBounds.top, olBounds.right) :
+ new OpenLayers.LonLat(olBounds.top, olBounds.right);
+ moBounds = new google.maps.LatLngBounds(
+ new google.maps.LatLng(sw.lat, sw.lon),
+ new google.maps.LatLng(ne.lat, ne.lon)
+ );
+ }
+ return moBounds;
+ },
+
+
+ /************************************
+ * *
+ * MapObject Interface Controls *
+ * *
+ ************************************/
+
+
+ // LonLat - Pixel Translation
+
+ /**
+ * APIMethod: getMapObjectLonLatFromMapObjectPixel
+ *
+ * Parameters:
+ * moPixel - {Object} MapObject Pixel format
+ *
+ * Returns:
+ * {Object} MapObject LonLat translated from MapObject Pixel
+ */
+ getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
+ var size = this.map.getSize();
+ var lon = this.getLongitudeFromMapObjectLonLat(this.mapObject.center);
+ var lat = this.getLatitudeFromMapObjectLonLat(this.mapObject.center);
+ var res = this.map.getResolution();
+
+ var delta_x = moPixel.x - (size.w / 2);
+ var delta_y = moPixel.y - (size.h / 2);
+
+ var lonlat = new OpenLayers.LonLat(
+ lon + delta_x * res,
+ lat - delta_y * res
+ );
+
+ if (this.wrapDateLine) {
+ lonlat = lonlat.wrapDateLine(this.maxExtent);
+ }
+ return this.getMapObjectLonLatFromLonLat(lonlat.lon, lonlat.lat);
+ },
+
+ /**
+ * APIMethod: getMapObjectPixelFromMapObjectLonLat
+ *
+ * Parameters:
+ * moLonLat - {Object} MapObject LonLat format
+ *
+ * Returns:
+ * {Object} MapObject Pixel transtlated from MapObject LonLat
+ */
+ getMapObjectPixelFromMapObjectLonLat: function(moLonLat) {
+ var lon = this.getLongitudeFromMapObjectLonLat(moLonLat);
+ var lat = this.getLatitudeFromMapObjectLonLat(moLonLat);
+ var res = this.map.getResolution();
+ var extent = this.map.getExtent();
+ var px = new OpenLayers.Pixel(
+ (1/res * (lon - extent.left)),
+ (1/res * (extent.top - lat))
+ );
+ return this.getMapObjectPixelFromXY(px.x, px.y);
+ },
+
+
+ /**
+ * APIMethod: setMapObjectCenter
+ * Set the mapObject to the specified center and zoom
+ *
+ * Parameters:
+ * center - {Object} MapObject LonLat format
+ * zoom - {int} MapObject zoom format
+ */
+ setMapObjectCenter: function(center, zoom) {
+ if (this.animationEnabled === false && zoom != this.mapObject.zoom) {
+ var mapContainer = this.getMapContainer();
+ google.maps.event.addListenerOnce(
+ this.mapObject,
+ "idle",
+ function() {
+ mapContainer.style.visibility = "";
+ }
+ );
+ mapContainer.style.visibility = "hidden";
+ }
+ this.mapObject.setOptions({
+ center: center,
+ zoom: zoom
+ });
+ },
+
+
+ // Bounds
+
+ /**
+ * APIMethod: getMapObjectZoomFromMapObjectBounds
+ *
+ * Parameters:
+ * moBounds - {Object} MapObject Bounds format
+ *
+ * Returns:
+ * {Object} MapObject Zoom for specified MapObject Bounds
+ */
+ getMapObjectZoomFromMapObjectBounds: function(moBounds) {
+ return this.mapObject.getBoundsZoomLevel(moBounds);
+ },
+
+ /************************************
+ * *
+ * MapObject Primitives *
+ * *
+ ************************************/
+
+
+ // LonLat
+
+ /**
+ * APIMethod: getMapObjectLonLatFromLonLat
+ *
+ * Parameters:
+ * lon - {Float}
+ * lat - {Float}
+ *
+ * Returns:
+ * {Object} MapObject LonLat built from lon and lat params
+ */
+ getMapObjectLonLatFromLonLat: function(lon, lat) {
+ var gLatLng;
+ if(this.sphericalMercator) {
+ var lonlat = this.inverseMercator(lon, lat);
+ gLatLng = new google.maps.LatLng(lonlat.lat, lonlat.lon);
+ } else {
+ gLatLng = new google.maps.LatLng(lat, lon);
+ }
+ return gLatLng;
+ },
+
+ // Pixel
+
+ /**
+ * APIMethod: getMapObjectPixelFromXY
+ *
+ * Parameters:
+ * x - {Integer}
+ * y - {Integer}
+ *
+ * Returns:
+ * {Object} MapObject Pixel from x and y parameters
+ */
+ getMapObjectPixelFromXY: function(x, y) {
+ return new google.maps.Point(x, y);
+ },
+
+ /**
+ * APIMethod: destroy
+ * Clean up this layer.
+ */
+ destroy: function() {
+ if (this.repositionListener) {
+ google.maps.event.removeListener(this.repositionListener);
+ }
+ if (this.repositionTimer) {
+ window.clearTimeout(this.repositionTimer);
+ }
+ OpenLayers.Layer.Google.prototype.destroy.apply(this, arguments);
+ }
+
+};
+/* ======================================================================
+ OpenLayers/Marker/Box.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Marker.js
+ */
+
+/**
+ * Class: OpenLayers.Marker.Box
+ *
+ * Inherits from:
+ * - <OpenLayers.Marker>
+ */
+OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, {
+
+ /**
+ * Property: bounds
+ * {<OpenLayers.Bounds>}
+ */
+ bounds: null,
+
+ /**
+ * Property: div
+ * {DOMElement}
+ */
+ div: null,
+
+ /**
+ * Constructor: OpenLayers.Marker.Box
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * borderColor - {String}
+ * borderWidth - {int}
+ */
+ initialize: function(bounds, borderColor, borderWidth) {
+ this.bounds = bounds;
+ this.div = OpenLayers.Util.createDiv();
+ this.div.style.overflow = 'hidden';
+ this.events = new OpenLayers.Events(this, this.div, null);
+ this.setBorder(borderColor, borderWidth);
+ },
+
+ /**
+ * Method: destroy
+ */
+ destroy: function() {
+
+ this.bounds = null;
+ this.div = null;
+
+ OpenLayers.Marker.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: setBorder
+ * Allow the user to change the box's color and border width
+ *
+ * Parameters:
+ * color - {String} Default is "red"
+ * width - {int} Default is 2
+ */
+ setBorder: function (color, width) {
+ if (!color) {
+ color = "red";
+ }
+ if (!width) {
+ width = 2;
+ }
+ this.div.style.border = width + "px solid " + color;
+ },
+
+ /**
+ * Method: draw
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ * sz - {<OpenLayers.Size>}
+ *
+ * Returns:
+ * {DOMElement} A new DOM Image with this marker´s icon set at the
+ * location passed-in
+ */
+ draw: function(px, sz) {
+ OpenLayers.Util.modifyDOMElement(this.div, null, px, sz);
+ return this.div;
+ },
+
+ /**
+ * Method: onScreen
+ *
+ * Rreturn:
+ * {Boolean} Whether or not the marker is currently visible on screen.
+ */
+ onScreen:function() {
+ var onScreen = false;
+ if (this.map) {
+ var screenBounds = this.map.getExtent();
+ onScreen = screenBounds.containsBounds(this.bounds, true, true);
+ }
+ return onScreen;
+ },
+
+ /**
+ * Method: display
+ * Hide or show the icon
+ *
+ * Parameters:
+ * display - {Boolean}
+ */
+ display: function(display) {
+ this.div.style.display = (display) ? "" : "none";
+ },
+
+ CLASS_NAME: "OpenLayers.Marker.Box"
+});
+
+/* ======================================================================
+ OpenLayers/Layer/MapGuide.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Request/XMLHttpRequest.js
+ * @requires OpenLayers/Layer/Grid.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.MapGuide
+ * Instances of OpenLayers.Layer.MapGuide are used to display
+ * data from a MapGuide OS instance.
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+ /**
+ * APIProperty: isBaseLayer
+ * {Boolean} Treat this layer as a base layer. Default is true.
+ **/
+ isBaseLayer: true,
+
+ /**
+ * APIProperty: useHttpTile
+ * {Boolean} use a tile cache exposed directly via a webserver rather than the
+ * via mapguide server. This does require extra configuration on the Mapguide Server,
+ * and will only work when singleTile is false. The url for the layer must be set to the
+ * webserver path rather than the Mapguide mapagent.
+ * See http://trac.osgeo.org/mapguide/wiki/CodeSamples/Tiles/ServingTilesViaHttp
+ **/
+ useHttpTile: false,
+
+ /**
+ * APIProperty: singleTile
+ * {Boolean} use tile server or request single tile image.
+ **/
+ singleTile: false,
+
+ /**
+ * APIProperty: useOverlay
+ * {Boolean} flag to indicate if the layer should be retrieved using
+ * GETMAPIMAGE (default) or using GETDYNAMICOVERLAY requests.
+ **/
+ useOverlay: false,
+
+ /**
+ * APIProperty: useAsyncOverlay
+ * {Boolean} indicates if the MapGuide site supports the asynchronous
+ * GETDYNAMICOVERLAY requests which is available in MapGuide Enterprise 2010
+ * and MapGuide Open Source v2.0.3 or higher. The newer versions of MG
+ * is called asynchronously, allows selections to be drawn separately from
+ * the map and offers styling options.
+ *
+ * With older versions of MapGuide, set useAsyncOverlay=false. Note that in
+ * this case a synchronous AJAX call is issued and the mapname and session
+ * parameters must be used to initialize the layer, not the mapdefinition
+ * parameter. Also note that this will issue a synchronous AJAX request
+ * before the image request can be issued so the users browser may lock
+ * up if the MG Web tier does not respond in a timely fashion.
+ **/
+ useAsyncOverlay: true,
+
+ /**
+ * Constant: TILE_PARAMS
+ * {Object} Hashtable of default parameter key/value pairs for tiled layer
+ */
+ TILE_PARAMS: {
+ operation: 'GETTILEIMAGE',
+ version: '1.2.0'
+ },
+
+ /**
+ * Constant: SINGLE_TILE_PARAMS
+ * {Object} Hashtable of default parameter key/value pairs for untiled layer
+ */
+ SINGLE_TILE_PARAMS: {
+ operation: 'GETMAPIMAGE',
+ format: 'PNG',
+ locale: 'en',
+ clip: '1',
+ version: '1.0.0'
+ },
+
+ /**
+ * Constant: OVERLAY_PARAMS
+ * {Object} Hashtable of default parameter key/value pairs for untiled layer
+ */
+ OVERLAY_PARAMS: {
+ operation: 'GETDYNAMICMAPOVERLAYIMAGE',
+ format: 'PNG',
+ locale: 'en',
+ clip: '1',
+ version: '2.0.0'
+ },
+
+ /**
+ * Constant: FOLDER_PARAMS
+ * {Object} Hashtable of parameter key/value pairs which describe
+ * the folder structure for tiles as configured in the mapguide
+ * serverconfig.ini section [TileServiceProperties]
+ */
+ FOLDER_PARAMS: {
+ tileColumnsPerFolder: 30,
+ tileRowsPerFolder: 30,
+ format: 'png',
+ querystring: null
+ },
+
+ /**
+ * Property: defaultSize
+ * {<OpenLayers.Size>} Tile size as produced by MapGuide server
+ **/
+ defaultSize: new OpenLayers.Size(300,300),
+
+ /**
+ * Constructor: OpenLayers.Layer.MapGuide
+ * Create a new Mapguide layer, either tiled or untiled.
+ *
+ * For tiled layers, the 'groupName' and 'mapDefinition' values
+ * must be specified as parameters in the constructor.
+ *
+ * For untiled base layers, specify either combination of 'mapName' and
+ * 'session', or 'mapDefinition' and 'locale'.
+ *
+ * For older versions of MapGuide and overlay layers, set useAsyncOverlay
+ * to false and in this case mapName and session are required parameters
+ * for the constructor.
+ *
+ * NOTE: MapGuide OS uses a DPI value and degrees to meters conversion
+ * factor that are different than the defaults used in OpenLayers,
+ * so these must be adjusted accordingly in your application.
+ * See the MapGuide example for how to set these values for MGOS.
+ *
+ * Parameters:
+ * name - {String} Name of the layer displayed in the interface
+ * url - {String} Location of the MapGuide mapagent executable
+ * (e.g. http://localhost:8008/mapguide/mapagent/mapagent.fcgi)
+ * params - {Object} hashtable of additional parameters to use. Some
+ * parameters may require additional code on the server. The ones that
+ * you may want to use are:
+ * - mapDefinition - {String} The MapGuide resource definition
+ * (e.g. Library://Samples/Gmap/Maps/gmapTiled.MapDefinition)
+ * - locale - Locale setting
+ * (for untiled overlays layers only)
+ * - mapName - {String} Name of the map as stored in the MapGuide session.
+ * (for untiled layers with a session parameter only)
+ * - session - { String} MapGuide session ID
+ * (for untiled overlays layers only)
+ * - basemaplayergroupname - {String} GroupName for tiled MapGuide layers only
+ * - format - Image format to be returned (for untiled overlay layers only)
+ * - showLayers - {String} A comma separated list of GUID's for the
+ * layers to display eg: 'cvc-xcv34,453-345-345sdf'.
+ * - hideLayers - {String} A comma separated list of GUID's for the
+ * layers to hide eg: 'cvc-xcv34,453-345-345sdf'.
+ * - showGroups - {String} A comma separated list of GUID's for the
+ * groups to display eg: 'cvc-xcv34,453-345-345sdf'.
+ * - hideGroups - {String} A comma separated list of GUID's for the
+ * groups to hide eg: 'cvc-xcv34,453-345-345sdf'
+ * - selectionXml - {String} A selection xml string Some server plumbing
+ * is required to read such a value.
+ * options - {Ojbect} Hashtable of extra options to tag onto the layer;
+ * will vary depending if tiled or untiled maps are being requested
+ */
+ initialize: function(name, url, params, options) {
+
+ OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments);
+
+ // unless explicitly set in options, if the layer is transparent,
+ // it will be an overlay
+ if (options == null || options.isBaseLayer == null) {
+ this.isBaseLayer = ((this.transparent != "true") &&
+ (this.transparent != true));
+ }
+
+ if (options && options.useOverlay!=null) {
+ this.useOverlay = options.useOverlay;
+ }
+
+ //initialize for untiled layers
+ if (this.singleTile) {
+ if (this.useOverlay) {
+ OpenLayers.Util.applyDefaults(
+ this.params,
+ this.OVERLAY_PARAMS
+ );
+ if (!this.useAsyncOverlay) {
+ this.params.version = "1.0.0";
+ }
+ } else {
+ OpenLayers.Util.applyDefaults(
+ this.params,
+ this.SINGLE_TILE_PARAMS
+ );
+ }
+ } else {
+ //initialize for tiled layers
+ if (this.useHttpTile) {
+ OpenLayers.Util.applyDefaults(
+ this.params,
+ this.FOLDER_PARAMS
+ );
+ } else {
+ OpenLayers.Util.applyDefaults(
+ this.params,
+ this.TILE_PARAMS
+ );
+ }
+ this.setTileSize(this.defaultSize);
+ }
+ },
+
+ /**
+ * Method: clone
+ * Create a clone of this layer
+ *
+ * Returns:
+ * {<OpenLayers.Layer.MapGuide>} An exact clone of this layer
+ */
+ clone: function (obj) {
+ if (obj == null) {
+ obj = new OpenLayers.Layer.MapGuide(this.name,
+ this.url,
+ this.params,
+ this.getOptions());
+ }
+ //get all additions from superclasses
+ obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+ return obj;
+ },
+
+ /**
+ * Method: addTile
+ * Creates a tile, initializes it, and adds it to the layer div.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * position - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+ */
+ addTile:function(bounds,position) {
+ return new OpenLayers.Tile.Image(this, position, bounds,
+ null, this.tileSize);
+ },
+
+ /**
+ * Method: getURL
+ * Return a query string for this layer
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox
+ * for the request
+ *
+ * Returns:
+ * {String} A string with the layer's url and parameters and also
+ * the passed-in bounds and appropriate tile size specified
+ * as parameters.
+ */
+ getURL: function (bounds) {
+ var url;
+ var center = bounds.getCenterLonLat();
+ var mapSize = this.map.getSize();
+
+ if (this.singleTile) {
+ //set up the call for GETMAPIMAGE or GETDYNAMICMAPOVERLAY with
+ //dynamic map parameters
+ var params = {
+ setdisplaydpi: OpenLayers.DOTS_PER_INCH,
+ setdisplayheight: mapSize.h*this.ratio,
+ setdisplaywidth: mapSize.w*this.ratio,
+ setviewcenterx: center.lon,
+ setviewcentery: center.lat,
+ setviewscale: this.map.getScale()
+ };
+
+ if (this.useOverlay && !this.useAsyncOverlay) {
+ //first we need to call GETVISIBLEMAPEXTENT to set the extent
+ var getVisParams = {};
+ getVisParams = OpenLayers.Util.extend(getVisParams, params);
+ getVisParams.operation = "GETVISIBLEMAPEXTENT";
+ getVisParams.version = "1.0.0";
+ getVisParams.session = this.params.session;
+ getVisParams.mapName = this.params.mapName;
+ getVisParams.format = 'text/xml';
+ url = this.getFullRequestString( getVisParams );
+
+ OpenLayers.Request.GET({url: url, async: false});
+ }
+ //construct the full URL
+ url = this.getFullRequestString( params );
+ } else {
+
+ //tiled version
+ var currentRes = this.map.getResolution();
+ var colidx = Math.floor((bounds.left-this.maxExtent.left)/currentRes);
+ colidx = Math.round(colidx/this.tileSize.w);
+ var rowidx = Math.floor((this.maxExtent.top-bounds.top)/currentRes);
+ rowidx = Math.round(rowidx/this.tileSize.h);
+
+ if (this.useHttpTile){
+ url = this.getImageFilePath(
+ {
+ tilecol: colidx,
+ tilerow: rowidx,
+ scaleindex: this.resolutions.length - this.map.zoom - 1
+ });
+
+ } else {
+ url = this.getFullRequestString(
+ {
+ tilecol: colidx,
+ tilerow: rowidx,
+ scaleindex: this.resolutions.length - this.map.zoom - 1
+ });
+ }
+ }
+ return url;
+ },
+
+ /**
+ * Method: getFullRequestString
+ * getFullRequestString on MapGuide layers is special, because we
+ * do a regular expression replace on ',' in parameters to '+'.
+ * This is why it is subclassed here.
+ *
+ * Parameters:
+ * altUrl - {String} Alternative base URL to use.
+ *
+ * Returns:
+ * {String} A string with the layer's url appropriately encoded for MapGuide
+ */
+ getFullRequestString:function(newParams, altUrl) {
+ // use layer's url unless altUrl passed in
+ var url = (altUrl == null) ? this.url : altUrl;
+
+ // if url is not a string, it should be an array of strings,
+ // in which case we will randomly select one of them in order
+ // to evenly distribute requests to different urls.
+ if (typeof url == "object") {
+ url = url[Math.floor(Math.random()*url.length)];
+ }
+ // requestString always starts with url
+ var requestString = url;
+
+ // create a new params hashtable with all the layer params and the
+ // new params together. then convert to string
+ var allParams = OpenLayers.Util.extend({}, this.params);
+ allParams = OpenLayers.Util.extend(allParams, newParams);
+ // ignore parameters that are already in the url search string
+ var urlParams = OpenLayers.Util.upperCaseObject(
+ OpenLayers.Util.getParameters(url));
+ for(var key in allParams) {
+ if(key.toUpperCase() in urlParams) {
+ delete allParams[key];
+ }
+ }
+ var paramsString = OpenLayers.Util.getParameterString(allParams);
+
+ /* MapGuide needs '+' seperating things like bounds/height/width.
+ Since typically this is URL encoded, we use a slight hack: we
+ depend on the list-like functionality of getParameterString to
+ leave ',' only in the case of list items (since otherwise it is
+ encoded) then do a regular expression replace on the , characters
+ to '+' */
+ paramsString = paramsString.replace(/,/g, "+");
+
+ if (paramsString != "") {
+ var lastServerChar = url.charAt(url.length - 1);
+ if ((lastServerChar == "&") || (lastServerChar == "?")) {
+ requestString += paramsString;
+ } else {
+ if (url.indexOf('?') == -1) {
+ //serverPath has no ? -- add one
+ requestString += '?' + paramsString;
+ } else {
+ //serverPath contains ?, so must already have paramsString at the end
+ requestString += '&' + paramsString;
+ }
+ }
+ }
+ return requestString;
+ },
+
+ /**
+ * Method: getImageFilePath
+ * special handler to request mapguide tiles from an http exposed tilecache
+ *
+ * Parameters:
+ * altUrl - {String} Alternative base URL to use.
+ *
+ * Returns:
+ * {String} A string with the url for the tile image
+ */
+ getImageFilePath:function(newParams, altUrl) {
+ // use layer's url unless altUrl passed in
+ var url = (altUrl == null) ? this.url : altUrl;
+
+ // if url is not a string, it should be an array of strings,
+ // in which case we will randomly select one of them in order
+ // to evenly distribute requests to different urls.
+ if (typeof url == "object") {
+ url = url[Math.floor(Math.random()*url.length)];
+ }
+ // requestString always starts with url
+ var requestString = url;
+
+ var tileRowGroup = "";
+ var tileColGroup = "";
+
+ if (newParams.tilerow < 0) {
+ tileRowGroup = '-';
+ }
+
+ if (newParams.tilerow == 0 ) {
+ tileRowGroup += '0';
+ } else {
+ tileRowGroup += Math.floor(Math.abs(newParams.tilerow/this.params.tileRowsPerFolder)) * this.params.tileRowsPerFolder;
+ }
+
+ if (newParams.tilecol < 0) {
+ tileColGroup = '-';
+ }
+
+ if (newParams.tilecol == 0) {
+ tileColGroup += '0';
+ } else {
+ tileColGroup += Math.floor(Math.abs(newParams.tilecol/this.params.tileColumnsPerFolder)) * this.params.tileColumnsPerFolder;
+ }
+
+ var tilePath = '/S' + Math.floor(newParams.scaleindex)
+ + '/' + this.params.basemaplayergroupname
+ + '/R' + tileRowGroup
+ + '/C' + tileColGroup
+ + '/' + (newParams.tilerow % this.params.tileRowsPerFolder)
+ + '_' + (newParams.tilecol % this.params.tileColumnsPerFolder)
+ + '.' + this.params.format;
+
+ if (this.params.querystring) {
+ tilePath += "?" + this.params.querystring;
+ }
+
+ requestString += tilePath;
+ return requestString;
+ },
+
+ /**
+ * Method: calculateGridLayout
+ * Generate parameters for the grid layout. This
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bound>}
+ * extent - {<OpenLayers.Bounds>}
+ * resolution - {Number}
+ *
+ * Returns:
+ * Object containing properties tilelon, tilelat, tileoffsetlat,
+ * tileoffsetlat, tileoffsetx, tileoffsety
+ */
+ calculateGridLayout: function(bounds, extent, resolution) {
+ var tilelon = resolution * this.tileSize.w;
+ var tilelat = resolution * this.tileSize.h;
+
+ var offsetlon = bounds.left - extent.left;
+ var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
+ var tilecolremain = offsetlon/tilelon - tilecol;
+ var tileoffsetx = -tilecolremain * this.tileSize.w;
+ var tileoffsetlon = extent.left + tilecol * tilelon;
+
+ var offsetlat = extent.top - bounds.top + tilelat;
+ var tilerow = Math.floor(offsetlat/tilelat) - this.buffer;
+ var tilerowremain = tilerow - offsetlat/tilelat;
+ var tileoffsety = tilerowremain * this.tileSize.h;
+ var tileoffsetlat = extent.top - tilelat*tilerow;
+
+ return {
+ tilelon: tilelon, tilelat: tilelat,
+ tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
+ tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
+ };
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.MapGuide"
+});
+/* ======================================================================
+ OpenLayers/Control/Measure.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Feature/Vector.js
+ */
+
+/**
+ * Class: OpenLayers.Control.Measure
+ * Allows for drawing of features for measurements.
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Constant: EVENT_TYPES
+ * {Array(String)} Supported application event types. Register a listener
+ * for a particular event with the following syntax:
+ * (code)
+ * control.events.register(type, obj, listener);
+ * (end)
+ *
+ * Listeners will be called with a reference to an event object. The
+ * properties of this event depends on exactly what happened.
+ *
+ * Supported control event types (in addition to those from <OpenLayers.Control>):
+ * measure - Triggered when a measurement sketch is complete. Listeners
+ * will receive an event with measure, units, order, and geometry
+ * properties.
+ * measurepartial - Triggered when a new point is added to the
+ * measurement sketch or if the <immediate> property is true and the
+ * measurement sketch is modified. Listeners receive an event with measure,
+ * units, order, and geometry.
+ */
+ EVENT_TYPES: ['measure', 'measurepartial'],
+
+ /**
+ * APIProperty: handlerOptions
+ * {Object} Used to set non-default properties on the control's handler
+ */
+ handlerOptions: null,
+
+ /**
+ * Property: callbacks
+ * {Object} The functions that are sent to the handler for callback
+ */
+ callbacks: null,
+
+ /**
+ * APIProperty: displaySystem
+ * {String} Display system for output measurements. Supported values
+ * are 'english', 'metric', and 'geographic'. Default is 'metric'.
+ */
+ displaySystem: 'metric',
+
+ /**
+ * APIProperty: geodesic
+ * {Boolean} Calculate geodesic metrics instead of planar metrics. This
+ * requires that geometries can be transformed into Geographic/WGS84
+ * (if that is not already the map projection). Default is false.
+ */
+ geodesic: false,
+
+ /**
+ * APIProperty: displaySystemUnits
+ * {Object} Units for various measurement systems. Values are arrays
+ * of unit abbreviations (from OpenLayers.INCHES_PER_UNIT) in decreasing
+ * order of length.
+ */
+ displaySystemUnits: {
+ geographic: ['dd'],
+ english: ['mi', 'ft', 'in'],
+ metric: ['km', 'm']
+ },
+
+ /**
+ * Property: delay
+ * {Number} Number of milliseconds between clicks before the event is
+ * considered a double-click. The "measurepartial" event will not
+ * be triggered if the sketch is completed within this time. This
+ * is required for IE where creating a browser reflow (if a listener
+ * is modifying the DOM by displaying the measurement values) messes
+ * with the dblclick listener in the sketch handler.
+ */
+ partialDelay: 300,
+
+ /**
+ * Property: delayedTrigger
+ * {Number} Timeout id of trigger for measurepartial.
+ */
+ delayedTrigger: null,
+
+ /**
+ * APIProperty: persist
+ * {Boolean} Keep the temporary measurement sketch drawn after the
+ * measurement is complete. The geometry will persist until a new
+ * measurement is started, the control is deactivated, or <cancel> is
+ * called.
+ */
+ persist: false,
+
+ /**
+ * APIProperty: immediate
+ * {Boolean} Activates the immediate measurement so that the "measurepartial"
+ * event is also fired once the measurement sketch is modified.
+ * Default is false.
+ */
+ immediate : false,
+
+ /**
+ * Constructor: OpenLayers.Control.Measure
+ *
+ * Parameters:
+ * handler - {<OpenLayers.Handler>}
+ * options - {Object}
+ */
+ initialize: function(handler, options) {
+ // concatenate events specific to measure with those from the base
+ this.EVENT_TYPES =
+ OpenLayers.Control.Measure.prototype.EVENT_TYPES.concat(
+ OpenLayers.Control.prototype.EVENT_TYPES
+ );
+ OpenLayers.Control.prototype.initialize.apply(this, [options]);
+ var callbacks = {done: this.measureComplete,
+ point: this.measurePartial};
+ if (this.immediate){
+ callbacks.modify = this.measureImmediate;
+ }
+ this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks);
+
+ // let the handler options override, so old code that passes 'persist'
+ // directly to the handler does not need an update
+ this.handlerOptions = OpenLayers.Util.extend(
+ {persist: this.persist}, this.handlerOptions
+ );
+ this.handler = new handler(this, this.callbacks, this.handlerOptions);
+ },
+
+ /**
+ * APIMethod: deactivate
+ */
+ deactivate: function() {
+ this.cancelDelay();
+ return OpenLayers.Control.prototype.deactivate.apply(this, arguments);
+ },
+
+ /**
+ * APIMethod: cancel
+ * Stop the control from measuring. If <persist> is true, the temporary
+ * sketch will be erased.
+ */
+ cancel: function() {
+ this.cancelDelay();
+ this.handler.cancel();
+ },
+
+ /**
+ * APIMethod: setImmediate
+ * Sets the <immediate> property. Changes the activity of immediate
+ * measurement.
+ */
+ setImmediate: function(immediate) {
+ this.immediate = immediate;
+ if (this.immediate){
+ this.callbacks.modify = this.measureImmediate;
+ } else {
+ delete this.callbacks.modify;
+ }
+ },
+
+ /**
+ * Method: updateHandler
+ *
+ * Parameters:
+ * handler - {Function} One of the sketch handler constructors.
+ * options - {Object} Options for the handler.
+ */
+ updateHandler: function(handler, options) {
+ var active = this.active;
+ if(active) {
+ this.deactivate();
+ }
+ this.handler = new handler(this, this.callbacks, options);
+ if(active) {
+ this.activate();
+ }
+ },
+
+ /**
+ * Method: measureComplete
+ * Called when the measurement sketch is done.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ */
+ measureComplete: function(geometry) {
+ this.cancelDelay();
+ this.measure(geometry, "measure");
+ },
+
+ /**
+ * Method: measurePartial
+ * Called each time a new point is added to the measurement sketch.
+ *
+ * Parameters:
+ * point - {<OpenLayers.Geometry.Point>} The last point added.
+ * geometry - {<OpenLayers.Geometry>} The sketch geometry.
+ */
+ measurePartial: function(point, geometry) {
+ this.cancelDelay();
+ geometry = geometry.clone();
+ // when we're wating for a dblclick, we have to trigger measurepartial
+ // after some delay to deal with reflow issues in IE
+ if (this.handler.freehandMode(this.handler.evt)) {
+ // no dblclick in freehand mode
+ this.measure(geometry, "measurepartial");
+ } else {
+ this.delayedTrigger = window.setTimeout(
+ OpenLayers.Function.bind(function() {
+ this.delayedTrigger = null;
+ this.measure(geometry, "measurepartial");
+ }, this),
+ this.partialDelay
+ );
+ }
+ },
+
+ /**
+ * Method: measureImmediate
+ * Called each time the measurement sketch is modified.
+ *
+ * Parameters: point - {<OpenLayers.Geometry.Point>} The point at the
+ * mouseposition. feature - {<OpenLayers.Feature.Vector>} The sketch feature.
+ */
+ measureImmediate : function(point, feature) {
+ if (this.delayedTrigger === null &&
+ !this.handler.freehandMode(this.handler.evt)) {
+ this.measure(feature.geometry, "measurepartial");
+ }
+ },
+
+ /**
+ * Method: cancelDelay
+ * Cancels the delay measurement that measurePartial began.
+ */
+ cancelDelay: function() {
+ if (this.delayedTrigger !== null) {
+ window.clearTimeout(this.delayedTrigger);
+ this.delayedTrigger = null;
+ }
+ },
+
+ /**
+ * Method: measure
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ * eventType - {String}
+ */
+ measure: function(geometry, eventType) {
+ var stat, order;
+ if(geometry.CLASS_NAME.indexOf('LineString') > -1) {
+ stat = this.getBestLength(geometry);
+ order = 1;
+ } else {
+ stat = this.getBestArea(geometry);
+ order = 2;
+ }
+ this.events.triggerEvent(eventType, {
+ measure: stat[0],
+ units: stat[1],
+ order: order,
+ geometry: geometry
+ });
+ },
+
+ /**
+ * Method: getBestArea
+ * Based on the <displaySystem> returns the area of a geometry.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {Array([Float, String])} Returns a two item array containing the
+ * area and the units abbreviation.
+ */
+ getBestArea: function(geometry) {
+ var units = this.displaySystemUnits[this.displaySystem];
+ var unit, area;
+ for(var i=0, len=units.length; i<len; ++i) {
+ unit = units[i];
+ area = this.getArea(geometry, unit);
+ if(area > 1) {
+ break;
+ }
+ }
+ return [area, unit];
+ },
+
+ /**
+ * Method: getArea
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ * units - {String} Unit abbreviation
+ *
+ * Returns:
+ * {Float} The geometry area in the given units.
+ */
+ getArea: function(geometry, units) {
+ var area, geomUnits;
+ if(this.geodesic) {
+ area = geometry.getGeodesicArea(this.map.getProjectionObject());
+ geomUnits = "m";
+ } else {
+ area = geometry.getArea();
+ geomUnits = this.map.getUnits();
+ }
+ var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units];
+ if(inPerDisplayUnit) {
+ var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits];
+ area *= Math.pow((inPerMapUnit / inPerDisplayUnit), 2);
+ }
+ return area;
+ },
+
+ /**
+ * Method: getBestLength
+ * Based on the <displaySystem> returns the length of a geometry.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {Array([Float, String])} Returns a two item array containing the
+ * length and the units abbreviation.
+ */
+ getBestLength: function(geometry) {
+ var units = this.displaySystemUnits[this.displaySystem];
+ var unit, length;
+ for(var i=0, len=units.length; i<len; ++i) {
+ unit = units[i];
+ length = this.getLength(geometry, unit);
+ if(length > 1) {
+ break;
+ }
+ }
+ return [length, unit];
+ },
+
+ /**
+ * Method: getLength
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ * units - {String} Unit abbreviation
+ *
+ * Returns:
+ * {Float} The geometry length in the given units.
+ */
+ getLength: function(geometry, units) {
+ var length, geomUnits;
+ if(this.geodesic) {
+ length = geometry.getGeodesicLength(this.map.getProjectionObject());
+ geomUnits = "m";
+ } else {
+ length = geometry.getLength();
+ geomUnits = this.map.getUnits();
+ }
+ var inPerDisplayUnit = OpenLayers.INCHES_PER_UNIT[units];
+ if(inPerDisplayUnit) {
+ var inPerMapUnit = OpenLayers.INCHES_PER_UNIT[geomUnits];
+ length *= (inPerMapUnit / inPerDisplayUnit);
+ }
+ return length;
+ },
+
+ CLASS_NAME: "OpenLayers.Control.Measure"
+});
+/* ======================================================================
+ OpenLayers/Control/DrawFeature.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Feature/Vector.js
+ */
+
+/**
+ * Class: OpenLayers.Control.DrawFeature
+ * The DrawFeature control draws point, line or polygon features on a vector
+ * layer when active.
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.DrawFeature = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Property: layer
+ * {<OpenLayers.Layer.Vector>}
+ */
+ layer: null,
+
+ /**
+ * Property: callbacks
+ * {Object} The functions that are sent to the handler for callback
+ */
+ callbacks: null,
+
+ /**
+ * Constant: EVENT_TYPES
+ *
+ * Supported event types:
+ * featureadded - Triggered when a feature is added
+ */
+ EVENT_TYPES: ["featureadded"],
+
+ /**
+ * APIProperty: multi
+ * {Boolean} Cast features to multi-part geometries before passing to the
+ * layer. Default is false.
+ */
+ multi: false,
+
+ /**
+ * APIProperty: featureAdded
+ * {Function} Called after each feature is added
+ */
+ featureAdded: function() {},
+
+ /**
+ * APIProperty: handlerOptions
+ * {Object} Used to set non-default properties on the control's handler
+ */
+ handlerOptions: null,
+
+ /**
+ * Constructor: OpenLayers.Control.DrawFeature
+ *
+ * Parameters:
+ * layer - {<OpenLayers.Layer.Vector>}
+ * handler - {<OpenLayers.Handler>}
+ * options - {Object}
+ */
+ initialize: function(layer, handler, options) {
+
+ // concatenate events specific to vector with those from the base
+ this.EVENT_TYPES =
+ OpenLayers.Control.DrawFeature.prototype.EVENT_TYPES.concat(
+ OpenLayers.Control.prototype.EVENT_TYPES
+ );
+
+ OpenLayers.Control.prototype.initialize.apply(this, [options]);
+ this.callbacks = OpenLayers.Util.extend(
+ {
+ done: this.drawFeature,
+ modify: function(vertex, feature) {
+ this.layer.events.triggerEvent(
+ "sketchmodified", {vertex: vertex, feature: feature}
+ );
+ },
+ create: function(vertex, feature) {
+ this.layer.events.triggerEvent(
+ "sketchstarted", {vertex: vertex, feature: feature}
+ );
+ }
+ },
+ this.callbacks
+ );
+ this.layer = layer;
+ this.handlerOptions = this.handlerOptions || {};
+ if (!("multi" in this.handlerOptions)) {
+ this.handlerOptions.multi = this.multi;
+ }
+ var sketchStyle = this.layer.styleMap && this.layer.styleMap.styles.temporary;
+ if(sketchStyle) {
+ this.handlerOptions.layerOptions = OpenLayers.Util.applyDefaults(
+ this.handlerOptions.layerOptions,
+ {styleMap: new OpenLayers.StyleMap({"default": sketchStyle})}
+ );
+ }
+ this.handler = new handler(this, this.callbacks, this.handlerOptions);
+ },
+
+ /**
+ * Method: drawFeature
+ */
+ drawFeature: function(geometry) {
+ var feature = new OpenLayers.Feature.Vector(geometry);
+ var proceed = this.layer.events.triggerEvent(
+ "sketchcomplete", {feature: feature}
+ );
+ if(proceed !== false) {
+ feature.state = OpenLayers.State.INSERT;
+ this.layer.addFeatures([feature]);
+ this.featureAdded(feature);
+ this.events.triggerEvent("featureadded",{feature : feature});
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Control.DrawFeature"
+});
+/* ======================================================================
+ OpenLayers/Symbolizer/Point.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Symbolizer.js
+ */
+
+/**
+ * Class: OpenLayers.Symbolizer.Point
+ * A symbolizer used to render point features.
+ */
+OpenLayers.Symbolizer.Point = OpenLayers.Class(OpenLayers.Symbolizer, {
+
+ /**
+ * APIProperty: strokeColor
+ * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000"
+ * for red).
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: strokeOpacity
+ * {Number} Stroke opacity (0-1).
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: strokeWidth
+ * {Number} Pixel stroke width.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: strokeLinecap
+ * {String} Stroke cap type ("butt", "round", or "square").
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * Property: strokeDashstyle
+ * {String} Stroke dash style according to the SLD spec. Note that the
+ * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot",
+ * "longdash", "longdashdot", or "solid") will not work in SLD, but
+ * most SLD patterns will render correctly in OpenLayers.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: fillColor
+ * {String} RGB hex fill color (e.g. "#ff0000" for red).
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: fillOpacity
+ * {Number} Fill opacity (0-1).
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: pointRadius
+ * {Number} Pixel point radius.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: externalGraphic
+ * {String} Url to an external graphic that will be used for rendering
+ * points.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: graphicWidth
+ * {Number} Pixel width for sizing an external graphic.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: graphicHeight
+ * {Number} Pixel height for sizing an external graphic.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: graphicOpacity
+ * {Number} Opacity (0-1) for an external graphic.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: graphicXOffset
+ * {Number} Pixel offset along the positive x axis for displacing an
+ * external graphic.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: graphicYOffset
+ * {Number} Pixel offset along the positive y axis for displacing an
+ * external graphic.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: rotation
+ * {Number} The rotation of a graphic in the clockwise direction about its
+ * center point (or any point off center as specified by
+ * <graphicXOffset> and <graphicYOffset>).
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: graphicName
+ * {String} Named graphic to use when rendering points. Supported values
+ * include "circle", "square", "star", "x", "cross", and "triangle".
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * Constructor: OpenLayers.Symbolizer.Point
+ * Create a symbolizer for rendering points.
+ *
+ * Parameters:
+ * config - {Object} An object containing properties to be set on the
+ * symbolizer. Any documented symbolizer property can be set at
+ * construction.
+ *
+ * Returns:
+ * A new point symbolizer.
+ */
+ initialize: function(config) {
+ OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
+ },
+
+ CLASS_NAME: "OpenLayers.Symbolizer.Point"
+
+});
+
+/* ======================================================================
+ OpenLayers/Symbolizer/Line.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Symbolizer.js
+ */
+
+/**
+ * Class: OpenLayers.Symbolizer.Line
+ * A symbolizer used to render line features.
+ */
+OpenLayers.Symbolizer.Line = OpenLayers.Class(OpenLayers.Symbolizer, {
+
+ /**
+ * APIProperty: strokeColor
+ * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000"
+ * for red).
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: strokeOpacity
+ * {Number} Stroke opacity (0-1).
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: strokeWidth
+ * {Number} Pixel stroke width.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: strokeLinecap
+ * {String} Stroke cap type ("butt", "round", or "square").
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * Property: strokeDashstyle
+ * {String} Stroke dash style according to the SLD spec. Note that the
+ * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot",
+ * "longdash", "longdashdot", or "solid") will not work in SLD, but
+ * most SLD patterns will render correctly in OpenLayers.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * Constructor: OpenLayers.Symbolizer.Line
+ * Create a symbolizer for rendering lines.
+ *
+ * Parameters:
+ * config - {Object} An object containing properties to be set on the
+ * symbolizer. Any documented symbolizer property can be set at
+ * construction.
+ *
+ * Returns:
+ * A new line symbolizer.
+ */
+ initialize: function(config) {
+ OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
+ },
+
+ CLASS_NAME: "OpenLayers.Symbolizer.Line"
+
+});
+
+/* ======================================================================
+ OpenLayers/Symbolizer/Polygon.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Symbolizer.js
+ */
+
+/**
+ * Class: OpenLayers.Symbolizer.Polygon
+ * A symbolizer used to render line features.
+ */
+OpenLayers.Symbolizer.Polygon = OpenLayers.Class(OpenLayers.Symbolizer, {
+
+ /**
+ * APIProperty: strokeColor
+ * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000"
+ * for red).
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: strokeOpacity
+ * {Number} Stroke opacity (0-1).
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: strokeWidth
+ * {Number} Pixel stroke width.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: strokeLinecap
+ * {String} Stroke cap type ("butt", "round", or "square").
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * Property: strokeDashstyle
+ * {String} Stroke dash style according to the SLD spec. Note that the
+ * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot",
+ * "longdash", "longdashdot", or "solid") will not work in SLD, but
+ * most SLD patterns will render correctly in OpenLayers.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: fillColor
+ * {String} RGB hex fill color (e.g. "#ff0000" for red).
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: fillOpacity
+ * {Number} Fill opacity (0-1).
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * Constructor: OpenLayers.Symbolizer.Polygon
+ * Create a symbolizer for rendering polygons.
+ *
+ * Parameters:
+ * config - {Object} An object containing properties to be set on the
+ * symbolizer. Any documented symbolizer property can be set at
+ * construction.
+ *
+ * Returns:
+ * A new polygon symbolizer.
+ */
+ initialize: function(config) {
+ OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
+ },
+
+ CLASS_NAME: "OpenLayers.Symbolizer.Polygon"
+
+});
+
+/* ======================================================================
+ OpenLayers/Symbolizer/Text.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Symbolizer.js
+ */
+
+/**
+ * Class: OpenLayers.Symbolizer.Text
+ * A symbolizer used to render text labels for features.
+ */
+OpenLayers.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, {
+
+ /**
+ * APIProperty: label
+ * {String} The text for the label.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: fontFamily
+ * {String} The font family for the label.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: fontSize
+ * {String} The font size for the label.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * APIProperty: fontWeight
+ * {String} The font weight for the label.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * Property: fontStyle
+ * {String} The font style for the label.
+ *
+ * No default set here. Use OpenLayers.Renderer.defaultRenderer for defaults.
+ */
+
+ /**
+ * Constructor: OpenLayers.Symbolizer.Text
+ * Create a symbolizer for rendering text labels.
+ *
+ * Parameters:
+ * config - {Object} An object containing properties to be set on the
+ * symbolizer. Any documented symbolizer property can be set at
+ * construction.
+ *
+ * Returns:
+ * A new text symbolizer.
+ */
+ initialize: function(config) {
+ OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
+ },
+
+ CLASS_NAME: "OpenLayers.Symbolizer.Text"
+
+});
+
+/* ======================================================================
+ OpenLayers/Rule.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/Util.js
+ * @requires OpenLayers/Style.js
+ * @requires OpenLayers/Symbolizer/Point.js
+ * @requires OpenLayers/Symbolizer/Line.js
+ * @requires OpenLayers/Symbolizer/Polygon.js
+ * @requires OpenLayers/Symbolizer/Text.js
+ * @requires OpenLayers/Symbolizer/Raster.js
+ */
+
+/**
+ * Class: OpenLayers.Rule
+ * This class represents an SLD Rule, as being used for rule-based SLD styling.
+ */
+OpenLayers.Rule = OpenLayers.Class({
+
+ /**
+ * Property: id
+ * {String} A unique id for this session.
+ */
+ id: null,
+
+ /**
+ * APIProperty: name
+ * {String} name of this rule
+ */
+ name: null,
+
+ /**
+ * Property: title
+ * {String} Title of this rule (set if included in SLD)
+ */
+ title: null,
+
+ /**
+ * Property: description
+ * {String} Description of this rule (set if abstract is included in SLD)
+ */
+ description: null,
+
+ /**
+ * Property: context
+ * {Object} An optional object with properties that the rule should be
+ * evaluated against. If no context is specified, feature.attributes will
+ * be used.
+ */
+ context: null,
+
+ /**
+ * Property: filter
+ * {<OpenLayers.Filter>} Optional filter for the rule.
+ */
+ filter: null,
+
+ /**
+ * Property: elseFilter
+ * {Boolean} Determines whether this rule is only to be applied only if
+ * no other rules match (ElseFilter according to the SLD specification).
+ * Default is false. For instances of OpenLayers.Rule, if elseFilter is
+ * false, the rule will always apply. For subclasses, the else property is
+ * ignored.
+ */
+ elseFilter: false,
+
+ /**
+ * Property: symbolizer
+ * {Object} Symbolizer or hash of symbolizers for this rule. If hash of
+ * symbolizers, keys are one or more of ["Point", "Line", "Polygon"]. The
+ * latter if useful if it is required to style e.g. vertices of a line
+ * with a point symbolizer. Note, however, that this is not implemented
+ * yet in OpenLayers, but it is the way how symbolizers are defined in
+ * SLD.
+ */
+ symbolizer: null,
+
+ /**
+ * Property: symbolizers
+ * {Array} Collection of symbolizers associated with this rule. If
+ * provided at construction, the symbolizers array has precedence
+ * over the deprecated symbolizer property. Note that multiple
+ * symbolizers are not currently supported by the vector renderers.
+ * Rules with multiple symbolizers are currently only useful for
+ * maintaining elements in an SLD document.
+ */
+ symbolizers: null,
+
+ /**
+ * APIProperty: minScaleDenominator
+ * {Number} or {String} minimum scale at which to draw the feature.
+ * In the case of a String, this can be a combination of text and
+ * propertyNames in the form "literal ${propertyName}"
+ */
+ minScaleDenominator: null,
+
+ /**
+ * APIProperty: maxScaleDenominator
+ * {Number} or {String} maximum scale at which to draw the feature.
+ * In the case of a String, this can be a combination of text and
+ * propertyNames in the form "literal ${propertyName}"
+ */
+ maxScaleDenominator: null,
+
+ /**
+ * Constructor: OpenLayers.Rule
+ * Creates a Rule.
+ *
+ * Parameters:
+ * options - {Object} An optional object with properties to set on the
+ * rule
+ *
+ * Returns:
+ * {<OpenLayers.Rule>}
+ */
+ initialize: function(options) {
+ this.symbolizer = {};
+ OpenLayers.Util.extend(this, options);
+ if (this.symbolizers) {
+ delete this.symbolizer;
+ }
+ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+ },
+
+ /**
+ * APIMethod: destroy
+ * nullify references to prevent circular references and memory leaks
+ */
+ destroy: function() {
+ for (var i in this.symbolizer) {
+ this.symbolizer[i] = null;
+ }
+ this.symbolizer = null;
+ delete this.symbolizers;
+ },
+
+ /**
+ * APIMethod: evaluate
+ * evaluates this rule for a specific feature
+ *
+ * Parameters:
+ * feature - {<OpenLayers.Feature>} feature to apply the rule to.
+ *
+ * Returns:
+ * {Boolean} true if the rule applies, false if it does not.
+ * This rule is the default rule and always returns true.
+ */
+ evaluate: function(feature) {
+ var context = this.getContext(feature);
+ var applies = true;
+
+ if (this.minScaleDenominator || this.maxScaleDenominator) {
+ var scale = feature.layer.map.getScale();
+ }
+
+ // check if within minScale/maxScale bounds
+ if (this.minScaleDenominator) {
+ applies = scale >= OpenLayers.Style.createLiteral(
+ this.minScaleDenominator, context);
+ }
+ if (applies && this.maxScaleDenominator) {
+ applies = scale < OpenLayers.Style.createLiteral(
+ this.maxScaleDenominator, context);
+ }
+
+ // check if optional filter applies
+ if(applies && this.filter) {
+ // feature id filters get the feature, others get the context
+ if(this.filter.CLASS_NAME == "OpenLayers.Filter.FeatureId") {
+ applies = this.filter.evaluate(feature);
+ } else {
+ applies = this.filter.evaluate(context);
+ }
+ }
+
+ return applies;
+ },
+
+ /**
+ * Method: getContext
+ * Gets the context for evaluating this rule
+ *
+ * Paramters:
+ * feature - {<OpenLayers.Feature>} feature to take the context from if
+ * none is specified.
+ */
+ getContext: function(feature) {
+ var context = this.context;
+ if (!context) {
+ context = feature.attributes || feature.data;
+ }
+ if (typeof this.context == "function") {
+ context = this.context(feature);
+ }
+ return context;
+ },
+
+ /**
+ * APIMethod: clone
+ * Clones this rule.
+ *
+ * Returns:
+ * {<OpenLayers.Rule>} Clone of this rule.
+ */
+ clone: function() {
+ var options = OpenLayers.Util.extend({}, this);
+ if (this.symbolizers) {
+ // clone symbolizers
+ var len = this.symbolizers.length;
+ options.symbolizers = new Array(len);
+ for (var i=0; i<len; ++i) {
+ options.symbolizers[i] = this.symbolizers[i].clone();
+ }
+ } else {
+ // clone symbolizer
+ options.symbolizer = {};
+ var value, type;
+ for(var key in this.symbolizer) {
+ value = this.symbolizer[key];
+ type = typeof value;
+ if(type === "object") {
+ options.symbolizer[key] = OpenLayers.Util.extend({}, value);
+ } else if(type === "string") {
+ options.symbolizer[key] = value;
+ }
+ }
+ }
+ // clone filter
+ options.filter = this.filter && this.filter.clone();
+ // clone context
+ options.context = this.context && OpenLayers.Util.extend({}, this.context);
+ return new OpenLayers.Rule(options);
+ },
+
+ CLASS_NAME: "OpenLayers.Rule"
+});
+/* ======================================================================
+ OpenLayers/Handler/Hover.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Hover
+ * The hover handler is to be used to emulate mouseovers on objects
+ * on the map that aren't DOM elements. For example one can use
+ * this handler to send WMS/GetFeatureInfo requests as the user
+ * moves the mouve over the map.
+ *
+ * Inherits from:
+ * - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.Hover = OpenLayers.Class(OpenLayers.Handler, {
+
+ /**
+ * APIProperty: delay
+ * {Integer} - Number of milliseconds between mousemoves before
+ * the event is considered a hover. Default is 500.
+ */
+ delay: 500,
+
+ /**
+ * APIProperty: pixelTolerance
+ * {Integer} - Maximum number of pixels between mousemoves for
+ * an event to be considered a hover. Default is null.
+ */
+ pixelTolerance: null,
+
+ /**
+ * APIProperty: stopMove
+ * {Boolean} - Stop other listeners from being notified on mousemoves.
+ * Default is false.
+ */
+ stopMove: false,
+
+ /**
+ * Property: px
+ * {<OpenLayers.Pixel>} - The location of the last mousemove, expressed
+ * in pixels.
+ */
+ px: null,
+
+ /**
+ * Property: timerId
+ * {Number} - The id of the timer.
+ */
+ timerId: null,
+
+ /**
+ * Constructor: OpenLayers.Handler.Hover
+ * Construct a hover handler.
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>} The control that initialized this
+ * handler. The control is assumed to have a valid map property; that
+ * map is used in the handler's own setMap method.
+ * callbacks - {Object} An object with keys corresponding to callbacks
+ * that will be called by the handler. The callbacks should
+ * expect to receive a single argument, the event. Callbacks for
+ * 'move', the mouse is moving, and 'pause', the mouse is pausing,
+ * are supported.
+ * options - {Object} An optional object whose properties will be set on
+ * the handler.
+ */
+ initialize: function(control, callbacks, options) {
+ OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * Method: mousemove
+ * Called when the mouse moves on the map.
+ *
+ * Parameters:
+ * evt - {<OpenLayers.Event>}
+ *
+ * Returns:
+ * {Boolean} Continue propagating this event.
+ */
+ mousemove: function(evt) {
+ if(this.passesTolerance(evt.xy)) {
+ this.clearTimer();
+ this.callback('move', [evt]);
+ this.px = evt.xy;
+ // clone the evt so original properties can be accessed even
+ // if the browser deletes them during the delay
+ evt = OpenLayers.Util.extend({}, evt);
+ this.timerId = window.setTimeout(
+ OpenLayers.Function.bind(this.delayedCall, this, evt),
+ this.delay
+ );
+ }
+ return !this.stopMove;
+ },
+
+ /**
+ * Method: mouseout
+ * Called when the mouse goes out of the map.
+ *
+ * Parameters:
+ * evt - {<OpenLayers.Event>}
+ *
+ * Returns:
+ * {Boolean} Continue propagating this event.
+ */
+ mouseout: function(evt) {
+ if (OpenLayers.Util.mouseLeft(evt, this.map.div)) {
+ this.clearTimer();
+ this.callback('move', [evt]);
+ }
+ return true;
+ },
+
+ /**
+ * Method: passesTolerance
+ * Determine whether the mouse move is within the optional pixel tolerance.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {Boolean} The mouse move is within the pixel tolerance.
+ */
+ passesTolerance: function(px) {
+ var passes = true;
+ if(this.pixelTolerance && this.px) {
+ var dpx = Math.sqrt(
+ Math.pow(this.px.x - px.x, 2) +
+ Math.pow(this.px.y - px.y, 2)
+ );
+ if(dpx < this.pixelTolerance) {
+ passes = false;
+ }
+ }
+ return passes;
+ },
+
+ /**
+ * Method: clearTimer
+ * Clear the timer and set <timerId> to null.
+ */
+ clearTimer: function() {
+ if(this.timerId != null) {
+ window.clearTimeout(this.timerId);
+ this.timerId = null;
+ }
+ },
+
+ /**
+ * Method: delayedCall
+ * Triggers pause callback.
+ *
+ * Parameters:
+ * evt - {<OpenLayers.Event>}
+ */
+ delayedCall: function(evt) {
+ this.callback('pause', [evt]);
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Deactivate the handler.
+ *
+ * Returns:
+ * {Boolean} The handler was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = false;
+ if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+ this.clearTimer();
+ deactivated = true;
+ }
+ return deactivated;
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.Hover"
+});
+/* ======================================================================
+ OpenLayers/Format/WFSDescribeFeatureType.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/XML.js
+ *
+ * Class: OpenLayers.Format.WFSDescribeFeatureType
+ * Read WFS DescribeFeatureType response
+ *
+ * Inherits from:
+ * - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.WFSDescribeFeatureType = OpenLayers.Class(
+ OpenLayers.Format.XML, {
+
+ /**
+ * Property: namespaces
+ * {Object} Mapping of namespace aliases to namespace URIs.
+ */
+ namespaces: {
+ xsd: "http://www.w3.org/2001/XMLSchema"
+ },
+
+ /**
+ * Constructor: OpenLayers.Format.WFSDescribeFeatureType
+ * Create a new parser for WFS DescribeFeatureType responses.
+ *
+ * Parameters:
+ * options - {Object} An optional object whose properties will be set on
+ * this instance.
+ */
+ initialize: function(options) {
+ OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * Property: readers
+ * Contains public functions, grouped by namespace prefix, that will
+ * be applied when a namespaced node is found matching the function
+ * name. The function will be applied in the scope of this parser
+ * with two arguments: the node being read and a context object passed
+ * from the parent.
+ */
+ readers: {
+ "xsd": {
+ "schema": function(node, obj) {
+ var complexTypes = [];
+ var customTypes = {};
+ var schema = {
+ complexTypes: complexTypes,
+ customTypes: customTypes
+ };
+
+ this.readChildNodes(node, schema);
+
+ var attributes = node.attributes;
+ var attr, name;
+ for(var i=0, len=attributes.length; i<len; ++i) {
+ attr = attributes[i];
+ name = attr.name;
+ if(name.indexOf("xmlns") == 0) {
+ this.setNamespace(name.split(":")[1] || "", attr.value);
+ } else {
+ obj[name] = attr.value;
+ }
+ }
+ obj.featureTypes = complexTypes;
+ obj.targetPrefix = this.namespaceAlias[obj.targetNamespace];
+
+ // map complexTypes to names of customTypes
+ var complexType, customType;
+ for(var i=0, len=complexTypes.length; i<len; ++i) {
+ complexType = complexTypes[i];
+ customType = customTypes[complexType.typeName];
+ if(customTypes[complexType.typeName]) {
+ complexType.typeName = customType.name;
+ }
+ }
+ },
+ "complexType": function(node, obj) {
+ var complexType = {
+ // this is a temporary typeName, it will be overwritten by
+ // the schema reader with the metadata found in the
+ // customTypes hash
+ "typeName": node.getAttribute("name")
+ };
+ this.readChildNodes(node, complexType);
+ obj.complexTypes.push(complexType);
+ },
+ "complexContent": function(node, obj) {
+ this.readChildNodes(node, obj);
+ },
+ "extension": function(node, obj) {
+ this.readChildNodes(node, obj);
+ },
+ "sequence": function(node, obj) {
+ var sequence = {
+ elements: []
+ };
+ this.readChildNodes(node, sequence);
+ obj.properties = sequence.elements;
+ },
+ "element": function(node, obj) {
+ if(obj.elements) {
+ var element = {};
+ var attributes = node.attributes;
+ var attr;
+ for(var i=0, len=attributes.length; i<len; ++i) {
+ attr = attributes[i];
+ element[attr.name] = attr.value;
+ }
+
+ var type = element.type;
+ if(!type) {
+ type = {};
+ this.readChildNodes(node, type);
+ element.restriction = type;
+ element.type = type.base;
+ }
+ var fullType = type.base || type;
+ element.localType = fullType.split(":").pop();
+ obj.elements.push(element);
+ }
+
+ if(obj.complexTypes) {
+ var type = node.getAttribute("type");
+ var localType = type.split(":").pop();
+ obj.customTypes[localType] = {
+ "name": node.getAttribute("name"),
+ "type": type
+ };
+ }
+ },
+ "simpleType": function(node, obj) {
+ this.readChildNodes(node, obj);
+ },
+ "restriction": function(node, obj) {
+ obj.base = node.getAttribute("base");
+ this.readRestriction(node, obj);
+ }
+ }
+ },
+
+ /**
+ * Method: readRestriction
+ * Reads restriction defined in the child nodes of a restriction element
+ *
+ * Parameters:
+ * node {DOMElement} - the node to parse
+ * obj {Object} - the object that receives the read result
+ */
+ readRestriction: function(node, obj) {
+ var children = node.childNodes;
+ var child, nodeName, value;
+ for(var i=0, len=children.length; i<len; ++i) {
+ child = children[i];
+ if(child.nodeType == 1) {
+ nodeName = child.nodeName.split(":").pop();
+ value = child.getAttribute("value");
+ if(!obj[nodeName]) {
+ obj[nodeName] = value;
+ } else {
+ if(typeof obj[nodeName] == "string") {
+ obj[nodeName] = [obj[nodeName]];
+ }
+ obj[nodeName].push(value);
+ }
+ }
+ }
+ },
+
+ /**
+ * Method: read
+ *
+ * Parameters:
+ * data - {DOMElement|String} A WFS DescribeFeatureType document.
+ *
+ * Returns:
+ * {Object} An object representing the WFS DescribeFeatureType response.
+ */
+ read: function(data) {
+ if(typeof data == "string") {
+ data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+ }
+ if(data && data.nodeType == 9) {
+ data = data.documentElement;
+ }
+ var schema = {};
+ this.readNode(data, schema);
+
+ return schema;
+ },
+
+ CLASS_NAME: "OpenLayers.Format.WFSDescribeFeatureType"
+
+});
+/* ======================================================================
+ OpenLayers/Strategy/Refresh.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Strategy.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.Refresh
+ * A strategy that refreshes the layer. By default the strategy waits for a
+ * call to <refresh> before refreshing. By configuring the strategy with
+ * the <interval> option, refreshing can take place automatically.
+ *
+ * Inherits from:
+ * - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.Refresh = OpenLayers.Class(OpenLayers.Strategy, {
+
+ /**
+ * Property: force
+ * {Boolean} Force a refresh on the layer. Default is false.
+ */
+ force: false,
+
+ /**
+ * Property: interval
+ * {Number} Auto-refresh. Default is 0. If > 0, layer will be refreshed
+ * every N milliseconds.
+ */
+ interval: 0,
+
+ /**
+ * Property: timer
+ * {Number} The id of the timer.
+ */
+ timer: null,
+
+ /**
+ * Constructor: OpenLayers.Strategy.Refresh
+ * Create a new Refresh strategy.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ */
+ initialize: function(options) {
+ OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * APIMethod: activate
+ * Activate the strategy. Register any listeners, do appropriate setup.
+ *
+ * Returns:
+ * {Boolean} True if the strategy was successfully activated.
+ */
+ activate: function() {
+ var activated = OpenLayers.Strategy.prototype.activate.call(this);
+ if(activated) {
+ if(this.layer.visibility === true) {
+ this.start();
+ }
+ this.layer.events.on({
+ "visibilitychanged": this.reset,
+ scope: this
+ });
+ }
+ return activated;
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Deactivate the strategy. Unregister any listeners, do appropriate
+ * tear-down.
+ *
+ * Returns:
+ * {Boolean} True if the strategy was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
+ if(deactivated) {
+ this.stop();
+ }
+ return deactivated;
+ },
+
+ /**
+ * Method: reset
+ * Start or cancel the refresh interval depending on the visibility of
+ * the layer.
+ */
+ reset: function() {
+ if(this.layer.visibility === true) {
+ this.start();
+ } else {
+ this.stop();
+ }
+ },
+
+ /**
+ * Method: start
+ * Start the refresh interval.
+ */
+ start: function() {
+ if(this.interval && typeof this.interval === "number" &&
+ this.interval > 0) {
+
+ this.timer = window.setInterval(
+ OpenLayers.Function.bind(this.refresh, this),
+ this.interval);
+ }
+ },
+
+ /**
+ * APIMethod: refresh
+ * Tell the strategy to refresh which will refresh the layer.
+ */
+ refresh: function() {
+ if (this.layer && this.layer.refresh &&
+ typeof this.layer.refresh == "function") {
+
+ this.layer.refresh({force: this.force});
+ }
+ },
+
+ /**
+ * Method: stop
+ * Cancels the refresh interval.
+ */
+ stop: function() {
+ if(this.timer !== null) {
+ window.clearInterval(this.timer);
+ this.timer = null;
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Strategy.Refresh"
+});
+/* ======================================================================
+ OpenLayers/Control/MousePosition.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.MousePosition
+ * The MousePosition control displays geographic coordinates of the mouse
+ * pointer, as it is moved about the map.
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.MousePosition = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * APIProperty: autoActivate
+ * {Boolean} Activate the control when it is added to a map. Default is
+ * true.
+ */
+ autoActivate: true,
+
+ /**
+ * Property: element
+ * {DOMElement}
+ */
+ element: null,
+
+ /**
+ * APIProperty: prefix
+ * {String}
+ */
+ prefix: '',
+
+ /**
+ * APIProperty: separator
+ * {String}
+ */
+ separator: ', ',
+
+ /**
+ * APIProperty: suffix
+ * {String}
+ */
+ suffix: '',
+
+ /**
+ * APIProperty: numDigits
+ * {Integer}
+ */
+ numDigits: 5,
+
+ /**
+ * APIProperty: granularity
+ * {Integer}
+ */
+ granularity: 10,
+
+ /**
+ * APIProperty: emptyString
+ * {String} Set this to some value to set when the mouse is outside the
+ * map.
+ */
+ emptyString: null,
+
+ /**
+ * Property: lastXy
+ * {<OpenLayers.Pixel>}
+ */
+ lastXy: null,
+
+ /**
+ * APIProperty: displayProjection
+ * {<OpenLayers.Projection>} The projection in which the
+ * mouse position is displayed
+ */
+ displayProjection: null,
+
+ /**
+ * Constructor: OpenLayers.Control.MousePosition
+ *
+ * Parameters:
+ * options - {Object} Options for control.
+ */
+ initialize: function(options) {
+ OpenLayers.Control.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * Method: destroy
+ */
+ destroy: function() {
+ this.deactivate();
+ OpenLayers.Control.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * APIMethod: activate
+ */
+ activate: function() {
+ if (OpenLayers.Control.prototype.activate.apply(this, arguments)) {
+ this.map.events.register('mousemove', this, this.redraw);
+ this.map.events.register('mouseout', this, this.reset);
+ this.redraw();
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * APIMethod: deactivate
+ */
+ deactivate: function() {
+ if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) {
+ this.map.events.unregister('mousemove', this, this.redraw);
+ this.map.events.unregister('mouseout', this, this.reset);
+ this.element.innerHTML = "";
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Method: draw
+ * {DOMElement}
+ */
+ draw: function() {
+ OpenLayers.Control.prototype.draw.apply(this, arguments);
+
+ if (!this.element) {
+ this.div.left = "";
+ this.div.top = "";
+ this.element = this.div;
+ }
+
+ return this.div;
+ },
+
+ /**
+ * Method: redraw
+ */
+ redraw: function(evt) {
+
+ var lonLat;
+
+ if (evt == null) {
+ this.reset();
+ return;
+ } else {
+ if (this.lastXy == null ||
+ Math.abs(evt.xy.x - this.lastXy.x) > this.granularity ||
+ Math.abs(evt.xy.y - this.lastXy.y) > this.granularity)
+ {
+ this.lastXy = evt.xy;
+ return;
+ }
+
+ lonLat = this.map.getLonLatFromPixel(evt.xy);
+ if (!lonLat) {
+ // map has not yet been properly initialized
+ return;
+ }
+ if (this.displayProjection) {
+ lonLat.transform(this.map.getProjectionObject(),
+ this.displayProjection );
+ }
+ this.lastXy = evt.xy;
+
+ }
+
+ var newHtml = this.formatOutput(lonLat);
+
+ if (newHtml != this.element.innerHTML) {
+ this.element.innerHTML = newHtml;
+ }
+ },
+
+ /**
+ * Method: reset
+ */
+ reset: function(evt) {
+ if (this.emptyString != null) {
+ this.element.innerHTML = this.emptyString;
+ }
+ },
+
+ /**
+ * Method: formatOutput
+ * Override to provide custom display output
+ *
+ * Parameters:
+ * lonLat - {<OpenLayers.LonLat>} Location to display
+ */
+ formatOutput: function(lonLat) {
+ var digits = parseInt(this.numDigits);
+ var newHtml =
+ this.prefix +
+ lonLat.lon.toFixed(digits) +
+ this.separator +
+ lonLat.lat.toFixed(digits) +
+ this.suffix;
+ return newHtml;
+ },
+
+ CLASS_NAME: "OpenLayers.Control.MousePosition"
+});
+/* ======================================================================
+ OpenLayers/Protocol/HTTP.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Console.js
+ * @requires OpenLayers/Protocol.js
+ * @requires OpenLayers/Feature/Vector.js
+ * @requires OpenLayers/Filter/Spatial.js
+ * @requires OpenLayers/Filter/Comparison.js
+ * @requires OpenLayers/Filter/Logical.js
+ * @requires OpenLayers/Request/XMLHttpRequest.js
+ */
+
+/**
+ * Class: OpenLayers.Protocol.HTTP
+ * A basic HTTP protocol for vector layers. Create a new instance with the
+ * <OpenLayers.Protocol.HTTP> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Protocol>
+ */
+OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
+
+ /**
+ * Property: url
+ * {String} Service URL, read-only, set through the options
+ * passed to constructor.
+ */
+ url: null,
+
+ /**
+ * Property: headers
+ * {Object} HTTP request headers, read-only, set through the options
+ * passed to the constructor,
+ * Example: {'Content-Type': 'plain/text'}
+ */
+ headers: null,
+
+ /**
+ * Property: params
+ * {Object} Parameters of GET requests, read-only, set through the options
+ * passed to the constructor,
+ * Example: {'bbox': '5,5,5,5'}
+ */
+ params: null,
+
+ /**
+ * Property: callback
+ * {Object} Function to be called when the <read>, <create>,
+ * <update>, <delete> or <commit> operation completes, read-only,
+ * set through the options passed to the constructor.
+ */
+ callback: null,
+
+ /**
+ * Property: scope
+ * {Object} Callback execution scope, read-only, set through the
+ * options passed to the constructor.
+ */
+ scope: null,
+
+ /**
+ * Property: readWithPOST
+ * {Boolean} true if read operations are done with POST requests
+ * instead of GET, defaults to false.
+ */
+ readWithPOST: false,
+
+ /**
+ * Property: wildcarded.
+ * {Boolean} If true percent signs are added around values
+ * read from LIKE filters, for example if the protocol
+ * read method is passed a LIKE filter whose property
+ * is "foo" and whose value is "bar" the string
+ * "foo__ilike=%bar%" will be sent in the query string;
+ * defaults to false.
+ */
+ wildcarded: false,
+
+ /**
+ * APIProperty: srsInBBOX
+ * {Boolean} Include the SRS identifier in BBOX query string parameter.
+ * Default is false. If true and the layer has a projection object set,
+ * any BBOX filter will be serialized with a fifth item identifying the
+ * projection. E.g. bbox=-1000,-1000,1000,1000,EPSG:900913
+ */
+ srsInBBOX: false,
+
+ /**
+ * Constructor: OpenLayers.Protocol.HTTP
+ * A class for giving layers generic HTTP protocol.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ *
+ * Valid options include:
+ * url - {String}
+ * headers - {Object}
+ * params - {Object}
+ * format - {<OpenLayers.Format>}
+ * callback - {Function}
+ * scope - {Object}
+ */
+ initialize: function(options) {
+ options = options || {};
+ this.params = {};
+ this.headers = {};
+ OpenLayers.Protocol.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * APIMethod: destroy
+ * Clean up the protocol.
+ */
+ destroy: function() {
+ this.params = null;
+ this.headers = null;
+ OpenLayers.Protocol.prototype.destroy.apply(this);
+ },
+
+ /**
+ * APIMethod: read
+ * Construct a request for reading new features.
+ *
+ * Parameters:
+ * options - {Object} Optional object for configuring the request.
+ * This object is modified and should not be reused.
+ *
+ * Valid options:
+ * url - {String} Url for the request.
+ * params - {Object} Parameters to get serialized as a query string.
+ * headers - {Object} Headers to be set on the request.
+ * filter - {<OpenLayers.Filter>} Filter to get serialized as a
+ * query string.
+ * readWithPOST - {Boolean} If the request should be done with POST.
+ *
+ * Returns:
+ * {<OpenLayers.Protocol.Response>} A response object, whose "priv" property
+ * references the HTTP request, this object is also passed to the
+ * callback function when the request completes, its "features" property
+ * is then populated with the the features received from the server.
+ */
+ read: function(options) {
+ OpenLayers.Protocol.prototype.read.apply(this, arguments);
+ options = OpenLayers.Util.applyDefaults(options, this.options);
+ options.params = OpenLayers.Util.applyDefaults(
+ options.params, this.options.params);
+ if(options.filter) {
+ options.params = this.filterToParams(
+ options.filter, options.params);
+ }
+ var readWithPOST = (options.readWithPOST !== undefined) ?
+ options.readWithPOST : this.readWithPOST;
+ var resp = new OpenLayers.Protocol.Response({requestType: "read"});
+ if(readWithPOST) {
+ resp.priv = OpenLayers.Request.POST({
+ url: options.url,
+ callback: this.createCallback(this.handleRead, resp, options),
+ data: OpenLayers.Util.getParameterString(options.params),
+ headers: {
+ "Content-Type": "application/x-www-form-urlencoded"
+ }
+ });
+ } else {
+ resp.priv = OpenLayers.Request.GET({
+ url: options.url,
+ callback: this.createCallback(this.handleRead, resp, options),
+ params: options.params,
+ headers: options.headers
+ });
+ }
+ return resp;
+ },
+
+ /**
+ * Method: handleRead
+ * Individual callbacks are created for read, create and update, should
+ * a subclass need to override each one separately.
+ *
+ * Parameters:
+ * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
+ * the user callback.
+ * options - {Object} The user options passed to the read call.
+ */
+ handleRead: function(resp, options) {
+ this.handleResponse(resp, options);
+ },
+
+ /**
+ * Method: filterToParams
+ * Convert an <OpenLayers.Filter> object to parameters.
+ *
+ * Parameters:
+ * filter - {OpenLayers.Filter} filter to convert.
+ * params - {Object} The parameters object.
+ *
+ * Returns:
+ * {Object} The resulting parameters object.
+ */
+ filterToParams: function(filter, params) {
+ params = params || {};
+ var className = filter.CLASS_NAME;
+ var filterType = className.substring(className.lastIndexOf(".") + 1);
+ switch(filterType) {
+ case "Spatial":
+ switch(filter.type) {
+ case OpenLayers.Filter.Spatial.BBOX:
+ params.bbox = filter.value.toArray();
+ if (this.srsInBBOX && filter.projection) {
+ params.bbox.push(filter.projection.getCode());
+ }
+ break;
+ case OpenLayers.Filter.Spatial.DWITHIN:
+ params.tolerance = filter.distance;
+ // no break here
+ case OpenLayers.Filter.Spatial.WITHIN:
+ params.lon = filter.value.x;
+ params.lat = filter.value.y;
+ break;
+ default:
+ OpenLayers.Console.warn(
+ "Unknown spatial filter type " + filter.type);
+ }
+ break;
+ case "Comparison":
+ var op = OpenLayers.Protocol.HTTP.COMP_TYPE_TO_OP_STR[filter.type];
+ if(op !== undefined) {
+ var value = filter.value;
+ if(filter.type == OpenLayers.Filter.Comparison.LIKE) {
+ value = this.regex2value(value);
+ if(this.wildcarded) {
+ value = "%" + value + "%";
+ }
+ }
+ params[filter.property + "__" + op] = value;
+ params.queryable = params.queryable || [];
+ params.queryable.push(filter.property);
+ } else {
+ OpenLayers.Console.warn(
+ "Unknown comparison filter type " + filter.type);
+ }
+ break;
+ case "Logical":
+ if(filter.type === OpenLayers.Filter.Logical.AND) {
+ for(var i=0,len=filter.filters.length; i<len; i++) {
+ params = this.filterToParams(filter.filters[i], params);
+ }
+ } else {
+ OpenLayers.Console.warn(
+ "Unsupported logical filter type " + filter.type);
+ }
+ break;
+ default:
+ OpenLayers.Console.warn("Unknown filter type " + filterType);
+ }
+ return params;
+ },
+
+ /**
+ * Method: regex2value
+ * Convert the value from a regular expression string to a LIKE/ILIKE
+ * string known to the web service.
+ *
+ * Parameters:
+ * value - {String} The regex string.
+ *
+ * Returns:
+ * {String} The converted string.
+ */
+ regex2value: function(value) {
+
+ // highly sensitive!! Do not change this without running the
+ // Protocol/HTTP.html unit tests
+
+ // convert % to \%
+ value = value.replace(/%/g, "\\%");
+
+ // convert \\. to \\_ (\\.* occurences converted later)
+ value = value.replace(/\\\\\.(\*)?/g, function($0, $1) {
+ return $1 ? $0 : "\\\\_";
+ });
+
+ // convert \\.* to \\%
+ value = value.replace(/\\\\\.\*/g, "\\\\%");
+
+ // convert . to _ (\. and .* occurences converted later)
+ value = value.replace(/(\\)?\.(\*)?/g, function($0, $1, $2) {
+ return $1 || $2 ? $0 : "_";
+ });
+
+ // convert .* to % (\.* occurnces converted later)
+ value = value.replace(/(\\)?\.\*/g, function($0, $1) {
+ return $1 ? $0 : "%";
+ });
+
+ // convert \. to .
+ value = value.replace(/\\\./g, ".");
+
+ // replace \* with * (watching out for \\*)
+ value = value.replace(/(\\)?\\\*/g, function($0, $1) {
+ return $1 ? $0 : "*";
+ });
+
+ return value;
+ },
+
+ /**
+ * APIMethod: create
+ * Construct a request for writing newly created features.
+ *
+ * Parameters:
+ * features - {Array({<OpenLayers.Feature.Vector>})} or
+ * {<OpenLayers.Feature.Vector>}
+ * options - {Object} Optional object for configuring the request.
+ * This object is modified and should not be reused.
+ *
+ * Returns:
+ * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+ * object, whose "priv" property references the HTTP request, this
+ * object is also passed to the callback function when the request
+ * completes, its "features" property is then populated with the
+ * the features received from the server.
+ */
+ create: function(features, options) {
+ options = OpenLayers.Util.applyDefaults(options, this.options);
+
+ var resp = new OpenLayers.Protocol.Response({
+ reqFeatures: features,
+ requestType: "create"
+ });
+
+ resp.priv = OpenLayers.Request.POST({
+ url: options.url,
+ callback: this.createCallback(this.handleCreate, resp, options),
+ headers: options.headers,
+ data: this.format.write(features)
+ });
+
+ return resp;
+ },
+
+ /**
+ * Method: handleCreate
+ * Called the the request issued by <create> is complete. May be overridden
+ * by subclasses.
+ *
+ * Parameters:
+ * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
+ * any user callback.
+ * options - {Object} The user options passed to the create call.
+ */
+ handleCreate: function(resp, options) {
+ this.handleResponse(resp, options);
+ },
+
+ /**
+ * APIMethod: update
+ * Construct a request updating modified feature.
+ *
+ * Parameters:
+ * feature - {<OpenLayers.Feature.Vector>}
+ * options - {Object} Optional object for configuring the request.
+ * This object is modified and should not be reused.
+ *
+ * Returns:
+ * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+ * object, whose "priv" property references the HTTP request, this
+ * object is also passed to the callback function when the request
+ * completes, its "features" property is then populated with the
+ * the feature received from the server.
+ */
+ update: function(feature, options) {
+ options = options || {};
+ var url = options.url ||
+ feature.url ||
+ this.options.url + "/" + feature.fid;
+ options = OpenLayers.Util.applyDefaults(options, this.options);
+
+ var resp = new OpenLayers.Protocol.Response({
+ reqFeatures: feature,
+ requestType: "update"
+ });
+
+ resp.priv = OpenLayers.Request.PUT({
+ url: url,
+ callback: this.createCallback(this.handleUpdate, resp, options),
+ headers: options.headers,
+ data: this.format.write(feature)
+ });
+
+ return resp;
+ },
+
+ /**
+ * Method: handleUpdate
+ * Called the the request issued by <update> is complete. May be overridden
+ * by subclasses.
+ *
+ * Parameters:
+ * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
+ * any user callback.
+ * options - {Object} The user options passed to the update call.
+ */
+ handleUpdate: function(resp, options) {
+ this.handleResponse(resp, options);
+ },
+
+ /**
+ * APIMethod: delete
+ * Construct a request deleting a removed feature.
+ *
+ * Parameters:
+ * feature - {<OpenLayers.Feature.Vector>}
+ * options - {Object} Optional object for configuring the request.
+ * This object is modified and should not be reused.
+ *
+ * Returns:
+ * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
+ * object, whose "priv" property references the HTTP request, this
+ * object is also passed to the callback function when the request
+ * completes.
+ */
+ "delete": function(feature, options) {
+ options = options || {};
+ var url = options.url ||
+ feature.url ||
+ this.options.url + "/" + feature.fid;
+ options = OpenLayers.Util.applyDefaults(options, this.options);
+
+ var resp = new OpenLayers.Protocol.Response({
+ reqFeatures: feature,
+ requestType: "delete"
+ });
+
+ resp.priv = OpenLayers.Request.DELETE({
+ url: url,
+ callback: this.createCallback(this.handleDelete, resp, options),
+ headers: options.headers
+ });
+
+ return resp;
+ },
+
+ /**
+ * Method: handleDelete
+ * Called the the request issued by <delete> is complete. May be overridden
+ * by subclasses.
+ *
+ * Parameters:
+ * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
+ * any user callback.
+ * options - {Object} The user options passed to the delete call.
+ */
+ handleDelete: function(resp, options) {
+ this.handleResponse(resp, options);
+ },
+
+ /**
+ * Method: handleResponse
+ * Called by CRUD specific handlers.
+ *
+ * Parameters:
+ * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
+ * any user callback.
+ * options - {Object} The user options passed to the create, read, update,
+ * or delete call.
+ */
+ handleResponse: function(resp, options) {
+ var request = resp.priv;
+ if(options.callback) {
+ if(request.status >= 200 && request.status < 300) {
+ // success
+ if(resp.requestType != "delete") {
+ resp.features = this.parseFeatures(request);
+ }
+ resp.code = OpenLayers.Protocol.Response.SUCCESS;
+ } else {
+ // failure
+ resp.code = OpenLayers.Protocol.Response.FAILURE;
+ }
+ options.callback.call(options.scope, resp);
+ }
+ },
+
+ /**
+ * Method: parseFeatures
+ * Read HTTP response body and return features.
+ *
+ * Parameters:
+ * request - {XMLHttpRequest} The request object
+ *
+ * Returns:
+ * {Array({<OpenLayers.Feature.Vector>})} or
+ * {<OpenLayers.Feature.Vector>} Array of features or a single feature.
+ */
+ parseFeatures: function(request) {
+ var doc = request.responseXML;
+ if (!doc || !doc.documentElement) {
+ doc = request.responseText;
+ }
+ if (!doc || doc.length <= 0) {
+ return null;
+ }
+ return this.format.read(doc);
+ },
+
+ /**
+ * APIMethod: commit
+ * Iterate over each feature and take action based on the feature state.
+ * Possible actions are create, update and delete.
+ *
+ * Parameters:
+ * features - {Array({<OpenLayers.Feature.Vector>})}
+ * options - {Object} Optional object for setting up intermediate commit
+ * callbacks.
+ *
+ * Valid options:
+ * create - {Object} Optional object to be passed to the <create> method.
+ * update - {Object} Optional object to be passed to the <update> method.
+ * delete - {Object} Optional object to be passed to the <delete> method.
+ * callback - {Function} Optional function to be called when the commit
+ * is complete.
+ * scope - {Object} Optional object to be set as the scope of the callback.
+ *
+ * Returns:
+ * {Array(<OpenLayers.Protocol.Response>)} An array of response objects,
+ * one per request made to the server, each object's "priv" property
+ * references the corresponding HTTP request.
+ */
+ commit: function(features, options) {
+ options = OpenLayers.Util.applyDefaults(options, this.options);
+ var resp = [], nResponses = 0;
+
+ // Divide up features before issuing any requests. This properly
+ // counts requests in the event that any responses come in before
+ // all requests have been issued.
+ var types = {};
+ types[OpenLayers.State.INSERT] = [];
+ types[OpenLayers.State.UPDATE] = [];
+ types[OpenLayers.State.DELETE] = [];
+ var feature, list, requestFeatures = [];
+ for(var i=0, len=features.length; i<len; ++i) {
+ feature = features[i];
+ list = types[feature.state];
+ if(list) {
+ list.push(feature);
+ requestFeatures.push(feature);
+ }
+ }
+ // tally up number of requests
+ var nRequests = (types[OpenLayers.State.INSERT].length > 0 ? 1 : 0) +
+ types[OpenLayers.State.UPDATE].length +
+ types[OpenLayers.State.DELETE].length;
+
+ // This response will be sent to the final callback after all the others
+ // have been fired.
+ var success = true;
+ var finalResponse = new OpenLayers.Protocol.Response({
+ reqFeatures: requestFeatures
+ });
+
+ function insertCallback(response) {
+ var len = response.features ? response.features.length : 0;
+ var fids = new Array(len);
+ for(var i=0; i<len; ++i) {
+ fids[i] = response.features[i].fid;
+ }
+ finalResponse.insertIds = fids;
+ callback.apply(this, [response]);
+ }
+
+ function callback(response) {
+ this.callUserCallback(response, options);
+ success = success && response.success();
+ nResponses++;
+ if (nResponses >= nRequests) {
+ if (options.callback) {
+ finalResponse.code = success ?
+ OpenLayers.Protocol.Response.SUCCESS :
+ OpenLayers.Protocol.Response.FAILURE;
+ options.callback.apply(options.scope, [finalResponse]);
+ }
+ }
+ }
+
+ // start issuing requests
+ var queue = types[OpenLayers.State.INSERT];
+ if(queue.length > 0) {
+ resp.push(this.create(
+ queue, OpenLayers.Util.applyDefaults(
+ {callback: insertCallback, scope: this}, options.create
+ )
+ ));
+ }
+ queue = types[OpenLayers.State.UPDATE];
+ for(var i=queue.length-1; i>=0; --i) {
+ resp.push(this.update(
+ queue[i], OpenLayers.Util.applyDefaults(
+ {callback: callback, scope: this}, options.update
+ ))
+ );
+ }
+ queue = types[OpenLayers.State.DELETE];
+ for(var i=queue.length-1; i>=0; --i) {
+ resp.push(this["delete"](
+ queue[i], OpenLayers.Util.applyDefaults(
+ {callback: callback, scope: this}, options["delete"]
+ ))
+ );
+ }
+ return resp;
+ },
+
+ /**
+ * APIMethod: abort
+ * Abort an ongoing request, the response object passed to
+ * this method must come from this HTTP protocol (as a result
+ * of a create, read, update, delete or commit operation).
+ *
+ * Parameters:
+ * response - {<OpenLayers.Protocol.Response>}
+ */
+ abort: function(response) {
+ if (response) {
+ response.priv.abort();
+ }
+ },
+
+ /**
+ * Method: callUserCallback
+ * This method is used from within the commit method each time an
+ * an HTTP response is received from the server, it is responsible
+ * for calling the user-supplied callbacks.
+ *
+ * Parameters:
+ * resp - {<OpenLayers.Protocol.Response>}
+ * options - {Object} The map of options passed to the commit call.
+ */
+ callUserCallback: function(resp, options) {
+ var opt = options[resp.requestType];
+ if(opt && opt.callback) {
+ opt.callback.call(opt.scope, resp);
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Protocol.HTTP"
+});
+
+/**
+ * Property: OpenLayers.Protocol.HTTP.COMP_TYPE_TO_OP_STR
+ * {Object} A private class-level property mapping the
+ * OpenLayers.Filter.Comparison types to the operation
+ * strings of the protocol.
+ */
+(function() {
+ var o = OpenLayers.Protocol.HTTP.COMP_TYPE_TO_OP_STR = {};
+ o[OpenLayers.Filter.Comparison.EQUAL_TO] = "eq";
+ o[OpenLayers.Filter.Comparison.NOT_EQUAL_TO] = "ne";
+ o[OpenLayers.Filter.Comparison.LESS_THAN] = "lt";
+ o[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO] = "lte";
+ o[OpenLayers.Filter.Comparison.GREATER_THAN] = "gt";
+ o[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO] = "gte";
+ o[OpenLayers.Filter.Comparison.LIKE] = "ilike";
+})();
+
+/* ======================================================================
+ OpenLayers/Strategy/Cluster.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Strategy.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.Cluster
+ * Strategy for vector feature clustering.
+ *
+ * Inherits from:
+ * - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, {
+
+ /**
+ * APIProperty: distance
+ * {Integer} Pixel distance between features that should be considered a
+ * single cluster. Default is 20 pixels.
+ */
+ distance: 20,
+
+ /**
+ * APIProperty: threshold
+ * {Integer} Optional threshold below which original features will be
+ * added to the layer instead of clusters. For example, a threshold
+ * of 3 would mean that any time there are 2 or fewer features in
+ * a cluster, those features will be added directly to the layer instead
+ * of a cluster representing those features. Default is null (which is
+ * equivalent to 1 - meaning that clusters may contain just one feature).
+ */
+ threshold: null,
+
+ /**
+ * Property: features
+ * {Array(<OpenLayers.Feature.Vector>)} Cached features.
+ */
+ features: null,
+
+ /**
+ * Property: clusters
+ * {Array(<OpenLayers.Feature.Vector>)} Calculated clusters.
+ */
+ clusters: null,
+
+ /**
+ * Property: clustering
+ * {Boolean} The strategy is currently clustering features.
+ */
+ clustering: false,
+
+ /**
+ * Property: resolution
+ * {Float} The resolution (map units per pixel) of the current cluster set.
+ */
+ resolution: null,
+
+ /**
+ * Constructor: OpenLayers.Strategy.Cluster
+ * Create a new clustering strategy.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ */
+ initialize: function(options) {
+ OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * APIMethod: activate
+ * Activate the strategy. Register any listeners, do appropriate setup.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully activated.
+ */
+ activate: function() {
+ var activated = OpenLayers.Strategy.prototype.activate.call(this);
+ if(activated) {
+ this.layer.events.on({
+ "beforefeaturesadded": this.cacheFeatures,
+ "moveend": this.cluster,
+ scope: this
+ });
+ }
+ return activated;
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Deactivate the strategy. Unregister any listeners, do appropriate
+ * tear-down.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
+ if(deactivated) {
+ this.clearCache();
+ this.layer.events.un({
+ "beforefeaturesadded": this.cacheFeatures,
+ "moveend": this.cluster,
+ scope: this
+ });
+ }
+ return deactivated;
+ },
+
+ /**
+ * Method: cacheFeatures
+ * Cache features before they are added to the layer.
+ *
+ * Parameters:
+ * event - {Object} The event that this was listening for. This will come
+ * with a batch of features to be clustered.
+ *
+ * Returns:
+ * {Boolean} False to stop features from being added to the layer.
+ */
+ cacheFeatures: function(event) {
+ var propagate = true;
+ if(!this.clustering) {
+ this.clearCache();
+ this.features = event.features;
+ this.cluster();
+ propagate = false;
+ }
+ return propagate;
+ },
+
+ /**
+ * Method: clearCache
+ * Clear out the cached features.
+ */
+ clearCache: function() {
+ this.features = null;
+ },
+
+ /**
+ * Method: cluster
+ * Cluster features based on some threshold distance.
+ *
+ * Parameters:
+ * event - {Object} The event received when cluster is called as a
+ * result of a moveend event.
+ */
+ cluster: function(event) {
+ if((!event || event.zoomChanged) && this.features) {
+ var resolution = this.layer.map.getResolution();
+ if(resolution != this.resolution || !this.clustersExist()) {
+ this.resolution = resolution;
+ var clusters = [];
+ var feature, clustered, cluster;
+ for(var i=0; i<this.features.length; ++i) {
+ feature = this.features[i];
+ if(feature.geometry) {
+ clustered = false;
+ for(var j=clusters.length-1; j>=0; --j) {
+ cluster = clusters[j];
+ if(this.shouldCluster(cluster, feature)) {
+ this.addToCluster(cluster, feature);
+ clustered = true;
+ break;
+ }
+ }
+ if(!clustered) {
+ clusters.push(this.createCluster(this.features[i]));
+ }
+ }
+ }
+ this.layer.removeAllFeatures();
+ if(clusters.length > 0) {
+ if(this.threshold > 1) {
+ var clone = clusters.slice();
+ clusters = [];
+ var candidate;
+ for(var i=0, len=clone.length; i<len; ++i) {
+ candidate = clone[i];
+ if(candidate.attributes.count < this.threshold) {
+ Array.prototype.push.apply(clusters, candidate.cluster);
+ } else {
+ clusters.push(candidate);
+ }
+ }
+ }
+ this.clustering = true;
+ // A legitimate feature addition could occur during this
+ // addFeatures call. For clustering to behave well, features
+ // should be removed from a layer before requesting a new batch.
+ this.layer.addFeatures(clusters);
+ this.clustering = false;
+ }
+ this.clusters = clusters;
+ }
+ }
+ },
+
+ /**
+ * Method: clustersExist
+ * Determine whether calculated clusters are already on the layer.
+ *
+ * Returns:
+ * {Boolean} The calculated clusters are already on the layer.
+ */
+ clustersExist: function() {
+ var exist = false;
+ if(this.clusters && this.clusters.length > 0 &&
+ this.clusters.length == this.layer.features.length) {
+ exist = true;
+ for(var i=0; i<this.clusters.length; ++i) {
+ if(this.clusters[i] != this.layer.features[i]) {
+ exist = false;
+ break;
+ }
+ }
+ }
+ return exist;
+ },
+
+ /**
+ * Method: shouldCluster
+ * Determine whether to include a feature in a given cluster.
+ *
+ * Parameters:
+ * cluster - {<OpenLayers.Feature.Vector>} A cluster.
+ * feature - {<OpenLayers.Feature.Vector>} A feature.
+ *
+ * Returns:
+ * {Boolean} The feature should be included in the cluster.
+ */
+ shouldCluster: function(cluster, feature) {
+ var cc = cluster.geometry.getBounds().getCenterLonLat();
+ var fc = feature.geometry.getBounds().getCenterLonLat();
+ var distance = (
+ Math.sqrt(
+ Math.pow((cc.lon - fc.lon), 2) + Math.pow((cc.lat - fc.lat), 2)
+ ) / this.resolution
+ );
+ return (distance <= this.distance);
+ },
+
+ /**
+ * Method: addToCluster
+ * Add a feature to a cluster.
+ *
+ * Parameters:
+ * cluster - {<OpenLayers.Feature.Vector>} A cluster.
+ * feature - {<OpenLayers.Feature.Vector>} A feature.
+ */
+ addToCluster: function(cluster, feature) {
+ cluster.cluster.push(feature);
+ cluster.attributes.count += 1;
+ },
+
+ /**
+ * Method: createCluster
+ * Given a feature, create a cluster.
+ *
+ * Parameters:
+ * feature - {<OpenLayers.Feature.Vector>}
+ *
+ * Returns:
+ * {<OpenLayers.Feature.Vector>} A cluster.
+ */
+ createCluster: function(feature) {
+ var center = feature.geometry.getBounds().getCenterLonLat();
+ var cluster = new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.Point(center.lon, center.lat),
+ {count: 1}
+ );
+ cluster.cluster = [feature];
+ return cluster;
+ },
+
+ CLASS_NAME: "OpenLayers.Strategy.Cluster"
+});
+/* ======================================================================
+ OpenLayers/Control/OverviewMap.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/BaseTypes.js
+ * @requires OpenLayers/Events.js
+ */
+
+/**
+ * Class: OpenLayers.Control.OverviewMap
+ * The OverMap control creates a small overview map, useful to display the
+ * extent of a zoomed map and your main map and provide additional
+ * navigation options to the User. By default the overview map is drawn in
+ * the lower right corner of the main map. Create a new overview map with the
+ * <OpenLayers.Control.OverviewMap> constructor.
+ *
+ * Inerits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Property: element
+ * {DOMElement} The DOM element that contains the overview map
+ */
+ element: null,
+
+ /**
+ * APIProperty: ovmap
+ * {<OpenLayers.Map>} A reference to the overview map itself.
+ */
+ ovmap: null,
+
+ /**
+ * APIProperty: size
+ * {<OpenLayers.Size>} The overvew map size in pixels. Note that this is
+ * the size of the map itself - the element that contains the map (default
+ * class name olControlOverviewMapElement) may have padding or other style
+ * attributes added via CSS.
+ */
+ size: new OpenLayers.Size(180, 90),
+
+ /**
+ * APIProperty: layers
+ * {Array(<OpenLayers.Layer>)} Ordered list of layers in the overview map.
+ * If none are sent at construction, the base layer for the main map is used.
+ */
+ layers: null,
+
+ /**
+ * APIProperty: minRectSize
+ * {Integer} The minimum width or height (in pixels) of the extent
+ * rectangle on the overview map. When the extent rectangle reaches
+ * this size, it will be replaced depending on the value of the
+ * <minRectDisplayClass> property. Default is 15 pixels.
+ */
+ minRectSize: 15,
+
+ /**
+ * APIProperty: minRectDisplayClass
+ * {String} Replacement style class name for the extent rectangle when
+ * <minRectSize> is reached. This string will be suffixed on to the
+ * displayClass. Default is "RectReplacement".
+ *
+ * Example CSS declaration:
+ * (code)
+ * .olControlOverviewMapRectReplacement {
+ * overflow: hidden;
+ * cursor: move;
+ * background-image: url("img/overview_replacement.gif");
+ * background-repeat: no-repeat;
+ * background-position: center;
+ * }
+ * (end)
+ */
+ minRectDisplayClass: "RectReplacement",
+
+ /**
+ * APIProperty: minRatio
+ * {Float} The ratio of the overview map resolution to the main map
+ * resolution at which to zoom farther out on the overview map.
+ */
+ minRatio: 8,
+
+ /**
+ * APIProperty: maxRatio
+ * {Float} The ratio of the overview map resolution to the main map
+ * resolution at which to zoom farther in on the overview map.
+ */
+ maxRatio: 32,
+
+ /**
+ * APIProperty: mapOptions
+ * {Object} An object containing any non-default properties to be sent to
+ * the overview map's map constructor. These should include any
+ * non-default options that the main map was constructed with.
+ */
+ mapOptions: null,
+
+ /**
+ * APIProperty: autoPan
+ * {Boolean} Always pan the overview map, so the extent marker remains in
+ * the center. Default is false. If true, when you drag the extent
+ * marker, the overview map will update itself so the marker returns
+ * to the center.
+ */
+ autoPan: false,
+
+ /**
+ * Property: handlers
+ * {Object}
+ */
+ handlers: null,
+
+ /**
+ * Property: resolutionFactor
+ * {Object}
+ */
+ resolutionFactor: 1,
+
+ /**
+ * APIProperty: maximized
+ * {Boolean} Start as maximized (visible). Defaults to false.
+ */
+ maximized: false,
+
+ /**
+ * Constructor: OpenLayers.Control.OverviewMap
+ * Create a new overview map
+ *
+ * Parameters:
+ * object - {Object} Properties of this object will be set on the overview
+ * map object. Note, to set options on the map object contained in this
+ * control, set <mapOptions> as one of the options properties.
+ */
+ initialize: function(options) {
+ this.layers = [];
+ this.handlers = {};
+ OpenLayers.Control.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * APIMethod: destroy
+ * Deconstruct the control
+ */
+ destroy: function() {
+ if (!this.mapDiv) { // we've already been destroyed
+ return;
+ }
+ if (this.handlers.click) {
+ this.handlers.click.destroy();
+ }
+ if (this.handlers.drag) {
+ this.handlers.drag.destroy();
+ }
+
+ this.ovmap && this.ovmap.viewPortDiv.removeChild(this.extentRectangle);
+ this.extentRectangle = null;
+
+ if (this.rectEvents) {
+ this.rectEvents.destroy();
+ this.rectEvents = null;
+ }
+
+ if (this.ovmap) {
+ this.ovmap.destroy();
+ this.ovmap = null;
+ }
+
+ this.element.removeChild(this.mapDiv);
+ this.mapDiv = null;
+
+ this.div.removeChild(this.element);
+ this.element = null;
+
+ if (this.maximizeDiv) {
+ OpenLayers.Event.stopObservingElement(this.maximizeDiv);
+ this.div.removeChild(this.maximizeDiv);
+ this.maximizeDiv = null;
+ }
+
+ if (this.minimizeDiv) {
+ OpenLayers.Event.stopObservingElement(this.minimizeDiv);
+ this.div.removeChild(this.minimizeDiv);
+ this.minimizeDiv = null;
+ }
+
+ this.map.events.un({
+ "moveend": this.update,
+ "changebaselayer": this.baseLayerDraw,
+ scope: this
+ });
+
+ OpenLayers.Control.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: draw
+ * Render the control in the browser.
+ */
+ draw: function() {
+ OpenLayers.Control.prototype.draw.apply(this, arguments);
+ if(!(this.layers.length > 0)) {
+ if (this.map.baseLayer) {
+ var layer = this.map.baseLayer.clone();
+ this.layers = [layer];
+ } else {
+ this.map.events.register("changebaselayer", this, this.baseLayerDraw);
+ return this.div;
+ }
+ }
+
+ // create overview map DOM elements
+ this.element = document.createElement('div');
+ this.element.className = this.displayClass + 'Element';
+ this.element.style.display = 'none';
+
+ this.mapDiv = document.createElement('div');
+ this.mapDiv.style.width = this.size.w + 'px';
+ this.mapDiv.style.height = this.size.h + 'px';
+ this.mapDiv.style.position = 'relative';
+ this.mapDiv.style.overflow = 'hidden';
+ this.mapDiv.id = OpenLayers.Util.createUniqueID('overviewMap');
+
+ this.extentRectangle = document.createElement('div');
+ this.extentRectangle.style.position = 'absolute';
+ this.extentRectangle.style.zIndex = 1000; //HACK
+ this.extentRectangle.className = this.displayClass+'ExtentRectangle';
+
+ this.element.appendChild(this.mapDiv);
+
+ this.div.appendChild(this.element);
+
+ // Optionally add min/max buttons if the control will go in the
+ // map viewport.
+ if(!this.outsideViewport) {
+ this.div.className += " " + this.displayClass + 'Container';
+ var imgLocation = OpenLayers.Util.getImagesLocation();
+ // maximize button div
+ var img = imgLocation + 'layer-switcher-maximize.png';
+ this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
+ this.displayClass + 'MaximizeButton',
+ null,
+ new OpenLayers.Size(18,18),
+ img,
+ 'absolute');
+ this.maximizeDiv.style.display = 'none';
+ this.maximizeDiv.className = this.displayClass + 'MaximizeButton';
+ OpenLayers.Event.observe(this.maximizeDiv, 'click',
+ OpenLayers.Function.bindAsEventListener(this.maximizeControl,
+ this)
+ );
+ this.div.appendChild(this.maximizeDiv);
+
+ // minimize button div
+ var img = imgLocation + 'layer-switcher-minimize.png';
+ this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
+ 'OpenLayers_Control_minimizeDiv',
+ null,
+ new OpenLayers.Size(18,18),
+ img,
+ 'absolute');
+ this.minimizeDiv.style.display = 'none';
+ this.minimizeDiv.className = this.displayClass + 'MinimizeButton';
+ OpenLayers.Event.observe(this.minimizeDiv, 'click',
+ OpenLayers.Function.bindAsEventListener(this.minimizeControl,
+ this)
+ );
+ this.div.appendChild(this.minimizeDiv);
+
+ var eventsToStop = ['dblclick','mousedown'];
+
+ for (var i=0, len=eventsToStop.length; i<len; i++) {
+
+ OpenLayers.Event.observe(this.maximizeDiv,
+ eventsToStop[i],
+ OpenLayers.Event.stop);
+
+ OpenLayers.Event.observe(this.minimizeDiv,
+ eventsToStop[i],
+ OpenLayers.Event.stop);
+ }
+
+ this.minimizeControl();
+ } else {
+ // show the overview map
+ this.element.style.display = '';
+ }
+ if(this.map.getExtent()) {
+ this.update();
+ }
+
+ this.map.events.register('moveend', this, this.update);
+
+ if (this.maximized) {
+ this.maximizeControl();
+ }
+ return this.div;
+ },
+
+ /**
+ * Method: baseLayerDraw
+ * Draw the base layer - called if unable to complete in the initial draw
+ */
+ baseLayerDraw: function() {
+ this.draw();
+ this.map.events.unregister("changebaselayer", this, this.baseLayerDraw);
+ },
+
+ /**
+ * Method: rectDrag
+ * Handle extent rectangle drag
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>} The pixel location of the drag.
+ */
+ rectDrag: function(px) {
+ var deltaX = this.handlers.drag.last.x - px.x;
+ var deltaY = this.handlers.drag.last.y - px.y;
+ if(deltaX != 0 || deltaY != 0) {
+ var rectTop = this.rectPxBounds.top;
+ var rectLeft = this.rectPxBounds.left;
+ var rectHeight = Math.abs(this.rectPxBounds.getHeight());
+ var rectWidth = this.rectPxBounds.getWidth();
+ // don't allow dragging off of parent element
+ var newTop = Math.max(0, (rectTop - deltaY));
+ newTop = Math.min(newTop,
+ this.ovmap.size.h - this.hComp - rectHeight);
+ var newLeft = Math.max(0, (rectLeft - deltaX));
+ newLeft = Math.min(newLeft,
+ this.ovmap.size.w - this.wComp - rectWidth);
+ this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
+ newTop + rectHeight,
+ newLeft + rectWidth,
+ newTop));
+ }
+ },
+
+ /**
+ * Method: mapDivClick
+ * Handle browser events
+ *
+ * Parameters:
+ * evt - {<OpenLayers.Event>} evt
+ */
+ mapDivClick: function(evt) {
+ var pxCenter = this.rectPxBounds.getCenterPixel();
+ var deltaX = evt.xy.x - pxCenter.x;
+ var deltaY = evt.xy.y - pxCenter.y;
+ var top = this.rectPxBounds.top;
+ var left = this.rectPxBounds.left;
+ var height = Math.abs(this.rectPxBounds.getHeight());
+ var width = this.rectPxBounds.getWidth();
+ var newTop = Math.max(0, (top + deltaY));
+ newTop = Math.min(newTop, this.ovmap.size.h - height);
+ var newLeft = Math.max(0, (left + deltaX));
+ newLeft = Math.min(newLeft, this.ovmap.size.w - width);
+ this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
+ newTop + height,
+ newLeft + width,
+ newTop));
+ this.updateMapToRect();
+ },
+
+ /**
+ * Method: maximizeControl
+ * Unhide the control. Called when the control is in the map viewport.
+ *
+ * Parameters:
+ * e - {<OpenLayers.Event>}
+ */
+ maximizeControl: function(e) {
+ this.element.style.display = '';
+ this.showToggle(false);
+ if (e != null) {
+ OpenLayers.Event.stop(e);
+ }
+ },
+
+ /**
+ * Method: minimizeControl
+ * Hide all the contents of the control, shrink the size,
+ * add the maximize icon
+ *
+ * Parameters:
+ * e - {<OpenLayers.Event>}
+ */
+ minimizeControl: function(e) {
+ this.element.style.display = 'none';
+ this.showToggle(true);
+ if (e != null) {
+ OpenLayers.Event.stop(e);
+ }
+ },
+
+ /**
+ * Method: showToggle
+ * Hide/Show the toggle depending on whether the control is minimized
+ *
+ * Parameters:
+ * minimize - {Boolean}
+ */
+ showToggle: function(minimize) {
+ this.maximizeDiv.style.display = minimize ? '' : 'none';
+ this.minimizeDiv.style.display = minimize ? 'none' : '';
+ },
+
+ /**
+ * Method: update
+ * Update the overview map after layers move.
+ */
+ update: function() {
+ if(this.ovmap == null) {
+ this.createMap();
+ }
+
+ if(this.autoPan || !this.isSuitableOverview()) {
+ this.updateOverview();
+ }
+
+ // update extent rectangle
+ this.updateRectToMap();
+ },
+
+ /**
+ * Method: isSuitableOverview
+ * Determines if the overview map is suitable given the extent and
+ * resolution of the main map.
+ */
+ isSuitableOverview: function() {
+ var mapExtent = this.map.getExtent();
+ var maxExtent = this.map.maxExtent;
+ var testExtent = new OpenLayers.Bounds(
+ Math.max(mapExtent.left, maxExtent.left),
+ Math.max(mapExtent.bottom, maxExtent.bottom),
+ Math.min(mapExtent.right, maxExtent.right),
+ Math.min(mapExtent.top, maxExtent.top));
+
+ if (this.ovmap.getProjection() != this.map.getProjection()) {
+ testExtent = testExtent.transform(
+ this.map.getProjectionObject(),
+ this.ovmap.getProjectionObject() );
+ }
+
+ var resRatio = this.ovmap.getResolution() / this.map.getResolution();
+ return ((resRatio > this.minRatio) &&
+ (resRatio <= this.maxRatio) &&
+ (this.ovmap.getExtent().containsBounds(testExtent)));
+ },
+
+ /**
+ * Method updateOverview
+ * Called by <update> if <isSuitableOverview> returns true
+ */
+ updateOverview: function() {
+ var mapRes = this.map.getResolution();
+ var targetRes = this.ovmap.getResolution();
+ var resRatio = targetRes / mapRes;
+ if(resRatio > this.maxRatio) {
+ // zoom in overview map
+ targetRes = this.minRatio * mapRes;
+ } else if(resRatio <= this.minRatio) {
+ // zoom out overview map
+ targetRes = this.maxRatio * mapRes;
+ }
+ var center;
+ if (this.ovmap.getProjection() != this.map.getProjection()) {
+ center = this.map.center.clone();
+ center.transform(this.map.getProjectionObject(),
+ this.ovmap.getProjectionObject() );
+ } else {
+ center = this.map.center;
+ }
+ this.ovmap.setCenter(center, this.ovmap.getZoomForResolution(
+ targetRes * this.resolutionFactor));
+ this.updateRectToMap();
+ },
+
+ /**
+ * Method: createMap
+ * Construct the map that this control contains
+ */
+ createMap: function() {
+ // create the overview map
+ var options = OpenLayers.Util.extend(
+ {controls: [], maxResolution: 'auto',
+ fallThrough: false}, this.mapOptions);
+ this.ovmap = new OpenLayers.Map(this.mapDiv, options);
+ this.ovmap.viewPortDiv.appendChild(this.extentRectangle);
+
+ // prevent ovmap from being destroyed when the page unloads, because
+ // the OverviewMap control has to do this (and does it).
+ OpenLayers.Event.stopObserving(window, 'unload', this.ovmap.unloadDestroy);
+
+ this.ovmap.addLayers(this.layers);
+ this.ovmap.zoomToMaxExtent();
+ // check extent rectangle border width
+ this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+ 'border-left-width')) +
+ parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+ 'border-right-width'));
+ this.wComp = (this.wComp) ? this.wComp : 2;
+ this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+ 'border-top-width')) +
+ parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+ 'border-bottom-width'));
+ this.hComp = (this.hComp) ? this.hComp : 2;
+
+ this.handlers.drag = new OpenLayers.Handler.Drag(
+ this, {move: this.rectDrag, done: this.updateMapToRect},
+ {map: this.ovmap}
+ );
+ this.handlers.click = new OpenLayers.Handler.Click(
+ this, {
+ "click": this.mapDivClick
+ },{
+ "single": true, "double": false,
+ "stopSingle": true, "stopDouble": true,
+ "pixelTolerance": 1,
+ map: this.ovmap
+ }
+ );
+ this.handlers.click.activate();
+
+ this.rectEvents = new OpenLayers.Events(this, this.extentRectangle,
+ null, true);
+ this.rectEvents.register("mouseover", this, function(e) {
+ if(!this.handlers.drag.active && !this.map.dragging) {
+ this.handlers.drag.activate();
+ }
+ });
+ this.rectEvents.register("mouseout", this, function(e) {
+ if(!this.handlers.drag.dragging) {
+ this.handlers.drag.deactivate();
+ }
+ });
+
+ if (this.ovmap.getProjection() != this.map.getProjection()) {
+ var sourceUnits = this.map.getProjectionObject().getUnits() ||
+ this.map.units || this.map.baseLayer.units;
+ var targetUnits = this.ovmap.getProjectionObject().getUnits() ||
+ this.ovmap.units || this.ovmap.baseLayer.units;
+ this.resolutionFactor = sourceUnits && targetUnits ?
+ OpenLayers.INCHES_PER_UNIT[sourceUnits] /
+ OpenLayers.INCHES_PER_UNIT[targetUnits] : 1;
+ }
+ },
+
+ /**
+ * Method: updateRectToMap
+ * Updates the extent rectangle position and size to match the map extent
+ */
+ updateRectToMap: function() {
+ // If the projections differ we need to reproject
+ var bounds;
+ if (this.ovmap.getProjection() != this.map.getProjection()) {
+ bounds = this.map.getExtent().transform(
+ this.map.getProjectionObject(),
+ this.ovmap.getProjectionObject() );
+ } else {
+ bounds = this.map.getExtent();
+ }
+ var pxBounds = this.getRectBoundsFromMapBounds(bounds);
+ if (pxBounds) {
+ this.setRectPxBounds(pxBounds);
+ }
+ },
+
+ /**
+ * Method: updateMapToRect
+ * Updates the map extent to match the extent rectangle position and size
+ */
+ updateMapToRect: function() {
+ var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds);
+ if (this.ovmap.getProjection() != this.map.getProjection()) {
+ lonLatBounds = lonLatBounds.transform(
+ this.ovmap.getProjectionObject(),
+ this.map.getProjectionObject() );
+ }
+ this.map.panTo(lonLatBounds.getCenterLonLat());
+ },
+
+ /**
+ * Method: setRectPxBounds
+ * Set extent rectangle pixel bounds.
+ *
+ * Parameters:
+ * pxBounds - {<OpenLayers.Bounds>}
+ */
+ setRectPxBounds: function(pxBounds) {
+ var top = Math.max(pxBounds.top, 0);
+ var left = Math.max(pxBounds.left, 0);
+ var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()),
+ this.ovmap.size.h - this.hComp);
+ var right = Math.min(pxBounds.left + pxBounds.getWidth(),
+ this.ovmap.size.w - this.wComp);
+ var width = Math.max(right - left, 0);
+ var height = Math.max(bottom - top, 0);
+ if(width < this.minRectSize || height < this.minRectSize) {
+ this.extentRectangle.className = this.displayClass +
+ this.minRectDisplayClass;
+ var rLeft = left + (width / 2) - (this.minRectSize / 2);
+ var rTop = top + (height / 2) - (this.minRectSize / 2);
+ this.extentRectangle.style.top = Math.round(rTop) + 'px';
+ this.extentRectangle.style.left = Math.round(rLeft) + 'px';
+ this.extentRectangle.style.height = this.minRectSize + 'px';
+ this.extentRectangle.style.width = this.minRectSize + 'px';
+ } else {
+ this.extentRectangle.className = this.displayClass +
+ 'ExtentRectangle';
+ this.extentRectangle.style.top = Math.round(top) + 'px';
+ this.extentRectangle.style.left = Math.round(left) + 'px';
+ this.extentRectangle.style.height = Math.round(height) + 'px';
+ this.extentRectangle.style.width = Math.round(width) + 'px';
+ }
+ this.rectPxBounds = new OpenLayers.Bounds(
+ Math.round(left), Math.round(bottom),
+ Math.round(right), Math.round(top)
+ );
+ },
+
+ /**
+ * Method: getRectBoundsFromMapBounds
+ * Get the rect bounds from the map bounds.
+ *
+ * Parameters:
+ * lonLatBounds - {<OpenLayers.Bounds>}
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>}A bounds which is the passed-in map lon/lat extent
+ * translated into pixel bounds for the overview map
+ */
+ getRectBoundsFromMapBounds: function(lonLatBounds) {
+ var leftBottomLonLat = new OpenLayers.LonLat(lonLatBounds.left,
+ lonLatBounds.bottom);
+ var rightTopLonLat = new OpenLayers.LonLat(lonLatBounds.right,
+ lonLatBounds.top);
+ var leftBottomPx = this.getOverviewPxFromLonLat(leftBottomLonLat);
+ var rightTopPx = this.getOverviewPxFromLonLat(rightTopLonLat);
+ var bounds = null;
+ if (leftBottomPx && rightTopPx) {
+ bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y,
+ rightTopPx.x, rightTopPx.y);
+ }
+ return bounds;
+ },
+
+ /**
+ * Method: getMapBoundsFromRectBounds
+ * Get the map bounds from the rect bounds.
+ *
+ * Parameters:
+ * pxBounds - {<OpenLayers.Bounds>}
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} Bounds which is the passed-in overview rect bounds
+ * translated into lon/lat bounds for the overview map
+ */
+ getMapBoundsFromRectBounds: function(pxBounds) {
+ var leftBottomPx = new OpenLayers.Pixel(pxBounds.left,
+ pxBounds.bottom);
+ var rightTopPx = new OpenLayers.Pixel(pxBounds.right,
+ pxBounds.top);
+ var leftBottomLonLat = this.getLonLatFromOverviewPx(leftBottomPx);
+ var rightTopLonLat = this.getLonLatFromOverviewPx(rightTopPx);
+ return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat,
+ rightTopLonLat.lon, rightTopLonLat.lat);
+ },
+
+ /**
+ * Method: getLonLatFromOverviewPx
+ * Get a map location from a pixel location
+ *
+ * Parameters:
+ * overviewMapPx - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} Location which is the passed-in overview map
+ * OpenLayers.Pixel, translated into lon/lat by the overview map
+ */
+ getLonLatFromOverviewPx: function(overviewMapPx) {
+ var size = this.ovmap.size;
+ var res = this.ovmap.getResolution();
+ var center = this.ovmap.getExtent().getCenterLonLat();
+
+ var delta_x = overviewMapPx.x - (size.w / 2);
+ var delta_y = overviewMapPx.y - (size.h / 2);
+
+ return new OpenLayers.LonLat(center.lon + delta_x * res ,
+ center.lat - delta_y * res);
+ },
+
+ /**
+ * Method: getOverviewPxFromLonLat
+ * Get a pixel location from a map location
+ *
+ * Parameters:
+ * lonlat - {<OpenLayers.LonLat>}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} Location which is the passed-in OpenLayers.LonLat,
+ * translated into overview map pixels
+ */
+ getOverviewPxFromLonLat: function(lonlat) {
+ var res = this.ovmap.getResolution();
+ var extent = this.ovmap.getExtent();
+ var px = null;
+ if (extent) {
+ px = new OpenLayers.Pixel(
+ Math.round(1/res * (lonlat.lon - extent.left)),
+ Math.round(1/res * (extent.top - lonlat.lat)));
+ }
+ return px;
+ },
+
+ CLASS_NAME: 'OpenLayers.Control.OverviewMap'
+});
+/* ======================================================================
+ OpenLayers/Format/WFSCapabilities/v1_0_0.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/WFSCapabilities/v1.js
+ */
+
+/**
+ * Class: OpenLayers.Format.WFSCapabilities/v1_0_0
+ * Read WMS Capabilities version 1.0.0.
+ *
+ * Inherits from:
+ * - <OpenLayers.Format.WFSCapabilities>
+ */
+OpenLayers.Format.WFSCapabilities.v1_0_0 = OpenLayers.Class(
+ OpenLayers.Format.WFSCapabilities.v1, {
+
+ /**
+ * Constructor: OpenLayers.Format.WFSCapabilities.v1_0_0
+ * Create a new parser for WFS capabilities version 1.0.0.
+ *
+ * Parameters:
+ * options - {Object} An optional object whose properties will be set on
+ * this instance.
+ */
+ initialize: function(options) {
+ OpenLayers.Format.WFSCapabilities.v1.prototype.initialize.apply(
+ this, [options]
+ );
+ },
+
+ /**
+ * Method: read_cap_Service
+ */
+ read_cap_Service: function(capabilities, node) {
+ var service = {};
+ this.runChildNodes(service, node);
+ capabilities.service = service;
+ },
+
+ /**
+ * Method: read_cap_Fees
+ */
+ read_cap_Fees: function(service, node) {
+ var fees = this.getChildValue(node);
+ if (fees && fees.toLowerCase() != "none") {
+ service.fees = fees;
+ }
+ },
+
+ /**
+ * Method: read_cap_AccessConstraints
+ */
+ read_cap_AccessConstraints: function(service, node) {
+ var constraints = this.getChildValue(node);
+ if (constraints && constraints.toLowerCase() != "none") {
+ service.accessConstraints = constraints;
+ }
+ },
+
+ /**
+ * Method: read_cap_OnlineResource
+ */
+ read_cap_OnlineResource: function(service, node) {
+ var onlineResource = this.getChildValue(node);
+ if (onlineResource && onlineResource.toLowerCase() != "none") {
+ service.onlineResource = onlineResource;
+ }
+ },
+
+ /**
+ * Method: read_cap_Keywords
+ */
+ read_cap_Keywords: function(service, node) {
+ var keywords = this.getChildValue(node);
+ if (keywords && keywords.toLowerCase() != "none") {
+ service.keywords = keywords.split(', ');
+ }
+ },
+
+ /**
+ * Method: read_cap_Capability
+ */
+ read_cap_Capability: function(capabilities, node) {
+ var capability = {};
+ this.runChildNodes(capability, node);
+ capabilities.capability = capability;
+ },
+
+ /**
+ * Method: read_cap_Request
+ */
+ read_cap_Request: function(obj, node) {
+ var request = {};
+ this.runChildNodes(request, node);
+ obj.request = request;
+ },
+
+ /**
+ * Method: read_cap_GetFeature
+ */
+ read_cap_GetFeature: function(request, node) {
+ var getfeature = {
+ href: {}, // DCPType
+ formats: [] // ResultFormat
+ };
+ this.runChildNodes(getfeature, node);
+ request.getfeature = getfeature;
+ },
+
+ /**
+ * Method: read_cap_ResultFormat
+ */
+ read_cap_ResultFormat: function(obj, node) {
+ var children = node.childNodes;
+ var childNode;
+ for(var i=0; i<children.length; i++) {
+ childNode = children[i];
+ if(childNode.nodeType == 1) {
+ obj.formats.push(childNode.nodeName);
+ }
+ }
+ },
+
+ /**
+ * Method: read_cap_DCPType
+ */
+ read_cap_DCPType: function(obj, node) {
+ this.runChildNodes(obj, node);
+ },
+
+ /**
+ * Method: read_cap_HTTP
+ */
+ read_cap_HTTP: function(obj, node) {
+ this.runChildNodes(obj.href, node);
+ },
+
+ /**
+ * Method: read_cap_Get
+ */
+ read_cap_Get: function(obj, node) {
+ obj.get = node.getAttribute("onlineResource");
+ },
+
+ /**
+ * Method: read_cap_Post
+ */
+ read_cap_Post: function(obj, node) {
+ obj.post = node.getAttribute("onlineResource");
+ },
+
+ CLASS_NAME: "OpenLayers.Format.WFSCapabilities.v1_0_0"
+
+});
+/* ======================================================================
+ OpenLayers/Layer/Yahoo.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/SphericalMercator.js
+ * @requires OpenLayers/Layer/EventPane.js
+ * @requires OpenLayers/Layer/FixedZoomLevels.js
+ * @requires OpenLayers/Lang.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.Yahoo
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer.EventPane>
+ * - <OpenLayers.Layer.FixedZoomLevels>
+ */
+OpenLayers.Layer.Yahoo = OpenLayers.Class(
+ OpenLayers.Layer.EventPane, OpenLayers.Layer.FixedZoomLevels, {
+
+ /**
+ * Constant: MIN_ZOOM_LEVEL
+ * {Integer} 0
+ */
+ MIN_ZOOM_LEVEL: 0,
+
+ /**
+ * Constant: MAX_ZOOM_LEVEL
+ * {Integer} 17
+ */
+ MAX_ZOOM_LEVEL: 17,
+
+ /**
+ * Constant: RESOLUTIONS
+ * {Array(Float)} Hardcode these resolutions so that they are more closely
+ * tied with the standard wms projection
+ */
+ RESOLUTIONS: [
+ 1.40625,
+ 0.703125,
+ 0.3515625,
+ 0.17578125,
+ 0.087890625,
+ 0.0439453125,
+ 0.02197265625,
+ 0.010986328125,
+ 0.0054931640625,
+ 0.00274658203125,
+ 0.001373291015625,
+ 0.0006866455078125,
+ 0.00034332275390625,
+ 0.000171661376953125,
+ 0.0000858306884765625,
+ 0.00004291534423828125,
+ 0.00002145767211914062,
+ 0.00001072883605957031
+ ],
+
+ /**
+ * APIProperty: type
+ * {YahooMapType}
+ */
+ type: null,
+
+ /**
+ * APIProperty: wrapDateLine
+ * {Boolean} Allow user to pan forever east/west. Default is true.
+ * Setting this to false only restricts panning if
+ * <sphericalMercator> is true.
+ */
+ wrapDateLine: true,
+
+ /**
+ * APIProperty: sphericalMercator
+ * {Boolean} Should the map act as a mercator-projected map? This will
+ * cause all interactions with the map to be in the actual map projection,
+ * which allows support for vector drawing, overlaying other maps, etc.
+ */
+ sphericalMercator: false,
+
+ /**
+ * Constructor: OpenLayers.Layer.Yahoo
+ *
+ * Parameters:
+ * name - {String}
+ * options - {Object}
+ */
+ initialize: function(name, options) {
+ OpenLayers.Layer.EventPane.prototype.initialize.apply(this, arguments);
+ OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,
+ arguments);
+ if(this.sphericalMercator) {
+ OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
+ this.initMercatorParameters();
+ }
+ },
+
+ /**
+ * Method: loadMapObject
+ */
+ loadMapObject:function() {
+ try { //do not crash!
+ var size = this.getMapObjectSizeFromOLSize(this.map.getSize());
+ this.mapObject = new YMap(this.div, this.type, size);
+ this.mapObject.disableKeyControls();
+ this.mapObject.disableDragMap();
+
+ //can we do smooth panning? (moveByXY is not an API function)
+ if ( !this.mapObject.moveByXY ||
+ (typeof this.mapObject.moveByXY != "function" ) ) {
+
+ this.dragPanMapObject = null;
+ }
+ } catch(e) {}
+ },
+
+ /**
+ * Method: onMapResize
+ *
+ */
+ onMapResize: function() {
+ try {
+ var size = this.getMapObjectSizeFromOLSize(this.map.getSize());
+ this.mapObject.resizeTo(size);
+ } catch(e) {}
+ },
+
+
+ /**
+ * APIMethod: setMap
+ * Overridden from EventPane because we need to remove this yahoo event
+ * pane which prohibits our drag and drop, and we can only do this
+ * once the map has been loaded and centered.
+ *
+ * Parameters:
+ * map - {<OpenLayers.Map>}
+ */
+ setMap: function(map) {
+ OpenLayers.Layer.EventPane.prototype.setMap.apply(this, arguments);
+
+ this.map.events.register("moveend", this, this.fixYahooEventPane);
+ },
+
+ /**
+ * Method: fixYahooEventPane
+ * The map has been centered, so the mysterious yahoo eventpane has been
+ * added. we remove it so that it doesnt mess with *our* event pane.
+ */
+ fixYahooEventPane: function() {
+ var yahooEventPane = OpenLayers.Util.getElement("ygddfdiv");
+ if (yahooEventPane != null) {
+ if (yahooEventPane.parentNode != null) {
+ yahooEventPane.parentNode.removeChild(yahooEventPane);
+ }
+ this.map.events.unregister("moveend", this,
+ this.fixYahooEventPane);
+ }
+ },
+
+ /**
+ * APIMethod: getWarningHTML
+ *
+ * Returns:
+ * {String} String with information on why layer is broken, how to get
+ * it working.
+ */
+ getWarningHTML:function() {
+ return OpenLayers.i18n(
+ "getLayerWarning", {'layerType':'Yahoo', 'layerLib':'Yahoo'}
+ );
+ },
+
+ /********************************************************/
+ /* */
+ /* Translation Functions */
+ /* */
+ /* The following functions translate GMaps and OL */
+ /* formats for Pixel, LonLat, Bounds, and Zoom */
+ /* */
+ /********************************************************/
+
+
+ //
+ // TRANSLATION: MapObject Zoom <-> OpenLayers Zoom
+ //
+
+ /**
+ * APIMethod: getOLZoomFromMapObjectZoom
+ *
+ * Parameters:
+ * gZoom - {Integer}
+ *
+ * Returns:
+ * {Integer} An OpenLayers Zoom level, translated from the passed in gZoom
+ * Returns null if null value is passed in.
+ */
+ getOLZoomFromMapObjectZoom: function(moZoom) {
+ var zoom = null;
+ if (moZoom != null) {
+ zoom = OpenLayers.Layer.FixedZoomLevels.prototype.getOLZoomFromMapObjectZoom.apply(this, [moZoom]);
+ zoom = 18 - zoom;
+ }
+ return zoom;
+ },
+
+ /**
+ * APIMethod: getMapObjectZoomFromOLZoom
+ *
+ * Parameters:
+ * olZoom - {Integer}
+ *
+ * Returns:
+ * {Integer} A MapObject level, translated from the passed in olZoom
+ * Returns null if null value is passed in
+ */
+ getMapObjectZoomFromOLZoom: function(olZoom) {
+ var zoom = null;
+ if (olZoom != null) {
+ zoom = OpenLayers.Layer.FixedZoomLevels.prototype.getMapObjectZoomFromOLZoom.apply(this, [olZoom]);
+ zoom = 18 - zoom;
+ }
+ return zoom;
+ },
+
+ /************************************
+ * *
+ * MapObject Interface Controls *
+ * *
+ ************************************/
+
+
+ // Get&Set Center, Zoom
+
+ /**
+ * APIMethod: setMapObjectCenter
+ * Set the mapObject to the specified center and zoom
+ *
+ * Parameters:
+ * center - {Object} MapObject LonLat format
+ * zoom - {int} MapObject zoom format
+ */
+ setMapObjectCenter: function(center, zoom) {
+ this.mapObject.drawZoomAndCenter(center, zoom);
+ },
+
+ /**
+ * APIMethod: getMapObjectCenter
+ *
+ * Returns:
+ * {Object} The mapObject's current center in Map Object format
+ */
+ getMapObjectCenter: function() {
+ return this.mapObject.getCenterLatLon();
+ },
+
+ /**
+ * APIMethod: dragPanMapObject
+ *
+ * Parameters:
+ * dX - {Integer}
+ * dY - {Integer}
+ */
+ dragPanMapObject: function(dX, dY) {
+ this.mapObject.moveByXY({
+ 'x': -dX,
+ 'y': dY
+ });
+ },
+
+ /**
+ * APIMethod: getMapObjectZoom
+ *
+ * Returns:
+ * {Integer} The mapObject's current zoom, in Map Object format
+ */
+ getMapObjectZoom: function() {
+ return this.mapObject.getZoomLevel();
+ },
+
+
+ // LonLat - Pixel Translation
+
+ /**
+ * APIMethod: getMapObjectLonLatFromMapObjectPixel
+ *
+ * Parameters:
+ * moPixel - {Object} MapObject Pixel format
+ *
+ * Returns:
+ * {Object} MapObject LonLat translated from MapObject Pixel
+ */
+ getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
+ return this.mapObject.convertXYLatLon(moPixel);
+ },
+
+ /**
+ * APIMethod: getMapObjectPixelFromMapObjectLonLat
+ *
+ * Parameters:
+ * moLonLat - {Object} MapObject LonLat format
+ *
+ * Returns:
+ * {Object} MapObject Pixel transtlated from MapObject LonLat
+ */
+ getMapObjectPixelFromMapObjectLonLat: function(moLonLat) {
+ return this.mapObject.convertLatLonXY(moLonLat);
+ },
+
+
+ /************************************
+ * *
+ * MapObject Primitives *
+ * *
+ ************************************/
+
+
+ // LonLat
+
+ /**
+ * APIMethod: getLongitudeFromMapObjectLonLat
+ *
+ * Parameters:
+ * moLonLat - {Object} MapObject LonLat format
+ *
+ * Returns:
+ * {Float} Longitude of the given MapObject LonLat
+ */
+ getLongitudeFromMapObjectLonLat: function(moLonLat) {
+ return this.sphericalMercator ?
+ this.forwardMercator(moLonLat.Lon, moLonLat.Lat).lon :
+ moLonLat.Lon;
+ },
+
+ /**
+ * APIMethod: getLatitudeFromMapObjectLonLat
+ *
+ * Parameters:
+ * moLonLat - {Object} MapObject LonLat format
+ *
+ * Returns:
+ * {Float} Latitude of the given MapObject LonLat
+ */
+ getLatitudeFromMapObjectLonLat: function(moLonLat) {
+ return this.sphericalMercator ?
+ this.forwardMercator(moLonLat.Lon, moLonLat.Lat).lat :
+ moLonLat.Lat;
+ },
+
+ /**
+ * APIMethod: getMapObjectLonLatFromLonLat
+ *
+ * Parameters:
+ * lon - {Float}
+ * lat - {Float}
+ *
+ * Returns:
+ * {Object} MapObject LonLat built from lon and lat params
+ */
+ getMapObjectLonLatFromLonLat: function(lon, lat) {
+ var yLatLong;
+ if(this.sphericalMercator) {
+ var lonlat = this.inverseMercator(lon, lat);
+ yLatLong = new YGeoPoint(lonlat.lat, lonlat.lon);
+ } else {
+ yLatLong = new YGeoPoint(lat, lon);
+ }
+ return yLatLong;
+ },
+
+ // Pixel
+
+ /**
+ * APIMethod: getXFromMapObjectPixel
+ *
+ * Parameters:
+ * moPixel - {Object} MapObject Pixel format
+ *
+ * Returns:
+ * {Integer} X value of the MapObject Pixel
+ */
+ getXFromMapObjectPixel: function(moPixel) {
+ return moPixel.x;
+ },
+
+ /**
+ * APIMethod: getYFromMapObjectPixel
+ *
+ * Parameters:
+ * moPixel - {Object} MapObject Pixel format
+ *
+ * Returns:
+ * {Integer} Y value of the MapObject Pixel
+ */
+ getYFromMapObjectPixel: function(moPixel) {
+ return moPixel.y;
+ },
+
+ /**
+ * APIMethod: getMapObjectPixelFromXY
+ *
+ * Parameters:
+ * x - {Integer}
+ * y - {Integer}
+ *
+ * Returns:
+ * {Object} MapObject Pixel from x and y parameters
+ */
+ getMapObjectPixelFromXY: function(x, y) {
+ return new YCoordPoint(x, y);
+ },
+
+ // Size
+
+ /**
+ * APIMethod: getMapObjectSizeFromOLSize
+ *
+ * Parameters:
+ * olSize - {<OpenLayers.Size>}
+ *
+ * Returns:
+ * {Object} MapObject Size from olSize parameter
+ */
+ getMapObjectSizeFromOLSize: function(olSize) {
+ return new YSize(olSize.w, olSize.h);
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.Yahoo"
+});
+/* ======================================================================
+ OpenLayers/Layer/MapServer.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.MapServer
+ * Instances of OpenLayers.Layer.MapServer are used to display
+ * data from a MapServer CGI instance.
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.MapServer = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+ /**
+ * Constant: DEFAULT_PARAMS
+ * {Object} Hashtable of default parameter key/value pairs
+ */
+ DEFAULT_PARAMS: {
+ mode: "map",
+ map_imagetype: "png"
+ },
+
+ /**
+ * Constructor: OpenLayers.Layer.MapServer
+ * Create a new MapServer layer object
+ *
+ * Parameters:
+ * name - {String} A name for the layer
+ * url - {String} Base url for the MapServer CGI
+ * (e.g. http://www2.dmsolutions.ca/cgi-bin/mapserv)
+ * params - {Object} An object with key/value pairs representing the
+ * GetMap query string parameters and parameter values.
+ * options - {Ojbect} Hashtable of extra options to tag onto the layer
+ */
+ initialize: function(name, url, params, options) {
+ var newArguments = [];
+ newArguments.push(name, url, params, options);
+ OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
+
+ this.params = OpenLayers.Util.applyDefaults(
+ this.params, this.DEFAULT_PARAMS
+ );
+
+ // unless explicitly set in options, if the layer is transparent,
+ // it will be an overlay
+ if (options == null || options.isBaseLayer == null) {
+ this.isBaseLayer = ((this.params.transparent != "true") &&
+ (this.params.transparent != true));
+ }
+ },
+
+ /**
+ * Method: clone
+ * Create a clone of this layer
+ *
+ * Returns:
+ * {<OpenLayers.Layer.MapServer>} An exact clone of this layer
+ */
+ clone: function (obj) {
+ if (obj == null) {
+ obj = new OpenLayers.Layer.MapServer(this.name,
+ this.url,
+ this.params,
+ this.getOptions());
+ }
+ //get all additions from superclasses
+ obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+ // copy/set any non-init, non-simple values here
+
+ return obj;
+ },
+
+ /**
+ * Method: addTile
+ * Creates a tile, initializes it, and adds it to the layer div.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * position - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+ */
+ addTile:function(bounds,position) {
+ return new OpenLayers.Tile.Image(this, position, bounds,
+ null, this.tileSize);
+ },
+
+ /**
+ * Method: getURL
+ * Return a query string for this layer
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox
+ * for the request
+ *
+ * Returns:
+ * {String} A string with the layer's url and parameters and also
+ * the passed-in bounds and appropriate tile size specified
+ * as parameters.
+ */
+ getURL: function (bounds) {
+ bounds = this.adjustBounds(bounds);
+ // Make a list, so that getFullRequestString uses literal ","
+ var extent = [bounds.left, bounds. bottom, bounds.right, bounds.top];
+
+ var imageSize = this.getImageSize();
+
+ // make lists, so that literal ','s are used
+ var url = this.getFullRequestString(
+ {mapext: extent,
+ imgext: extent,
+ map_size: [imageSize.w, imageSize.h],
+ imgx: imageSize.w / 2,
+ imgy: imageSize.h / 2,
+ imgxy: [imageSize.w, imageSize.h]
+ });
+
+ return url;
+ },
+
+ /**
+ * Method: getFullRequestString
+ * combine the layer's url with its params and these newParams.
+ *
+ * Parameter:
+ * newParams - {Object} New parameters that should be added to the
+ * request string.
+ * altUrl - {String} (optional) Replace the URL in the full request
+ * string with the provided URL.
+ *
+ * Returns:
+ * {String} A string with the layer's url and parameters embedded in it.
+ */
+ getFullRequestString:function(newParams, altUrl) {
+ // use layer's url unless altUrl passed in
+ var url = (altUrl == null) ? this.url : altUrl;
+
+ // create a new params hashtable with all the layer params and the
+ // new params together. then convert to string
+ var allParams = OpenLayers.Util.extend({}, this.params);
+ allParams = OpenLayers.Util.extend(allParams, newParams);
+ var paramsString = OpenLayers.Util.getParameterString(allParams);
+
+ // if url is not a string, it should be an array of strings,
+ // in which case we will deterministically select one of them in
+ // order to evenly distribute requests to different urls.
+ if (url instanceof Array) {
+ url = this.selectUrl(paramsString, url);
+ }
+
+ // ignore parameters that are already in the url search string
+ var urlParams = OpenLayers.Util.upperCaseObject(
+ OpenLayers.Util.getParameters(url));
+ for(var key in allParams) {
+ if(key.toUpperCase() in urlParams) {
+ delete allParams[key];
+ }
+ }
+ paramsString = OpenLayers.Util.getParameterString(allParams);
+
+ // requestString always starts with url
+ var requestString = url;
+
+ // MapServer needs '+' seperating things like bounds/height/width.
+ // Since typically this is URL encoded, we use a slight hack: we
+ // depend on the list-like functionality of getParameterString to
+ // leave ',' only in the case of list items (since otherwise it is
+ // encoded) then do a regular expression replace on the , characters
+ // to '+'
+ //
+ paramsString = paramsString.replace(/,/g, "+");
+
+ if (paramsString != "") {
+ var lastServerChar = url.charAt(url.length - 1);
+ if ((lastServerChar == "&") || (lastServerChar == "?")) {
+ requestString += paramsString;
+ } else {
+ if (url.indexOf('?') == -1) {
+ //serverPath has no ? -- add one
+ requestString += '?' + paramsString;
+ } else {
+ //serverPath contains ?, so must already have paramsString at the end
+ requestString += '&' + paramsString;
+ }
+ }
+ }
+ return requestString;
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.MapServer"
+});
+/* ======================================================================
+ OpenLayers/Renderer/VML.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Renderer/Elements.js
+ */
+
+/**
+ * Class: OpenLayers.Renderer.VML
+ * Render vector features in browsers with VML capability. Construct a new
+ * VML renderer with the <OpenLayers.Renderer.VML> constructor.
+ *
+ * Note that for all calculations in this class, we use (num | 0) to truncate a
+ * float value to an integer. This is done because it seems that VML doesn't
+ * support float values.
+ *
+ * Inherits from:
+ * - <OpenLayers.Renderer.Elements>
+ */
+OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
+
+ /**
+ * Property: xmlns
+ * {String} XML Namespace URN
+ */
+ xmlns: "urn:schemas-microsoft-com:vml",
+
+ /**
+ * Property: symbolCache
+ * {DOMElement} node holding symbols. This hash is keyed by symbol name,
+ * and each value is a hash with a "path" and an "extent" property.
+ */
+ symbolCache: {},
+
+ /**
+ * Property: offset
+ * {Object} Hash with "x" and "y" properties
+ */
+ offset: null,
+
+ /**
+ * Constructor: OpenLayers.Renderer.VML
+ * Create a new VML renderer.
+ *
+ * Parameters:
+ * containerID - {String} The id for the element that contains the renderer
+ */
+ initialize: function(containerID) {
+ if (!this.supported()) {
+ return;
+ }
+ if (!document.namespaces.olv) {
+ document.namespaces.add("olv", this.xmlns);
+ var style = document.createStyleSheet();
+ var shapes = ['shape','rect', 'oval', 'fill', 'stroke', 'imagedata', 'group','textbox'];
+ for (var i = 0, len = shapes.length; i < len; i++) {
+
+ style.addRule('olv\\:' + shapes[i], "behavior: url(#default#VML); " +
+ "position: absolute; display: inline-block;");
+ }
+ }
+
+ OpenLayers.Renderer.Elements.prototype.initialize.apply(this,
+ arguments);
+ },
+
+ /**
+ * APIMethod: destroy
+ * Deconstruct the renderer.
+ */
+ destroy: function() {
+ OpenLayers.Renderer.Elements.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * APIMethod: supported
+ * Determine whether a browser supports this renderer.
+ *
+ * Returns:
+ * {Boolean} The browser supports the VML renderer
+ */
+ supported: function() {
+ return !!(document.namespaces);
+ },
+
+ /**
+ * Method: setExtent
+ * Set the renderer's extent
+ *
+ * Parameters:
+ * extent - {<OpenLayers.Bounds>}
+ * resolutionChanged - {Boolean}
+ *
+ * Returns:
+ * {Boolean} true to notify the layer that the new extent does not exceed
+ * the coordinate range, and the features will not need to be redrawn.
+ */
+ setExtent: function(extent, resolutionChanged) {
+ OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,
+ arguments);
+ var resolution = this.getResolution();
+
+ var left = (extent.left/resolution) | 0;
+ var top = (extent.top/resolution - this.size.h) | 0;
+ if (resolutionChanged || !this.offset) {
+ this.offset = {x: left, y: top};
+ left = 0;
+ top = 0;
+ } else {
+ left = left - this.offset.x;
+ top = top - this.offset.y;
+ }
+
+
+ var org = left + " " + top;
+ this.root.coordorigin = org;
+ var roots = [this.root, this.vectorRoot, this.textRoot];
+ var root;
+ for(var i=0, len=roots.length; i<len; ++i) {
+ root = roots[i];
+
+ var size = this.size.w + " " + this.size.h;
+ root.coordsize = size;
+
+ }
+ // flip the VML display Y axis upside down so it
+ // matches the display Y axis of the map
+ this.root.style.flip = "y";
+
+ return true;
+ },
+
+
+ /**
+ * Method: setSize
+ * Set the size of the drawing surface
+ *
+ * Parameters:
+ * size - {<OpenLayers.Size>} the size of the drawing surface
+ */
+ setSize: function(size) {
+ OpenLayers.Renderer.prototype.setSize.apply(this, arguments);
+
+ // setting width and height on all roots to avoid flicker which we
+ // would get with 100% width and height on child roots
+ var roots = [
+ this.rendererRoot,
+ this.root,
+ this.vectorRoot,
+ this.textRoot
+ ];
+ var w = this.size.w + "px";
+ var h = this.size.h + "px";
+ var root;
+ for(var i=0, len=roots.length; i<len; ++i) {
+ root = roots[i];
+ root.style.width = w;
+ root.style.height = h;
+ }
+ },
+
+ /**
+ * Method: getNodeType
+ * Get the node type for a geometry and style
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ * style - {Object}
+ *
+ * Returns:
+ * {String} The corresponding node type for the specified geometry
+ */
+ getNodeType: function(geometry, style) {
+ var nodeType = null;
+ switch (geometry.CLASS_NAME) {
+ case "OpenLayers.Geometry.Point":
+ if (style.externalGraphic) {
+ nodeType = "olv:rect";
+ } else if (this.isComplexSymbol(style.graphicName)) {
+ nodeType = "olv:shape";
+ } else {
+ nodeType = "olv:oval";
+ }
+ break;
+ case "OpenLayers.Geometry.Rectangle":
+ nodeType = "olv:rect";
+ break;
+ case "OpenLayers.Geometry.LineString":
+ case "OpenLayers.Geometry.LinearRing":
+ case "OpenLayers.Geometry.Polygon":
+ case "OpenLayers.Geometry.Curve":
+ case "OpenLayers.Geometry.Surface":
+ nodeType = "olv:shape";
+ break;
+ default:
+ break;
+ }
+ return nodeType;
+ },
+
+ /**
+ * Method: setStyle
+ * Use to set all the style attributes to a VML node.
+ *
+ * Parameters:
+ * node - {DOMElement} An VML element to decorate
+ * style - {Object}
+ * options - {Object} Currently supported options include
+ * 'isFilled' {Boolean} and
+ * 'isStroked' {Boolean}
+ * geometry - {<OpenLayers.Geometry>}
+ */
+ setStyle: function(node, style, options, geometry) {
+ style = style || node._style;
+ options = options || node._options;
+ var fillColor = style.fillColor;
+
+ if (node._geometryClass === "OpenLayers.Geometry.Point") {
+ if (style.externalGraphic) {
+ options.isFilled = true;
+ if (style.graphicTitle) {
+ node.title=style.graphicTitle;
+ }
+ var width = style.graphicWidth || style.graphicHeight;
+ var height = style.graphicHeight || style.graphicWidth;
+ width = width ? width : style.pointRadius*2;
+ height = height ? height : style.pointRadius*2;
+
+ var resolution = this.getResolution();
+ var xOffset = (style.graphicXOffset != undefined) ?
+ style.graphicXOffset : -(0.5 * width);
+ var yOffset = (style.graphicYOffset != undefined) ?
+ style.graphicYOffset : -(0.5 * height);
+
+ node.style.left = (((geometry.x/resolution - this.offset.x)+xOffset) | 0) + "px";
+ node.style.top = (((geometry.y/resolution - this.offset.y)-(yOffset+height)) | 0) + "px";
+ node.style.width = width + "px";
+ node.style.height = height + "px";
+ node.style.flip = "y";
+
+ // modify fillColor and options for stroke styling below
+ fillColor = "none";
+ options.isStroked = false;
+ } else if (this.isComplexSymbol(style.graphicName)) {
+ var cache = this.importSymbol(style.graphicName);
+ node.path = cache.path;
+ node.coordorigin = cache.left + "," + cache.bottom;
+ var size = cache.size;
+ node.coordsize = size + "," + size;
+ this.drawCircle(node, geometry, style.pointRadius);
+ node.style.flip = "y";
+ } else {
+ this.drawCircle(node, geometry, style.pointRadius);
+ }
+ }
+
+ // fill
+ if (options.isFilled) {
+ node.fillcolor = fillColor;
+ } else {
+ node.filled = "false";
+ }
+ var fills = node.getElementsByTagName("fill");
+ var fill = (fills.length == 0) ? null : fills[0];
+ if (!options.isFilled) {
+ if (fill) {
+ node.removeChild(fill);
+ }
+ } else {
+ if (!fill) {
+ fill = this.createNode('olv:fill', node.id + "_fill");
+ }
+ fill.opacity = style.fillOpacity;
+
+ if (node._geometryClass === "OpenLayers.Geometry.Point" &&
+ style.externalGraphic) {
+
+ // override fillOpacity
+ if (style.graphicOpacity) {
+ fill.opacity = style.graphicOpacity;
+ }
+
+ fill.src = style.externalGraphic;
+ fill.type = "frame";
+
+ if (!(style.graphicWidth && style.graphicHeight)) {
+ fill.aspect = "atmost";
+ }
+ }
+ if (fill.parentNode != node) {
+ node.appendChild(fill);
+ }
+ }
+
+ // additional rendering for rotated graphics or symbols
+ var rotation = style.rotation;
+ if ((rotation !== undefined || node._rotation !== undefined)) {
+ node._rotation = rotation;
+ if (style.externalGraphic) {
+ this.graphicRotate(node, xOffset, yOffset, style);
+ // make the fill fully transparent, because we now have
+ // the graphic as imagedata element. We cannot just remove
+ // the fill, because this is part of the hack described
+ // in graphicRotate
+ fill.opacity = 0;
+ } else if(node._geometryClass === "OpenLayers.Geometry.Point") {
+ node.style.rotation = rotation || 0;
+ }
+ }
+
+ // stroke
+ var strokes = node.getElementsByTagName("stroke");
+ var stroke = (strokes.length == 0) ? null : strokes[0];
+ if (!options.isStroked) {
+ node.stroked = false;
+ if (stroke) {
+ stroke.on = false;
+ }
+ } else {
+ if (!stroke) {
+ stroke = this.createNode('olv:stroke', node.id + "_stroke");
+ node.appendChild(stroke);
+ }
+ stroke.on = true;
+ stroke.color = style.strokeColor;
+ stroke.weight = style.strokeWidth + "px";
+ stroke.opacity = style.strokeOpacity;
+ stroke.endcap = style.strokeLinecap == 'butt' ? 'flat' :
+ (style.strokeLinecap || 'round');
+ if (style.strokeDashstyle) {
+ stroke.dashstyle = this.dashStyle(style);
+ }
+ }
+
+ if (style.cursor != "inherit" && style.cursor != null) {
+ node.style.cursor = style.cursor;
+ }
+ return node;
+ },
+
+ /**
+ * Method: graphicRotate
+ * If a point is to be styled with externalGraphic and rotation, VML fills
+ * cannot be used to display the graphic, because rotation of graphic
+ * fills is not supported by the VML implementation of Internet Explorer.
+ * This method creates a olv:imagedata element inside the VML node,
+ * DXImageTransform.Matrix and BasicImage filters for rotation and
+ * opacity, and a 3-step hack to remove rendering artefacts from the
+ * graphic and preserve the ability of graphics to trigger events.
+ * Finally, OpenLayers methods are used to determine the correct
+ * insertion point of the rotated image, because DXImageTransform.Matrix
+ * does the rotation without the ability to specify a rotation center
+ * point.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * xOffset - {Number} rotation center relative to image, x coordinate
+ * yOffset - {Number} rotation center relative to image, y coordinate
+ * style - {Object}
+ */
+ graphicRotate: function(node, xOffset, yOffset, style) {
+ var style = style || node._style;
+ var rotation = style.rotation || 0;
+
+ var aspectRatio, size;
+ if (!(style.graphicWidth && style.graphicHeight)) {
+ // load the image to determine its size
+ var img = new Image();
+ img.onreadystatechange = OpenLayers.Function.bind(function() {
+ if(img.readyState == "complete" ||
+ img.readyState == "interactive") {
+ aspectRatio = img.width / img.height;
+ size = Math.max(style.pointRadius * 2,
+ style.graphicWidth || 0,
+ style.graphicHeight || 0);
+ xOffset = xOffset * aspectRatio;
+ style.graphicWidth = size * aspectRatio;
+ style.graphicHeight = size;
+ this.graphicRotate(node, xOffset, yOffset, style);
+ }
+ }, this);
+ img.src = style.externalGraphic;
+
+ // will be called again by the onreadystate handler
+ return;
+ } else {
+ size = Math.max(style.graphicWidth, style.graphicHeight);
+ aspectRatio = style.graphicWidth / style.graphicHeight;
+ }
+
+ var width = Math.round(style.graphicWidth || size * aspectRatio);
+ var height = Math.round(style.graphicHeight || size);
+ node.style.width = width + "px";
+ node.style.height = height + "px";
+
+ // Three steps are required to remove artefacts for images with
+ // transparent backgrounds (resulting from using DXImageTransform
+ // filters on svg objects), while preserving awareness for browser
+ // events on images:
+ // - Use the fill as usual (like for unrotated images) to handle
+ // events
+ // - specify an imagedata element with the same src as the fill
+ // - style the imagedata element with an AlphaImageLoader filter
+ // with empty src
+ var image = document.getElementById(node.id + "_image");
+ if (!image) {
+ image = this.createNode("olv:imagedata", node.id + "_image");
+ node.appendChild(image);
+ }
+ image.style.width = width + "px";
+ image.style.height = height + "px";
+ image.src = style.externalGraphic;
+ image.style.filter =
+ "progid:DXImageTransform.Microsoft.AlphaImageLoader(" +
+ "src='', sizingMethod='scale')";
+
+ var rot = rotation * Math.PI / 180;
+ var sintheta = Math.sin(rot);
+ var costheta = Math.cos(rot);
+
+ // do the rotation on the image
+ var filter =
+ "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta +
+ ",M12=" + (-sintheta) + ",M21=" + sintheta + ",M22=" + costheta +
+ ",SizingMethod='auto expand')\n";
+
+ // set the opacity (needed for the imagedata)
+ var opacity = style.graphicOpacity || style.fillOpacity;
+ if (opacity && opacity != 1) {
+ filter +=
+ "progid:DXImageTransform.Microsoft.BasicImage(opacity=" +
+ opacity+")\n";
+ }
+ node.style.filter = filter;
+
+ // do the rotation again on a box, so we know the insertion point
+ var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset);
+ var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry();
+ imgBox.rotate(style.rotation, centerPoint);
+ var imgBounds = imgBox.getBounds();
+
+ node.style.left = Math.round(
+ parseInt(node.style.left) + imgBounds.left) + "px";
+ node.style.top = Math.round(
+ parseInt(node.style.top) - imgBounds.bottom) + "px";
+ },
+
+ /**
+ * Method: postDraw
+ * Does some node postprocessing to work around browser issues:
+ * - Some versions of Internet Explorer seem to be unable to set fillcolor
+ * and strokecolor to "none" correctly before the fill node is appended
+ * to a visible vml node. This method takes care of that and sets
+ * fillcolor and strokecolor again if needed.
+ * - In some cases, a node won't become visible after being drawn. Setting
+ * style.visibility to "visible" works around that.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ */
+ postDraw: function(node) {
+ node.style.visibility = "visible";
+ var fillColor = node._style.fillColor;
+ var strokeColor = node._style.strokeColor;
+ if (fillColor == "none" &&
+ node.fillcolor != fillColor) {
+ node.fillcolor = fillColor;
+ }
+ if (strokeColor == "none" &&
+ node.strokecolor != strokeColor) {
+ node.strokecolor = strokeColor;
+ }
+ },
+
+
+ /**
+ * Method: setNodeDimension
+ * Get the geometry's bounds, convert it to our vml coordinate system,
+ * then set the node's position, size, and local coordinate system.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ */
+ setNodeDimension: function(node, geometry) {
+
+ var bbox = geometry.getBounds();
+ if(bbox) {
+ var resolution = this.getResolution();
+
+ var scaledBox =
+ new OpenLayers.Bounds((bbox.left/resolution - this.offset.x) | 0,
+ (bbox.bottom/resolution - this.offset.y) | 0,
+ (bbox.right/resolution - this.offset.x) | 0,
+ (bbox.top/resolution - this.offset.y) | 0);
+
+ // Set the internal coordinate system to draw the path
+ node.style.left = scaledBox.left + "px";
+ node.style.top = scaledBox.top + "px";
+ node.style.width = scaledBox.getWidth() + "px";
+ node.style.height = scaledBox.getHeight() + "px";
+
+ node.coordorigin = scaledBox.left + " " + scaledBox.top;
+ node.coordsize = scaledBox.getWidth()+ " " + scaledBox.getHeight();
+ }
+ },
+
+ /**
+ * Method: dashStyle
+ *
+ * Parameters:
+ * style - {Object}
+ *
+ * Returns:
+ * {String} A VML compliant 'stroke-dasharray' value
+ */
+ dashStyle: function(style) {
+ var dash = style.strokeDashstyle;
+ switch (dash) {
+ case 'solid':
+ case 'dot':
+ case 'dash':
+ case 'dashdot':
+ case 'longdash':
+ case 'longdashdot':
+ return dash;
+ default:
+ // very basic guessing of dash style patterns
+ var parts = dash.split(/[ ,]/);
+ if (parts.length == 2) {
+ if (1*parts[0] >= 2*parts[1]) {
+ return "longdash";
+ }
+ return (parts[0] == 1 || parts[1] == 1) ? "dot" : "dash";
+ } else if (parts.length == 4) {
+ return (1*parts[0] >= 2*parts[1]) ? "longdashdot" :
+ "dashdot";
+ }
+ return "solid";
+ }
+ },
+
+ /**
+ * Method: createNode
+ * Create a new node
+ *
+ * Parameters:
+ * type - {String} Kind of node to draw
+ * id - {String} Id for node
+ *
+ * Returns:
+ * {DOMElement} A new node of the given type and id
+ */
+ createNode: function(type, id) {
+ var node = document.createElement(type);
+ if (id) {
+ node.id = id;
+ }
+
+ // IE hack to make elements unselectable, to prevent 'blue flash'
+ // while dragging vectors; #1410
+ node.unselectable = 'on';
+ node.onselectstart = OpenLayers.Function.False;
+
+ return node;
+ },
+
+ /**
+ * Method: nodeTypeCompare
+ * Determine whether a node is of a given type
+ *
+ * Parameters:
+ * node - {DOMElement} An VML element
+ * type - {String} Kind of node
+ *
+ * Returns:
+ * {Boolean} Whether or not the specified node is of the specified type
+ */
+ nodeTypeCompare: function(node, type) {
+
+ //split type
+ var subType = type;
+ var splitIndex = subType.indexOf(":");
+ if (splitIndex != -1) {
+ subType = subType.substr(splitIndex+1);
+ }
+
+ //split nodeName
+ var nodeName = node.nodeName;
+ splitIndex = nodeName.indexOf(":");
+ if (splitIndex != -1) {
+ nodeName = nodeName.substr(splitIndex+1);
+ }
+
+ return (subType == nodeName);
+ },
+
+ /**
+ * Method: createRenderRoot
+ * Create the renderer root
+ *
+ * Returns:
+ * {DOMElement} The specific render engine's root element
+ */
+ createRenderRoot: function() {
+ return this.nodeFactory(this.container.id + "_vmlRoot", "div");
+ },
+
+ /**
+ * Method: createRoot
+ * Create the main root element
+ *
+ * Parameters:
+ * suffix - {String} suffix to append to the id
+ *
+ * Returns:
+ * {DOMElement}
+ */
+ createRoot: function(suffix) {
+ return this.nodeFactory(this.container.id + suffix, "olv:group");
+ },
+
+ /**************************************
+ * *
+ * GEOMETRY DRAWING FUNCTIONS *
+ * *
+ **************************************/
+
+ /**
+ * Method: drawPoint
+ * Render a point
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement} or false if the point could not be drawn
+ */
+ drawPoint: function(node, geometry) {
+ return this.drawCircle(node, geometry, 1);
+ },
+
+ /**
+ * Method: drawCircle
+ * Render a circle.
+ * Size and Center a circle given geometry (x,y center) and radius
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ * radius - {float}
+ *
+ * Returns:
+ * {DOMElement} or false if the circle could not ne drawn
+ */
+ drawCircle: function(node, geometry, radius) {
+ if(!isNaN(geometry.x)&& !isNaN(geometry.y)) {
+ var resolution = this.getResolution();
+
+ node.style.left = (((geometry.x /resolution - this.offset.x) | 0) - radius) + "px";
+ node.style.top = (((geometry.y /resolution - this.offset.y) | 0) - radius) + "px";
+
+ var diameter = radius * 2;
+
+ node.style.width = diameter + "px";
+ node.style.height = diameter + "px";
+ return node;
+ }
+ return false;
+ },
+
+
+ /**
+ * Method: drawLineString
+ * Render a linestring.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement}
+ */
+ drawLineString: function(node, geometry) {
+ return this.drawLine(node, geometry, false);
+ },
+
+ /**
+ * Method: drawLinearRing
+ * Render a linearring
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement}
+ */
+ drawLinearRing: function(node, geometry) {
+ return this.drawLine(node, geometry, true);
+ },
+
+ /**
+ * Method: DrawLine
+ * Render a line.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ * closeLine - {Boolean} Close the line? (make it a ring?)
+ *
+ * Returns:
+ * {DOMElement}
+ */
+ drawLine: function(node, geometry, closeLine) {
+
+ this.setNodeDimension(node, geometry);
+
+ var resolution = this.getResolution();
+ var numComponents = geometry.components.length;
+ var parts = new Array(numComponents);
+
+ var comp, x, y;
+ for (var i = 0; i < numComponents; i++) {
+ comp = geometry.components[i];
+ x = (comp.x/resolution - this.offset.x) | 0;
+ y = (comp.y/resolution - this.offset.y) | 0;
+ parts[i] = " " + x + "," + y + " l ";
+ }
+ var end = (closeLine) ? " x e" : " e";
+ node.path = "m" + parts.join("") + end;
+ return node;
+ },
+
+ /**
+ * Method: drawPolygon
+ * Render a polygon
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement}
+ */
+ drawPolygon: function(node, geometry) {
+ this.setNodeDimension(node, geometry);
+
+ var resolution = this.getResolution();
+
+ var path = [];
+ var j, jj, points, area, first, second, i, ii, comp, pathComp, x, y;
+ for (j=0, jj=geometry.components.length; j<jj; j++) {
+ path.push("m");
+ points = geometry.components[j].components;
+ // we only close paths of interior rings with area
+ area = (j === 0);
+ first = null;
+ second = null;
+ for (i=0, ii=points.length; i<ii; i++) {
+ comp = points[i];
+ x = (comp.x / resolution - this.offset.x) | 0;
+ y = (comp.y / resolution - this.offset.y) | 0;
+ pathComp = " " + x + "," + y;
+ path.push(pathComp)
+ if (i==0) {
+ path.push(" l");
+ }
+ if (!area) {
+ // IE improperly renders sub-paths that have no area.
+ // Instead of checking the area of every ring, we confirm
+ // the ring has at least three distinct points. This does
+ // not catch all non-zero area cases, but it greatly improves
+ // interior ring digitizing and is a minor performance hit
+ // when rendering rings with many points.
+ if (!first) {
+ first = pathComp;
+ } else if (first != pathComp) {
+ if (!second) {
+ second = pathComp;
+ } else if (second != pathComp) {
+ // stop looking
+ area = true;
+ }
+ }
+ }
+ }
+ path.push(area ? " x " : " ");
+ }
+ path.push("e");
+ node.path = path.join("");
+ return node;
+ },
+
+ /**
+ * Method: drawRectangle
+ * Render a rectangle
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement}
+ */
+ drawRectangle: function(node, geometry) {
+ var resolution = this.getResolution();
+
+ node.style.left = ((geometry.x/resolution - this.offset.x) | 0) + "px";
+ node.style.top = ((geometry.y/resolution - this.offset.y) | 0) + "px";
+ node.style.width = ((geometry.width/resolution) | 0) + "px";
+ node.style.height = ((geometry.height/resolution) | 0) + "px";
+
+ return node;
+ },
+
+ /**
+ * Method: drawText
+ * This method is only called by the renderer itself.
+ *
+ * Parameters:
+ * featureId - {String}
+ * style -
+ * location - {<OpenLayers.Geometry.Point>}
+ */
+ drawText: function(featureId, style, location) {
+ var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "olv:rect");
+ var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox");
+
+ var resolution = this.getResolution();
+ label.style.left = ((location.x/resolution - this.offset.x) | 0) + "px";
+ label.style.top = ((location.y/resolution - this.offset.y) | 0) + "px";
+ label.style.flip = "y";
+
+ textbox.innerText = style.label;
+
+ if (style.fontColor) {
+ textbox.style.color = style.fontColor;
+ }
+ if (style.fontOpacity) {
+ textbox.style.filter = 'alpha(opacity=' + (style.fontOpacity * 100) + ')';
+ }
+ if (style.fontFamily) {
+ textbox.style.fontFamily = style.fontFamily;
+ }
+ if (style.fontSize) {
+ textbox.style.fontSize = style.fontSize;
+ }
+ if (style.fontWeight) {
+ textbox.style.fontWeight = style.fontWeight;
+ }
+ if(style.labelSelect === true) {
+ label._featureId = featureId;
+ textbox._featureId = featureId;
+ textbox._geometry = location;
+ textbox._geometryClass = location.CLASS_NAME;
+ }
+ textbox.style.whiteSpace = "nowrap";
+ // fun with IE: IE7 in standards compliant mode does not display any
+ // text with a left inset of 0. So we set this to 1px and subtract one
+ // pixel later when we set label.style.left
+ textbox.inset = "1px,0px,0px,0px";
+
+ if(!label.parentNode) {
+ label.appendChild(textbox);
+ this.textRoot.appendChild(label);
+ }
+
+ var align = style.labelAlign || "cm";
+ if (align.length == 1) {
+ align += "m";
+ }
+ var xshift = textbox.clientWidth *
+ (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0,1)]);
+ var yshift = textbox.clientHeight *
+ (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1,1)]);
+ label.style.left = parseInt(label.style.left)-xshift-1+"px";
+ label.style.top = parseInt(label.style.top)+yshift+"px";
+
+ },
+
+ /**
+ * Method: drawSurface
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement}
+ */
+ drawSurface: function(node, geometry) {
+
+ this.setNodeDimension(node, geometry);
+
+ var resolution = this.getResolution();
+
+ var path = [];
+ var comp, x, y;
+ for (var i=0, len=geometry.components.length; i<len; i++) {
+ comp = geometry.components[i];
+ x = (comp.x / resolution - this.offset.x) | 0;
+ y = (comp.y / resolution - this.offset.y) | 0;
+ if ((i%3)==0 && (i/3)==0) {
+ path.push("m");
+ } else if ((i%3)==1) {
+ path.push(" c");
+ }
+ path.push(" " + x + "," + y);
+ }
+ path.push(" x e");
+
+ node.path = path.join("");
+ return node;
+ },
+
+ /**
+ * Method: moveRoot
+ * moves this renderer's root to a different renderer.
+ *
+ * Parameters:
+ * renderer - {<OpenLayers.Renderer>} target renderer for the moved root
+ * root - {DOMElement} optional root node. To be used when this renderer
+ * holds roots from multiple layers to tell this method which one to
+ * detach
+ *
+ * Returns:
+ * {Boolean} true if successful, false otherwise
+ */
+ moveRoot: function(renderer) {
+ var layer = this.map.getLayer(renderer.container.id);
+ if(layer instanceof OpenLayers.Layer.Vector.RootContainer) {
+ layer = this.map.getLayer(this.container.id);
+ }
+ layer && layer.renderer.clear();
+ OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments);
+ layer && layer.redraw();
+ },
+
+ /**
+ * Method: importSymbol
+ * add a new symbol definition from the rendererer's symbol hash
+ *
+ * Parameters:
+ * graphicName - {String} name of the symbol to import
+ *
+ * Returns:
+ * {Object} - hash of {DOMElement} "symbol" and {Number} "size"
+ */
+ importSymbol: function (graphicName) {
+ var id = this.container.id + "-" + graphicName;
+
+ // check if symbol already exists in the cache
+ var cache = this.symbolCache[id];
+ if (cache) {
+ return cache;
+ }
+
+ var symbol = OpenLayers.Renderer.symbol[graphicName];
+ if (!symbol) {
+ throw new Error(graphicName + ' is not a valid symbol name');
+ }
+
+ var symbolExtent = new OpenLayers.Bounds(
+ Number.MAX_VALUE, Number.MAX_VALUE, 0, 0);
+
+ var pathitems = ["m"];
+ for (var i=0; i<symbol.length; i=i+2) {
+ var x = symbol[i];
+ var y = symbol[i+1];
+ symbolExtent.left = Math.min(symbolExtent.left, x);
+ symbolExtent.bottom = Math.min(symbolExtent.bottom, y);
+ symbolExtent.right = Math.max(symbolExtent.right, x);
+ symbolExtent.top = Math.max(symbolExtent.top, y);
+
+ pathitems.push(x);
+ pathitems.push(y);
+ if (i == 0) {
+ pathitems.push("l");
+ }
+ }
+ pathitems.push("x e");
+ var path = pathitems.join(" ");
+
+ var diff = (symbolExtent.getWidth() - symbolExtent.getHeight()) / 2;
+ if(diff > 0) {
+ symbolExtent.bottom = symbolExtent.bottom - diff;
+ symbolExtent.top = symbolExtent.top + diff;
+ } else {
+ symbolExtent.left = symbolExtent.left + diff;
+ symbolExtent.right = symbolExtent.right - diff;
+ }
+
+ cache = {
+ path: path,
+ size: symbolExtent.getWidth(), // equals getHeight() now
+ left: symbolExtent.left,
+ bottom: symbolExtent.bottom
+ };
+ this.symbolCache[id] = cache;
+
+ return cache;
+ },
+
+ CLASS_NAME: "OpenLayers.Renderer.VML"
+});
+
+/**
+ * Constant: OpenLayers.Renderer.VML.LABEL_SHIFT
+ * {Object}
+ */
+OpenLayers.Renderer.VML.LABEL_SHIFT = {
+ "l": 0,
+ "c": .5,
+ "r": 1,
+ "t": 0,
+ "m": .5,
+ "b": 1
+};
+/* ======================================================================
+ OpenLayers/Protocol/WFS/v1_0_0.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Protocol/WFS/v1.js
+ * @requires OpenLayers/Format/WFST/v1_0_0.js
+ */
+
+/**
+ * Class: OpenLayers.Protocol.WFS.v1_0_0
+ * A WFS v1.0.0 protocol for vector layers. Create a new instance with the
+ * <OpenLayers.Protocol.WFS.v1_0_0> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Protocol.WFS.v1>
+ */
+OpenLayers.Protocol.WFS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, {
+
+ /**
+ * Property: version
+ * {String} WFS version number.
+ */
+ version: "1.0.0",
+
+ /**
+ * Constructor: OpenLayers.Protocol.WFS.v1_0_0
+ * A class for giving layers WFS v1.0.0 protocol.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ *
+ * Valid options properties:
+ * featureType - {String} Local (without prefix) feature typeName (required).
+ * featureNS - {String} Feature namespace (optional).
+ * featurePrefix - {String} Feature namespace alias (optional - only used
+ * if featureNS is provided). Default is 'feature'.
+ * geometryName - {String} Name of geometry attribute. Default is 'the_geom'.
+ */
+
+ CLASS_NAME: "OpenLayers.Protocol.WFS.v1_0_0"
+});
+/* ======================================================================
+ OpenLayers/Handler/RegularPolygon.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Handler/Drag.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.RegularPolygon
+ * Handler to draw a regular polygon on the map. Polygon is displayed on mouse
+ * down, moves or is modified on mouse move, and is finished on mouse up.
+ * The handler triggers callbacks for 'done' and 'cancel'. Create a new
+ * instance with the <OpenLayers.Handler.RegularPolygon> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.RegularPolygon = OpenLayers.Class(OpenLayers.Handler.Drag, {
+
+ /**
+ * APIProperty: sides
+ * {Integer} Number of sides for the regular polygon. Needs to be greater
+ * than 2. Defaults to 4.
+ */
+ sides: 4,
+
+ /**
+ * APIProperty: radius
+ * {Float} Optional radius in map units of the regular polygon. If this is
+ * set to some non-zero value, a polygon with a fixed radius will be
+ * drawn and dragged with mose movements. If this property is not
+ * set, dragging changes the radius of the polygon. Set to null by
+ * default.
+ */
+ radius: null,
+
+ /**
+ * APIProperty: snapAngle
+ * {Float} If set to a non-zero value, the handler will snap the polygon
+ * rotation to multiples of the snapAngle. Value is an angle measured
+ * in degrees counterclockwise from the positive x-axis.
+ */
+ snapAngle: null,
+
+ /**
+ * APIProperty: snapToggle
+ * {String} If set, snapToggle is checked on mouse events and will set
+ * the snap mode to the opposite of what it currently is. To disallow
+ * toggling between snap and non-snap mode, set freehandToggle to
+ * null. Acceptable toggle values are 'shiftKey', 'ctrlKey', and
+ * 'altKey'. Snap mode is only possible if this.snapAngle is set to a
+ * non-zero value.
+ */
+ snapToggle: 'shiftKey',
+
+ /**
+ * Property: layerOptions
+ * {Object} Any optional properties to be set on the sketch layer.
+ */
+ layerOptions: null,
+
+ /**
+ * APIProperty: persist
+ * {Boolean} Leave the feature rendered until clear is called. Default
+ * is false. If set to true, the feature remains rendered until
+ * clear is called, typically by deactivating the handler or starting
+ * another drawing.
+ */
+ persist: false,
+
+ /**
+ * APIProperty: irregular
+ * {Boolean} Draw an irregular polygon instead of a regular polygon.
+ * Default is false. If true, the initial mouse down will represent
+ * one corner of the polygon bounds and with each mouse movement, the
+ * polygon will be stretched so the opposite corner of its bounds
+ * follows the mouse position. This property takes precedence over
+ * the radius property. If set to true, the radius property will
+ * be ignored.
+ */
+ irregular: false,
+
+ /**
+ * Property: angle
+ * {Float} The angle from the origin (mouse down) to the current mouse
+ * position, in radians. This is measured counterclockwise from the
+ * positive x-axis.
+ */
+ angle: null,
+
+ /**
+ * Property: fixedRadius
+ * {Boolean} The polygon has a fixed radius. True if a radius is set before
+ * drawing begins. False otherwise.
+ */
+ fixedRadius: false,
+
+ /**
+ * Property: feature
+ * {<OpenLayers.Feature.Vector>} The currently drawn polygon feature
+ */
+ feature: null,
+
+ /**
+ * Property: layer
+ * {<OpenLayers.Layer.Vector>} The temporary drawing layer
+ */
+ layer: null,
+
+ /**
+ * Property: origin
+ * {<OpenLayers.Geometry.Point>} Location of the first mouse down
+ */
+ origin: null,
+
+ /**
+ * Constructor: OpenLayers.Handler.RegularPolygon
+ * Create a new regular polygon handler.
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>} The control that owns this handler
+ * callbacks - {Object} An object with a properties whose values are
+ * functions. Various callbacks described below.
+ * options - {Object} An object with properties to be set on the handler.
+ * If the options.sides property is not specified, the number of sides
+ * will default to 4.
+ *
+ * Named callbacks:
+ * create - Called when a sketch is first created. Callback called with
+ * the creation point geometry and sketch feature.
+ * done - Called when the sketch drawing is finished. The callback will
+ * recieve a single argument, the sketch geometry.
+ * cancel - Called when the handler is deactivated while drawing. The
+ * cancel callback will receive a geometry.
+ */
+ initialize: function(control, callbacks, options) {
+ if(!(options && options.layerOptions && options.layerOptions.styleMap)) {
+ this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {});
+ }
+
+ OpenLayers.Handler.prototype.initialize.apply(this,
+ [control, callbacks, options]);
+ this.options = (options) ? options : {};
+ },
+
+ /**
+ * APIMethod: setOptions
+ *
+ * Parameters:
+ * newOptions - {Object}
+ */
+ setOptions: function (newOptions) {
+ OpenLayers.Util.extend(this.options, newOptions);
+ OpenLayers.Util.extend(this, newOptions);
+ },
+
+ /**
+ * APIMethod: activate
+ * Turn on the handler.
+ *
+ * Return:
+ * {Boolean} The handler was successfully activated
+ */
+ activate: function() {
+ var activated = false;
+ if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+ // create temporary vector layer for rendering geometry sketch
+ var options = OpenLayers.Util.extend({
+ displayInLayerSwitcher: false,
+ // indicate that the temp vector layer will never be out of range
+ // without this, resolution properties must be specified at the
+ // map-level for this temporary layer to init its resolutions
+ // correctly
+ calculateInRange: OpenLayers.Function.True
+ }, this.layerOptions);
+ this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options);
+ this.map.addLayer(this.layer);
+ activated = true;
+ }
+ return activated;
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Turn off the handler.
+ *
+ * Return:
+ * {Boolean} The handler was successfully deactivated
+ */
+ deactivate: function() {
+ var deactivated = false;
+ if(OpenLayers.Handler.Drag.prototype.deactivate.apply(this, arguments)) {
+ // call the cancel callback if mid-drawing
+ if(this.dragging) {
+ this.cancel();
+ }
+ // If a layer's map property is set to null, it means that that
+ // layer isn't added to the map. Since we ourself added the layer
+ // to the map in activate(), we can assume that if this.layer.map
+ // is null it means that the layer has been destroyed (as a result
+ // of map.destroy() for example.
+ if (this.layer.map != null) {
+ this.layer.destroy(false);
+ if (this.feature) {
+ this.feature.destroy();
+ }
+ }
+ this.layer = null;
+ this.feature = null;
+ deactivated = true;
+ }
+ return deactivated;
+ },
+
+ /**
+ * Method: down
+ * Start drawing a new feature
+ *
+ * Parameters:
+ * evt - {Event} The drag start event
+ */
+ down: function(evt) {
+ this.fixedRadius = !!(this.radius);
+ var maploc = this.map.getLonLatFromPixel(evt.xy);
+ this.origin = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat);
+ // create the new polygon
+ if(!this.fixedRadius || this.irregular) {
+ // smallest radius should not be less one pixel in map units
+ // VML doesn't behave well with smaller
+ this.radius = this.map.getResolution();
+ }
+ if(this.persist) {
+ this.clear();
+ }
+ this.feature = new OpenLayers.Feature.Vector();
+ this.createGeometry();
+ this.callback("create", [this.origin, this.feature]);
+ this.layer.addFeatures([this.feature], {silent: true});
+ this.layer.drawFeature(this.feature, this.style);
+ },
+
+ /**
+ * Method: move
+ * Respond to drag move events
+ *
+ * Parameters:
+ * evt - {Evt} The move event
+ */
+ move: function(evt) {
+ var maploc = this.map.getLonLatFromPixel(evt.xy);
+ var point = new OpenLayers.Geometry.Point(maploc.lon, maploc.lat);
+ if(this.irregular) {
+ var ry = Math.sqrt(2) * Math.abs(point.y - this.origin.y) / 2;
+ this.radius = Math.max(this.map.getResolution() / 2, ry);
+ } else if(this.fixedRadius) {
+ this.origin = point;
+ } else {
+ this.calculateAngle(point, evt);
+ this.radius = Math.max(this.map.getResolution() / 2,
+ point.distanceTo(this.origin));
+ }
+ this.modifyGeometry();
+ if(this.irregular) {
+ var dx = point.x - this.origin.x;
+ var dy = point.y - this.origin.y;
+ var ratio;
+ if(dy == 0) {
+ ratio = dx / (this.radius * Math.sqrt(2));
+ } else {
+ ratio = dx / dy;
+ }
+ this.feature.geometry.resize(1, this.origin, ratio);
+ this.feature.geometry.move(dx / 2, dy / 2);
+ }
+ this.layer.drawFeature(this.feature, this.style);
+ },
+
+ /**
+ * Method: up
+ * Finish drawing the feature
+ *
+ * Parameters:
+ * evt - {Event} The mouse up event
+ */
+ up: function(evt) {
+ this.finalize();
+ // the mouseup method of superclass doesn't call the
+ // "done" callback if there's been no move between
+ // down and up
+ if (this.start == this.last) {
+ this.callback("done", [evt.xy]);
+ }
+ },
+
+ /**
+ * Method: out
+ * Finish drawing the feature.
+ *
+ * Parameters:
+ * evt - {Event} The mouse out event
+ */
+ out: function(evt) {
+ this.finalize();
+ },
+
+ /**
+ * Method: createGeometry
+ * Create the new polygon geometry. This is called at the start of the
+ * drag and at any point during the drag if the number of sides
+ * changes.
+ */
+ createGeometry: function() {
+ this.angle = Math.PI * ((1/this.sides) - (1/2));
+ if(this.snapAngle) {
+ this.angle += this.snapAngle * (Math.PI / 180);
+ }
+ this.feature.geometry = OpenLayers.Geometry.Polygon.createRegularPolygon(
+ this.origin, this.radius, this.sides, this.snapAngle
+ );
+ },
+
+ /**
+ * Method: modifyGeometry
+ * Modify the polygon geometry in place.
+ */
+ modifyGeometry: function() {
+ var angle, point;
+ var ring = this.feature.geometry.components[0];
+ // if the number of sides ever changes, create a new geometry
+ if(ring.components.length != (this.sides + 1)) {
+ this.createGeometry();
+ ring = this.feature.geometry.components[0];
+ }
+ for(var i=0; i<this.sides; ++i) {
+ point = ring.components[i];
+ angle = this.angle + (i * 2 * Math.PI / this.sides);
+ point.x = this.origin.x + (this.radius * Math.cos(angle));
+ point.y = this.origin.y + (this.radius * Math.sin(angle));
+ point.clearBounds();
+ }
+ },
+
+ /**
+ * Method: calculateAngle
+ * Calculate the angle based on settings.
+ *
+ * Parameters:
+ * point - {<OpenLayers.Geometry.Point>}
+ * evt - {Event}
+ */
+ calculateAngle: function(point, evt) {
+ var alpha = Math.atan2(point.y - this.origin.y,
+ point.x - this.origin.x);
+ if(this.snapAngle && (this.snapToggle && !evt[this.snapToggle])) {
+ var snapAngleRad = (Math.PI / 180) * this.snapAngle;
+ this.angle = Math.round(alpha / snapAngleRad) * snapAngleRad;
+ } else {
+ this.angle = alpha;
+ }
+ },
+
+ /**
+ * APIMethod: cancel
+ * Finish the geometry and call the "cancel" callback.
+ */
+ cancel: function() {
+ // the polygon geometry gets cloned in the callback method
+ this.callback("cancel", null);
+ this.finalize();
+ },
+
+ /**
+ * Method: finalize
+ * Finish the geometry and call the "done" callback.
+ */
+ finalize: function() {
+ this.origin = null;
+ this.radius = this.options.radius;
+ },
+
+ /**
+ * APIMethod: clear
+ * Clear any rendered features on the temporary layer. This is called
+ * when the handler is deactivated, canceled, or done (unless persist
+ * is true).
+ */
+ clear: function() {
+ if (this.layer) {
+ this.layer.renderer.clear();
+ this.layer.destroyFeatures();
+ }
+ },
+
+ /**
+ * Method: callback
+ * Trigger the control's named callback with the given arguments
+ *
+ * Parameters:
+ * name - {String} The key for the callback that is one of the properties
+ * of the handler's callbacks object.
+ * args - {Array} An array of arguments with which to call the callback
+ * (defined by the control).
+ */
+ callback: function (name, args) {
+ // override the callback method to always send the polygon geometry
+ if (this.callbacks[name]) {
+ this.callbacks[name].apply(this.control,
+ [this.feature.geometry.clone()]);
+ }
+ // since sketch features are added to the temporary layer
+ // they must be cleared here if done or cancel
+ if(!this.persist && (name == "done" || name == "cancel")) {
+ this.clear();
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.RegularPolygon"
+});
+/* ======================================================================
+ OpenLayers/Handler/Feature.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Handler.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Feature
+ * Handler to respond to mouse events related to a drawn feature. Callbacks
+ * with the following keys will be notified of the following events
+ * associated with features: click, clickout, over, out, and dblclick.
+ *
+ * This handler stops event propagation for mousedown and mouseup if those
+ * browser events target features that can be selected.
+ */
+OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, {
+
+ /**
+ * Property: EVENTMAP
+ * {Object} A object mapping the browser events to objects with callback
+ * keys for in and out.
+ */
+ EVENTMAP: {
+ 'click': {'in': 'click', 'out': 'clickout'},
+ 'mousemove': {'in': 'over', 'out': 'out'},
+ 'dblclick': {'in': 'dblclick', 'out': null},
+ 'mousedown': {'in': null, 'out': null},
+ 'mouseup': {'in': null, 'out': null}
+ },
+
+ /**
+ * Property: feature
+ * {<OpenLayers.Feature.Vector>} The last feature that was hovered.
+ */
+ feature: null,
+
+ /**
+ * Property: lastFeature
+ * {<OpenLayers.Feature.Vector>} The last feature that was handled.
+ */
+ lastFeature: null,
+
+ /**
+ * Property: down
+ * {<OpenLayers.Pixel>} The location of the last mousedown.
+ */
+ down: null,
+
+ /**
+ * Property: up
+ * {<OpenLayers.Pixel>} The location of the last mouseup.
+ */
+ up: null,
+
+ /**
+ * Property: clickTolerance
+ * {Number} The number of pixels the mouse can move between mousedown
+ * and mouseup for the event to still be considered a click.
+ * Dragging the map should not trigger the click and clickout callbacks
+ * unless the map is moved by less than this tolerance. Defaults to 4.
+ */
+ clickTolerance: 4,
+
+ /**
+ * Property: geometryTypes
+ * To restrict dragging to a limited set of geometry types, send a list
+ * of strings corresponding to the geometry class names.
+ *
+ * @type Array(String)
+ */
+ geometryTypes: null,
+
+ /**
+ * Property: stopClick
+ * {Boolean} If stopClick is set to true, handled clicks do not
+ * propagate to other click listeners. Otherwise, handled clicks
+ * do propagate. Unhandled clicks always propagate, whatever the
+ * value of stopClick. Defaults to true.
+ */
+ stopClick: true,
+
+ /**
+ * Property: stopDown
+ * {Boolean} If stopDown is set to true, handled mousedowns do not
+ * propagate to other mousedown listeners. Otherwise, handled
+ * mousedowns do propagate. Unhandled mousedowns always propagate,
+ * whatever the value of stopDown. Defaults to true.
+ */
+ stopDown: true,
+
+ /**
+ * Property: stopUp
+ * {Boolean} If stopUp is set to true, handled mouseups do not
+ * propagate to other mouseup listeners. Otherwise, handled mouseups
+ * do propagate. Unhandled mouseups always propagate, whatever the
+ * value of stopUp. Defaults to false.
+ */
+ stopUp: false,
+
+ /**
+ * Constructor: OpenLayers.Handler.Feature
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>}
+ * layer - {<OpenLayers.Layer.Vector>}
+ * callbacks - {Object} An object with a 'over' property whos value is
+ * a function to be called when the mouse is over a feature. The
+ * callback should expect to recieve a single argument, the feature.
+ * options - {Object}
+ */
+ initialize: function(control, layer, callbacks, options) {
+ OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]);
+ this.layer = layer;
+ },
+
+
+ /**
+ * Method: mousedown
+ * Handle mouse down. Stop propagation if a feature is targeted by this
+ * event (stops map dragging during feature selection).
+ *
+ * Parameters:
+ * evt - {Event}
+ */
+ mousedown: function(evt) {
+ this.down = evt.xy;
+ return this.handle(evt) ? !this.stopDown : true;
+ },
+
+ /**
+ * Method: mouseup
+ * Handle mouse up. Stop propagation if a feature is targeted by this
+ * event.
+ *
+ * Parameters:
+ * evt - {Event}
+ */
+ mouseup: function(evt) {
+ this.up = evt.xy;
+ return this.handle(evt) ? !this.stopUp : true;
+ },
+
+ /**
+ * Method: click
+ * Handle click. Call the "click" callback if click on a feature,
+ * or the "clickout" callback if click outside any feature.
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean}
+ */
+ click: function(evt) {
+ return this.handle(evt) ? !this.stopClick : true;
+ },
+
+ /**
+ * Method: mousemove
+ * Handle mouse moves. Call the "over" callback if moving in to a feature,
+ * or the "out" callback if moving out of a feature.
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean}
+ */
+ mousemove: function(evt) {
+ if (!this.callbacks['over'] && !this.callbacks['out']) {
+ return true;
+ }
+ this.handle(evt);
+ return true;
+ },
+
+ /**
+ * Method: dblclick
+ * Handle dblclick. Call the "dblclick" callback if dblclick on a feature.
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean}
+ */
+ dblclick: function(evt) {
+ return !this.handle(evt);
+ },
+
+ /**
+ * Method: geometryTypeMatches
+ * Return true if the geometry type of the passed feature matches
+ * one of the geometry types in the geometryTypes array.
+ *
+ * Parameters:
+ * feature - {<OpenLayers.Vector.Feature>}
+ *
+ * Returns:
+ * {Boolean}
+ */
+ geometryTypeMatches: function(feature) {
+ return this.geometryTypes == null ||
+ OpenLayers.Util.indexOf(this.geometryTypes,
+ feature.geometry.CLASS_NAME) > -1;
+ },
+
+ /**
+ * Method: handle
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} The event occurred over a relevant feature.
+ */
+ handle: function(evt) {
+ if(this.feature && !this.feature.layer) {
+ // feature has been destroyed
+ this.feature = null;
+ }
+ var type = evt.type;
+ var handled = false;
+ var previouslyIn = !!(this.feature); // previously in a feature
+ var click = (type == "click" || type == "dblclick");
+ this.feature = this.layer.getFeatureFromEvent(evt);
+ if(this.feature && !this.feature.layer) {
+ // feature has been destroyed
+ this.feature = null;
+ }
+ if(this.lastFeature && !this.lastFeature.layer) {
+ // last feature has been destroyed
+ this.lastFeature = null;
+ }
+ if(this.feature) {
+ var inNew = (this.feature != this.lastFeature);
+ if(this.geometryTypeMatches(this.feature)) {
+ // in to a feature
+ if(previouslyIn && inNew) {
+ // out of last feature and in to another
+ if(this.lastFeature) {
+ this.triggerCallback(type, 'out', [this.lastFeature]);
+ }
+ this.triggerCallback(type, 'in', [this.feature]);
+ } else if(!previouslyIn || click) {
+ // in feature for the first time
+ this.triggerCallback(type, 'in', [this.feature]);
+ }
+ this.lastFeature = this.feature;
+ handled = true;
+ } else {
+ // not in to a feature
+ if(this.lastFeature && (previouslyIn && inNew || click)) {
+ // out of last feature for the first time
+ this.triggerCallback(type, 'out', [this.lastFeature]);
+ }
+ // next time the mouse goes in a feature whose geometry type
+ // doesn't match we don't want to call the 'out' callback
+ // again, so let's set this.feature to null so that
+ // previouslyIn will evaluate to false the next time
+ // we enter handle. Yes, a bit hackish...
+ this.feature = null;
+ }
+ } else {
+ if(this.lastFeature && (previouslyIn || click)) {
+ this.triggerCallback(type, 'out', [this.lastFeature]);
+ }
+ }
+ return handled;
+ },
+
+ /**
+ * Method: triggerCallback
+ * Call the callback keyed in the event map with the supplied arguments.
+ * For click and clickout, the <clickTolerance> is checked first.
+ *
+ * Parameters:
+ * type - {String}
+ */
+ triggerCallback: function(type, mode, args) {
+ var key = this.EVENTMAP[type][mode];
+ if(key) {
+ if(type == 'click' && this.up && this.down) {
+ // for click/clickout, only trigger callback if tolerance is met
+ var dpx = Math.sqrt(
+ Math.pow(this.up.x - this.down.x, 2) +
+ Math.pow(this.up.y - this.down.y, 2)
+ );
+ if(dpx <= this.clickTolerance) {
+ this.callback(key, args);
+ }
+ } else {
+ this.callback(key, args);
+ }
+ }
+ },
+
+ /**
+ * Method: activate
+ * Turn on the handler. Returns false if the handler was already active.
+ *
+ * Returns:
+ * {Boolean}
+ */
+ activate: function() {
+ var activated = false;
+ if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+ this.moveLayerToTop();
+ this.map.events.on({
+ "removelayer": this.handleMapEvents,
+ "changelayer": this.handleMapEvents,
+ scope: this
+ });
+ activated = true;
+ }
+ return activated;
+ },
+
+ /**
+ * Method: deactivate
+ * Turn off the handler. Returns false if the handler was already active.
+ *
+ * Returns:
+ * {Boolean}
+ */
+ deactivate: function() {
+ var deactivated = false;
+ if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+ this.moveLayerBack();
+ this.feature = null;
+ this.lastFeature = null;
+ this.down = null;
+ this.up = null;
+ this.map.events.un({
+ "removelayer": this.handleMapEvents,
+ "changelayer": this.handleMapEvents,
+ scope: this
+ });
+ deactivated = true;
+ }
+ return deactivated;
+ },
+
+ /**
+ * Method handleMapEvents
+ *
+ * Parameters:
+ * evt - {Object}
+ */
+ handleMapEvents: function(evt) {
+ if (!evt.property || evt.property == "order") {
+ this.moveLayerToTop();
+ }
+ },
+
+ /**
+ * Method: moveLayerToTop
+ * Moves the layer for this handler to the top, so mouse events can reach
+ * it.
+ */
+ moveLayerToTop: function() {
+ var index = Math.max(this.map.Z_INDEX_BASE['Feature'] - 1,
+ this.layer.getZIndex()) + 1;
+ this.layer.setZIndex(index);
+
+ },
+
+ /**
+ * Method: moveLayerBack
+ * Moves the layer back to the position determined by the map's layers
+ * array.
+ */
+ moveLayerBack: function() {
+ var index = this.layer.getZIndex() - 1;
+ if (index >= this.map.Z_INDEX_BASE['Feature']) {
+ this.layer.setZIndex(index);
+ } else {
+ this.map.setLayerZIndex(this.layer,
+ this.map.getLayerIndex(this.layer));
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.Feature"
+});
+/* ======================================================================
+ OpenLayers/Protocol/WFS/v1_1_0.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Protocol/WFS/v1.js
+ * @requires OpenLayers/Format/WFST/v1_1_0.js
+ */
+
+/**
+ * Class: OpenLayers.Protocol.WFS.v1_1_0
+ * A WFS v1.1.0 protocol for vector layers. Create a new instance with the
+ * <OpenLayers.Protocol.WFS.v1_1_0> constructor.
+ *
+ * Differences from the v1.0.0 protocol:
+ * - uses Filter Encoding 1.1.0 instead of 1.0.0
+ * - uses GML 3 instead of 2 if no format is provided
+ *
+ * Inherits from:
+ * - <OpenLayers.Protocol.WFS.v1>
+ */
+OpenLayers.Protocol.WFS.v1_1_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, {
+
+ /**
+ * Property: version
+ * {String} WFS version number.
+ */
+ version: "1.1.0",
+
+ /**
+ * Constructor: OpenLayers.Protocol.WFS.v1_1_0
+ * A class for giving layers WFS v1.1.0 protocol.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ *
+ * Valid options properties:
+ * featureType - {String} Local (without prefix) feature typeName (required).
+ * featureNS - {String} Feature namespace (optional).
+ * featurePrefix - {String} Feature namespace alias (optional - only used
+ * if featureNS is provided). Default is 'feature'.
+ * geometryName - {String} Name of geometry attribute. Default is 'the_geom'.
+ * outputFormat - {String} Optional output format to use for WFS GetFeature
+ * requests. This can be any format advertized by the WFS's
+ * GetCapabilities response. If set, an appropriate readFormat also
+ * has to be provided, unless outputFormat is GML3, GML2 or JSON.
+ * readFormat - {<OpenLayers.Format>} An appropriate format parser if
+ * outputFormat is none of GML3, GML2 or JSON.
+ */
+ initialize: function(options) {
+ OpenLayers.Protocol.WFS.v1.prototype.initialize.apply(this, arguments);
+ if (this.outputFormat && !this.readFormat) {
+ if (this.outputFormat.toLowerCase() == "gml2") {
+ this.readFormat = new OpenLayers.Format.GML.v2({
+ featureType: this.featureType,
+ featureNS: this.featureNS,
+ geometryName: this.geometryName
+ });
+ } else if (this.outputFormat.toLowerCase() == "json") {
+ this.readFormat = new OpenLayers.Format.GeoJSON();
+ }
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Protocol.WFS.v1_1_0"
+});
+/* ======================================================================
+ OpenLayers/Control/ArgParser.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the Clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.ArgParser
+ * The ArgParser control adds location bar querystring parsing functionality
+ * to an OpenLayers Map.
+ * When added to a Map control, on a page load/refresh, the Map will
+ * automatically take the href string and parse it for lon, lat, zoom, and
+ * layers information.
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Parameter: center
+ * {<OpenLayers.LonLat>}
+ */
+ center: null,
+
+ /**
+ * Parameter: zoom
+ * {int}
+ */
+ zoom: null,
+
+ /**
+ * Parameter: layers
+ * {Array(<OpenLayers.Layer>)}
+ */
+ layers: null,
+
+ /**
+ * APIProperty: displayProjection
+ * {<OpenLayers.Projection>} Requires proj4js support.
+ * Projection used when reading the coordinates from the URL. This will
+ *
+ * reproject the map coordinates from the URL into the map's
+ * projection.
+ *
+ * If you are using this functionality, be aware that any permalink
+ * which is added to the map will determine the coordinate type which
+ * is read from the URL, which means you should not add permalinks with
+ * different displayProjections to the same map.
+ */
+ displayProjection: null,
+
+ /**
+ * Constructor: OpenLayers.Control.ArgParser
+ *
+ * Parameters:
+ * options - {Object}
+ */
+ initialize: function(options) {
+ OpenLayers.Control.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * Method: setMap
+ * Set the map property for the control.
+ *
+ * Parameters:
+ * map - {<OpenLayers.Map>}
+ */
+ setMap: function(map) {
+ OpenLayers.Control.prototype.setMap.apply(this, arguments);
+
+ //make sure we dont already have an arg parser attached
+ for(var i=0, len=this.map.controls.length; i<len; i++) {
+ var control = this.map.controls[i];
+ if ( (control != this) &&
+ (control.CLASS_NAME == "OpenLayers.Control.ArgParser") ) {
+
+ // If a second argparser is added to the map, then we
+ // override the displayProjection to be the one added to the
+ // map.
+ if (control.displayProjection != this.displayProjection) {
+ this.displayProjection = control.displayProjection;
+ }
+
+ break;
+ }
+ }
+ if (i == this.map.controls.length) {
+
+ var args = OpenLayers.Util.getParameters();
+ // Be careful to set layer first, to not trigger unnecessary layer loads
+ if (args.layers) {
+ this.layers = args.layers;
+
+ // when we add a new layer, set its visibility
+ this.map.events.register('addlayer', this,
+ this.configureLayers);
+ this.configureLayers();
+ }
+ if (args.lat && args.lon) {
+ this.center = new OpenLayers.LonLat(parseFloat(args.lon),
+ parseFloat(args.lat));
+ if (args.zoom) {
+ this.zoom = parseInt(args.zoom);
+ }
+
+ // when we add a new baselayer to see when we can set the center
+ this.map.events.register('changebaselayer', this,
+ this.setCenter);
+ this.setCenter();
+ }
+ }
+ },
+
+ /**
+ * Method: setCenter
+ * As soon as a baseLayer has been loaded, we center and zoom
+ * ...and remove the handler.
+ */
+ setCenter: function() {
+
+ if (this.map.baseLayer) {
+ //dont need to listen for this one anymore
+ this.map.events.unregister('changebaselayer', this,
+ this.setCenter);
+
+ if (this.displayProjection) {
+ this.center.transform(this.displayProjection,
+ this.map.getProjectionObject());
+ }
+
+ this.map.setCenter(this.center, this.zoom);
+ }
+ },
+
+ /**
+ * Method: configureLayers
+ * As soon as all the layers are loaded, cycle through them and
+ * hide or show them.
+ */
+ configureLayers: function() {
+
+ if (this.layers.length == this.map.layers.length) {
+ this.map.events.unregister('addlayer', this, this.configureLayers);
+
+ for(var i=0, len=this.layers.length; i<len; i++) {
+
+ var layer = this.map.layers[i];
+ var c = this.layers.charAt(i);
+
+ if (c == "B") {
+ this.map.setBaseLayer(layer);
+ } else if ( (c == "T") || (c == "F") ) {
+ layer.setVisibility(c == "T");
+ }
+ }
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Control.ArgParser"
+});
Modified: branches/fusion-2.2/lib/proj4js-combined.js
===================================================================
--- branches/fusion-2.2/lib/proj4js-combined.js 2011-01-20 19:46:05 UTC (rev 2322)
+++ branches/fusion-2.2/lib/proj4js-combined.js 2011-01-20 19:56:47 UTC (rev 2323)
@@ -487,7 +487,7 @@
(srsCode.indexOf('PROJCS') >= 0) ||
(srsCode.indexOf('LOCAL_CS') >= 0)) {
this.parseWKT(srsCode);
- this.datum = new Proj4js.datum(this);
+ this.deriveConstants();
this.loadProjCode(this.projName);
return;
}
@@ -759,9 +759,9 @@
this.unitsPerMeter = parseFloat(wktArray.shift());
break;
case 'PARAMETER':
- var name = wktName;
- var value = parseFloat(parseFloat(wktArray.shift()));
- //there amy be many variations on the wktName values, add in case
+ var name = wktName.toLowerCase();
+ var value = parseFloat(wktArray.shift());
+ //there may be many variations on the wktName values, add in case
//statements as required
switch (name) {
case 'false_easting':
@@ -774,10 +774,10 @@
this.k0 = value;
break;
case 'central_meridian':
- this.long0 = value;
+ this.long0 = value*Proj4js.common.D2R;
break;
case 'latitude_of_origin':
- this.lat0 = value;
+ this.lat0 = value*Proj4js.common.D2R;
break;
case 'more_here':
break;
@@ -1313,7 +1313,7 @@
/* --------------------------------------------------------------
* Following iterative algorithm was developped by
- * "Institut für Erdmessung", University of Hannover, July 1988.
+ * "Institut f�r Erdmessung", University of Hannover, July 1988.
* Internet: www.ife.uni-hannover.de
* Iterative computation of CPHI,SPHI and Height.
* Iteration of CPHI and SPHI to 10**-12 radian resp.
@@ -3087,6 +3087,8 @@
lon = (x == 0. && y == 0.) ? 0. : Math.atan2(x, y);
break;
}
+ p.x = Proj4js.common.adjust_lon(lon + this.long0);
+ p.y = lat;
} else {
rho = Math.sqrt(x*x + y*y);
switch (this.mode) {
@@ -4701,6 +4703,7 @@
cosphi = Math.cos(phi);
coslam = Math.cos(lam);
switch (this.mode) {
+ case this.OBLIQ:
case this.EQUIT:
y = (this.mode == this.EQUIT) ? 1. + cosphi * coslam : 1. + this.sinph0 * sinphi + this.cosph0 * cosphi * coslam;
if (y <= Proj4js.common.EPSLN) {
Modified: branches/fusion-2.2/lib/proj4js-compressed.js
===================================================================
--- branches/fusion-2.2/lib/proj4js-compressed.js 2011-01-20 19:46:05 UTC (rev 2322)
+++ branches/fusion-2.2/lib/proj4js-compressed.js 2011-01-20 19:56:47 UTC (rev 2323)
@@ -34,7 +34,7 @@
Proj4js.extend(extended,parent);}
Class.prototype=extended;return Class;},bind:function(func,object){var args=Array.prototype.slice.apply(arguments,[2]);return function(){var newArgs=args.concat(Array.prototype.slice.apply(arguments,[0]));return func.apply(object,newArgs);};},scriptName:"proj4js-compressed.js",defsLookupService:'http://spatialreference.org/ref',libPath:null,getScriptLocation:function(){if(this.libPath)return this.libPath;var scriptName=this.scriptName;var scriptNameLen=scriptName.length;var scripts=document.getElementsByTagName('script');for(var i=0;i<scripts.length;i++){var src=scripts[i].getAttribute('src');if(src){var index=src.lastIndexOf(scriptName);if((index>-1)&&(index+scriptNameLen==src.length)){this.libPath=src.slice(0,-scriptNameLen);break;}}}
return this.libPath||"";},loadScript:function(url,onload,onfail,loadCheck){var script=document.createElement('script');script.defer=false;script.type="text/javascript";script.id=url;script.src=url;script.onload=onload;script.onerror=onfail;script.loadCheck=loadCheck;if(/MSIE/.test(navigator.userAgent)){script.onreadystatechange=this.checkReadyState;}
-document.getElementsByTagName('head')[0].appendChild(script);},checkReadyState:function(){if(this.readyState=='loaded'){if(!this.loadCheck()){this.onerror();}else{this.onload();}}}};Proj4js.Proj=Proj4js.Class({readyToUse:false,title:null,projName:null,units:null,datum:null,x0:0,y0:0,localCS:false,initialize:function(srsCode){this.srsCodeInput=srsCode;if((srsCode.indexOf('GEOGCS')>=0)||(srsCode.indexOf('GEOCCS')>=0)||(srsCode.indexOf('PROJCS')>=0)||(srsCode.indexOf('LOCAL_CS')>=0)){this.parseWKT(srsCode);this.datum=new Proj4js.datum(this);this.loadProjCode(this.projName);return;}
+document.getElementsByTagName('head')[0].appendChild(script);},checkReadyState:function(){if(this.readyState=='loaded'){if(!this.loadCheck()){this.onerror();}else{this.onload();}}}};Proj4js.Proj=Proj4js.Class({readyToUse:false,title:null,projName:null,units:null,datum:null,x0:0,y0:0,localCS:false,initialize:function(srsCode){this.srsCodeInput=srsCode;if((srsCode.indexOf('GEOGCS')>=0)||(srsCode.indexOf('GEOCCS')>=0)||(srsCode.indexOf('PROJCS')>=0)||(srsCode.indexOf('LOCAL_CS')>=0)){this.parseWKT(srsCode);this.deriveConstants();this.loadProjCode(this.projName);return;}
if(srsCode.indexOf('urn:')==0){var urn=srsCode.split(':');if((urn[1]=='ogc'||urn[1]=='x-ogc')&&(urn[2]=='def')&&(urn[3]=='crs')){srsCode=urn[4]+':'+urn[urn.length-1];}}else if(srsCode.indexOf('http://')==0){var url=srsCode.split('#');if(url[0].match(/epsg.org/)){srsCode='EPSG:'+url[1];}else if(url[0].match(/RIG.xml/)){srsCode='IGNF:'+url[1];}}
this.srsCode=srsCode.toUpperCase();if(this.srsCode.indexOf("EPSG")==0){this.srsCode=this.srsCode;this.srsAuth='epsg';this.srsProjNumber=this.srsCode.substring(5);}else if(this.srsCode.indexOf("IGNF")==0){this.srsCode=this.srsCode;this.srsAuth='IGNF';this.srsProjNumber=this.srsCode.substring(5);}else if(this.srsCode.indexOf("CRS")==0){this.srsCode=this.srsCode;this.srsAuth='CRS';this.srsProjNumber=this.srsCode.substring(4);}else{this.srsAuth='';this.srsProjNumber=this.srsCode;}
this.loadProjDefinition();},loadProjDefinition:function(){if(Proj4js.defs[this.srsCode]){this.defsLoaded();return;}
@@ -44,7 +44,7 @@
switch(wktObject){case'LOCAL_CS':this.projName='identity'
this.localCS=true;this.srsCode=wktName;break;case'GEOGCS':this.projName='longlat'
this.geocsCode=wktName;if(!this.srsCode)this.srsCode=wktName;break;case'PROJCS':this.srsCode=wktName;break;case'GEOCCS':break;case'PROJECTION':this.projName=Proj4js.wktProjections[wktName]
-break;case'DATUM':this.datumName=wktName;break;case'LOCAL_DATUM':this.datumCode='none';break;case'SPHEROID':this.ellps=wktName;this.a=parseFloat(wktArray.shift());this.rf=parseFloat(wktArray.shift());break;case'PRIMEM':this.from_greenwich=parseFloat(wktArray.shift());break;case'UNIT':this.units=wktName;this.unitsPerMeter=parseFloat(wktArray.shift());break;case'PARAMETER':var name=wktName;var value=parseFloat(parseFloat(wktArray.shift()));switch(name){case'false_easting':this.x0=value;break;case'false_northing':this.y0=value;break;case'scale_factor':this.k0=value;break;case'central_meridian':this.long0=value;break;case'latitude_of_origin':this.lat0=value;break;case'more_here':break;default:break;}
+break;case'DATUM':this.datumName=wktName;break;case'LOCAL_DATUM':this.datumCode='none';break;case'SPHEROID':this.ellps=wktName;this.a=parseFloat(wktArray.shift());this.rf=parseFloat(wktArray.shift());break;case'PRIMEM':this.from_greenwich=parseFloat(wktArray.shift());break;case'UNIT':this.units=wktName;this.unitsPerMeter=parseFloat(wktArray.shift());break;case'PARAMETER':var name=wktName.toLowerCase();var value=parseFloat(wktArray.shift());switch(name){case'false_easting':this.x0=value;break;case'false_northing':this.y0=value;break;case'scale_factor':this.k0=value;break;case'central_meridian':this.long0=value*Proj4js.common.D2R;break;case'latitude_of_origin':this.lat0=value*Proj4js.common.D2R;break;case'more_here':break;default:break;}
break;case'TOWGS84':this.datum_params=wktArray;break;case'MORE_HERE':break;default:break;}
for(var i=0;i<wktArray.length;++i){this.parseWKT(wktArray[i]);}},parseDefs:function(){this.defData=Proj4js.defs[this.srsCode];var paramName,paramVal;if(!this.defData){return;}
var paramArray=this.defData.split("+");for(var prop=0;prop<paramArray.length;prop++){var property=paramArray[prop].split("=");paramName=property[0].toLowerCase();paramVal=property[1];switch(paramName.replace(/\s/gi,"")){case"":break;case"title":this.title=paramVal;break;case"proj":this.projName=paramVal.replace(/\s/gi,"");break;case"units":this.units=paramVal.replace(/\s/gi,"");break;case"datum":this.datumCode=paramVal.replace(/\s/gi,"");break;case"nadgrids":this.nagrids=paramVal.replace(/\s/gi,"");break;case"ellps":this.ellps=paramVal.replace(/\s/gi,"");break;case"a":this.a=parseFloat(paramVal);break;case"b":this.b=parseFloat(paramVal);break;case"rf":this.rf=parseFloat(paramVal);break;case"lat_0":this.lat0=paramVal*Proj4js.common.D2R;break;case"lat_1":this.lat1=paramVal*Proj4js.common.D2R;break;case"lat_2":this.lat2=paramVal*Proj4js.common.D2R;break;case"lat_ts":this.lat_ts=paramVal*Proj4js.common.D2R;break;case"lon_0":this.long0=paramVal*Proj4js.common.D2R;break;case"alpha
":this.alpha=parseFloat(paramVal)*Proj4js.common.D2R;break;case"lonc":this.longc=paramVal*Proj4js.common.D2R;break;case"x_0":this.x0=parseFloat(paramVal);break;case"y_0":this.y0=parseFloat(paramVal);break;case"k_0":this.k0=parseFloat(paramVal);break;case"k":this.k0=parseFloat(paramVal);break;case"r_a":this.R_A=true;break;case"zone":this.zone=parseInt(paramVal);break;case"south":this.utmSouth=true;break;case"towgs84":this.datum_params=paramVal.split(",");break;case"to_meter":this.to_meter=parseFloat(paramVal);break;case"from_greenwich":this.from_greenwich=paramVal*Proj4js.common.D2R;break;case"pm":paramVal=paramVal.replace(/\s/gi,"");this.from_greenwich=Proj4js.PrimeMeridian[paramVal]?Proj4js.PrimeMeridian[paramVal]:parseFloat(paramVal);this.from_greenwich*=Proj4js.common.D2R;break;case"no_defs":break;default:}}
@@ -151,7 +151,8 @@
if(cosc!=0.||x!=0.)lon=Math.atan2(x*sinc,cosc*rh);break;case this.OBLIQ:if(Math.abs(rh)<=Proj4js.common.EPSLN){lat=this.phi0;}else{lat=Math.asin(cosc*sinph0+y*sinc*cosph0/rh);}
c=cosc-sinph0*Math.sin(lat);if(c!=0.||x!=0.){lon=Math.atan2(x*sinc*cosph0,c*rh);}
break;case this.N_POLE:y=-y;case this.S_POLE:if(Math.abs(rh)<=Proj4js.common.EPSLN){lat=this.phi0;}else{lat=Math.asin(this.mode==this.S_POLE?-cosc:cosc);}
-lon=(x==0.&&y==0.)?0.:Math.atan2(x,y);break;}}else{rho=Math.sqrt(x*x+y*y);switch(this.mode){case this.OBLIQ:case this.EQUIT:tp=2.*Math.atan2(rho*this.cosX1,this.akm1);cosphi=Math.cos(tp);sinphi=Math.sin(tp);if(rho==0.0){phi_l=Math.asin(cosphi*this.sinX1);}else{phi_l=Math.asin(cosphi*this.sinX1+(y*sinphi*this.cosX1/rho));}
+lon=(x==0.&&y==0.)?0.:Math.atan2(x,y);break;}
+p.x=Proj4js.common.adjust_lon(lon+this.long0);p.y=lat;}else{rho=Math.sqrt(x*x+y*y);switch(this.mode){case this.OBLIQ:case this.EQUIT:tp=2.*Math.atan2(rho*this.cosX1,this.akm1);cosphi=Math.cos(tp);sinphi=Math.sin(tp);if(rho==0.0){phi_l=Math.asin(cosphi*this.sinX1);}else{phi_l=Math.asin(cosphi*this.sinX1+(y*sinphi*this.cosX1/rho));}
tp=Math.tan(.5*(Proj4js.common.HALF_PI+phi_l));x*=sinphi;y=rho*this.cosX1*cosphi-y*this.sinX1*sinphi;pi2=Proj4js.common.HALF_PI;halfe=.5*this.e;break;case this.N_POLE:y=-y;case this.S_POLE:tp=-rho/this.akm1;phi_l=Proj4js.common.HALF_PI-2.*Math.atan(tp);pi2=-Proj4js.common.HALF_PI;halfe=-.5*this.e;break;}
for(i=this.NITER;i--;phi_l=lat){sinphi=this.e*Math.sin(phi_l);lat=2.*Math.atan(tp*Math.pow((1.+sinphi)/(1.-sinphi),halfe))-pi2;if(Math.abs(phi_l-lat)<this.CONV){if(this.mode==this.S_POLE)lat=-lat;lon=(x==0.&&y==0.)?0.:Math.atan2(x,y);p.x=Proj4js.common.adjust_lon(lon+this.long0);p.y=lat;return p;}}}}};Proj4js.Proj.nzmg={iterations:1,init:function(){this.A=new Array();this.A[1]=+0.6399175073;this.A[2]=-0.1358797613;this.A[3]=+0.063294409;this.A[4]=-0.02526853;this.A[5]=+0.0117879;this.A[6]=-0.0055161;this.A[7]=+0.0026906;this.A[8]=-0.001333;this.A[9]=+0.00067;this.A[10]=-0.00034;this.B_re=new Array();this.B_im=new Array();this.B_re[1]=+0.7557853228;this.B_im[1]=0.0;this.B_re[2]=+0.249204646;this.B_im[2]=+0.003371507;this.B_re[3]=-0.001541739;this.B_im[3]=+0.041058560;this.B_re[4]=-0.10162907;this.B_im[4]=+0.01727609;this.B_re[5]=-0.26623489;this.B_im[5]=-0.36249218;this.B_re[6]=-0.6870983;this.B_im[6]=-1.1651967;this.C_re=new Array();this.C_im=new Array();this.C_re[1]=+1.3231
270439;this.C_im[1]=0.0;this.C_re[2]=-0.577245789;this.C_im[2]=-0.007809598;this.C_re[3]=+0.508307513;this.C_im[3]=-0.112208952;this.C_re[4]=-0.15094762;this.C_im[4]=+0.18200602;this.C_re[5]=+1.01418179;this.C_im[5]=+1.64497696;this.C_re[6]=+1.9660549;this.C_im[6]=+2.5127645;this.D=new Array();this.D[1]=+1.5627014243;this.D[2]=+0.5185406398;this.D[3]=-0.03333098;this.D[4]=-0.1052906;this.D[5]=-0.0368594;this.D[6]=+0.007317;this.D[7]=+0.01220;this.D[8]=+0.00394;this.D[9]=-0.0013;},forward:function(p){var lon=p.x;var lat=p.y;var delta_lat=lat-this.lat0;var delta_lon=lon-this.long0;var d_phi=delta_lat/Proj4js.common.SEC_TO_RAD*1E-5;var d_lambda=delta_lon;var d_phi_n=1;var d_psi=0;for(n=1;n<=10;n++){d_phi_n=d_phi_n*d_phi;d_psi=d_psi+this.A[n]*d_phi_n;}
var th_re=d_psi;var th_im=d_lambda;var th_n_re=1;var th_n_im=0;var th_n_re1;var th_n_im1;var z_re=0;var z_im=0;for(n=1;n<=6;n++){th_n_re1=th_n_re*th_re-th_n_im*th_im;th_n_im1=th_n_im*th_re+th_n_re*th_im;th_n_re=th_n_re1;th_n_im=th_n_im1;z_re=z_re+this.B_re[n]*th_n_re-this.B_im[n]*th_n_im;z_im=z_im+this.B_im[n]*th_n_re+this.B_re[n]*th_n_im;}
@@ -199,7 +200,7 @@
var theta=0.0;if(rh1!=0){theta=Math.atan2((con*x),(con*y));}
if((rh1!=0)||(this.ns>0.0)){con=1.0/this.ns;ts=Math.pow((rh1/(this.a*this.f0)),con);lat=Proj4js.common.phi2z(this.e,ts);if(lat==-9999)return null;}else{lat=-Proj4js.common.HALF_PI;}
lon=Proj4js.common.adjust_lon(theta/this.ns+this.long0);p.x=lon;p.y=lat;return p;}};Proj4js.Proj.laea={S_POLE:1,N_POLE:2,EQUIT:3,OBLIQ:4,init:function(){var t=Math.abs(this.lat0);if(Math.abs(t-Proj4js.common.HALF_PI)<Proj4js.common.EPSLN){this.mode=this.lat0<0.?this.S_POLE:this.N_POLE;}else if(Math.abs(t)<Proj4js.common.EPSLN){this.mode=this.EQUIT;}else{this.mode=this.OBLIQ;}
-if(this.es>0){var sinphi;this.qp=Proj4js.common.qsfnz(this.e,1.0);this.mmf=.5/(1.-this.es);this.apa=this.authset(this.es);switch(this.mode){case this.N_POLE:case this.S_POLE:this.dd=1.;break;case this.EQUIT:this.rq=Math.sqrt(.5*this.qp);this.dd=1./this.rq;this.xmf=1.;this.ymf=.5*this.qp;break;case this.OBLIQ:this.rq=Math.sqrt(.5*this.qp);sinphi=Math.sin(this.lat0);this.sinb1=Proj4js.common.qsfnz(this.e,sinphi)/this.qp;this.cosb1=Math.sqrt(1.-this.sinb1*this.sinb1);this.dd=Math.cos(this.lat0)/(Math.sqrt(1.-this.es*sinphi*sinphi)*this.rq*this.cosb1);this.ymf=(this.xmf=this.rq)/this.dd;this.xmf*=this.dd;break;}}else{if(this.mode==this.OBLIQ){this.sinph0=Math.sin(this.lat0);this.cosph0=Math.cos(this.lat0);}}},forward:function(p){var x,y;var lam=p.x;var phi=p.y;lam=Proj4js.common.adjust_lon(lam-this.long0);if(this.sphere){var coslam,cosphi,sinphi;sinphi=Math.sin(phi);cosphi=Math.cos(phi);coslam=Math.cos(lam);switch(this.mode){case this.EQUIT:y=(this.mode==this.EQUIT)?1.+cosphi*co
slam:1.+this.sinph0*sinphi+this.cosph0*cosphi*coslam;if(y<=Proj4js.common.EPSLN){Proj4js.reportError("laea:fwd:y less than eps");return null;}
+if(this.es>0){var sinphi;this.qp=Proj4js.common.qsfnz(this.e,1.0);this.mmf=.5/(1.-this.es);this.apa=this.authset(this.es);switch(this.mode){case this.N_POLE:case this.S_POLE:this.dd=1.;break;case this.EQUIT:this.rq=Math.sqrt(.5*this.qp);this.dd=1./this.rq;this.xmf=1.;this.ymf=.5*this.qp;break;case this.OBLIQ:this.rq=Math.sqrt(.5*this.qp);sinphi=Math.sin(this.lat0);this.sinb1=Proj4js.common.qsfnz(this.e,sinphi)/this.qp;this.cosb1=Math.sqrt(1.-this.sinb1*this.sinb1);this.dd=Math.cos(this.lat0)/(Math.sqrt(1.-this.es*sinphi*sinphi)*this.rq*this.cosb1);this.ymf=(this.xmf=this.rq)/this.dd;this.xmf*=this.dd;break;}}else{if(this.mode==this.OBLIQ){this.sinph0=Math.sin(this.lat0);this.cosph0=Math.cos(this.lat0);}}},forward:function(p){var x,y;var lam=p.x;var phi=p.y;lam=Proj4js.common.adjust_lon(lam-this.long0);if(this.sphere){var coslam,cosphi,sinphi;sinphi=Math.sin(phi);cosphi=Math.cos(phi);coslam=Math.cos(lam);switch(this.mode){case this.OBLIQ:case this.EQUIT:y=(this.mode==this.EQU
IT)?1.+cosphi*coslam:1.+this.sinph0*sinphi+this.cosph0*cosphi*coslam;if(y<=Proj4js.common.EPSLN){Proj4js.reportError("laea:fwd:y less than eps");return null;}
y=Math.sqrt(2./y);x=y*cosphi*Math.sin(lam);y*=(this.mode==this.EQUIT)?sinphi:this.cosph0*sinphi-this.sinph0*cosphi*coslam;break;case this.N_POLE:coslam=-coslam;case this.S_POLE:if(Math.abs(phi+this.phi0)<Proj4js.common.EPSLN){Proj4js.reportError("laea:fwd:phi < eps");return null;}
y=Proj4js.common.FORTPI-phi*.5;y=2.*((this.mode==this.S_POLE)?Math.cos(y):Math.sin(y));x=y*Math.sin(lam);y*=coslam;break;}}else{var coslam,sinlam,sinphi,q,sinb=0.0,cosb=0.0,b=0.0;coslam=Math.cos(lam);sinlam=Math.sin(lam);sinphi=Math.sin(phi);q=Proj4js.common.qsfnz(this.e,sinphi);if(this.mode==this.OBLIQ||this.mode==this.EQUIT){sinb=q/this.qp;cosb=Math.sqrt(1.-sinb*sinb);}
switch(this.mode){case this.OBLIQ:b=1.+this.sinb1*sinb+this.cosb1*cosb*coslam;break;case this.EQUIT:b=1.+cosb*coslam;break;case this.N_POLE:b=Proj4js.common.HALF_PI+phi;q=this.qp-q;break;case this.S_POLE:b=phi-Proj4js.common.HALF_PI;q=this.qp+q;break;}
More information about the fusion-commits
mailing list