From b1404a6591674f1e278fe399f29ac438ee378d90 Mon Sep 17 00:00:00 2001 From: tschaub Date: Mon, 19 Sep 2011 17:05:25 -0600 Subject: [PATCH 01/36] Raster. --- examples/raster-array.html | 50 ++++++++++ examples/raster-array.js | 59 ++++++++++++ examples/raster-grid-layer.html | 43 +++++++++ examples/raster-grid-layer.js | 44 +++++++++ examples/raster-magnify.html | 45 +++++++++ examples/raster-magnify.js | 75 +++++++++++++++ examples/raster-operations.html | 75 +++++++++++++++ examples/raster-operations.js | 139 +++++++++++++++++++++++++++ examples/raster-query.html | 57 ++++++++++++ examples/raster-query.js | 83 +++++++++++++++++ lib/OpenLayers.js | 5 + lib/OpenLayers/Layer/Raster.js | 94 +++++++++++++++++++ lib/OpenLayers/Raster.js | 4 + lib/OpenLayers/Raster/Composite.js | 145 +++++++++++++++++++++++++++++ lib/OpenLayers/Raster/Grid.js | 91 ++++++++++++++++++ lib/OpenLayers/Raster/Operation.js | 84 +++++++++++++++++ 16 files changed, 1093 insertions(+) create mode 100644 examples/raster-array.html create mode 100644 examples/raster-array.js create mode 100644 examples/raster-grid-layer.html create mode 100644 examples/raster-grid-layer.js create mode 100644 examples/raster-magnify.html create mode 100644 examples/raster-magnify.js create mode 100644 examples/raster-operations.html create mode 100644 examples/raster-operations.js create mode 100644 examples/raster-query.html create mode 100644 examples/raster-query.js create mode 100644 lib/OpenLayers/Layer/Raster.js create mode 100644 lib/OpenLayers/Raster.js create mode 100644 lib/OpenLayers/Raster/Composite.js create mode 100644 lib/OpenLayers/Raster/Grid.js create mode 100644 lib/OpenLayers/Raster/Operation.js diff --git a/examples/raster-array.html b/examples/raster-array.html new file mode 100644 index 0000000000..95d1bb4017 --- /dev/null +++ b/examples/raster-array.html @@ -0,0 +1,50 @@ + + + + OpenLayers Raster from Array Example + + + + + + + + + + + + +

Array as Raster Data

+
+ Raster, Grid, Array +
+

This demo generates a raster grid from array data.

+
+
+ hue: +
+
+

See the raster-array.js source for details on how this is done.

+ + + diff --git a/examples/raster-array.js b/examples/raster-array.js new file mode 100644 index 0000000000..eb0f9b5e19 --- /dev/null +++ b/examples/raster-array.js @@ -0,0 +1,59 @@ +var cols = 256; +var rows = 4; + +var array = new Array(rows); +var values = new Array(cols); +for (var i=0; i + + + OpenLayers Raster Grid Layer Example + + + + + + + + + +

Raster Layer from Grid Data

+
+ Raster, Grid, Layer +
+

This demo generates a raster layer based on modified data from another layer.

+
+
+
+

+ This example generates a OpenLayers.Raster.Composite + from a WMS layer. The composite data is a luminosity calculation + from a OpenLayers.Raster.Operation that works with + the source RGBA data. The resulting luminosity data is displayed + on a second map with a OpenLayers.Layer.Raster. +

+

+ See the raster-grid-layer.js + source for details on how this is done. +

+ + + diff --git a/examples/raster-grid-layer.js b/examples/raster-grid-layer.js new file mode 100644 index 0000000000..982c48ce24 --- /dev/null +++ b/examples/raster-grid-layer.js @@ -0,0 +1,44 @@ + +var luminance = OpenLayers.Raster.Operation.create(function(rgba) { + var lum = Math.min(255, 30 + (0.299 * rgba[0]) + (0.587 * rgba[1]) + (0.114 * rgba[2])); + return [lum, lum, lum, rgba[3]]; +}); + +var marble = new OpenLayers.Layer.WMS( + "Blue Marble", + "/geoserver/gwc/service/wms", + {layers: "topp:bluemarble", format: "image/png"} +); + +var raster = new OpenLayers.Layer.Raster({ + name: "Luminance", + data: luminance(OpenLayers.Raster.Composite.fromLayer(marble)), + isBaseLayer: true +}); + +var map = new OpenLayers.Map({ + div: "map", + theme: null, + controls: [ + new OpenLayers.Control.Attribution(), + new OpenLayers.Control.Navigation(), + new OpenLayers.Control.ZoomPanel() + ], + layers: [ + marble + ], + center: new OpenLayers.LonLat(0, 0), + zoom: 1 +}); + +var view = new OpenLayers.Map({ + div: "view", + theme: null, + controls: [], + layers: [ + raster + ], + center: new OpenLayers.LonLat(0, 0), + zoom: 1 +}); + diff --git a/examples/raster-magnify.html b/examples/raster-magnify.html new file mode 100644 index 0000000000..1833d77ac7 --- /dev/null +++ b/examples/raster-magnify.html @@ -0,0 +1,45 @@ + + + + OpenLayers Raster Magnification Example + + + + + + + + + +

Magnify Raster

+
+ Raster, Grid, Resample +
+

This demo shows how raster data can be resampled.

+
+
+

+ This example uses a OpenLayers.Raster.Composite + to resample data from a WMS layer. Move your mouse over the + map to change the center of the magnification lens. +

+

+ See the raster-magnify.js + source for details on how this is done. +

+
+ + + diff --git a/examples/raster-magnify.js b/examples/raster-magnify.js new file mode 100644 index 0000000000..4b875df94e --- /dev/null +++ b/examples/raster-magnify.js @@ -0,0 +1,75 @@ +var marble = new OpenLayers.Layer.WMS( + "Blue Marble", + "/geoserver/gwc/service/wms", + {layers: "topp:bluemarble", format: "image/png"} +); + +var data = OpenLayers.Raster.Composite.fromLayer(marble); + +var focus = [256, 128]; +var radius = 50; +var magnification = 2.5; + +var magnified = new OpenLayers.Raster.Composite({ + numRows: function() { + return data.numRows(); + }, + numCols: function() { + return data.numCols(); + }, + getCount: function() { + return data.getCount(); + }, + getValue: function(col, row) { + var dx = focus[0] - col; + var dy = focus[1] - row; + var d = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); + var value; + if (d < radius) { + value = data.getValue( + Math.round(col + (dx / magnification)), + Math.round(row + (dy / magnification)) + ); + } else { + value = [0, 0, 0, 0]; + } + return value; + } +}); + +data.events.on({ + update: function() { + magnified.events.triggerEvent("update"); + } +}); + +var raster = new OpenLayers.Layer.Raster({ + name: "Magnified Blue Marble", + data: magnified +}); + +var map = new OpenLayers.Map({ + div: "map", + theme: null, + controls: [ + new OpenLayers.Control.Attribution(), + new OpenLayers.Control.Navigation(), + new OpenLayers.Control.ZoomPanel(), + new OpenLayers.Control.LayerSwitcher(), + ], + layers: [ + marble, raster + ], + center: new OpenLayers.LonLat(0, 0), + zoom: 1 +}); + +map.events.on({ + mousemove: function(event) { + if (!map.dragging) { + var pixel = event.xy; + focus = [pixel.x, pixel.y]; + magnified.events.triggerEvent("update"); + } + } +}); diff --git a/examples/raster-operations.html b/examples/raster-operations.html new file mode 100644 index 0000000000..bf46e60f74 --- /dev/null +++ b/examples/raster-operations.html @@ -0,0 +1,75 @@ + + + + OpenLayers Raster Operations Example + + + + + + + + + + + + + +

Raster Operations

+
+ Raster, Grid, Operation +
+

This demo uses raster operations to manipulate layer based data.

+
+
+ hue: +
+
+
+ saturation: +
+
+
+ lightness: +
+
+ reset +
+

+ This example manipulates data in a OpenLayers.Raster.Composite + using a series of OpenLayers.Raster.Operation methods. + RGB data from the WMS layer is translated to HSL, modified using + user supplied values, and translated back to RGB. The resulting + composite is displayed on the map with a OpenLayers.Layer.Raster. +

+

+ See the raster-operations.js + source for details on how this is done. +

+
+ + + diff --git a/examples/raster-operations.js b/examples/raster-operations.js new file mode 100644 index 0000000000..aa5de4c743 --- /dev/null +++ b/examples/raster-operations.js @@ -0,0 +1,139 @@ + +// alias for operations +var op = OpenLayers.Raster.Operation; + +// operation for converting rgb values to hsl values +var rgb2hsl = op.create(function(rgb) { + var r = rgb[0] / 255, + g = rgb[1] / 255, + b = rgb[2] / 255; + var max = Math.max(r, g, b), + min = Math.min(r, g, b); + var h, s, l = (max + min) / 2; + + if (max == min) { + h = s = 0; // achromatic + } else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch (max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; + } + return [h, s, l, rgb[3]]; +}); + +// helper function for hsl2rgb operation +function hue2rgb(p, q, t) { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1/6) return p + (q - p) * 6 * t; + if (t < 1/2) return q; + if (t < 2/3) return p + (q - p) * (2/3 - t) * 6; + return p; +} + +// operation for converting hsl values to rgb values +var hsl2rgb = op.create(function(hsl) { + var r, g, b; + var h = hsl[0], + s = hsl[1], + l = hsl[2]; + + if (s == 0) { + r = g = b = l; // achromatic + } else { + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1/3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1/3); + } + + return [r * 255, g * 255, b * 255, hsl[3]]; +}); + +var adjustments = { + hue: 0, + saturation: 0, + lightness: 0 +}; + +var adjust = op.create(function(hsl, deltas) { + var h = (hsl[0] + deltas.hue) % 1; + if (h < 0) { + h += 1; + } + var s = Math.max(0 , Math.min(hsl[1] + deltas.saturation, 1)); + var l = Math.max(0 , Math.min(hsl[2] + deltas.lightness, 1)); + return [h, s, l, hsl[3]]; +}); + +var marble = new OpenLayers.Layer.WMS( + "Blue Marble", + "/geoserver/gwc/service/wms", + {layers: "topp:bluemarble", format: "image/png"} +); + +var data = OpenLayers.Raster.Composite.fromLayer(marble); +var adjusted = hsl2rgb(adjust(rgb2hsl(data), adjustments)); + +var raster = new OpenLayers.Layer.Raster({ + name: "Adjusted Blue Marble", + data: adjusted +}); + +var map = new OpenLayers.Map({ + div: "map", + theme: null, + controls: [ + new OpenLayers.Control.Attribution(), + new OpenLayers.Control.Navigation(), + new OpenLayers.Control.ZoomPanel(), + new OpenLayers.Control.LayerSwitcher() + ], + layers: [ + marble, raster + ], + center: new OpenLayers.LonLat(0, 0), + zoom: 1 +}); + +// add hsl sliders that modify properties of the adjustments object and update data +$("#hue-slider").slider({ + step: 2, + value: 50, + stop: function(event, ui) { + adjustments.hue = (ui.value / 100) - 0.5; + adjusted.events.triggerEvent("update"); + } +}); +$("#sat-slider").slider({ + step: 2, + value: 50, + stop: function(event, ui) { + adjustments.saturation = (2 * ui.value / 100) - 1; + adjusted.events.triggerEvent("update"); + } +}); +$("#lit-slider").slider({ + step: 2, + value: 50, + stop: function(event, ui) { + adjustments.lightness = (2 * ui.value / 100) - 1; + adjusted.events.triggerEvent("update"); + } +}); +$("#reset").button(); +$("#reset").click(function() { + $("#hue-slider").slider("value", 50); + adjustments.hue = 0; + $("#sat-slider").slider("value", 50); + adjustments.saturation = 0; + $("#lit-slider").slider("value", 50); + adjustments.lightness = 0; + adjusted.events.triggerEvent("update"); +}); diff --git a/examples/raster-query.html b/examples/raster-query.html new file mode 100644 index 0000000000..e03b355c64 --- /dev/null +++ b/examples/raster-query.html @@ -0,0 +1,57 @@ + + + + OpenLayers Raster Query Example + + + + + + + + + +

Query Grid Data

+
+ Raster, Grid, Query +
+

This demo shows querying of pixel data.

+
+

+ Selected pixel value (RGBA): + none selected +

+

+ Area selected: + none +

+
+

+ This example uses a OpenLayers.Raster.Operation + to query composite data from a WMS layer. Click on the map to + query pixel data. The results of the query are displayed on + the map as a OpenLayers.Layer.Raster. +

+

+ See the raster-query.js + source for details on how this is done. +

+
+ + + diff --git a/examples/raster-query.js b/examples/raster-query.js new file mode 100644 index 0000000000..fb3efcde75 --- /dev/null +++ b/examples/raster-query.js @@ -0,0 +1,83 @@ + +var osm = new OpenLayers.Layer.OSM(); +var veg = new OpenLayers.Layer.WMS( + "Vegetation", + "/geoserver/gwc/service/wms", + {layers: "za:za_vegetation", format: "image/png8", transparent: "TRUE"}, + {isBaseLayer: false, opacity: 0.5} +); + +var vegData = OpenLayers.Raster.Composite.fromLayer(veg); + +var pixelValues; +var Click = OpenLayers.Class(OpenLayers.Control, { + autoActivate: true, + initialize: function(options) { + OpenLayers.Control.prototype.initialize.apply(this, arguments); + this.handler = new OpenLayers.Handler.Click(this, {click: this.trigger}); + }, + trigger: function(event) { + var pixel = event.xy; + pixelValues = vegData.getValue(pixel.x, pixel.y); + selected.events.triggerEvent("update"); + } +}); + +function close(a, b) { + return Math.abs(a - b) < 15; +} +var query = OpenLayers.Raster.Operation.create(function(vegValues) { + var rgba = [0, 0, 0, 0]; + if (pixelValues) { + if (close(vegValues[0], pixelValues[0]) && close(vegValues[1], pixelValues[1]) && + close(vegValues[2], pixelValues[2]) && close(vegValues[3], pixelValues[3])) { + rgba[3] = 150; + } + } + return rgba; +}); + +var selected = query(vegData); + +var map = new OpenLayers.Map({ + div: "map", + theme: null, + projection: "EPSG:900913", + units: "m", + maxExtent: new OpenLayers.Bounds(-20037508, -20037508, 20037508, 20037508), + maxResolution: 156543.0339, + controls: [ + new OpenLayers.Control.Attribution(), + new OpenLayers.Control.Navigation(), + new OpenLayers.Control.ZoomPanel(), + new OpenLayers.Control.LayerSwitcher(), + new Click() + ], + layers: [ + osm, veg, new OpenLayers.Layer.Raster({name: "Selected", data: selected}) + ], + center: new OpenLayers.LonLat(2622095, -3512434), + zoom: 5 +}); + +selected.events.on({ + update: function() { + if (pixelValues) { + document.getElementById("output").innerHTML = "[" + pixelValues.join(", ") + "]"; + window.setTimeout(updateStats, 0); + } + } +}) + +function updateStats() { + var count = 0; + selected.forEach(function(value) { + if (value[3] > 0) { + ++count; + } + }); + var res = map.getResolution(); + var area = (count * res * res / 10e6).toFixed(0); + + document.getElementById("stats").innerHTML = area + " km2"; +} \ No newline at end of file diff --git a/lib/OpenLayers.js b/lib/OpenLayers.js index b378b7d24b..48d97469df 100644 --- a/lib/OpenLayers.js +++ b/lib/OpenLayers.js @@ -120,6 +120,10 @@ "OpenLayers/Marker.js", "OpenLayers/Marker/Box.js", "OpenLayers/Popup.js", + "OpenLayers/Raster.js", + "OpenLayers/Raster/Grid.js", + "OpenLayers/Raster/Composite.js", + "OpenLayers/Raster/Operation.js", "OpenLayers/Tile.js", "OpenLayers/Tile/BackBufferable.js", "OpenLayers/Tile/Image.js", @@ -135,6 +139,7 @@ "OpenLayers/Layer/Yahoo.js", "OpenLayers/Layer/HTTPRequest.js", "OpenLayers/Layer/Grid.js", + "OpenLayers/Layer/Raster.js", "OpenLayers/Layer/MapGuide.js", "OpenLayers/Layer/MapServer.js", "OpenLayers/Layer/MapServer/Untiled.js", diff --git a/lib/OpenLayers/Layer/Raster.js b/lib/OpenLayers/Layer/Raster.js new file mode 100644 index 0000000000..b1aa2e8f48 --- /dev/null +++ b/lib/OpenLayers/Layer/Raster.js @@ -0,0 +1,94 @@ +/** + * @requires OpenLayers/Layer.js + * @requires OpenLayers/Raster/Composite.js + */ + +/** + * Class: OpenLayers.Layer.Raster + * + * Inherits from: + * - + */ +OpenLayers.Layer.Raster = OpenLayers.Class(OpenLayers.Layer, { + + needsUpdate: false, + + initialize: function(config) { + config = config || {}; + var data = config.data; + delete config.data; + OpenLayers.Layer.prototype.initialize.apply(this, [config.name, config]); + + this.canvas = document.createElement("canvas"); + this.canvas.style.position = "absolute"; + this.div.appendChild(this.canvas); + this.context = this.canvas.getContext("2d"); + if (data) { + this.setData(data); + } + + }, + + setData: function(data) { + this.clearData(); + this.data = data; + data.events.register("update", this, this.onDataUpdate); + }, + + clearData: function() { + if (this.data) { + this.data.events.unregister("update", this, this.onDataUpdate); + delete this.data; + } + }, + + moveTo: function() { + this.needsUpdate = true; + OpenLayers.Layer.prototype.moveTo.apply(this, arguments); + window.setTimeout(OpenLayers.Function.bind(this.afterMoveTo, this), 0); + }, + + afterMoveTo: function() { + if (this.needsUpdate) { + this.onDataUpdate(); + } + }, + + onDataUpdate: function() { + var map = this.map; + if (map) { + var size = map.getSize(); + var cols = this.data.numCols(); + var rows = this.data.numRows(); + var style = map.layerContainerDiv.style; + this.canvas.width = cols; + this.canvas.height = rows; + this.canvas.style.top = (-parseInt(style.top)) + "px"; + this.canvas.style.left = (-parseInt(style.left)) + "px"; + this.canvas.style.width = size.w + "px"; + this.canvas.style.height = size.h + "px"; + + var imageData = this.context.createImageData(cols, rows); + var data = imageData.data; + this.data.forEach(function(value, index) { + var offset = 4 * index; + if (!value.length) { + value = [value, value, value]; + } + data[offset + 0] = value[0]; // red + data[offset + 1] = value[1]; // green + data[offset + 2] = value[2]; // blue + if (value.length > 3) { + data[offset + 3] = value[3]; // opacity + } else { + data[offset + 3] = 255; // assume opaque + } + }); + this.context.putImageData(imageData, 0, 0); + this.needsUpdate = false; + } + }, + + CLASS_NAME: "OpenLayers.Layer.Raster" + +}); diff --git a/lib/OpenLayers/Raster.js b/lib/OpenLayers/Raster.js new file mode 100644 index 0000000000..2c20a7f346 --- /dev/null +++ b/lib/OpenLayers/Raster.js @@ -0,0 +1,4 @@ +/** + * @requires OpenLayers/SingleFile.js + */ +OpenLayers.Raster = {}; \ No newline at end of file diff --git a/lib/OpenLayers/Raster/Composite.js b/lib/OpenLayers/Raster/Composite.js new file mode 100644 index 0000000000..981a24bbec --- /dev/null +++ b/lib/OpenLayers/Raster/Composite.js @@ -0,0 +1,145 @@ +/** + * @requires OpenLayers/Raster/Grid.js + */ + +OpenLayers.Raster.Composite = OpenLayers.Class(OpenLayers.Raster.Grid, (function() { + + var grids; + + return { + + /** + * Constructor: OpenLayers.Raster.Composite + */ + initialize: function(config) { + if (config.grids) { + grids = config.grids; + delete config.grids; + } + OpenLayers.Raster.Grid.prototype.initialize.apply(this, [config]); + if (grids) { + for (var i=0, ii=grids.length; i= this.getCount()) { + throw new Error("Bad grid index.") + } + var composite = this; + return new OpenLayers.Raster.Grid({ + numCols: function() { + return composite.numCols(); + }, + numRows: function() { + return composite.numRows(); + }, + getValue: function(col, row) { + return composite.getValue(col, row)[index]; + } + }); + }, + + + CLASS_NAME: "OpenLayers.Raster.Composite" + }; + +})()); + +OpenLayers.Raster.Composite.fromLayer = function(layer) { + + if (!(layer instanceof OpenLayers.Layer.Grid)) { + throw new Error("Only OpenLayers.Layer.Grid type layers can be used to create a raster"); + } + + var canvas = document.createElement("canvas"); + var context = canvas.getContext("2d"); + + var composite = new OpenLayers.Raster.Composite({ + numCols: function() { + return canvas.width; + }, + numRows: function() { + return canvas.height; + }, + getCount: function() { + return 4; + }, + getValue: function(col, row) { + var pixelArray = getPixelArray(); + var cols = canvas.width; + var offset = 4 * (col + (row * cols)); + return Array.prototype.slice.apply(pixelArray, [offset, offset+4]); + } + }); + + var cache = {}; + function getPixelArray() { + if (!cache.pixelArray) { + var imageData = context.getImageData(0, 0, canvas.width, canvas.height); + cache.pixelArray = imageData.data; + } + return cache.pixelArray; + } + + function update() { + cache = {}; + var map = layer.map; + var tileSize = layer.tileSize; + var mapSize = map.getSize(); + canvas.width = mapSize.w; + canvas.height = mapSize.h; + var mapBounds = map.getExtent(); + var tiles = layer.grid; + var array, tile, tileBounds, img, cornerLocation, cornerPixel; + for (var i=0, ii=tiles.length; i 1) ? Composite : Grid; + var grid = new Constructor({ + numCols: function() { + return getFirstGrid().numCols(); + }, + numRows: function() { + return getFirstGrid().numRows(); + }, + getValue: function(col, row) { + var values = new Array(len); + var arg; + for (var i=0; i Date: Mon, 19 Sep 2011 17:06:03 -0600 Subject: [PATCH 02/36] Raster specific build. --- OpenLayers.js | 433 +++++++++++++++++++++++++++++++++++++++++++++++ build/raster.cfg | 19 +++ 2 files changed, 452 insertions(+) create mode 100644 OpenLayers.js create mode 100644 build/raster.cfg diff --git a/OpenLayers.js b/OpenLayers.js new file mode 100644 index 0000000000..d6980eb996 --- /dev/null +++ b/OpenLayers.js @@ -0,0 +1,433 @@ +/* + + OpenLayers.js -- OpenLayers Map Viewer Library + + Copyright 2005-2011 OpenLayers Contributors, released under the FreeBSD + license. Please see http://svn.openlayers.org/trunk/openlayers/license.txt + for the full text of the license. + + Includes compressed code under the following licenses: + + (For uncompressed versions of the code used please see the + OpenLayers SVN repository: ) + +*/ + +/* Contains portions of Prototype.js: + * + * Prototype JavaScript framework, version 1.4.0 + * (c) 2005 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://prototype.conio.net/ + * + *--------------------------------------------------------------------------*/ + +/** +* +* Contains portions of Rico +* +* Copyright 2005 Sabre Airline Solutions +* +* Licensed under the Apache License, Version 2.0 (the "License"); you +* may not use this file except in compliance with the License. You +* may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +* implied. See the License for the specific language governing +* permissions and limitations under the License. +* +**/ + +/** + * Contains XMLHttpRequest.js + * Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + */ + +/** + * Contains portions of Gears + * + * Copyright 2007, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Google Inc. nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * Sets up google.gears.*, which is *the only* supported way to access Gears. + * + * Circumvent this file at your own risk! + * + * In the future, Gears may automatically define google.gears.* without this + * file. Gears may use these objects to transparently fix bugs and compatibility + * 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. + */var OpenLayers={VERSION_NUMBER:"$Revision$",singleFile:!0,_getScriptLocation:function(){for(var a=/(^|(.*?\/))(OpenLayers.js)(\?|$)/,b=document.getElementsByTagName("script"),c,d="",e=0,f=b.length;e1?(a=[d,b].concat(Array.prototype.slice.call(arguments).slice(1,a-1),c),OpenLayers.inherit.apply(null,a)):d.prototype=c;return d};OpenLayers.Class.isPrototype=function(){};OpenLayers.Class.create=function(){return function(){arguments&&arguments[0]!=OpenLayers.Class.isPrototype&&this.initialize.apply(this,arguments)}}; +OpenLayers.Class.inherit=function(a){var b=function(){a.call(this)},c=[b].concat(Array.prototype.slice.call(arguments));OpenLayers.inherit.apply(null,c);return b.prototype};OpenLayers.inherit=function(a,b){var c=function(){};c.prototype=b.prototype;a.prototype=new c;var d,e;for(c=2,d=arguments.length;cthis.duration&&this.stop()},CLASS_NAME:"OpenLayers.Tween"});OpenLayers.Easing={CLASS_NAME:"OpenLayers.Easing"};OpenLayers.Easing.Linear={easeIn:function(a,b,c,d){return c*a/d+b},easeOut:function(a,b,c,d){return c*a/d+b},easeInOut:function(a,b,c,d){return c*a/d+b},CLASS_NAME:"OpenLayers.Easing.Linear"}; +OpenLayers.Easing.Expo={easeIn:function(a,b,c,d){return a==0?b:c*Math.pow(2,10*(a/d-1))+b},easeOut:function(a,b,c,d){return a==d?b+c:c*(-Math.pow(2,-10*a/d)+1)+b},easeInOut:function(a,b,c,d){return a==0?b:a==d?b+c:(a/=d/2)<1?c/2*Math.pow(2,10*(a-1))+b:c/2*(-Math.pow(2,-10*--a)+2)+b},CLASS_NAME:"OpenLayers.Easing.Expo"}; +OpenLayers.Easing.Quad={easeIn:function(a,b,c,d){return c*(a/=d)*a+b},easeOut:function(a,b,c,d){return-c*(a/=d)*(a-2)+b},easeInOut:function(a,b,c,d){return(a/=d/2)<1?c/2*a*a+b:-c/2*(--a*(a-2)-1)+b},CLASS_NAME:"OpenLayers.Easing.Quad"}; +OpenLayers.Raster.Grid=OpenLayers.Class({EVENT_TYPES:["update"],initialize:function(a){OpenLayers.Util.extend(this,a);this.events=new OpenLayers.Events(this,null,this.EVENT_TYPES)},getValue:function(){throw Error("getValue must be defined");},numCols:function(){throw Error("numCols must be defined");},numRows:function(){throw Error("numRows must be defined");},forEach:function(a){for(var b=this.numCols(),c=this.numRows(),d=0;d=this.getCount())throw Error("Bad grid index.");var c=this;return new OpenLayers.Raster.Grid({numCols:function(){return c.numCols()},numRows:function(){return c.numRows()},getValue:function(d,e){return c.getValue(d,e)[a]}})},CLASS_NAME:"OpenLayers.Raster.Composite"}}()); +OpenLayers.Raster.Composite.fromLayer=function(a){var b;function c(){b=void 0;var c=a.map,h=a.tileSize,i=c.getSize();d.width=i.w;d.height=i.h;for(var i=c.getExtent(),j=a.grid,k,n,m,l=0,o=j.length;l1?b:a)({numCols:function(){return e().numCols()},numRows:function(){return e().numRows()}, +getValue:function(b,e){for(var h=Array(g),i,j=0;j0&&(c=parseFloat(a.toPrecision(b)));return c},format:function(a,b,c,d){b=typeof b!="undefined"?b:0;c=typeof c!="undefined"?c:OpenLayers.Number.thousandsSeparator;d=typeof d!="undefined"?d:OpenLayers.Number.decimalSeparator;b!=null&&(a=parseFloat(a.toFixed(b)));var e=a.toString().split(".");e.length==1&&b==null&&(b=0);a=e[0];if(c)for(var f=/(-?[0-9]+)([0-9]{3})/;f.test(a);)a=a.replace(f,"$1"+c+"$2"); +b==0?b=a:(c=e.length>1?e[1]:"0",b!=null&&(c+=Array(b-c.length+1).join("0")),b=a+d+c);return b}};if(!Number.prototype.limitSigDigs)Number.prototype.limitSigDigs=function(a){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{newMethod:"OpenLayers.Number.limitSigDigs"}));return OpenLayers.Number.limitSigDigs(this,a)}; +OpenLayers.Function={bind:function(a,b){var c=Array.prototype.slice.apply(arguments,[2]);return function(){var d=c.concat(Array.prototype.slice.apply(arguments,[0]));return a.apply(b,d)}},bindAsEventListener:function(a,b){return function(c){return a.call(b,c||window.event)}},False:function(){return!1},True:function(){return!0},Void:function(){}}; +if(!Function.prototype.bind)Function.prototype.bind=function(){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{newMethod:"OpenLayers.Function.bind"}));Array.prototype.unshift.apply(arguments,[this]);return OpenLayers.Function.bind.apply(null,arguments)}; +if(!Function.prototype.bindAsEventListener)Function.prototype.bindAsEventListener=function(a){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{newMethod:"OpenLayers.Function.bindAsEventListener"}));return OpenLayers.Function.bindAsEventListener(this,a)};OpenLayers.Array={filter:function(a,b,c){var d=[];if(Array.prototype.filter)d=a.filter(b,c);else{var e=a.length;if(typeof b!="function")throw new TypeError;for(var f=0;fthis.right)this.right=b.right;if(this.top==null||b.top> +this.top)this.top=b.top}}},containsLonLat:function(a,b){return this.contains(a.lon,a.lat,b)},containsPixel:function(a,b){return this.contains(a.x,a.y,b)},contains:function(a,b,c){c==null&&(c=!0);if(a==null||b==null)return!1;var a=OpenLayers.Util.toFloat(a),b=OpenLayers.Util.toFloat(b),d=!1;return d=c?a>=this.left&&a<=this.right&&b>=this.bottom&&b<=this.top:a>this.left&&athis.bottom&&b=this.bottom&&a.top<=this.top||this.top>a.bottom&&this.top=this.left&&a.left<=this.right||this.left>=a.left&&this.left<=a.right,e=a.right>=this.left&&a.right<=this.right||this.right>=a.left&&this.right<=a.right,c=(a.bottom>=this.bottom&&a.bottom<=this.top||this.bottom>=a.bottom&&this.bottom<=a.top||c)&&(d||e);return c},containsBounds:function(a,b,c){b==null&&(b=!1);c==null&&(c=!0);var d=this.contains(a.left,a.bottom, +c),e=this.contains(a.right,a.bottom,c),f=this.contains(a.left,a.top,c),a=this.contains(a.right,a.top,c);return b?d||e||f||a:d&&e&&f&&a},determineQuadrant:function(a){var b="",c=this.getCenterLonLat();b+=a.lat=a.right&&e.right>a.right;)e=e.add(-a.getWidth(),0)}return e},CLASS_NAME:"OpenLayers.Bounds"}); +OpenLayers.Bounds.fromString=function(a,b){var c=a.split(",");return OpenLayers.Bounds.fromArray(c,b)};OpenLayers.Bounds.fromArray=function(a,b){return b===!0?new OpenLayers.Bounds(parseFloat(a[1]),parseFloat(a[0]),parseFloat(a[3]),parseFloat(a[2])):new OpenLayers.Bounds(parseFloat(a[0]),parseFloat(a[1]),parseFloat(a[2]),parseFloat(a[3]))};OpenLayers.Bounds.fromSize=function(a){return new OpenLayers.Bounds(0,a.h,a.w,0)}; +OpenLayers.Bounds.oppositeQuadrant=function(a){var b="";b+=a.charAt(0)=="t"?"b":"t";b+=a.charAt(1)=="l"?"r":"l";return b}; +OpenLayers.Element={visible:function(a){return OpenLayers.Util.getElement(a).style.display!="none"},toggle:function(){for(var a=0,b=arguments.length;aa.right;)b.lon-=a.getWidth()}return b},CLASS_NAME:"OpenLayers.LonLat"}); +OpenLayers.LonLat.fromString=function(a){a=a.split(",");return new OpenLayers.LonLat(a[0],a[1])};OpenLayers.LonLat.fromArray=function(a){var b=OpenLayers.Util.isArray(a);return new OpenLayers.LonLat(b&&a[0],b&&a[1])}; +OpenLayers.Pixel=OpenLayers.Class({x:0,y:0,initialize:function(a,b){this.x=parseFloat(a);this.y=parseFloat(b)},toString:function(){return"x="+this.x+",y="+this.y},clone:function(){return new OpenLayers.Pixel(this.x,this.y)},equals:function(a){var b=!1;a!=null&&(b=this.x==a.x&&this.y==a.y||isNaN(this.x)&&isNaN(this.y)&&isNaN(a.x)&&isNaN(a.y));return b},distanceTo:function(a){return Math.sqrt(Math.pow(this.x-a.x,2)+Math.pow(this.y-a.y,2))},add:function(a,b){if(a==null||b==null){var c=OpenLayers.i18n("pixelAddError"); +OpenLayers.Console.error(c);return null}return new OpenLayers.Pixel(this.x+a,this.y+b)},offset:function(a){var b=this.clone();a&&(b=this.add(a.x,a.y));return b},CLASS_NAME:"OpenLayers.Pixel"}); +OpenLayers.Size=OpenLayers.Class({w:0,h:0,initialize:function(a,b){this.w=parseFloat(a);this.h=parseFloat(b)},toString:function(){return"w="+this.w+",h="+this.h},clone:function(){return new OpenLayers.Size(this.w,this.h)},equals:function(a){var b=!1;a!=null&&(b=this.w==a.w&&this.h==a.h||isNaN(this.w)&&isNaN(this.h)&&isNaN(a.w)&&isNaN(a.h));return b},CLASS_NAME:"OpenLayers.Size"});OpenLayers.Util=OpenLayers.Util||{}; +OpenLayers.Util.getElement=function(){for(var a=[],b=0,c=arguments.length;b=0;c--)a[c]==b&&a.splice(c,1);return a};OpenLayers.Util.clearArray=function(a){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{newMethod:"array = []"}));a.length=0};OpenLayers.Util.indexOf=function(a,b){if(typeof a.indexOf=="function")return a.indexOf(b);else{for(var c=0,d=a.length;c=0&&parseFloat(h)<1)a.style.filter="alpha(opacity="+h*100+")",a.style.opacity=h;else if(parseFloat(h)==1)a.style.filter="",a.style.opacity=""}; +OpenLayers.Util.createDiv=function(a,b,c,d,e,f,g,h){var i=document.createElement("div");if(d)i.style.backgroundImage="url("+d+")";a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="absolute");OpenLayers.Util.modifyDOMElement(i,a,b,c,e,f,g,h);return i}; +OpenLayers.Util.createImage=function(a,b,c,d,e,f,g,h){var i=document.createElement("img");a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="relative");OpenLayers.Util.modifyDOMElement(i,a,b,c,e,f,null,g);if(h)i.style.display="none",OpenLayers.Event.observe(i,"load",OpenLayers.Function.bind(OpenLayers.Util.onImageLoad,i)),OpenLayers.Event.observe(i,"error",OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError,i));i.style.alt=a;i.galleryImg="no";if(d)i.src=d;return i}; +OpenLayers.Util.setOpacity=function(a,b){OpenLayers.Util.modifyDOMElement(a,null,null,null,null,null,null,b)};OpenLayers.Util.onImageLoad=function(){if(!this.viewRequestID||this.map&&this.viewRequestID==this.map.viewRequestID)this.style.display="";OpenLayers.Element.removeClass(this,"olImageLoadError")};OpenLayers.IMAGE_RELOAD_ATTEMPTS=0; +OpenLayers.Util.onImageLoadError=function(){this._attempts=this._attempts?this._attempts+1:1;if(this._attempts<=OpenLayers.IMAGE_RELOAD_ATTEMPTS){var a=this.urls;if(a&&OpenLayers.Util.isArray(a)&&a.length>1){var b=this.src.toString(),c,d;for(d=0;c=a[d];d++)if(b.indexOf(c)!=-1)break;var e=Math.floor(a.length*Math.random()),e=a[e];for(d=0;e==c&&d++<4;)e=Math.floor(a.length*Math.random()),e=a[e];this.src=b.replace(c,e)}else this.src=this.src}else OpenLayers.Element.addClass(this,"olImageLoadError"); +this.style.display=""};OpenLayers.Util.alphaHackNeeded=null;OpenLayers.Util.alphaHack=function(){if(OpenLayers.Util.alphaHackNeeded==null){var a=navigator.appVersion.split("MSIE"),a=parseFloat(a[1]),b=!1;try{b=!!document.body.filters}catch(c){}OpenLayers.Util.alphaHackNeeded=b&&a>=5.5&&a<7}return OpenLayers.Util.alphaHackNeeded}; +OpenLayers.Util.modifyAlphaImageDiv=function(a,b,c,d,e,f,g,h,i){OpenLayers.Util.modifyDOMElement(a,b,c,d,f,null,null,i);b=a.childNodes[0];if(e)b.src=e;OpenLayers.Util.modifyDOMElement(b,a.id+"_innerImage",null,d,"relative",g);if(OpenLayers.Util.alphaHack()){if(a.style.display!="none")a.style.display="inline-block";h==null&&(h="scale");a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+b.src+"', sizingMethod='"+h+"')";parseFloat(a.style.opacity)>=0&&parseFloat(a.style.opacity)< +1&&(a.style.filter+=" alpha(opacity="+a.style.opacity*100+")");b.style.filter="alpha(opacity=0)"}}; +OpenLayers.Util.createAlphaImageDiv=function(a,b,c,d,e,f,g,h,i){var j=OpenLayers.Util.createDiv(),k=OpenLayers.Util.createImage(null,null,null,null,null,null,null,!1);j.appendChild(k);if(i)k.style.display="none",OpenLayers.Event.observe(k,"load",OpenLayers.Function.bind(OpenLayers.Util.onImageLoad,j)),OpenLayers.Event.observe(k,"error",OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError,j));OpenLayers.Util.modifyAlphaImageDiv(j,a,b,c,d,e,f,g,h);return j}; +OpenLayers.Util.upperCaseObject=function(a){var b={},c;for(c in a)b[c.toUpperCase()]=a[c];return b};OpenLayers.Util.applyDefaults=function(a,b){var a=a||{},c=typeof window.Event=="function"&&b instanceof window.Event,d;for(d in b)if(a[d]===void 0||!c&&b.hasOwnProperty&&b.hasOwnProperty(d)&&!a.hasOwnProperty(d))a[d]=b[d];if(!c&&b&&b.hasOwnProperty&&b.hasOwnProperty("toString")&&!a.hasOwnProperty("toString"))a.toString=b.toString;return a}; +OpenLayers.Util.getParameterString=function(a){var b=[],c;for(c in a){var d=a[c];if(d!=null&&typeof d!="function"){if(typeof d=="object"&&d.constructor==Array){for(var e=[],f,g=0,h=d.length;g1.0E-12&&--m>0;){var l=Math.sin(k),o=Math.cos(k),q=Math.sqrt(h*l*h*l+(g*j-i*h*o)*(g*j-i*h*o));if(q==0)return 0;var o=i*j+g*h*o,p=Math.atan2(q,o),r=Math.asin(g* +h*l/q),s=Math.cos(r)*Math.cos(r),l=o-2*i*j/s,t=c/16*s*(4+c*(4-3*s)),n=k,k=f+(1-t)*c*Math.sin(r)*(p+t*q*(l+t*o*(-1+2*l*l)))}if(m==0)return NaN;d=s*(d*d-e*e)/(e*e);c=d/1024*(256+d*(-128+d*(74-47*d)));return(e*(1+d/16384*(4096+d*(-768+d*(320-175*d))))*(p-c*q*(l+c/4*(o*(-1+2*l*l)-c/6*l*(-3+4*q*q)*(-3+4*l*l))))).toFixed(3)/1E3}; +OpenLayers.Util.destinationVincenty=function(a,b,c){for(var d=OpenLayers.Util,e=d.VincentyConstants,f=e.a,g=e.b,h=e.f,e=a.lon,a=a.lat,i=d.rad(b),b=Math.sin(i),i=Math.cos(i),a=(1-h)*Math.tan(d.rad(a)),j=1/Math.sqrt(1+a*a),k=a*j,n=Math.atan2(a,i),a=j*b,m=1-a*a,f=m*(f*f-g*g)/(g*g),l=1+f/16384*(4096+f*(-768+f*(320-175*f))),o=f/1024*(256+f*(-128+f*(74-47*f))),f=c/(g*l),q=2*Math.PI;Math.abs(f-q)>1.0E-12;)var p=Math.cos(2*n+f),r=Math.sin(f),s=Math.cos(f),t=o*r*(p+o/4*(s*(-1+2*p*p)-o/6*p*(-3+4*r*r)*(-3+4* +p*p))),q=f,f=c/(g*l)+t;c=k*r-j*s*i;g=Math.atan2(k*s+j*r*i,(1-h)*Math.sqrt(a*a+c*c));b=Math.atan2(r*b,j*s-k*r*i);i=h/16*m*(4+h*(4-3*m));p=b-(1-i)*h*a*(f+i*r*(p+i*s*(-1+2*p*p)));Math.atan2(a,-c);return new OpenLayers.LonLat(e+d.deg(p),d.deg(g))}; +OpenLayers.Util.getParameters=function(a){var a=a===null||a===void 0?window.location.href:a,b="";if(OpenLayers.String.contains(a,"?"))var b=a.indexOf("?")+1,c=OpenLayers.String.contains(a,"#")?a.indexOf("#"):a.length,b=a.substring(b,c);for(var a={},b=b.split(/[&;]/),c=0,d=b.length;c1?1/a:a};OpenLayers.Util.getResolutionFromScale=function(a,b){var c;a&&(b==null&&(b="degrees"),c=1/(OpenLayers.Util.normalizeScale(a)*OpenLayers.INCHES_PER_UNIT[b]*OpenLayers.DOTS_PER_INCH));return c}; +OpenLayers.Util.getScaleFromResolution=function(a,b){b==null&&(b="degrees");return a*OpenLayers.INCHES_PER_UNIT[b]*OpenLayers.DOTS_PER_INCH};OpenLayers.Util.safeStopPropagation=function(a){OpenLayers.Event.stop(a,!0)}; +OpenLayers.Util.pagePosition=function(a){var b=[0,0],c=OpenLayers.Util.getViewportElement();if(!a||a==window||a==c)return b;var d=OpenLayers.IS_GECKO&&document.getBoxObjectFor&&OpenLayers.Element.getStyle(a,"position")=="absolute"&&(a.style.top==""||a.style.left==""),e=null;if(a.getBoundingClientRect)a=a.getBoundingClientRect(),e=c.scrollTop,b[0]=a.left+c.scrollLeft,b[1]=a.top+e;else if(document.getBoxObjectFor&&!d)a=document.getBoxObjectFor(a),c=document.getBoxObjectFor(c),b[0]=a.screenX-c.screenX, +b[1]=a.screenY-c.screenY;else{b[0]=a.offsetLeft;b[1]=a.offsetTop;e=a.offsetParent;if(e!=a)for(;e;)b[0]+=e.offsetLeft,b[1]+=e.offsetTop,e=e.offsetParent;c=OpenLayers.BROWSER_NAME;if(c=="opera"||c=="safari"&&OpenLayers.Element.getStyle(a,"position")=="absolute")b[1]-=document.body.offsetTop;for(e=a.offsetParent;e&&e!=document.body;){b[0]-=e.scrollLeft;if(c!="opera"||e.tagName!="TR")b[1]-=e.scrollTop;e=e.offsetParent}}return b}; +OpenLayers.Util.getViewportElement=function(){var a=arguments.callee.viewportElement;if(a==void 0)a=OpenLayers.BROWSER_NAME=="msie"&&document.compatMode!="CSS1Compat"?document.body:document.documentElement,arguments.callee.viewportElement=a;return a}; +OpenLayers.Util.isEquivalentUrl=function(a,b,c){c=c||{};OpenLayers.Util.applyDefaults(c,{ignoreCase:!0,ignorePort80:!0,ignoreHash:!0});var a=OpenLayers.Util.createUrlObject(a,c),b=OpenLayers.Util.createUrlObject(b,c),d;for(d in a)if(d!=="args"&&a[d]!=b[d])return!1;for(d in a.args){if(a.args[d]!=b.args[d])return!1;delete b.args[d]}for(d in b.args)return!1;return!0}; +OpenLayers.Util.createUrlObject=function(a,b){b=b||{};if(!/^\w+:\/\//.test(a)){var c=window.location,d=c.port?":"+c.port:"",d=c.protocol+"//"+c.host.split(":").shift()+d;a.indexOf("/")===0?a=d+a:(c=c.pathname.split("/"),c.pop(),a=d+c.join("/")+"/"+a)}b.ignoreCase&&(a=a.toLowerCase());c=document.createElement("a");c.href=a;d={};d.host=c.host.split(":").shift();d.protocol=c.protocol;d.port=b.ignorePort80?c.port=="80"||c.port=="0"?"":c.port:c.port==""||c.port=="0"?"80":c.port;d.hash=b.ignoreHash||c.hash=== +"#"?"":c.hash;var e=c.search;e||(e=a.indexOf("?"),e=e!=-1?a.substr(e):"");d.args=OpenLayers.Util.getParameters(e);d.pathname=c.pathname.charAt(0)=="/"?c.pathname:"/"+c.pathname;return d};OpenLayers.Util.removeTail=function(a){var b=null,b=a.indexOf("?"),c=a.indexOf("#");return b=b==-1?c!=-1?a.substr(0,c):a:c!=-1?a.substr(0,Math.min(b,c)):a.substr(0,b)};OpenLayers.IS_GECKO=function(){var a=navigator.userAgent.toLowerCase();return a.indexOf("webkit")==-1&&a.indexOf("gecko")!=-1}(); +OpenLayers.BROWSER_NAME=function(){var a="",b=navigator.userAgent.toLowerCase();b.indexOf("opera")!=-1?a="opera":b.indexOf("msie")!=-1?a="msie":b.indexOf("safari")!=-1?a="safari":b.indexOf("mozilla")!=-1&&(a=b.indexOf("firefox")!=-1?"firefox":"mozilla");return a}();OpenLayers.Util.getBrowserName=function(){return OpenLayers.BROWSER_NAME}; +OpenLayers.Util.getRenderedDimensions=function(a,b,c){var d,e,f=document.createElement("div");f.style.visibility="hidden";var g=c&&c.containerElement?c.containerElement:document.body;if(b)if(b.w)d=b.w,f.style.width=d+"px";else if(b.h)e=b.h,f.style.height=e+"px";if(c&&c.displayClass)f.className=c.displayClass;b=document.createElement("div");b.innerHTML=a;b.style.overflow="visible";if(b.childNodes){a=0;for(c=b.childNodes.length;a=60&&(f-=60,d+=1,d>=60&&(d-=60,e+=1));e<10&&(e="0"+e);e+="\u00b0";c.indexOf("dm")>=0&&(d<10&&(d="0"+d),e+=d+"'",c.indexOf("dms")>=0&&(f<10&&(f="0"+f),e+=f+'"'));e+=b=="lon"?a<0?OpenLayers.i18n("W"):OpenLayers.i18n("E"):a<0?OpenLayers.i18n("S"):OpenLayers.i18n("N");return e}; +OpenLayers.Event={observers:!1,KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,element:function(a){return a.target||a.srcElement},isSingleTouch:function(a){return a.touches&&a.touches.length==1},isMultiTouch:function(a){return a.touches&&a.touches.length>1},isLeftClick:function(a){return a.which&&a.which==1||a.button&&a.button==1},isRightClick:function(a){return a.which&&a.which==3||a.button&&a.button==2},stop:function(a,b){if(!b)a.preventDefault? +a.preventDefault():a.returnValue=!1;a.stopPropagation?a.stopPropagation():a.cancelBubble=!0},findElement:function(a,b){for(var c=OpenLayers.Event.element(a);c.parentNode&&(!c.tagName||c.tagName.toUpperCase()!=b.toUpperCase());)c=c.parentNode;return c},observe:function(a,b,c,d){a=OpenLayers.Util.getElement(a);d=d||!1;if(b=="keypress"&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||a.attachEvent))b="keydown";if(!this.observers)this.observers={};if(!a._eventCacheID){var e="eventCacheID_";a.id&& +(e=a.id+"_"+e);a._eventCacheID=OpenLayers.Util.createUniqueID(e)}e=a._eventCacheID;this.observers[e]||(this.observers[e]=[]);this.observers[e].push({element:a,name:b,observer:c,useCapture:d});a.addEventListener?a.addEventListener(b,c,d):a.attachEvent&&a.attachEvent("on"+b,c)},stopObservingElement:function(a){a=OpenLayers.Util.getElement(a)._eventCacheID;this._removeElementObservers(OpenLayers.Event.observers[a])},_removeElementObservers:function(a){if(a)for(var b=a.length-1;b>=0;b--){var c=a[b];OpenLayers.Event.stopObserving.apply(this, +[c.element,c.name,c.observer,c.useCapture])}},stopObserving:function(a,b,c,d){var d=d||!1,a=OpenLayers.Util.getElement(a),e=a._eventCacheID;if(b=="keypress"&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||a.detachEvent))b="keydown";var f=!1,g=OpenLayers.Event.observers[e];if(g)for(var h=0;!f&&h=0;--a)this.controls[a].destroy();this.controls=null}if(this.layers!=null){for(a=this.layers.length-1;a>=0;--a)this.layers[a].destroy(!1);this.layers=null}this.viewPortDiv&&this.div.removeChild(this.viewPortDiv); +this.viewPortDiv=null;if(this.eventListeners)this.events.un(this.eventListeners),this.eventListeners=null;this.events.destroy();this.events=null},setOptions:function(a){var b=this.minPx&&a.restrictedExtent!=this.restrictedExtent;OpenLayers.Util.extend(this,a);b&&this.moveTo(this.getCachedCenter(),this.zoom,{forceZoomChange:!0})},getTileSize:function(){return this.tileSize},getBy:function(a,b,c){var d=typeof c.test=="function";return OpenLayers.Array.filter(this[a],function(a){return a[b]==c||d&&c.test(a[b])})}, +getLayersBy:function(a,b){return this.getBy("layers",a,b)},getLayersByName:function(a){return this.getLayersBy("name",a)},getLayersByClass:function(a){return this.getLayersBy("CLASS_NAME",a)},getControlsBy:function(a,b){return this.getBy("controls",a,b)},getControlsByClass:function(a){return this.getControlsBy("CLASS_NAME",a)},getLayer:function(a){for(var b=null,c=0,d=this.layers.length;cthis.layers.length)b=this.layers.length;if(c!=b){this.layers.splice(c,1);this.layers.splice(b,0,a);for(var c=0,d=this.layers.length;c=0;--c)this.removePopup(this.popups[c]); +a.map=this;this.popups.push(a);if(c=a.draw())c.style.zIndex=this.Z_INDEX_BASE.Popup+this.popups.length,this.layerContainerDiv.appendChild(c)},removePopup:function(a){OpenLayers.Util.removeItem(this.popups,a);if(a.div)try{this.layerContainerDiv.removeChild(a.div)}catch(b){}a.map=null},getSize:function(){var a=null;this.size!=null&&(a=this.size.clone());return a},updateSize:function(){var a=this.getCurrentSize();if(a&&!isNaN(a.h)&&!isNaN(a.w)){this.events.clearMouseCache();var b=this.getSize();if(b== +null)this.size=b=a;if(!a.equals(b)){this.size=a;a=0;for(b=this.layers.length;a=this.minPx.x+h?Math.round(a):0;b=f<=this.maxPx.y-i&&f>=this.minPx.y+i?Math.round(b):0;c=this.minPx.x;d=this.maxPx.x;if(a||b){if(!this.dragging)this.dragging=!0,this.events.triggerEvent("movestart");this.center=null;if(a)this.layerContainerDiv.style.left= +parseInt(this.layerContainerDiv.style.left)-a+"px",this.minPx.x-=a,this.maxPx.x-=a,g&&(this.maxPx.x>d&&(this.maxPx.x-=d-c),this.minPx.xthis.restrictedExtent.getWidth()? +a=new OpenLayers.LonLat(g.lon,a.lat):f.leftthis.restrictedExtent.right&&(a=a.add(this.restrictedExtent.right-f.right,0));f.getHeight()>this.restrictedExtent.getHeight()?a=new OpenLayers.LonLat(a.lon,g.lat):f.bottomthis.restrictedExtent.top&&(a=a.add(0,this.restrictedExtent.top-f.top))}}e=e||this.isValidZoomLevel(b)&&b!=this.getZoom(); +f=this.isValidLonLat(a)&&!a.equals(this.center);if(e||f||d){d||this.events.triggerEvent("movestart");if(f)!e&&this.center&&this.centerLayerContainer(a),this.center=a.clone();a=e?this.getResolutionForZoom(b):this.getResolution();if(e||this.layerContainerOrigin==null){this.layerContainerOrigin=this.getCachedCenter();this.layerContainerDiv.style.left="0px";this.layerContainerDiv.style.top="0px";var h=this.getMaxExtent({restricted:!0}),f=h.getCenterLonLat(),g=this.center.lon-f.lon,i=f.lat-this.center.lat, +f=Math.round(h.getWidth()/a),h=Math.round(h.getHeight()/a),g=(this.size.w-f)/2-g/a,i=(this.size.h-h)/2-i/a;this.minPx=new OpenLayers.Pixel(g,i);this.maxPx=new OpenLayers.Pixel(g+f,i+h)}if(e)this.zoom=b,this.resolution=a,this.viewRequestID++;a=this.getExtent();this.baseLayer.visibility&&(this.baseLayer.moveTo(a,e,c.dragging),c.dragging||this.baseLayer.events.triggerEvent("moveend",{zoomChanged:e}));a=this.baseLayer.getExtent();for(b=this.layers.length-1;b>=0;--b)if(f=this.layers[b],f!==this.baseLayer&& +!f.isBaseLayer){g=f.calculateInRange();if(f.inRange!=g)(f.inRange=g)||f.display(!1),this.events.triggerEvent("changelayer",{layer:f,property:"visibility"});g&&f.visibility&&(f.moveTo(a,e,c.dragging),c.dragging||f.events.triggerEvent("moveend",{zoomChanged:e}))}this.events.triggerEvent("move");d||this.events.triggerEvent("moveend");if(e){b=0;for(c=this.popups.length;b=0&&a0&&(a=this.layers[0].getResolution());return a},getUnits:function(){var a=null;if(this.baseLayer!=null)a=this.baseLayer.units;return a},getScale:function(){var a=null;this.baseLayer!=null&&(a=this.getResolution(), +a=OpenLayers.Util.getScaleFromResolution(a,this.baseLayer.units));return a},getZoomForExtent:function(a,b){var c=null;this.baseLayer!=null&&(c=this.baseLayer.getZoomForExtent(a,b));return c},getResolutionForZoom:function(a){var b=null;this.baseLayer&&(b=this.baseLayer.getResolutionForZoom(a));return b},getZoomForResolution:function(a,b){var c=null;this.baseLayer!=null&&(c=this.baseLayer.getZoomForResolution(a,b));return c},zoomTo:function(a){this.isValidZoomLevel(a)&&this.setCenter(null,a)},zoomIn:function(){this.zoomTo(this.getZoom()+ +1)},zoomOut:function(){this.zoomTo(this.getZoom()-1)},zoomToExtent:function(a,b){var c=a.getCenterLonLat();if(this.baseLayer.wrapDateLine){c=this.getMaxExtent();for(a=a.clone();a.right=0){this.initResolutions();b&&this.map.baseLayer===this&&(this.map.setCenter(this.map.getCenter(),this.map.getZoomForResolution(c),!1,!0),this.map.events.triggerEvent("changebaselayer", +{layer:this}));break}}},onMapResize:function(){},redraw:function(){var a=!1;if(this.map){this.inRange=this.calculateInRange();var b=this.getExtent();b&&this.inRange&&this.visibility&&(this.moveTo(b,!0,!1),this.events.triggerEvent("moveend",{zoomChanged:!0}),a=!0)}return a},moveTo:function(){var a=this.visibility;this.isBaseLayer||(a=a&&this.inRange);this.display(a)},moveByPx:function(){},setMap:function(a){if(this.map==null){this.map=a;this.maxExtent=this.maxExtent||this.map.maxExtent;this.minExtent= +this.minExtent||this.map.minExtent;this.projection=this.projection||this.map.projection;if(typeof this.projection=="string")this.projection=new OpenLayers.Projection(this.projection);this.units=this.projection.getUnits()||this.units||this.map.units;this.initResolutions();if(!this.isBaseLayer)this.inRange=this.calculateInRange(),this.div.style.display=this.visibility&&this.inRange?"":"none";this.setTileSize()}},afterAdd:function(){},removeMap:function(){},getImageSize:function(){return this.imageSize|| +this.tileSize},setTileSize:function(a){this.tileSize=a=a?a:this.tileSize?this.tileSize:this.map.getTileSize();if(this.gutter)this.imageOffset=new OpenLayers.Pixel(-this.gutter,-this.gutter),this.imageSize=new OpenLayers.Size(a.w+2*this.gutter,a.h+2*this.gutter)},getVisibility:function(){return this.visibility},setVisibility:function(a){if(a!=this.visibility)this.visibility=a,this.display(a),this.redraw(),this.map!=null&&this.map.events.triggerEvent("changelayer",{layer:this,property:"visibility"}), +this.events.triggerEvent("visibilitychanged")},display:function(a){if(a!=(this.div.style.display!="none"))this.div.style.display=a&&this.calculateInRange()?"block":"none"},calculateInRange:function(){var a=!1;this.alwaysInRange?a=!0:this.map&&(a=this.map.getResolution(),a=a>=this.minResolution&&a<=this.maxResolution);return a},setIsBaseLayer:function(a){if(a!=this.isBaseLayer)this.isBaseLayer=a,this.map!=null&&this.map.events.triggerEvent("changebaselayer",{layer:this})},initResolutions:function(){var a, +b,c,d={},e=!0;for(a=0,b=this.RESOLUTION_PROPERTIES.length;a=a&&(f=h,e=c),h<=a){g=h;break}c=f-g;c=c>0?e+(f-a)/c:e}else{f=Number.POSITIVE_INFINITY;for(c=0,d=this.resolutions.length;cf)break;f=e}else if(this.resolutions[c]=a.bottom-f*this.buffer||n=0&&h=0&&(i=this.grid[g][h]);i!=null&&!i.queued? +(a.unshift(i),i.queued=!0,f=0,c=g,d=h):(e=(e+1)%4,f++)}b=0;for(c=a.length;b-this.tileSize.w*(b-1)?this.shiftColumn(!0): +c.x<-this.tileSize.w*b?this.shiftColumn(!1):c.y>-this.tileSize.h*(b-1)?this.shiftRow(!0):c.y<-this.tileSize.h*b?this.shiftRow(!1):a=!1;if(a)this.timerId=window.setTimeout(this._moveGriddedTiles,0)},shiftRow:function(a){var b=this.grid,c=b[a?0:this.grid.length-1],d=this.map.getResolution(),e=a?-this.tileSize.h:this.tileSize.h;d*=-e;for(var f=a?b.pop():b.shift(),g=0,h=c.length;ga;)for(var c=this.grid.pop(),d=0,e=c.length;d +b;){d=0;for(e=this.grid.length;d=this.down.xy.distanceTo(a.xy))&&this.touch&&this.down.touches.length===this.last.touches.length)for(var a=0,c=this.down.touches.length;a< +c;++a)if(this.getTouchDistance(this.down.touches[a],this.last.touches[a])>this.pixelTolerance){b=!1;break}return b},getTouchDistance:function(a,b){return Math.sqrt(Math.pow(a.clientX-b.clientX,2)+Math.pow(a.clientY-b.clientY,2))},passesDblclickTolerance:function(){var a=!0;this.down&&this.first&&(a=this.down.xy.distanceTo(this.first.xy)<=this.dblclickTolerance);return a},clearTimer:function(){if(this.timerId!=null)window.clearTimeout(this.timerId),this.timerId=null;if(this.rightclickTimerId!=null)window.clearTimeout(this.rightclickTimerId), +this.rightclickTimerId=null},delayedCall:function(a){this.timerId=null;a&&this.callback("click",[a])},getEventInfo:function(a){var b;if(a.touches){var c=a.touches.length;b=Array(c);for(var d,e=0;ethis.nbPoints&&this.points.pop()},end:function(a){for(var b,c=(new Date).getTime(),d=0,e=this.points.length,f;dthis.delay)break;b=f}if(b&&(d=(new Date).getTime()-b.tick,c=Math.sqrt(Math.pow(a.x-b.xy.x,2)+Math.pow(a.y-b.xy.y,2)),d=c/d,!(d==0||d=0;b--)a=this.controls[b],a.events&&a.events.un({activate:this.iconOn,deactivate:this.iconOff}),OpenLayers.Event.stopObservingElement(a.panel_div), +a.panel_div=null;this.activeState=null},activate:function(){if(OpenLayers.Control.prototype.activate.apply(this,arguments)){for(var a,b=0,c=this.controls.length;b=0;a--)this.div.removeChild(this.div.childNodes[a]);this.div.innerHTML="";if(this.active)for(var a=0,b=this.controls.length;a0)this.timeoutId=setTimeout(OpenLayers.Function.bind(this.removeTimeout,this),this.interval);this.dragging=!0;this.move(a);this.callback("move",[a.xy]);if(!this.oldOnselectstart)this.oldOnselectstart= +document.onselectstart,document.onselectstart=OpenLayers.Function.False;this.last=a.xy}return!0},dragend:function(a){if(this.started){this.documentDrag===!0&&this.documentEvents&&(this.adjustXY(a),this.removeDocumentEvents());var b=this.start!=this.last;this.dragging=this.started=!1;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.up(a);this.callback("up",[a.xy]);b&&this.callback("done",[a.xy]);document.onselectstart=this.oldOnselectstart}return!0},down:function(){},move:function(){}, +up:function(){},out:function(){},mousedown:function(a){return this.dragstart(a)},touchstart:function(a){if(!this.touch)this.touch=!0,this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,mousemove:this.mousemove,click:this.click,scope:this});return this.dragstart(a)},mousemove:function(a){return this.dragmove(a)},touchmove:function(a){return this.dragmove(a)},removeTimeout:function(){this.timeoutId=null;this.dragging&&this.mousemove(this.lastMoveEvt)},mouseup:function(a){return this.dragend(a)}, +touchend:function(a){a.xy=this.last;return this.dragend(a)},mouseout:function(a){if(this.started&&OpenLayers.Util.mouseLeft(a,this.map.eventsDiv))if(this.documentDrag===!0)this.addDocumentEvents();else{var b=this.start!=this.last;this.dragging=this.started=!1;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.out(a);this.callback("out",[]);b&&this.callback("done",[a.xy]);if(document.onselectstart)document.onselectstart=this.oldOnselectstart}return!0},click:function(){return this.start== +this.last},activate:function(){var a=!1;if(OpenLayers.Handler.prototype.activate.apply(this,arguments))this.dragging=!1,a=!0;return a},deactivate:function(){var a=!1;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments))this.dragging=this.started=this.touch=!1,this.last=this.start=null,a=!0,OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");return a},adjustXY:function(a){var b=OpenLayers.Util.pagePosition(this.map.viewPortDiv);a.xy.x-=b[0];a.xy.y-=b[1]},addDocumentEvents:function(){OpenLayers.Element.addClass(document.body, +"olDragDown");this.documentEvents=!0;OpenLayers.Event.observe(document,"mousemove",this._docMove);OpenLayers.Event.observe(document,"mouseup",this._docUp)},removeDocumentEvents:function(){OpenLayers.Element.removeClass(document.body,"olDragDown");this.documentEvents=!1;OpenLayers.Event.stopObserving(document,"mousemove",this._docMove);OpenLayers.Event.stopObserving(document,"mouseup",this._docUp)},CLASS_NAME:"OpenLayers.Handler.Drag"}); +OpenLayers.Handler.Box=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,boxDivClassName:"olHandlerBoxZoomBox",boxOffsets:null,initialize:function(a,b,c){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})},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);if(this.dragHandler)this.dragHandler.destroy(),this.dragHandler= +null},setMap:function(a){OpenLayers.Handler.prototype.setMap.apply(this,arguments);this.dragHandler&&this.dragHandler.setMap(a)},startBox:function(){this.callback("start",[]);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.eventsDiv.appendChild(this.zoomBox);OpenLayers.Element.addClass(this.map.eventsDiv,"olDrawBox")},moveBox:function(a){var b=this.dragHandler.start.x, +c=this.dragHandler.start.y,d=Math.abs(b-a.x),e=Math.abs(c-a.y),f=this.getBoxOffsets();this.zoomBox.style.width=d+f.width+1+"px";this.zoomBox.style.height=e+f.height+1+"px";this.zoomBox.style.left=(a.x5||Math.abs(this.dragHandler.start.y-a.y)>5){var c=this.dragHandler.start;b=Math.min(c.y,a.y);var d=Math.max(c.y,a.y),e=Math.min(c.x,a.x),a=Math.max(c.x, +a.x);b=new OpenLayers.Bounds(e,d,a,b)}else b=this.dragHandler.start.clone();this.removeBox();this.callback("done",[b])},removeBox:function(){this.map.eventsDiv.removeChild(this.zoomBox);this.boxOffsets=this.zoomBox=null;OpenLayers.Element.removeClass(this.map.eventsDiv,"olDrawBox")},activate:function(){return OpenLayers.Handler.prototype.activate.apply(this,arguments)?(this.dragHandler.activate(),!0):!1},deactivate:function(){return OpenLayers.Handler.prototype.deactivate.apply(this,arguments)?(this.dragHandler.deactivate()&& +this.zoomBox&&this.removeBox(),!0):!1},getBoxOffsets:function(){if(!this.boxOffsets){var a=document.createElement("div");a.style.position="absolute";a.style.border="1px solid black";a.style.width="3px";document.body.appendChild(a);var b=a.clientWidth==3;document.body.removeChild(a);var a=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-left-width")),c=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-right-width")),d=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-top-width")), +e=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-bottom-width"));this.boxOffsets={left:a,right:c,top:d,bottom:e,width:b===!1?a+c:0,height:b===!1?d+e:0}}return this.boxOffsets},CLASS_NAME:"OpenLayers.Handler.Box"}); +OpenLayers.Control.ZoomBox=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,out:!1,alwaysZoom:!1,draw:function(){this.handler=new OpenLayers.Handler.Box(this,{done:this.zoomBox},{keyMask:this.keyMask})},zoomBox:function(a){if(a instanceof OpenLayers.Bounds){var b;if(this.out){b=Math.abs(a.right-a.left);var c=Math.abs(a.top-a.bottom);b=Math.min(this.map.size.h/c,this.map.size.w/b);var c=this.map.getExtent(),d=this.map.getLonLatFromPixel(a.getCenterPixel()),a=d.lon-c.getWidth()/ +2*b,e=d.lon+c.getWidth()/2*b,f=d.lat-c.getHeight()/2*b;b=d.lat+c.getHeight()/2*b;b=new OpenLayers.Bounds(a,f,e,b)}else b=this.map.getLonLatFromPixel(new OpenLayers.Pixel(a.left,a.bottom)),c=this.map.getLonLatFromPixel(new OpenLayers.Pixel(a.right,a.top)),b=new OpenLayers.Bounds(b.lon,b.lat,c.lon,c.lat);c=this.map.getZoom();this.map.zoomToExtent(b);c==this.map.getZoom()&&this.alwaysZoom==!0&&this.map.zoomTo(c+(this.out?-1:1))}else this.out?this.map.setCenter(this.map.getLonLatFromPixel(a),this.map.getZoom()- +1):this.map.setCenter(this.map.getLonLatFromPixel(a),this.map.getZoom()+1)},CLASS_NAME:"OpenLayers.Control.ZoomBox"}); +OpenLayers.Control.DragPan=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:!1,interval:1,documentDrag:!1,kinetic:null,enableKinetic:!1,kineticInterval:10,draw:function(){if(this.enableKinetic){var a={interval:this.kineticInterval};typeof this.enableKinetic==="object"&&(a=OpenLayers.Util.extend(a,this.enableKinetic));this.kinetic=new OpenLayers.Kinetic(a)}this.handler=new OpenLayers.Handler.Drag(this,{move:this.panMap,done:this.panMapDone,down:this.panMapStart},{interval:this.interval, +documentDrag:this.documentDrag})},panMapStart:function(){this.kinetic&&this.kinetic.begin()},panMap:function(a){this.kinetic&&this.kinetic.update(a);this.panned=!0;this.map.pan(this.handler.last.x-a.x,this.handler.last.y-a.y,{dragging:!0,animate:!1})},panMapDone:function(a){if(this.panned){var b=null;this.kinetic&&(b=this.kinetic.end(a));this.map.pan(this.handler.last.x-a.x,this.handler.last.y-a.y,{dragging:!!b,animate:!1});if(b){var c=this;this.kinetic.move(b,function(a,b,f){c.map.pan(a,b,{dragging:!f, +animate:!1})})}this.panned=!1}},CLASS_NAME:"OpenLayers.Control.DragPan"}); +OpenLayers.Handler.MouseWheel=OpenLayers.Class(OpenLayers.Handler,{wheelListener:null,mousePosition:null,interval:0,delta:0,cumulative:!0,initialize:function(a,b,c){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.wheelListener=OpenLayers.Function.bindAsEventListener(this.onWheelEvent,this)},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);this.wheelListener=null},onWheelEvent:function(a){if(this.map&&this.checkModifiers(a)){for(var b=!1,c=!1,d=!1,e= +OpenLayers.Event.element(a);e!=null&&!d&&!b;){if(!b)try{var f=e.currentStyle?e.currentStyle.overflow:document.defaultView.getComputedStyle(e,null).getPropertyValue("overflow"),b=f&&f=="auto"||f=="scroll"}catch(g){}if(!c)for(var d=0,h=this.map.layers.length;da.lon)b.lon<0?b.lon=-180-(b.lon+180):a.lon=180+a.lon+180;return new OpenLayers.Bounds(b.lon,a.lat,a.lon,b.lat)},CLASS_NAME:"OpenLayers.Tile"}); +OpenLayers.Tile.BackBufferable=OpenLayers.Class(OpenLayers.Tile,{backBufferMode:null,backBufferData:null,initialize:function(){OpenLayers.Tile.prototype.initialize.apply(this,arguments);this.backBufferMode=(this.layer.singleTile&&1)|(OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS,this.layer.transitionEffect)!=-1&&2);this.backBufferData={};if(!this.size)this.size=new OpenLayers.Size(256,256)},draw:function(){var a=OpenLayers.Tile.prototype.shouldDraw.apply(this,arguments);a&&this.updateBackBuffer(); +this.clear();a||this.resetBackBuffer();return a},setBackBufferData:function(){this.backBufferData=OpenLayers.Util.extend(this.backBufferData,{bounds:this.bounds,resolution:this.layer.map.getResolution()})},updateBackBuffer:function(){var a=this.layer,b=a.map,c=this.backBufferMode,d=this.backBufferData,e=this.getTile(),f=d.tile,g=d.resolution,g=g?g/b.getResolution():1,h=e&&e.parentNode!==a.div,i=!(e&&e.childNodes.length>0),j=d.tile&&!this.isLoading;if(!(g==1?c&1:c&2)||h||i||j)this.setBackBufferData(); +else{if(!f)f=this.createBackBuffer(),a.events.register("loadend",this,this.resetBackBuffer),d.tile=f,a.div.insertBefore(f,e);a=b.getPixelFromLonLat({lon:d.bounds.left,lat:d.bounds.top});c=b.layerContainerDiv.style;b=parseInt(c.left,10);c=parseInt(c.top,10);d=f.style;d.left=a.x-b+"px";d.top=a.y-c+"px";d.width=this.size.w*g+"px";d.height=this.size.h*g+"px";return f}},resetBackBuffer:function(){this.layer.events.unregister("loadend",this,this.resetBackBuffer);this.removeBackBuffer();this.setBackBufferData()}, +removeBackBuffer:function(){var a=this.backBufferData,b=a.tile;delete a.tile;a=b&&b.parentNode;b&&a.removeChild(b)},destroy:function(){this.removeBackBuffer();this.layer.events.unregister("loadend",this,this.resetBackBuffer);this.backBufferData=null;OpenLayers.Tile.prototype.destroy.apply(this,arguments)}}); +OpenLayers.Tile.Image=OpenLayers.Class(OpenLayers.Tile.BackBufferable,{url:null,imgDiv:null,frame:null,imageReloadAttempts:null,layerAlphaHack:null,asyncRequestId:null,blankImageUrl:"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7",maxGetUrlLength:null,initialize:function(a,b,c,d,e,f){OpenLayers.Tile.BackBufferable.prototype.initialize.apply(this,arguments);this.url=d;this.frame=document.createElement("div");this.frame.style.position="absolute";this.frame.style.overflow= +"hidden";this.layerAlphaHack=this.layer.alpha&&OpenLayers.Util.alphaHack();this.maxGetUrlLength!=null&&OpenLayers.Util.extend(this,OpenLayers.Tile.Image.IFrame)},destroy:function(){if(this.frame!=null)this.clear(),this.frame=this.imgDiv=null;this.asyncRequestId=null;OpenLayers.Tile.BackBufferable.prototype.destroy.apply(this,arguments)},draw:function(){var a=OpenLayers.Tile.BackBufferable.prototype.draw.apply(this,arguments);if(a){if(this.layer!=this.layer.map.baseLayer&&this.layer.reproject)this.bounds= +this.getBoundsFromBaseLayer(this.position);this.isLoading?this.events.triggerEvent("reload"):(this.isLoading=!0,this.events.triggerEvent("loadstart"));this.positionTile();this.renderTile()}else this.unload();return a},renderTile:function(){this.layer.div.appendChild(this.frame);if(this.layer.async){var a=this.asyncRequestId=(this.asyncRequestId||0)+1;this.layer.getURLasync(this.bounds,this,"url",function(){a==this.asyncRequestId&&this.initImage()})}else this.url=this.layer.getURL(this.bounds),this.initImage()}, +positionTile:function(){var a=this.frame.style;a.left=this.position.x+"px";a.top=this.position.y+"px";a.width=this.size.w+"px";a.height=this.size.h+"px"},clear:function(){var a=this.imgDiv;if(a){OpenLayers.Event.stopObservingElement(a);this.frame.parentNode===this.layer.div&&this.layer.div.removeChild(this.frame);this.setImgSrc();if(this.layerAlphaHack===!0)a.style.filter="";OpenLayers.Element.removeClass(a,"olImageLoadError")}},createImage:function(){var a=document.createElement("img");this.imgDiv= +a;a.className="olTileImage";a.galleryImg="no";var b=a.style,c=this.layer.gutter;if(c){var d=this.layer.tileSize,e=c/d.w*100,c=c/d.h*100;b.left=-e+"%";b.top=-c+"%";b.width=2*e+100+"%";b.height=2*c+100+"%";b.position="absolute"}else b.width="100%",b.height="100%";b.display="none";this.layer.opacity<1&&OpenLayers.Util.modifyDOMElement(a,null,null,null,null,null,null,this.layer.opacity);if(this.layerAlphaHack)b.paddingTop=b.height,b.height="0";this.frame.appendChild(a);return a},initImage:function(){var a= +this.imgDiv||this.createImage();if(this.url&&a.getAttribute("src")==this.url)this.onImageLoad();else{var b=OpenLayers.Function.bind(function(){OpenLayers.Event.stopObservingElement(a);OpenLayers.Event.observe(a,"load",OpenLayers.Function.bind(this.onImageLoad,this));OpenLayers.Event.observe(a,"error",OpenLayers.Function.bind(this.onImageError,this));this.imageReloadAttempts=0;this.setImgSrc(this.url)},this);a.getAttribute("src")==this.blankImageUrl?b():(OpenLayers.Event.observe(a,"load",b),OpenLayers.Event.observe(a, +"error",b),a.src=this.blankImageUrl)}},setImgSrc:function(a){var b=this.imgDiv;b.style.display="none";if(a)b.src=a},getTile:function(){return this.frame},createBackBuffer:function(){var a=this.frame.cloneNode(!1);OpenLayers.Event.stopObservingElement(this.imgDiv);a.appendChild(this.imgDiv);this.imgDiv=null;return a},onImageLoad:function(){var a=this.imgDiv;a.style.display="";this.isLoading=!1;this.events.triggerEvent("loadend");if(this.layerAlphaHack===!0)a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+ +a.src+"', sizingMethod='scale')"},onImageError:function(){var a=this.imgDiv;a.src!=null&&(this.imageReloadAttempts++,this.imageReloadAttempts<=OpenLayers.IMAGE_RELOAD_ATTEMPTS?this.setImgSrc(this.layer.getURL(this.bounds)):(OpenLayers.Element.addClass(a,"olImageLoadError"),this.onImageLoad()))},CLASS_NAME:"OpenLayers.Tile.Image"}); +OpenLayers.Layer.WMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{service:"WMS",version:"1.1.1",request:"GetMap",styles:"",format:"image/jpeg"},reproject:!1,isBaseLayer:!0,encodeBBOX:!1,noMagic:!1,yx:{"EPSG:4326":!0},initialize:function(a,b,c,d){var e=[],c=OpenLayers.Util.upperCaseObject(c);if(parseFloat(c.VERSION)>=1.3&&!c.EXCEPTIONS)c.EXCEPTIONS="INIMAGE";e.push(a,b,c,d);OpenLayers.Layer.Grid.prototype.initialize.apply(this,e);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)); +if(!this.noMagic&&this.params.TRANSPARENT&&this.params.TRANSPARENT.toString().toLowerCase()=="true"){if(d==null||!d.isBaseLayer)this.isBaseLayer=!1;if(this.params.FORMAT=="image/jpeg")this.params.FORMAT=OpenLayers.Util.alphaHack()?"image/gif":"image/png"}},destroy:function(){OpenLayers.Layer.Grid.prototype.destroy.apply(this,arguments)},clone:function(a){a==null&&(a=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this, +[a])},reverseAxisOrder:function(){return parseFloat(this.params.VERSION)>=1.3&&!!this.yx[this.map.getProjectionObject().getCode()]},getURL:function(a){var a=this.adjustBounds(a),b=this.getImageSize(),c={},d=this.reverseAxisOrder();c.BBOX=this.encodeBBOX?a.toBBOX(null,d):a.toArray(d);c.WIDTH=b.w;c.HEIGHT=b.h;return this.getFullRequestString(c)},mergeNewParams:function(a){a=[OpenLayers.Util.upperCaseObject(a)];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,a)},getFullRequestString:function(a, +b){var c=this.map.getProjectionObject(),c=this.projection&&this.projection.equals(c)?this.projection.getCode():c.getCode(),c=c=="none"?null:c;parseFloat(this.params.VERSION)>=1.3?this.params.CRS=c:this.params.SRS=c;if(typeof this.params.TRANSPARENT=="boolean")a.TRANSPARENT=this.params.TRANSPARENT?"TRUE":"FALSE";return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments)},CLASS_NAME:"OpenLayers.Layer.WMS"}); +OpenLayers.Layer.XYZ=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,sphericalMercator:!1,zoomOffset:0,serverResolutions:null,initialize:function(a,b,c){if(c&&c.sphericalMercator||this.sphericalMercator)c=OpenLayers.Util.extend({maxExtent:new OpenLayers.Bounds(-2.003750834E7,-2.003750834E7,2.003750834E7,2.003750834E7),maxResolution:156543.03390625,numZoomLevels:19,units:"m",projection:"EPSG:900913"},c);b=b||this.url;a=a||this.name;OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a,b, +{},c])},clone:function(a){a==null&&(a=new OpenLayers.Layer.XYZ(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getURL:function(a){var a=this.getXYZ(a),b=this.url;OpenLayers.Util.isArray(b)&&(b=this.selectUrl(""+a.x+a.y+a.z,b));return OpenLayers.String.format(b,a)},getXYZ:function(a){var b=this.map.getResolution(),c=Math.round((a.left-this.maxExtent.left)/(b*this.tileSize.w)),a=Math.round((this.maxExtent.top-a.top)/(b*this.tileSize.h)),b=this.serverResolutions!= +null?OpenLayers.Util.indexOf(this.serverResolutions,b):this.map.getZoom()+this.zoomOffset,d=Math.pow(2,b);this.wrapDateLine&&(c=(c%d+d)%d);return{x:c,y:a,z:b}},setMap:function(a){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"}); +OpenLayers.Layer.OSM=OpenLayers.Class(OpenLayers.Layer.XYZ,{name:"OpenStreetMap",attribution:"Data CC-By-SA by OpenStreetMap",sphericalMercator:!0,url:"http://tile.openstreetmap.org/${z}/${x}/${y}.png",clone:function(a){a==null&&(a=new OpenLayers.Layer.OSM(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.XYZ.prototype.clone.apply(this,[a])},wrapDateLine:!0,CLASS_NAME:"OpenLayers.Layer.OSM"}); +OpenLayers.Layer.Raster=OpenLayers.Class(OpenLayers.Layer,{needsUpdate:!1,initialize:function(a){var a=a||{},b=a.data;delete a.data;OpenLayers.Layer.prototype.initialize.apply(this,[a.name,a]);this.canvas=document.createElement("canvas");this.canvas.style.position="absolute";this.div.appendChild(this.canvas);this.context=this.canvas.getContext("2d");b&&this.setData(b)},setData:function(a){this.clearData();this.data=a;a.events.register("update",this,this.onDataUpdate)},clearData:function(){this.data&& +(this.data.events.unregister("update",this,this.onDataUpdate),delete this.data)},moveTo:function(){this.needsUpdate=!0;OpenLayers.Layer.prototype.moveTo.apply(this,arguments);window.setTimeout(OpenLayers.Function.bind(this.afterMoveTo,this),0)},afterMoveTo:function(){if(this.needsUpdate)this.onDataUpdate()},onDataUpdate:function(){var a=this.map;if(a){var b=a.getSize(),c=this.data.numCols(),d=this.data.numRows(),a=a.layerContainerDiv.style;this.canvas.width=c;this.canvas.height=d;this.canvas.style.top= +-parseInt(a.top)+"px";this.canvas.style.left=-parseInt(a.left)+"px";this.canvas.style.width=b.w+"px";this.canvas.style.height=b.h+"px";var b=this.context.createImageData(c,d),e=b.data;this.data.forEach(function(a,b){var c=4*b;a.length||(a=[a,a,a]);e[c+0]=a[0];e[c+1]=a[1];e[c+2]=a[2];e[c+3]=a.length>3?a[3]:255});this.context.putImageData(b,0,0);this.needsUpdate=!1}},CLASS_NAME:"OpenLayers.Layer.Raster"});OpenLayers.Rico=OpenLayers.Rico||{}; +OpenLayers.Rico.Color=OpenLayers.Class({initialize:function(a,b,c){this.rgb={r:a,g:b,b:c}},setRed:function(a){this.rgb.r=a},setGreen:function(a){this.rgb.g=a},setBlue:function(a){this.rgb.b=a},setHue:function(a){var b=this.asHSB();b.h=a;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,b.b)},setSaturation:function(a){var b=this.asHSB();b.s=a;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,b.b)},setBrightness:function(a){var b=this.asHSB();b.b=a;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,b.b)}, +darken:function(a){var b=this.asHSB();this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,Math.max(b.b-a,0))},brighten:function(a){var b=this.asHSB();this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,Math.min(b.b+a,1))},blend:function(a){this.rgb.r=Math.floor((this.rgb.r+a.rgb.r)/2);this.rgb.g=Math.floor((this.rgb.g+a.rgb.g)/2);this.rgb.b=Math.floor((this.rgb.b+a.rgb.b)/2)},isBright:function(){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(a){if(a.length==4)for(var b=a,a="#",c=1;c<4;c++)a+=b.charAt(c)+b.charAt(c);a.indexOf("#")==0&&(a=a.substring(1));b=a.substring(0,2);c=a.substring(2,4);a=a.substring(4,6);return new OpenLayers.Rico.Color(parseInt(b,16),parseInt(c,16),parseInt(a,16))}; +OpenLayers.Rico.Color.createColorFromBackground=function(a){var b=OpenLayers.Element.getStyle(OpenLayers.Util.getElement(a),"backgroundColor");if(b=="transparent"&&a.parentNode)return OpenLayers.Rico.Color.createColorFromBackground(a.parentNode);return b==null?new OpenLayers.Rico.Color(255,255,255):b.indexOf("rgb(")==0?(a=b.substring(4,b.length-1).split(","),new OpenLayers.Rico.Color(parseInt(a[0]),parseInt(a[1]),parseInt(a[2]))):b.indexOf("#")==0?OpenLayers.Rico.Color.createFromHex(b):new OpenLayers.Rico.Color(255, +255,255)}; +OpenLayers.Rico.Color.HSBtoRGB=function(a,b,c){var d=0,e=0,f=0;if(b==0)f=e=d=parseInt(c*255+0.5);else{var a=(a-Math.floor(a))*6,g=a-Math.floor(a),h=c*(1-b),i=c*(1-b*g),b=c*(1-b*(1-g));switch(parseInt(a)){case 0:d=c*255+0.5;e=b*255+0.5;f=h*255+0.5;break;case 1:d=i*255+0.5;e=c*255+0.5;f=h*255+0.5;break;case 2:d=h*255+0.5;e=c*255+0.5;f=b*255+0.5;break;case 3:d=h*255+0.5;e=i*255+0.5;f=c*255+0.5;break;case 4:d=b*255+0.5;e=h*255+0.5;f=c*255+0.5;break;case 5:d=c*255+0.5,e=h*255+0.5,f=i*255+0.5}}return{r:parseInt(d),g:parseInt(e), +b:parseInt(f)}};OpenLayers.Rico.Color.RGBtoHSB=function(a,b,c){var d,e=a>b?a:b;c>e&&(e=c);var f=a"+a.innerHTML+"
"},_roundTopCorners:function(a,b,c){for(var d=this._createCorner(c),e=0;e=0;e--)d.appendChild(this._createCornerSlice(b, +c,e,"bottom"));a.style.paddingBottom=0;a.appendChild(d)},_createCorner:function(a){var b=document.createElement("div");b.style.backgroundColor=this._isTransparent()?"transparent":a;return b},_createCornerSlice:function(a,b,c,d){var e=document.createElement("span"),f=e.style;f.backgroundColor=a;f.display="block";f.height="1px";f.overflow="hidden";f.fontSize="1px";a=this._borderColor(a,b);if(this.options.border&&c==0)f.borderTopStyle="solid",f.borderTopWidth="1px",f.borderLeftWidth="0px",f.borderRightWidth= +"0px",f.borderBottomWidth="0px",f.height="0px",f.borderColor=a;else if(a)f.borderColor=a,f.borderStyle="solid",f.borderWidth="0px 1px";if(!this.options.compact&&c==this.options.numSlices-1)f.height="2px";this._setMargin(e,c,d);this._setBorder(e,c,d);return e},_setOptions:function(a){this.options={corners:"all",color:"fromElement",bgColor:"fromParent",blend:!0,border:!1,compact:!1};OpenLayers.Util.extend(this.options,a||{});this.options.numSlices=this.options.compact?2:4;if(this._isTransparent())this.options.blend= +!1},_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(a,b){return a=="transparent"?b:this.options.border?this.options.border:this.options.blend?this._blend(b,a):""},_setMargin:function(a,b,c){b=this._marginSize(b);c=c=="top"?this._whichSideTop():this._whichSideBottom();c=="left"?(a.style.marginLeft=b+"px",a.style.marginRight="0px"):c=="right"?(a.style.marginRight=b+"px",a.style.marginLeft="0px"):(a.style.marginLeft=b+"px",a.style.marginRight=b+ +"px")},_setBorder:function(a,b,c){b=this._borderSize(b);c=c=="top"?this._whichSideTop():this._whichSideBottom();c=="left"?(a.style.borderLeftWidth=b+"px",a.style.borderRightWidth="0px"):c=="right"?(a.style.borderRightWidth=b+"px",a.style.borderLeftWidth="0px"):(a.style.borderLeftWidth=b+"px",a.style.borderRightWidth=b+"px");if(this.options.border!=!1)a.style.borderLeftWidth=b+"px",a.style.borderRightWidth=b+"px"},_marginSize:function(a){if(this._isTransparent())return 0;var b=[5,3,2,1],c=[3,2,1,0], +d=[2,1],e=[1,0];return this.options.compact&&this.options.blend?e[a]:this.options.compact?d[a]:this.options.blend?c[a]:b[a]},_borderSize:function(a){var b=[5,3,2,1],c=[2,1,1,1],d=[1,0],e=[0,2,0,0];if(this.options.compact&&(this.options.blend||this._isTransparent()))return 1;else if(this.options.compact)return d[a];else if(this.options.blend)return c[a];else if(this.options.border)return e[a];else if(this._isTransparent())return b[a];return 0},_hasString:function(a){for(var b=1;b= +0)return!0;return!1},_blend:function(a,b){var c=OpenLayers.Rico.Color.createFromHex(a);c.blend(OpenLayers.Rico.Color.createFromHex(b));return c},_background:function(a){try{return OpenLayers.Rico.Color.createColorFromBackground(a).asHex()}catch(b){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(a){return a.childNodes.length==1&&a.childNodes[0].nodeType==3}}; +OpenLayers.Control.LayerSwitcher=OpenLayers.Class(OpenLayers.Control,{roundedCorner:!0,roundedCornerColor:"darkblue",layerStates:null,layersDiv:null,baseLayersDiv:null,baseLayers:null,dataLbl:null,dataLayersDiv:null,dataLayers:null,minimizeDiv:null,maximizeDiv:null,ascending:!0,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,arguments);this.layerStates=[]},destroy:function(){OpenLayers.Event.stopObservingElement(this.div);OpenLayers.Event.stopObservingElement(this.minimizeDiv); +OpenLayers.Event.stopObservingElement(this.maximizeDiv);this.clearLayersArray("base");this.clearLayersArray("data");this.map.events.un({addlayer:this.redraw,changelayer:this.redraw,removelayer:this.redraw,changebaselayer:this.redraw,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments)},setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);this.map.events.on({addlayer:this.redraw,changelayer:this.redraw,removelayer:this.redraw,changebaselayer:this.redraw,scope:this})}, +draw:function(){OpenLayers.Control.prototype.draw.apply(this);this.loadContents();this.outsideViewport||this.minimizeControl();this.redraw();return this.div},clearLayersArray:function(a){var b=this[a+"Layers"];if(b)for(var c=0,d=b.length;c Date: Wed, 4 Apr 2012 16:14:47 -1000 Subject: [PATCH 03/36] Avoiding pink. --- examples/raster-grid-layer.js | 2 +- examples/raster-magnify.js | 2 +- examples/raster-operations.js | 2 +- examples/raster-query.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/raster-grid-layer.js b/examples/raster-grid-layer.js index 982c48ce24..e2d3709b54 100644 --- a/examples/raster-grid-layer.js +++ b/examples/raster-grid-layer.js @@ -6,7 +6,7 @@ var luminance = OpenLayers.Raster.Operation.create(function(rgba) { var marble = new OpenLayers.Layer.WMS( "Blue Marble", - "/geoserver/gwc/service/wms", + "/geoserver/wms", {layers: "topp:bluemarble", format: "image/png"} ); diff --git a/examples/raster-magnify.js b/examples/raster-magnify.js index 4b875df94e..f2c51bcfb6 100644 --- a/examples/raster-magnify.js +++ b/examples/raster-magnify.js @@ -1,6 +1,6 @@ var marble = new OpenLayers.Layer.WMS( "Blue Marble", - "/geoserver/gwc/service/wms", + "/geoserver/wms", {layers: "topp:bluemarble", format: "image/png"} ); diff --git a/examples/raster-operations.js b/examples/raster-operations.js index aa5de4c743..a9b77c8c13 100644 --- a/examples/raster-operations.js +++ b/examples/raster-operations.js @@ -74,7 +74,7 @@ var adjust = op.create(function(hsl, deltas) { var marble = new OpenLayers.Layer.WMS( "Blue Marble", - "/geoserver/gwc/service/wms", + "/geoserver/wms", {layers: "topp:bluemarble", format: "image/png"} ); diff --git a/examples/raster-query.js b/examples/raster-query.js index fb3efcde75..b29080b6da 100644 --- a/examples/raster-query.js +++ b/examples/raster-query.js @@ -2,7 +2,7 @@ var osm = new OpenLayers.Layer.OSM(); var veg = new OpenLayers.Layer.WMS( "Vegetation", - "/geoserver/gwc/service/wms", + "/geoserver/wms", {layers: "za:za_vegetation", format: "image/png8", transparent: "TRUE"}, {isBaseLayer: false, opacity: 0.5} ); From d6e2f8396d3a635cf3ee2cbd3fd5a64cfd1e6e54 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Wed, 4 Apr 2012 16:23:20 -1000 Subject: [PATCH 04/36] Example updates. --- OpenLayers.js | 589 +++++++++++++--------------------- build/raster.cfg | 5 +- examples/raster-array.js | 2 +- examples/raster-grid-layer.js | 2 +- examples/raster-magnify.js | 3 +- examples/raster-operations.js | 3 +- examples/raster-query.js | 3 +- 7 files changed, 233 insertions(+), 374 deletions(-) diff --git a/OpenLayers.js b/OpenLayers.js index d6980eb996..13cad74d98 100644 --- a/OpenLayers.js +++ b/OpenLayers.js @@ -2,47 +2,17 @@ OpenLayers.js -- OpenLayers Map Viewer Library - Copyright 2005-2011 OpenLayers Contributors, released under the FreeBSD - license. Please see http://svn.openlayers.org/trunk/openlayers/license.txt - for the full text of the license. + Copyright (c) 2006-2012 by OpenLayers Contributors + Published under the 2-clause BSD license. + See http://openlayers.org/dev/license.txt for the full text of the license, and http://openlayers.org/dev/authors.txt for full list of contributors. Includes compressed code under the following licenses: - (For uncompressed versions of the code used please see the - OpenLayers SVN repository: ) + (For uncompressed versions of the code used, please see the + OpenLayers Github repository: ) */ -/* Contains portions of Prototype.js: - * - * Prototype JavaScript framework, version 1.4.0 - * (c) 2005 Sam Stephenson - * - * Prototype is freely distributable under the terms of an MIT-style license. - * For details, see the Prototype web site: http://prototype.conio.net/ - * - *--------------------------------------------------------------------------*/ - -/** -* -* Contains portions of Rico -* -* Copyright 2005 Sabre Airline Solutions -* -* Licensed under the Apache License, Version 2.0 (the "License"); you -* may not use this file except in compliance with the License. You -* may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -* implied. See the License for the specific language governing -* permissions and limitations under the License. -* -**/ - /** * Contains XMLHttpRequest.js * Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com) @@ -53,44 +23,6 @@ * http://www.apache.org/licenses/LICENSE-2.0 */ -/** - * Contains portions of Gears - * - * Copyright 2007, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. 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. - * 3. Neither the name of Google Inc. nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. - * - * Sets up google.gears.*, which is *the only* supported way to access Gears. - * - * Circumvent this file at your own risk! - * - * In the future, Gears may automatically define google.gears.* without this - * file. Gears may use these objects to transparently fix bugs and compatibility - * 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. @@ -122,312 +54,243 @@ * 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. - */var OpenLayers={VERSION_NUMBER:"$Revision$",singleFile:!0,_getScriptLocation:function(){for(var a=/(^|(.*?\/))(OpenLayers.js)(\?|$)/,b=document.getElementsByTagName("script"),c,d="",e=0,f=b.length;e1?(a=[d,b].concat(Array.prototype.slice.call(arguments).slice(1,a-1),c),OpenLayers.inherit.apply(null,a)):d.prototype=c;return d};OpenLayers.Class.isPrototype=function(){};OpenLayers.Class.create=function(){return function(){arguments&&arguments[0]!=OpenLayers.Class.isPrototype&&this.initialize.apply(this,arguments)}}; -OpenLayers.Class.inherit=function(a){var b=function(){a.call(this)},c=[b].concat(Array.prototype.slice.call(arguments));OpenLayers.inherit.apply(null,c);return b.prototype};OpenLayers.inherit=function(a,b){var c=function(){};c.prototype=b.prototype;a.prototype=new c;var d,e;for(c=2,d=arguments.length;cthis.duration&&this.stop()},CLASS_NAME:"OpenLayers.Tween"});OpenLayers.Easing={CLASS_NAME:"OpenLayers.Easing"};OpenLayers.Easing.Linear={easeIn:function(a,b,c,d){return c*a/d+b},easeOut:function(a,b,c,d){return c*a/d+b},easeInOut:function(a,b,c,d){return c*a/d+b},CLASS_NAME:"OpenLayers.Easing.Linear"}; -OpenLayers.Easing.Expo={easeIn:function(a,b,c,d){return a==0?b:c*Math.pow(2,10*(a/d-1))+b},easeOut:function(a,b,c,d){return a==d?b+c:c*(-Math.pow(2,-10*a/d)+1)+b},easeInOut:function(a,b,c,d){return a==0?b:a==d?b+c:(a/=d/2)<1?c/2*Math.pow(2,10*(a-1))+b:c/2*(-Math.pow(2,-10*--a)+2)+b},CLASS_NAME:"OpenLayers.Easing.Expo"}; -OpenLayers.Easing.Quad={easeIn:function(a,b,c,d){return c*(a/=d)*a+b},easeOut:function(a,b,c,d){return-c*(a/=d)*(a-2)+b},easeInOut:function(a,b,c,d){return(a/=d/2)<1?c/2*a*a+b:-c/2*(--a*(a-2)-1)+b},CLASS_NAME:"OpenLayers.Easing.Quad"}; -OpenLayers.Raster.Grid=OpenLayers.Class({EVENT_TYPES:["update"],initialize:function(a){OpenLayers.Util.extend(this,a);this.events=new OpenLayers.Events(this,null,this.EVENT_TYPES)},getValue:function(){throw Error("getValue must be defined");},numCols:function(){throw Error("numCols must be defined");},numRows:function(){throw Error("numRows must be defined");},forEach:function(a){for(var b=this.numCols(),c=this.numRows(),d=0;d=this.getCount())throw Error("Bad grid index.");var c=this;return new OpenLayers.Raster.Grid({numCols:function(){return c.numCols()},numRows:function(){return c.numRows()},getValue:function(d,e){return c.getValue(d,e)[a]}})},CLASS_NAME:"OpenLayers.Raster.Composite"}}()); -OpenLayers.Raster.Composite.fromLayer=function(a){var b;function c(){b=void 0;var c=a.map,h=a.tileSize,i=c.getSize();d.width=i.w;d.height=i.h;for(var i=c.getExtent(),j=a.grid,k,n,m,l=0,o=j.length;lthis.duration&&this.stop()},CLASS_NAME:"OpenLayers.Tween"});OpenLayers.Easing={CLASS_NAME:"OpenLayers.Easing"};OpenLayers.Easing.Linear={easeIn:function(a,b,c,d){return c*a/d+b},easeOut:function(a,b,c,d){return c*a/d+b},easeInOut:function(a,b,c,d){return c*a/d+b},CLASS_NAME:"OpenLayers.Easing.Linear"}; +OpenLayers.Easing.Expo={easeIn:function(a,b,c,d){return 0==a?b:c*Math.pow(2,10*(a/d-1))+b},easeOut:function(a,b,c,d){return a==d?b+c:c*(-Math.pow(2,-10*a/d)+1)+b},easeInOut:function(a,b,c,d){return 0==a?b:a==d?b+c:1>(a/=d/2)?c/2*Math.pow(2,10*(a-1))+b:c/2*(-Math.pow(2,-10*--a)+2)+b},CLASS_NAME:"OpenLayers.Easing.Expo"}; +OpenLayers.Easing.Quad={easeIn:function(a,b,c,d){return c*(a/=d)*a+b},easeOut:function(a,b,c,d){return-c*(a/=d)*(a-2)+b},easeInOut:function(a,b,c,d){return 1>(a/=d/2)?c/2*a*a+b:-c/2*(--a*(a-2)-1)+b},CLASS_NAME:"OpenLayers.Easing.Quad"};OpenLayers.Raster.Grid=OpenLayers.Class({EVENT_TYPES:["update"],initialize:function(a){OpenLayers.Util.extend(this,a);this.events=new OpenLayers.Events(this,null,this.EVENT_TYPES)},getValue:function(){throw Error("getValue must be defined");},numCols:function(){throw Error("numCols must be defined");},numRows:function(){throw Error("numRows must be defined");},forEach:function(a){for(var b=this.numCols(),c=this.numRows(),d=0;da||a>=this.getCount())throw Error("Bad grid index.");var c=this;return new OpenLayers.Raster.Grid({numCols:function(){return c.numCols()},numRows:function(){return c.numRows()},getValue:function(d,e){return c.getValue(d,e)[a]}})},CLASS_NAME:"OpenLayers.Raster.Composite"}}()); +OpenLayers.Raster.Composite.fromLayer=function(a){var b;function c(){b=void 0;var c=a.map,h=a.tileSize,i=c.getSize();d.width=i.w;d.height=i.h;for(var i=c.getExtent(),j=a.grid,o,q,l,k=0,p=j.length;k1?b:a)({numCols:function(){return e().numCols()},numRows:function(){return e().numRows()}, -getValue:function(b,e){for(var h=Array(g),i,j=0;j0&&(c=parseFloat(a.toPrecision(b)));return c},format:function(a,b,c,d){b=typeof b!="undefined"?b:0;c=typeof c!="undefined"?c:OpenLayers.Number.thousandsSeparator;d=typeof d!="undefined"?d:OpenLayers.Number.decimalSeparator;b!=null&&(a=parseFloat(a.toFixed(b)));var e=a.toString().split(".");e.length==1&&b==null&&(b=0);a=e[0];if(c)for(var f=/(-?[0-9]+)([0-9]{3})/;f.test(a);)a=a.replace(f,"$1"+c+"$2"); -b==0?b=a:(c=e.length>1?e[1]:"0",b!=null&&(c+=Array(b-c.length+1).join("0")),b=a+d+c);return b}};if(!Number.prototype.limitSigDigs)Number.prototype.limitSigDigs=function(a){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{newMethod:"OpenLayers.Number.limitSigDigs"}));return OpenLayers.Number.limitSigDigs(this,a)}; -OpenLayers.Function={bind:function(a,b){var c=Array.prototype.slice.apply(arguments,[2]);return function(){var d=c.concat(Array.prototype.slice.apply(arguments,[0]));return a.apply(b,d)}},bindAsEventListener:function(a,b){return function(c){return a.call(b,c||window.event)}},False:function(){return!1},True:function(){return!0},Void:function(){}}; -if(!Function.prototype.bind)Function.prototype.bind=function(){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{newMethod:"OpenLayers.Function.bind"}));Array.prototype.unshift.apply(arguments,[this]);return OpenLayers.Function.bind.apply(null,arguments)}; -if(!Function.prototype.bindAsEventListener)Function.prototype.bindAsEventListener=function(a){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{newMethod:"OpenLayers.Function.bindAsEventListener"}));return OpenLayers.Function.bindAsEventListener(this,a)};OpenLayers.Array={filter:function(a,b,c){var d=[];if(Array.prototype.filter)d=a.filter(b,c);else{var e=a.length;if(typeof b!="function")throw new TypeError;for(var f=0;fthis.right)this.right=b.right;if(this.top==null||b.top> -this.top)this.top=b.top}}},containsLonLat:function(a,b){return this.contains(a.lon,a.lat,b)},containsPixel:function(a,b){return this.contains(a.x,a.y,b)},contains:function(a,b,c){c==null&&(c=!0);if(a==null||b==null)return!1;var a=OpenLayers.Util.toFloat(a),b=OpenLayers.Util.toFloat(b),d=!1;return d=c?a>=this.left&&a<=this.right&&b>=this.bottom&&b<=this.top:a>this.left&&athis.bottom&&b=this.bottom&&a.top<=this.top||this.top>a.bottom&&this.top=this.left&&a.left<=this.right||this.left>=a.left&&this.left<=a.right,e=a.right>=this.left&&a.right<=this.right||this.right>=a.left&&this.right<=a.right,c=(a.bottom>=this.bottom&&a.bottom<=this.top||this.bottom>=a.bottom&&this.bottom<=a.top||c)&&(d||e);return c},containsBounds:function(a,b,c){b==null&&(b=!1);c==null&&(c=!0);var d=this.contains(a.left,a.bottom, -c),e=this.contains(a.right,a.bottom,c),f=this.contains(a.left,a.top,c),a=this.contains(a.right,a.top,c);return b?d||e||f||a:d&&e&&f&&a},determineQuadrant:function(a){var b="",c=this.getCenterLonLat();b+=a.lat=a.right&&e.right>a.right;)e=e.add(-a.getWidth(),0)}return e},CLASS_NAME:"OpenLayers.Bounds"}); -OpenLayers.Bounds.fromString=function(a,b){var c=a.split(",");return OpenLayers.Bounds.fromArray(c,b)};OpenLayers.Bounds.fromArray=function(a,b){return b===!0?new OpenLayers.Bounds(parseFloat(a[1]),parseFloat(a[0]),parseFloat(a[3]),parseFloat(a[2])):new OpenLayers.Bounds(parseFloat(a[0]),parseFloat(a[1]),parseFloat(a[2]),parseFloat(a[3]))};OpenLayers.Bounds.fromSize=function(a){return new OpenLayers.Bounds(0,a.h,a.w,0)}; -OpenLayers.Bounds.oppositeQuadrant=function(a){var b="";b+=a.charAt(0)=="t"?"b":"t";b+=a.charAt(1)=="l"?"r":"l";return b}; -OpenLayers.Element={visible:function(a){return OpenLayers.Util.getElement(a).style.display!="none"},toggle:function(){for(var a=0,b=arguments.length;aa.right;)b.lon-=a.getWidth()}return b},CLASS_NAME:"OpenLayers.LonLat"}); -OpenLayers.LonLat.fromString=function(a){a=a.split(",");return new OpenLayers.LonLat(a[0],a[1])};OpenLayers.LonLat.fromArray=function(a){var b=OpenLayers.Util.isArray(a);return new OpenLayers.LonLat(b&&a[0],b&&a[1])}; -OpenLayers.Pixel=OpenLayers.Class({x:0,y:0,initialize:function(a,b){this.x=parseFloat(a);this.y=parseFloat(b)},toString:function(){return"x="+this.x+",y="+this.y},clone:function(){return new OpenLayers.Pixel(this.x,this.y)},equals:function(a){var b=!1;a!=null&&(b=this.x==a.x&&this.y==a.y||isNaN(this.x)&&isNaN(this.y)&&isNaN(a.x)&&isNaN(a.y));return b},distanceTo:function(a){return Math.sqrt(Math.pow(this.x-a.x,2)+Math.pow(this.y-a.y,2))},add:function(a,b){if(a==null||b==null){var c=OpenLayers.i18n("pixelAddError"); -OpenLayers.Console.error(c);return null}return new OpenLayers.Pixel(this.x+a,this.y+b)},offset:function(a){var b=this.clone();a&&(b=this.add(a.x,a.y));return b},CLASS_NAME:"OpenLayers.Pixel"}); -OpenLayers.Size=OpenLayers.Class({w:0,h:0,initialize:function(a,b){this.w=parseFloat(a);this.h=parseFloat(b)},toString:function(){return"w="+this.w+",h="+this.h},clone:function(){return new OpenLayers.Size(this.w,this.h)},equals:function(a){var b=!1;a!=null&&(b=this.w==a.w&&this.h==a.h||isNaN(this.w)&&isNaN(this.h)&&isNaN(a.w)&&isNaN(a.h));return b},CLASS_NAME:"OpenLayers.Size"});OpenLayers.Util=OpenLayers.Util||{}; -OpenLayers.Util.getElement=function(){for(var a=[],b=0,c=arguments.length;b=0;c--)a[c]==b&&a.splice(c,1);return a};OpenLayers.Util.clearArray=function(a){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{newMethod:"array = []"}));a.length=0};OpenLayers.Util.indexOf=function(a,b){if(typeof a.indexOf=="function")return a.indexOf(b);else{for(var c=0,d=a.length;c=0&&parseFloat(h)<1)a.style.filter="alpha(opacity="+h*100+")",a.style.opacity=h;else if(parseFloat(h)==1)a.style.filter="",a.style.opacity=""}; +null,c);return f};OpenLayers.Raster.Operation=function(){var a=OpenLayers.Raster.Grid,b=OpenLayers.Raster.Composite,c={};return{create:function(c){return function(){function e(){for(var b,c=0;cthis.right)this.right=b.right;if(null==this.top||b.top>this.top)this.top=b.top}}},containsLonLat:function(a,b){"boolean"===typeof b&&(b={inclusive:b});var b=b||{},c=this.contains(a.lon,a.lat,b.inclusive),d=b.worldBounds;d&&!c&&(c=d.getWidth(),d=Math.round((a.lon-(d.left+d.right)/2)/c),c=this.containsLonLat({lon:a.lon-d*c,lat:a.lat},{inclusive:b.inclusive}));return c},containsPixel:function(a,b){return this.contains(a.x, +a.y,b)},contains:function(a,b,c){null==c&&(c=!0);if(null==a||null==b)return!1;var a=OpenLayers.Util.toFloat(a),b=OpenLayers.Util.toFloat(b),d=!1;return d=c?a>=this.left&&a<=this.right&&b>=this.bottom&&b<=this.top:a>this.left&&athis.bottom&&b=c.bottom&&a.top<=c.top||c.top>a.bottom&&c.top=c.left&&a.left<=c.right||c.left>=a.left&&c.left<=a.right,f=a.right>=c.left&&a.right<=c.right||c.right>=a.left&&c.right<=a.right,d=(a.bottom>=c.bottom&&a.bottom<=c.top||c.bottom>=a.bottom&&c.bottom<=a.top||d)&&(e||f);if(b.worldBounds&&!d){var g=b.worldBounds,e=g.getWidth(),f=!g.containsBounds(c),g=!g.containsBounds(a);f&&!g?(a=a.add(-e,0),d=c.intersectsBounds(a, +{inclusive:b.inclusive})):g&&!f&&(c=c.add(-e,0),d=a.intersectsBounds(c,{inclusive:b.inclusive}))}return d},containsBounds:function(a,b,c){null==b&&(b=!1);null==c&&(c=!0);var d=this.contains(a.left,a.bottom,c),e=this.contains(a.right,a.bottom,c),f=this.contains(a.left,a.top,c),a=this.contains(a.right,a.top,c);return b?d||e||f||a:d&&e&&f&&a},determineQuadrant:function(a){var b="",c=this.getCenterLonLat(),b=b+(a.lat=a.right&&e.right>a.right;)e=e.add(-f,0);c=e.left+c;ca.left&&e.right-d>a.right&&(e=e.add(-f,0))}return e},CLASS_NAME:"OpenLayers.Bounds"});OpenLayers.Bounds.fromString=function(a,b){var c=a.split(",");return OpenLayers.Bounds.fromArray(c,b)};OpenLayers.Bounds.fromArray=function(a,b){return!0===b?new OpenLayers.Bounds(a[1],a[0],a[3],a[2]):new OpenLayers.Bounds(a[0],a[1],a[2],a[3])}; +OpenLayers.Bounds.fromSize=function(a){return new OpenLayers.Bounds(0,a.h,a.w,0)};OpenLayers.Bounds.oppositeQuadrant=function(a){var b;b=""+("t"==a.charAt(0)?"b":"t");return b+="l"==a.charAt(1)?"r":"l"};OpenLayers.Element={visible:function(a){return"none"!=OpenLayers.Util.getElement(a).style.display},toggle:function(){for(var a=0,b=arguments.length;aa.right;)b.lon-=a.getWidth()}return b},CLASS_NAME:"OpenLayers.LonLat"}); +OpenLayers.LonLat.fromString=function(a){a=a.split(",");return new OpenLayers.LonLat(a[0],a[1])};OpenLayers.LonLat.fromArray=function(a){var b=OpenLayers.Util.isArray(a);return new OpenLayers.LonLat(b&&a[0],b&&a[1])};OpenLayers.Pixel=OpenLayers.Class({x:0,y:0,initialize:function(a,b){this.x=parseFloat(a);this.y=parseFloat(b)},toString:function(){return"x="+this.x+",y="+this.y},clone:function(){return new OpenLayers.Pixel(this.x,this.y)},equals:function(a){var b=!1;null!=a&&(b=this.x==a.x&&this.y==a.y||isNaN(this.x)&&isNaN(this.y)&&isNaN(a.x)&&isNaN(a.y));return b},distanceTo:function(a){return Math.sqrt(Math.pow(this.x-a.x,2)+Math.pow(this.y-a.y,2))},add:function(a,b){if(null==a||null==b)throw new TypeError("Pixel.add cannot receive null values"); +return new OpenLayers.Pixel(this.x+a,this.y+b)},offset:function(a){var b=this.clone();a&&(b=this.add(a.x,a.y));return b},CLASS_NAME:"OpenLayers.Pixel"});OpenLayers.Size=OpenLayers.Class({w:0,h:0,initialize:function(a,b){this.w=parseFloat(a);this.h=parseFloat(b)},toString:function(){return"w="+this.w+",h="+this.h},clone:function(){return new OpenLayers.Size(this.w,this.h)},equals:function(a){var b=!1;null!=a&&(b=this.w==a.w&&this.h==a.h||isNaN(this.w)&&isNaN(this.h)&&isNaN(a.w)&&isNaN(a.h));return b},CLASS_NAME:"OpenLayers.Size"});OpenLayers.Console={log:function(){},debug:function(){},info:function(){},warn:function(){},error:function(){},userError:function(a){alert(a)},assert:function(){},dir:function(){},dirxml:function(){},trace:function(){},group:function(){},groupEnd:function(){},time:function(){},timeEnd:function(){},profile:function(){},profileEnd:function(){},count:function(){},CLASS_NAME:"OpenLayers.Console"}; +(function(){for(var a=document.getElementsByTagName("script"),b=0,c=a.length;bparseFloat(h))a.style.filter="alpha(opacity="+100*h+")",a.style.opacity=h;else if(1==parseFloat(h))a.style.filter="",a.style.opacity=""}; OpenLayers.Util.createDiv=function(a,b,c,d,e,f,g,h){var i=document.createElement("div");if(d)i.style.backgroundImage="url("+d+")";a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="absolute");OpenLayers.Util.modifyDOMElement(i,a,b,c,e,f,g,h);return i}; -OpenLayers.Util.createImage=function(a,b,c,d,e,f,g,h){var i=document.createElement("img");a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="relative");OpenLayers.Util.modifyDOMElement(i,a,b,c,e,f,null,g);if(h)i.style.display="none",OpenLayers.Event.observe(i,"load",OpenLayers.Function.bind(OpenLayers.Util.onImageLoad,i)),OpenLayers.Event.observe(i,"error",OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError,i));i.style.alt=a;i.galleryImg="no";if(d)i.src=d;return i}; -OpenLayers.Util.setOpacity=function(a,b){OpenLayers.Util.modifyDOMElement(a,null,null,null,null,null,null,b)};OpenLayers.Util.onImageLoad=function(){if(!this.viewRequestID||this.map&&this.viewRequestID==this.map.viewRequestID)this.style.display="";OpenLayers.Element.removeClass(this,"olImageLoadError")};OpenLayers.IMAGE_RELOAD_ATTEMPTS=0; -OpenLayers.Util.onImageLoadError=function(){this._attempts=this._attempts?this._attempts+1:1;if(this._attempts<=OpenLayers.IMAGE_RELOAD_ATTEMPTS){var a=this.urls;if(a&&OpenLayers.Util.isArray(a)&&a.length>1){var b=this.src.toString(),c,d;for(d=0;c=a[d];d++)if(b.indexOf(c)!=-1)break;var e=Math.floor(a.length*Math.random()),e=a[e];for(d=0;e==c&&d++<4;)e=Math.floor(a.length*Math.random()),e=a[e];this.src=b.replace(c,e)}else this.src=this.src}else OpenLayers.Element.addClass(this,"olImageLoadError"); -this.style.display=""};OpenLayers.Util.alphaHackNeeded=null;OpenLayers.Util.alphaHack=function(){if(OpenLayers.Util.alphaHackNeeded==null){var a=navigator.appVersion.split("MSIE"),a=parseFloat(a[1]),b=!1;try{b=!!document.body.filters}catch(c){}OpenLayers.Util.alphaHackNeeded=b&&a>=5.5&&a<7}return OpenLayers.Util.alphaHackNeeded}; -OpenLayers.Util.modifyAlphaImageDiv=function(a,b,c,d,e,f,g,h,i){OpenLayers.Util.modifyDOMElement(a,b,c,d,f,null,null,i);b=a.childNodes[0];if(e)b.src=e;OpenLayers.Util.modifyDOMElement(b,a.id+"_innerImage",null,d,"relative",g);if(OpenLayers.Util.alphaHack()){if(a.style.display!="none")a.style.display="inline-block";h==null&&(h="scale");a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+b.src+"', sizingMethod='"+h+"')";parseFloat(a.style.opacity)>=0&&parseFloat(a.style.opacity)< -1&&(a.style.filter+=" alpha(opacity="+a.style.opacity*100+")");b.style.filter="alpha(opacity=0)"}}; -OpenLayers.Util.createAlphaImageDiv=function(a,b,c,d,e,f,g,h,i){var j=OpenLayers.Util.createDiv(),k=OpenLayers.Util.createImage(null,null,null,null,null,null,null,!1);j.appendChild(k);if(i)k.style.display="none",OpenLayers.Event.observe(k,"load",OpenLayers.Function.bind(OpenLayers.Util.onImageLoad,j)),OpenLayers.Event.observe(k,"error",OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError,j));OpenLayers.Util.modifyAlphaImageDiv(j,a,b,c,d,e,f,g,h);return j}; -OpenLayers.Util.upperCaseObject=function(a){var b={},c;for(c in a)b[c.toUpperCase()]=a[c];return b};OpenLayers.Util.applyDefaults=function(a,b){var a=a||{},c=typeof window.Event=="function"&&b instanceof window.Event,d;for(d in b)if(a[d]===void 0||!c&&b.hasOwnProperty&&b.hasOwnProperty(d)&&!a.hasOwnProperty(d))a[d]=b[d];if(!c&&b&&b.hasOwnProperty&&b.hasOwnProperty("toString")&&!a.hasOwnProperty("toString"))a.toString=b.toString;return a}; -OpenLayers.Util.getParameterString=function(a){var b=[],c;for(c in a){var d=a[c];if(d!=null&&typeof d!="function"){if(typeof d=="object"&&d.constructor==Array){for(var e=[],f,g=0,h=d.length;g1.0E-12&&--m>0;){var l=Math.sin(k),o=Math.cos(k),q=Math.sqrt(h*l*h*l+(g*j-i*h*o)*(g*j-i*h*o));if(q==0)return 0;var o=i*j+g*h*o,p=Math.atan2(q,o),r=Math.asin(g* -h*l/q),s=Math.cos(r)*Math.cos(r),l=o-2*i*j/s,t=c/16*s*(4+c*(4-3*s)),n=k,k=f+(1-t)*c*Math.sin(r)*(p+t*q*(l+t*o*(-1+2*l*l)))}if(m==0)return NaN;d=s*(d*d-e*e)/(e*e);c=d/1024*(256+d*(-128+d*(74-47*d)));return(e*(1+d/16384*(4096+d*(-768+d*(320-175*d))))*(p-c*q*(l+c/4*(o*(-1+2*l*l)-c/6*l*(-3+4*q*q)*(-3+4*l*l))))).toFixed(3)/1E3}; -OpenLayers.Util.destinationVincenty=function(a,b,c){for(var d=OpenLayers.Util,e=d.VincentyConstants,f=e.a,g=e.b,h=e.f,e=a.lon,a=a.lat,i=d.rad(b),b=Math.sin(i),i=Math.cos(i),a=(1-h)*Math.tan(d.rad(a)),j=1/Math.sqrt(1+a*a),k=a*j,n=Math.atan2(a,i),a=j*b,m=1-a*a,f=m*(f*f-g*g)/(g*g),l=1+f/16384*(4096+f*(-768+f*(320-175*f))),o=f/1024*(256+f*(-128+f*(74-47*f))),f=c/(g*l),q=2*Math.PI;Math.abs(f-q)>1.0E-12;)var p=Math.cos(2*n+f),r=Math.sin(f),s=Math.cos(f),t=o*r*(p+o/4*(s*(-1+2*p*p)-o/6*p*(-3+4*r*r)*(-3+4* -p*p))),q=f,f=c/(g*l)+t;c=k*r-j*s*i;g=Math.atan2(k*s+j*r*i,(1-h)*Math.sqrt(a*a+c*c));b=Math.atan2(r*b,j*s-k*r*i);i=h/16*m*(4+h*(4-3*m));p=b-(1-i)*h*a*(f+i*r*(p+i*s*(-1+2*p*p)));Math.atan2(a,-c);return new OpenLayers.LonLat(e+d.deg(p),d.deg(g))}; -OpenLayers.Util.getParameters=function(a){var a=a===null||a===void 0?window.location.href:a,b="";if(OpenLayers.String.contains(a,"?"))var b=a.indexOf("?")+1,c=OpenLayers.String.contains(a,"#")?a.indexOf("#"):a.length,b=a.substring(b,c);for(var a={},b=b.split(/[&;]/),c=0,d=b.length;ca}return OpenLayers.Util.alphaHackNeeded}; +OpenLayers.Util.modifyAlphaImageDiv=function(a,b,c,d,e,f,g,h,i){OpenLayers.Util.modifyDOMElement(a,b,c,d,f,null,null,i);b=a.childNodes[0];if(e)b.src=e;OpenLayers.Util.modifyDOMElement(b,a.id+"_innerImage",null,d,"relative",g);if(OpenLayers.Util.alphaHack()){if("none"!=a.style.display)a.style.display="inline-block";null==h&&(h="scale");a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+b.src+"', sizingMethod='"+h+"')";0<=parseFloat(a.style.opacity)&&1>parseFloat(a.style.opacity)&& +(a.style.filter+=" alpha(opacity="+100*a.style.opacity+")");b.style.filter="alpha(opacity=0)"}};OpenLayers.Util.createAlphaImageDiv=function(a,b,c,d,e,f,g,h,i){var j=OpenLayers.Util.createDiv(),i=OpenLayers.Util.createImage(null,null,null,null,null,null,null,i);i.className="olAlphaImg";j.appendChild(i);OpenLayers.Util.modifyAlphaImageDiv(j,a,b,c,d,e,f,g,h);return j};OpenLayers.Util.upperCaseObject=function(a){var b={},c;for(c in a)b[c.toUpperCase()]=a[c];return b}; +OpenLayers.Util.applyDefaults=function(a,b){var a=a||{},c="function"==typeof window.Event&&b instanceof window.Event,d;for(d in b)if(void 0===a[d]||!c&&b.hasOwnProperty&&b.hasOwnProperty(d)&&!a.hasOwnProperty(d))a[d]=b[d];if(!c&&b&&b.hasOwnProperty&&b.hasOwnProperty("toString")&&!a.hasOwnProperty("toString"))a.toString=b.toString;return a}; +OpenLayers.Util.getParameterString=function(a){var b=[],c;for(c in a){var d=a[c];if(null!=d&&"function"!=typeof d){if("object"==typeof d&&d.constructor==Array){for(var e=[],f,g=0,h=d.length;g1?1/a:a};OpenLayers.Util.getResolutionFromScale=function(a,b){var c;a&&(b==null&&(b="degrees"),c=1/(OpenLayers.Util.normalizeScale(a)*OpenLayers.INCHES_PER_UNIT[b]*OpenLayers.DOTS_PER_INCH));return c}; -OpenLayers.Util.getScaleFromResolution=function(a,b){b==null&&(b="degrees");return a*OpenLayers.INCHES_PER_UNIT[b]*OpenLayers.DOTS_PER_INCH};OpenLayers.Util.safeStopPropagation=function(a){OpenLayers.Event.stop(a,!0)}; -OpenLayers.Util.pagePosition=function(a){var b=[0,0],c=OpenLayers.Util.getViewportElement();if(!a||a==window||a==c)return b;var d=OpenLayers.IS_GECKO&&document.getBoxObjectFor&&OpenLayers.Element.getStyle(a,"position")=="absolute"&&(a.style.top==""||a.style.left==""),e=null;if(a.getBoundingClientRect)a=a.getBoundingClientRect(),e=c.scrollTop,b[0]=a.left+c.scrollLeft,b[1]=a.top+e;else if(document.getBoxObjectFor&&!d)a=document.getBoxObjectFor(a),c=document.getBoxObjectFor(c),b[0]=a.screenX-c.screenX, -b[1]=a.screenY-c.screenY;else{b[0]=a.offsetLeft;b[1]=a.offsetTop;e=a.offsetParent;if(e!=a)for(;e;)b[0]+=e.offsetLeft,b[1]+=e.offsetTop,e=e.offsetParent;c=OpenLayers.BROWSER_NAME;if(c=="opera"||c=="safari"&&OpenLayers.Element.getStyle(a,"position")=="absolute")b[1]-=document.body.offsetTop;for(e=a.offsetParent;e&&e!=document.body;){b[0]-=e.scrollLeft;if(c!="opera"||e.tagName!="TR")b[1]-=e.scrollTop;e=e.offsetParent}}return b}; -OpenLayers.Util.getViewportElement=function(){var a=arguments.callee.viewportElement;if(a==void 0)a=OpenLayers.BROWSER_NAME=="msie"&&document.compatMode!="CSS1Compat"?document.body:document.documentElement,arguments.callee.viewportElement=a;return a}; -OpenLayers.Util.isEquivalentUrl=function(a,b,c){c=c||{};OpenLayers.Util.applyDefaults(c,{ignoreCase:!0,ignorePort80:!0,ignoreHash:!0});var a=OpenLayers.Util.createUrlObject(a,c),b=OpenLayers.Util.createUrlObject(b,c),d;for(d in a)if(d!=="args"&&a[d]!=b[d])return!1;for(d in a.args){if(a.args[d]!=b.args[d])return!1;delete b.args[d]}for(d in b.args)return!1;return!0}; -OpenLayers.Util.createUrlObject=function(a,b){b=b||{};if(!/^\w+:\/\//.test(a)){var c=window.location,d=c.port?":"+c.port:"",d=c.protocol+"//"+c.host.split(":").shift()+d;a.indexOf("/")===0?a=d+a:(c=c.pathname.split("/"),c.pop(),a=d+c.join("/")+"/"+a)}b.ignoreCase&&(a=a.toLowerCase());c=document.createElement("a");c.href=a;d={};d.host=c.host.split(":").shift();d.protocol=c.protocol;d.port=b.ignorePort80?c.port=="80"||c.port=="0"?"":c.port:c.port==""||c.port=="0"?"80":c.port;d.hash=b.ignoreHash||c.hash=== -"#"?"":c.hash;var e=c.search;e||(e=a.indexOf("?"),e=e!=-1?a.substr(e):"");d.args=OpenLayers.Util.getParameters(e);d.pathname=c.pathname.charAt(0)=="/"?c.pathname:"/"+c.pathname;return d};OpenLayers.Util.removeTail=function(a){var b=null,b=a.indexOf("?"),c=a.indexOf("#");return b=b==-1?c!=-1?a.substr(0,c):a:c!=-1?a.substr(0,Math.min(b,c)):a.substr(0,b)};OpenLayers.IS_GECKO=function(){var a=navigator.userAgent.toLowerCase();return a.indexOf("webkit")==-1&&a.indexOf("gecko")!=-1}(); -OpenLayers.BROWSER_NAME=function(){var a="",b=navigator.userAgent.toLowerCase();b.indexOf("opera")!=-1?a="opera":b.indexOf("msie")!=-1?a="msie":b.indexOf("safari")!=-1?a="safari":b.indexOf("mozilla")!=-1&&(a=b.indexOf("firefox")!=-1?"firefox":"mozilla");return a}();OpenLayers.Util.getBrowserName=function(){return OpenLayers.BROWSER_NAME}; +OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT,{mm:OpenLayers.INCHES_PER_UNIT.Meter/1E3,cm:OpenLayers.INCHES_PER_UNIT.Meter/100,dm:100*OpenLayers.INCHES_PER_UNIT.Meter,km:1E3*OpenLayers.INCHES_PER_UNIT.Meter,kmi:OpenLayers.INCHES_PER_UNIT.nmi,fath:OpenLayers.INCHES_PER_UNIT.Fathom,ch:OpenLayers.INCHES_PER_UNIT.IntnlChain,link:OpenLayers.INCHES_PER_UNIT.IntnlLink,"us-in":OpenLayers.INCHES_PER_UNIT.inches,"us-ft":OpenLayers.INCHES_PER_UNIT.Foot,"us-yd":OpenLayers.INCHES_PER_UNIT.Yard,"us-ch":OpenLayers.INCHES_PER_UNIT.GunterChain, +"us-mi":OpenLayers.INCHES_PER_UNIT.Mile,"ind-yd":OpenLayers.INCHES_PER_UNIT.IndianYd37,"ind-ft":OpenLayers.INCHES_PER_UNIT.IndianFt37,"ind-ch":20.11669506/OpenLayers.METERS_PER_INCH});OpenLayers.DOTS_PER_INCH=72;OpenLayers.Util.normalizeScale=function(a){return 1=60&&(f-=60,d+=1,d>=60&&(d-=60,e+=1));e<10&&(e="0"+e);e+="\u00b0";c.indexOf("dm")>=0&&(d<10&&(d="0"+d),e+=d+"'",c.indexOf("dms")>=0&&(f<10&&(f="0"+f),e+=f+'"'));e+=b=="lon"?a<0?OpenLayers.i18n("W"):OpenLayers.i18n("E"):a<0?OpenLayers.i18n("S"):OpenLayers.i18n("N");return e}; -OpenLayers.Event={observers:!1,KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,element:function(a){return a.target||a.srcElement},isSingleTouch:function(a){return a.touches&&a.touches.length==1},isMultiTouch:function(a){return a.touches&&a.touches.length>1},isLeftClick:function(a){return a.which&&a.which==1||a.button&&a.button==1},isRightClick:function(a){return a.which&&a.which==3||a.button&&a.button==2},stop:function(a,b){if(!b)a.preventDefault? -a.preventDefault():a.returnValue=!1;a.stopPropagation?a.stopPropagation():a.cancelBubble=!0},findElement:function(a,b){for(var c=OpenLayers.Event.element(a);c.parentNode&&(!c.tagName||c.tagName.toUpperCase()!=b.toUpperCase());)c=c.parentNode;return c},observe:function(a,b,c,d){a=OpenLayers.Util.getElement(a);d=d||!1;if(b=="keypress"&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||a.attachEvent))b="keydown";if(!this.observers)this.observers={};if(!a._eventCacheID){var e="eventCacheID_";a.id&& -(e=a.id+"_"+e);a._eventCacheID=OpenLayers.Util.createUniqueID(e)}e=a._eventCacheID;this.observers[e]||(this.observers[e]=[]);this.observers[e].push({element:a,name:b,observer:c,useCapture:d});a.addEventListener?a.addEventListener(b,c,d):a.attachEvent&&a.attachEvent("on"+b,c)},stopObservingElement:function(a){a=OpenLayers.Util.getElement(a)._eventCacheID;this._removeElementObservers(OpenLayers.Event.observers[a])},_removeElementObservers:function(a){if(a)for(var b=a.length-1;b>=0;b--){var c=a[b];OpenLayers.Event.stopObserving.apply(this, -[c.element,c.name,c.observer,c.useCapture])}},stopObserving:function(a,b,c,d){var d=d||!1,a=OpenLayers.Util.getElement(a),e=a._eventCacheID;if(b=="keypress"&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||a.detachEvent))b="keydown";var f=!1,g=OpenLayers.Event.observers[e];if(g)for(var h=0;!f&&h=0;--a)this.controls[a].destroy();this.controls=null}if(this.layers!=null){for(a=this.layers.length-1;a>=0;--a)this.layers[a].destroy(!1);this.layers=null}this.viewPortDiv&&this.div.removeChild(this.viewPortDiv); -this.viewPortDiv=null;if(this.eventListeners)this.events.un(this.eventListeners),this.eventListeners=null;this.events.destroy();this.events=null},setOptions:function(a){var b=this.minPx&&a.restrictedExtent!=this.restrictedExtent;OpenLayers.Util.extend(this,a);b&&this.moveTo(this.getCachedCenter(),this.zoom,{forceZoomChange:!0})},getTileSize:function(){return this.tileSize},getBy:function(a,b,c){var d=typeof c.test=="function";return OpenLayers.Array.filter(this[a],function(a){return a[b]==c||d&&c.test(a[b])})}, -getLayersBy:function(a,b){return this.getBy("layers",a,b)},getLayersByName:function(a){return this.getLayersBy("name",a)},getLayersByClass:function(a){return this.getLayersBy("CLASS_NAME",a)},getControlsBy:function(a,b){return this.getBy("controls",a,b)},getControlsByClass:function(a){return this.getControlsBy("CLASS_NAME",a)},getLayer:function(a){for(var b=null,c=0,d=this.layers.length;cthis.layers.length)b=this.layers.length;if(c!=b){this.layers.splice(c,1);this.layers.splice(b,0,a);for(var c=0,d=this.layers.length;c=0;--c)this.removePopup(this.popups[c]); -a.map=this;this.popups.push(a);if(c=a.draw())c.style.zIndex=this.Z_INDEX_BASE.Popup+this.popups.length,this.layerContainerDiv.appendChild(c)},removePopup:function(a){OpenLayers.Util.removeItem(this.popups,a);if(a.div)try{this.layerContainerDiv.removeChild(a.div)}catch(b){}a.map=null},getSize:function(){var a=null;this.size!=null&&(a=this.size.clone());return a},updateSize:function(){var a=this.getCurrentSize();if(a&&!isNaN(a.h)&&!isNaN(a.w)){this.events.clearMouseCache();var b=this.getSize();if(b== -null)this.size=b=a;if(!a.equals(b)){this.size=a;a=0;for(b=this.layers.length;a=this.minPx.x+h?Math.round(a):0;b=f<=this.maxPx.y-i&&f>=this.minPx.y+i?Math.round(b):0;c=this.minPx.x;d=this.maxPx.x;if(a||b){if(!this.dragging)this.dragging=!0,this.events.triggerEvent("movestart");this.center=null;if(a)this.layerContainerDiv.style.left= -parseInt(this.layerContainerDiv.style.left)-a+"px",this.minPx.x-=a,this.maxPx.x-=a,g&&(this.maxPx.x>d&&(this.maxPx.x-=d-c),this.minPx.xthis.restrictedExtent.getWidth()? -a=new OpenLayers.LonLat(g.lon,a.lat):f.leftthis.restrictedExtent.right&&(a=a.add(this.restrictedExtent.right-f.right,0));f.getHeight()>this.restrictedExtent.getHeight()?a=new OpenLayers.LonLat(a.lon,g.lat):f.bottomthis.restrictedExtent.top&&(a=a.add(0,this.restrictedExtent.top-f.top))}}e=e||this.isValidZoomLevel(b)&&b!=this.getZoom(); -f=this.isValidLonLat(a)&&!a.equals(this.center);if(e||f||d){d||this.events.triggerEvent("movestart");if(f)!e&&this.center&&this.centerLayerContainer(a),this.center=a.clone();a=e?this.getResolutionForZoom(b):this.getResolution();if(e||this.layerContainerOrigin==null){this.layerContainerOrigin=this.getCachedCenter();this.layerContainerDiv.style.left="0px";this.layerContainerDiv.style.top="0px";var h=this.getMaxExtent({restricted:!0}),f=h.getCenterLonLat(),g=this.center.lon-f.lon,i=f.lat-this.center.lat, -f=Math.round(h.getWidth()/a),h=Math.round(h.getHeight()/a),g=(this.size.w-f)/2-g/a,i=(this.size.h-h)/2-i/a;this.minPx=new OpenLayers.Pixel(g,i);this.maxPx=new OpenLayers.Pixel(g+f,i+h)}if(e)this.zoom=b,this.resolution=a,this.viewRequestID++;a=this.getExtent();this.baseLayer.visibility&&(this.baseLayer.moveTo(a,e,c.dragging),c.dragging||this.baseLayer.events.triggerEvent("moveend",{zoomChanged:e}));a=this.baseLayer.getExtent();for(b=this.layers.length-1;b>=0;--b)if(f=this.layers[b],f!==this.baseLayer&& -!f.isBaseLayer){g=f.calculateInRange();if(f.inRange!=g)(f.inRange=g)||f.display(!1),this.events.triggerEvent("changelayer",{layer:f,property:"visibility"});g&&f.visibility&&(f.moveTo(a,e,c.dragging),c.dragging||f.events.triggerEvent("moveend",{zoomChanged:e}))}this.events.triggerEvent("move");d||this.events.triggerEvent("moveend");if(e){b=0;for(c=this.popups.length;b=0&&a0&&(a=this.layers[0].getResolution());return a},getUnits:function(){var a=null;if(this.baseLayer!=null)a=this.baseLayer.units;return a},getScale:function(){var a=null;this.baseLayer!=null&&(a=this.getResolution(), -a=OpenLayers.Util.getScaleFromResolution(a,this.baseLayer.units));return a},getZoomForExtent:function(a,b){var c=null;this.baseLayer!=null&&(c=this.baseLayer.getZoomForExtent(a,b));return c},getResolutionForZoom:function(a){var b=null;this.baseLayer&&(b=this.baseLayer.getResolutionForZoom(a));return b},getZoomForResolution:function(a,b){var c=null;this.baseLayer!=null&&(c=this.baseLayer.getZoomForResolution(a,b));return c},zoomTo:function(a){this.isValidZoomLevel(a)&&this.setCenter(null,a)},zoomIn:function(){this.zoomTo(this.getZoom()+ -1)},zoomOut:function(){this.zoomTo(this.getZoom()-1)},zoomToExtent:function(a,b){var c=a.getCenterLonLat();if(this.baseLayer.wrapDateLine){c=this.getMaxExtent();for(a=a.clone();a.right=0){this.initResolutions();b&&this.map.baseLayer===this&&(this.map.setCenter(this.map.getCenter(),this.map.getZoomForResolution(c),!1,!0),this.map.events.triggerEvent("changebaselayer", -{layer:this}));break}}},onMapResize:function(){},redraw:function(){var a=!1;if(this.map){this.inRange=this.calculateInRange();var b=this.getExtent();b&&this.inRange&&this.visibility&&(this.moveTo(b,!0,!1),this.events.triggerEvent("moveend",{zoomChanged:!0}),a=!0)}return a},moveTo:function(){var a=this.visibility;this.isBaseLayer||(a=a&&this.inRange);this.display(a)},moveByPx:function(){},setMap:function(a){if(this.map==null){this.map=a;this.maxExtent=this.maxExtent||this.map.maxExtent;this.minExtent= -this.minExtent||this.map.minExtent;this.projection=this.projection||this.map.projection;if(typeof this.projection=="string")this.projection=new OpenLayers.Projection(this.projection);this.units=this.projection.getUnits()||this.units||this.map.units;this.initResolutions();if(!this.isBaseLayer)this.inRange=this.calculateInRange(),this.div.style.display=this.visibility&&this.inRange?"":"none";this.setTileSize()}},afterAdd:function(){},removeMap:function(){},getImageSize:function(){return this.imageSize|| -this.tileSize},setTileSize:function(a){this.tileSize=a=a?a:this.tileSize?this.tileSize:this.map.getTileSize();if(this.gutter)this.imageOffset=new OpenLayers.Pixel(-this.gutter,-this.gutter),this.imageSize=new OpenLayers.Size(a.w+2*this.gutter,a.h+2*this.gutter)},getVisibility:function(){return this.visibility},setVisibility:function(a){if(a!=this.visibility)this.visibility=a,this.display(a),this.redraw(),this.map!=null&&this.map.events.triggerEvent("changelayer",{layer:this,property:"visibility"}), -this.events.triggerEvent("visibilitychanged")},display:function(a){if(a!=(this.div.style.display!="none"))this.div.style.display=a&&this.calculateInRange()?"block":"none"},calculateInRange:function(){var a=!1;this.alwaysInRange?a=!0:this.map&&(a=this.map.getResolution(),a=a>=this.minResolution&&a<=this.maxResolution);return a},setIsBaseLayer:function(a){if(a!=this.isBaseLayer)this.isBaseLayer=a,this.map!=null&&this.map.events.triggerEvent("changebaselayer",{layer:this})},initResolutions:function(){var a, -b,c,d={},e=!0;for(a=0,b=this.RESOLUTION_PROPERTIES.length;a=a&&(f=h,e=c),h<=a){g=h;break}c=f-g;c=c>0?e+(f-a)/c:e}else{f=Number.POSITIVE_INFINITY;for(c=0,d=this.resolutions.length;cf)break;f=e}else if(this.resolutions[c]=a.bottom-f*this.buffer||n=0&&h=0&&(i=this.grid[g][h]);i!=null&&!i.queued? -(a.unshift(i),i.queued=!0,f=0,c=g,d=h):(e=(e+1)%4,f++)}b=0;for(c=a.length;b-this.tileSize.w*(b-1)?this.shiftColumn(!0): -c.x<-this.tileSize.w*b?this.shiftColumn(!1):c.y>-this.tileSize.h*(b-1)?this.shiftRow(!0):c.y<-this.tileSize.h*b?this.shiftRow(!1):a=!1;if(a)this.timerId=window.setTimeout(this._moveGriddedTiles,0)},shiftRow:function(a){var b=this.grid,c=b[a?0:this.grid.length-1],d=this.map.getResolution(),e=a?-this.tileSize.h:this.tileSize.h;d*=-e;for(var f=a?b.pop():b.shift(),g=0,h=c.length;ga;)for(var c=this.grid.pop(),d=0,e=c.length;d -b;){d=0;for(e=this.grid.length;de&&(e="0"+e);e+="\u00b0";0<=c.indexOf("dm")&&(10>d&&(d="0"+d),e+=d+"'",0<=c.indexOf("dms")&&(10>f&&(f="0"+f),e+=f+'"'));return e="lon"==b?e+(0>a?OpenLayers.i18n("W"):OpenLayers.i18n("E")):e+(0>a?OpenLayers.i18n("S"):OpenLayers.i18n("N"))};OpenLayers.Event={observers:!1,KEY_SPACE:32,KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,element:function(a){return a.target||a.srcElement},isSingleTouch:function(a){return a.touches&&1==a.touches.length},isMultiTouch:function(a){return a.touches&&1b)b=0;else if(b>this.layers.length)b=this.layers.length;if(c!=b){this.layers.splice(c,1);this.layers.splice(b,0,a);for(var c=0,d=this.layers.length;c=this.minPx.x+h?Math.round(a):0;b=f<=this.maxPx.y-i&&f>=this.minPx.y+i?Math.round(b):0;if(a||b){if(!this.dragging)this.dragging=!0,this.events.triggerEvent("movestart"); +this.center=null;if(a)this.layerContainerDiv.style.left=parseInt(this.layerContainerDiv.style.left)-a+"px",this.minPx.x-=a,this.maxPx.x-=a;if(b)this.layerContainerDiv.style.top=parseInt(this.layerContainerDiv.style.top)-b+"px",this.minPx.y-=b,this.maxPx.y-=b;for(d=0,e=this.layers.length;dc)for(var d=a|0,e=b.length;dthis.restrictedExtent.getWidth()?a=new OpenLayers.LonLat(g.lon,a.lat):f.leftthis.restrictedExtent.right&&(a=a.add(this.restrictedExtent.right- +f.right,0));f.getHeight()>this.restrictedExtent.getHeight()?a=new OpenLayers.LonLat(a.lon,g.lat):f.bottomthis.restrictedExtent.top&&(a=a.add(0,this.restrictedExtent.top-f.top))}}e=e||this.isValidZoomLevel(b)&&b!=this.getZoom();f=this.isValidLonLat(a)&&!a.equals(this.center);if(e||f||d){d||this.events.triggerEvent("movestart");if(f)!e&&this.center&&this.centerLayerContainer(a),this.center=a.clone();a=e?this.getResolutionForZoom(b): +this.getResolution();if(e||null==this.layerContainerOrigin){this.layerContainerOrigin=this.getCachedCenter();this.layerContainerDiv.style.left="0px";this.layerContainerDiv.style.top="0px";var f=this.getMaxExtent({restricted:!0}),h=f.getCenterLonLat(),g=this.center.lon-h.lon,h=h.lat-this.center.lat,i=Math.round(f.getWidth()/a),j=Math.round(f.getHeight()/a);this.minPx={x:(this.size.w-i)/2-g/a,y:(this.size.h-j)/2-h/a};this.maxPx={x:this.minPx.x+Math.round(f.getWidth()/a),y:this.minPx.y+Math.round(f.getHeight()/ +a)}}if(e)this.zoom=b,this.resolution=a;a=this.getExtent();this.baseLayer.visibility&&(this.baseLayer.moveTo(a,e,c.dragging),c.dragging||this.baseLayer.events.triggerEvent("moveend",{zoomChanged:e}));a=this.baseLayer.getExtent();for(b=this.layers.length-1;0<=b;--b)if(f=this.layers[b],f!==this.baseLayer&&!f.isBaseLayer){g=f.calculateInRange();if(f.inRange!=g)(f.inRange=g)||f.display(!1),this.events.triggerEvent("changelayer",{layer:f,property:"visibility"});g&&f.visibility&&(f.moveTo(a,e,c.dragging), +c.dragging||f.events.triggerEvent("moveend",{zoomChanged:e}))}this.events.triggerEvent("move");d||this.events.triggerEvent("moveend");if(e){b=0;for(c=this.popups.length;b=this.minResolution&&a<=this.maxResolution);return a},setIsBaseLayer:function(a){if(a!=this.isBaseLayer)this.isBaseLayer= +a,null!=this.map&&this.map.events.triggerEvent("changebaselayer",{layer:this})},initResolutions:function(){var a,b,c,d={},e=!0;for(a=0,b=this.RESOLUTION_PROPERTIES.length;a=a||"number"!==typeof d&&"number"!==typeof c)){b=Array(a);var e=2;"number"==typeof c&&"number"==typeof d&&(e=Math.pow(d/c,1/(a-1)));var f;if("number"===typeof d)for(f=0;f=a&&(f=h,e=c),h<=a){g=h;break}c=f-g;c=0f)break;f=e}else if(this.resolutions[c]this.layer.opacity)a.filter="alpha(opacity="+100*this.layer.opacity+")";a.position="absolute";if(this.layerAlphaHack)a.paddingTop= +a.height,a.height="0",a.width="100%";if(this.frame)a.width="100%",a.height="100%",this.frame.appendChild(this.imgDiv)}return this.imgDiv},initImage:function(){this.events.triggerEvent(this._loadEvent);var a=this.getImage();if(this.url&&a.getAttribute("src")==this.url)this.onImageLoad();else{var b=OpenLayers.Function.bind(function(){OpenLayers.Event.stopObservingElement(a);OpenLayers.Event.observe(a,"load",OpenLayers.Function.bind(this.onImageLoad,this));OpenLayers.Event.observe(a,"error",OpenLayers.Function.bind(this.onImageError, +this));this.imageReloadAttempts=0;this.setImgSrc(this.url)},this);a.getAttribute("src")==this.blankImageUrl?b():(OpenLayers.Event.observe(a,"load",b),OpenLayers.Event.observe(a,"error",b),this.crossOriginKeyword&&a.removeAttribute("crossorigin"),a.src=this.blankImageUrl)}},setImgSrc:function(a){var b=this.imgDiv;b.style.visibility="hidden";b.style.opacity=0;if(a)this.crossOriginKeyword&&("data:"!==a.substr(0,5)?b.setAttribute("crossorigin",this.crossOriginKeyword):b.removeAttribute("crossorigin")), +b.src=a},getTile:function(){return this.frame?this.frame:this.getImage()},createBackBuffer:function(){if(this.imgDiv&&!this.isLoading){var a;this.frame?(a=this.frame.cloneNode(!1),a.appendChild(this.imgDiv)):a=this.imgDiv;this.imgDiv=null;return a}},onImageLoad:function(){var a=this.imgDiv;OpenLayers.Event.stopObservingElement(a);a.style.visibility="inherit";a.style.opacity=this.layer.opacity;this.isLoading=!1;this.canvasContext=null;this.events.triggerEvent("loadend");if(7>parseFloat(navigator.appVersion.split("MSIE")[1])&& +this.layer&&this.layer.div){var b=document.createElement("span");b.style.display="none";var c=this.layer.div;c.appendChild(b);window.setTimeout(function(){b.parentNode===c&&b.parentNode.removeChild(b)},0)}if(!0===this.layerAlphaHack)a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+a.src+"', sizingMethod='scale')"},onImageError:function(){var a=this.imgDiv;null!=a.src&&(this.imageReloadAttempts++,this.imageReloadAttempts<=OpenLayers.IMAGE_RELOAD_ATTEMPTS?this.setImgSrc(this.layer.getURL(this.bounds)): +(OpenLayers.Element.addClass(a,"olImageLoadError"),this.events.triggerEvent("loaderror"),this.onImageLoad()))},getCanvasContext:function(){if(OpenLayers.CANVAS_SUPPORTED&&this.imgDiv&&!this.isLoading){if(!this.canvasContext){var a=document.createElement("canvas");a.width=this.size.w;a.height=this.size.h;this.canvasContext=a.getContext("2d");this.canvasContext.drawImage(this.imgDiv,0,0)}return this.canvasContext}},CLASS_NAME:"OpenLayers.Tile.Image"});OpenLayers.Layer.Grid=OpenLayers.Class(OpenLayers.Layer.HTTPRequest,{tileSize:null,tileOriginCorner:"bl",tileOrigin:null,tileOptions:null,tileClass:OpenLayers.Tile.Image,grid:null,singleTile:!1,ratio:1.5,buffer:0,transitionEffect:null,numLoadingTiles:0,tileLoadingDelay:85,serverResolutions:null,moveTimerId:null,deferMoveGriddedTiles:null,tileQueueId:null,tileQueue:null,loading:!1,backBuffer:null,gridResolution:null,backBufferResolution:null,backBufferLonLat:null,backBufferTimerId:null,removeBackBufferDelay:null, +className:null,initialize:function(a,b,c,d){OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,arguments);this.grid=[];this.tileQueue=[];if(null===this.removeBackBufferDelay)this.removeBackBufferDelay=this.singleTile?0:2500;if(null===this.className)this.className=this.singleTile?"olLayerGridSingleTile":"olLayerGrid";if(!OpenLayers.Animation.isNative)this.deferMoveGriddedTiles=OpenLayers.Function.bind(function(){this.moveGriddedTiles(!0);this.moveTimerId=null},this)},setMap:function(a){OpenLayers.Layer.HTTPRequest.prototype.setMap.call(this, +a);OpenLayers.Element.addClass(this.div,this.className)},removeMap:function(){if(null!==this.moveTimerId)window.clearTimeout(this.moveTimerId),this.moveTimerId=null;this.clearTileQueue();if(null!==this.backBufferTimerId)window.clearTimeout(this.backBufferTimerId),this.backBufferTimerId=null},destroy:function(){this.removeBackBuffer();this.clearGrid();this.tileSize=this.grid=null;OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this,arguments)},clearGrid:function(){this.clearTileQueue();if(this.grid){for(var a= +0,b=this.grid.length;aa){a=c;break}if(-1===b)throw"no appropriate resolution in serverResolutions";}return a},getServerZoom:function(){return this.map.getZoomForResolution(this.getServerResolution())},transformDiv:function(a){this.div.style.width=100*a+"%";this.div.style.height=100*a+"%";var b=this.map.getSize(),c=parseInt(this.map.layerContainerDiv.style.left,10),d=(parseInt(this.map.layerContainerDiv.style.top,10)-b.h/2)*(a-1);this.div.style.left=(c-b.w/2)*(a-1)+"%";this.div.style.top= +d+"%"},getResolutionScale:function(){return parseInt(this.div.style.width,10)/100},applyBackBuffer:function(a){null!==this.backBufferTimerId&&this.removeBackBuffer();var b=this.backBuffer;if(!b){b=this.createBackBuffer();if(!b)return;this.div.insertBefore(b,this.div.firstChild);this.backBuffer=b;var c=this.grid[0][0].bounds;this.backBufferLonLat={lon:c.left,lat:c.top};this.backBufferResolution=this.gridResolution}var c=b.style,d=this.backBufferResolution/a;c.width=100*d+"%";c.height=100*d+"%";a=this.getViewPortPxFromLonLat(this.backBufferLonLat, +a);c=parseInt(this.map.layerContainerDiv.style.left,10);d=parseInt(this.map.layerContainerDiv.style.top,10);b.style.left=Math.round(a.x-c)+"%";b.style.top=Math.round(a.y-d)+"%"},createBackBuffer:function(){var a;if(0=a.bottom-j*this.buffer||l-e*(a-1))this.shiftColumn(!0);else if(c<-e*a)this.shiftColumn(!1);else if(d>-f*(a-1))this.shiftRow(!0);else if(d<-f*a)this.shiftRow(!1);else break}},shiftRow:function(a){for(var b=this.grid,c=b[a?0:this.grid.length-1],d=this.getServerResolution(),e=a?-this.tileSize.h:this.tileSize.h,d=d*-e,f=a?b.pop():b.shift(),g=0,h=c.length;ga;)for(var c=this.grid.pop(),d=0,e=c.length;d +b;){d=0;for(e=this.grid.length;d=this.down.xy.distanceTo(a.xy))&&this.touch&&this.down.touches.length===this.last.touches.length)for(var a=0,c=this.down.touches.length;a< -c;++a)if(this.getTouchDistance(this.down.touches[a],this.last.touches[a])>this.pixelTolerance){b=!1;break}return b},getTouchDistance:function(a,b){return Math.sqrt(Math.pow(a.clientX-b.clientX,2)+Math.pow(a.clientY-b.clientY,2))},passesDblclickTolerance:function(){var a=!0;this.down&&this.first&&(a=this.down.xy.distanceTo(this.first.xy)<=this.dblclickTolerance);return a},clearTimer:function(){if(this.timerId!=null)window.clearTimeout(this.timerId),this.timerId=null;if(this.rightclickTimerId!=null)window.clearTimeout(this.rightclickTimerId), -this.rightclickTimerId=null},delayedCall:function(a){this.timerId=null;a&&this.callback("click",[a])},getEventInfo:function(a){var b;if(a.touches){var c=a.touches.length;b=Array(c);for(var d,e=0;ethis.nbPoints&&this.points.pop()},end:function(a){for(var b,c=(new Date).getTime(),d=0,e=this.points.length,f;dthis.delay)break;b=f}if(b&&(d=(new Date).getTime()-b.tick,c=Math.sqrt(Math.pow(a.x-b.xy.x,2)+Math.pow(a.y-b.xy.y,2)),d=c/d,!(d==0||d=0;b--)a=this.controls[b],a.events&&a.events.un({activate:this.iconOn,deactivate:this.iconOff}),OpenLayers.Event.stopObservingElement(a.panel_div), -a.panel_div=null;this.activeState=null},activate:function(){if(OpenLayers.Control.prototype.activate.apply(this,arguments)){for(var a,b=0,c=this.controls.length;b=0;a--)this.div.removeChild(this.div.childNodes[a]);this.div.innerHTML="";if(this.active)for(var a=0,b=this.controls.length;a=this.down.xy.distanceTo(a.xy))&&this.touch&&this.down.touches.length===this.last.touches.length)for(var a=0,c=this.down.touches.length;athis.pixelTolerance){b= +!1;break}return b},getTouchDistance:function(a,b){return Math.sqrt(Math.pow(a.clientX-b.clientX,2)+Math.pow(a.clientY-b.clientY,2))},passesDblclickTolerance:function(){var a=!0;this.down&&this.first&&(a=this.down.xy.distanceTo(this.first.xy)<=this.dblclickTolerance);return a},clearTimer:function(){if(null!=this.timerId)window.clearTimeout(this.timerId),this.timerId=null;if(null!=this.rightclickTimerId)window.clearTimeout(this.rightclickTimerId),this.rightclickTimerId=null},delayedCall:function(a){this.timerId= +null;a&&this.callback("click",[a])},getEventInfo:function(a){var b;if(a.touches){var c=a.touches.length;b=Array(c);for(var d,e=0;ethis.nbPoints&&this.points.pop()},end:function(a){for(var b,c=(new Date).getTime(),d=0,e=this.points.length,f;dthis.delay)break;b=f}if(b&&(d=(new Date).getTime()-b.tick,c=Math.sqrt(Math.pow(a.x-b.xy.x,2)+Math.pow(a.y-b.xy.y,2)),d=c/d,!(0==d||d=-this.deceleration*a+c)OpenLayers.Animation.stop(this.timerId),this.timerId=null,q=!0;a=o-g;l=j-h;g=o;h=j;b(a,l,q)}},this))},CLASS_NAME:"OpenLayers.Kinetic"});OpenLayers.Events.buttonclick=OpenLayers.Class({target:null,events:"mousedown,mouseup,click,dblclick,touchstart,touchmove,touchend,keydown".split(","),startRegEx:/^mousedown|touchstart$/,cancelRegEx:/^touchmove$/,completeRegEx:/^mouseup|touchend$/,initialize:function(a){this.target=a;for(a=this.events.length-1;0<=a;--a)this.target.register(this.events[a],this,this.buttonClick,{extension:!0})},destroy:function(){for(var a=this.events.length-1;0<=a;--a)this.target.unregister(this.events[a],this,this.buttonClick); +delete this.target},getPressedButton:function(a){var b=3,c;do{if(OpenLayers.Element.hasClass(a,"olButton")){c=a;break}a=a.parentNode}while(0<--b&&a);return c},buttonClick:function(a){var b=!0,c=OpenLayers.Event.element(a);if(c&&(OpenLayers.Event.isLeftClick(a)||!~a.type.indexOf("mouse")))if(c=this.getPressedButton(c)){if("keydown"===a.type)switch(a.keyCode){case OpenLayers.Event.KEY_RETURN:case OpenLayers.Event.KEY_SPACE:this.target.triggerEvent("buttonclick",{buttonElement:c}),OpenLayers.Event.stop(a), +b=!1}else this.startEvt&&(this.completeRegEx.test(a.type)&&(b=OpenLayers.Util.pagePosition(c),this.target.triggerEvent("buttonclick",{buttonElement:c,buttonXY:{x:this.startEvt.clientX-b[0],y:this.startEvt.clientY-b[1]}})),this.cancelRegEx.test(a.type)&&delete this.startEvt,OpenLayers.Event.stop(a),b=!1);if(this.startRegEx.test(a.type))this.startEvt=a,OpenLayers.Event.stop(a),b=!1}else delete this.startEvt;return b}});OpenLayers.Handler.Drag=OpenLayers.Class(OpenLayers.Handler,{started:!1,stopDown:!0,dragging:!1,touch:!1,last:null,start:null,lastMoveEvt:null,oldOnselectstart:null,interval:0,timeoutId:null,documentDrag:!1,documentEvents:null,initialize:function(a,b,c){OpenLayers.Handler.prototype.initialize.apply(this,arguments);if(!0===this.documentDrag){var d=this;this._docMove=function(a){d.mousemove({xy:{x:a.clientX,y:a.clientY},element:document})};this._docUp=function(a){d.mouseup({xy:{x:a.clientX,y:a.clientY}})}}}, dragstart:function(a){var b=!0;this.dragging=!1;if(this.checkModifiers(a)&&(OpenLayers.Event.isLeftClick(a)||OpenLayers.Event.isSingleTouch(a))){this.started=!0;this.last=this.start=a.xy;OpenLayers.Element.addClass(this.map.viewPortDiv,"olDragDown");this.down(a);this.callback("down",[a.xy]);OpenLayers.Event.stop(a);if(!this.oldOnselectstart)this.oldOnselectstart=document.onselectstart?document.onselectstart:OpenLayers.Function.True;document.onselectstart=OpenLayers.Function.False;b=!this.stopDown}else this.started= -!1,this.last=this.start=null;return b},dragmove:function(a){this.lastMoveEvt=a;if(this.started&&!this.timeoutId&&(a.xy.x!=this.last.x||a.xy.y!=this.last.y)){this.documentDrag===!0&&this.documentEvents&&(a.element===document?(this.adjustXY(a),this.setEvent(a)):this.removeDocumentEvents());if(this.interval>0)this.timeoutId=setTimeout(OpenLayers.Function.bind(this.removeTimeout,this),this.interval);this.dragging=!0;this.move(a);this.callback("move",[a.xy]);if(!this.oldOnselectstart)this.oldOnselectstart= -document.onselectstart,document.onselectstart=OpenLayers.Function.False;this.last=a.xy}return!0},dragend:function(a){if(this.started){this.documentDrag===!0&&this.documentEvents&&(this.adjustXY(a),this.removeDocumentEvents());var b=this.start!=this.last;this.dragging=this.started=!1;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.up(a);this.callback("up",[a.xy]);b&&this.callback("done",[a.xy]);document.onselectstart=this.oldOnselectstart}return!0},down:function(){},move:function(){}, +!1,this.last=this.start=null;return b},dragmove:function(a){this.lastMoveEvt=a;if(this.started&&!this.timeoutId&&(a.xy.x!=this.last.x||a.xy.y!=this.last.y)){!0===this.documentDrag&&this.documentEvents&&(a.element===document?(this.adjustXY(a),this.setEvent(a)):this.removeDocumentEvents());if(05||Math.abs(this.dragHandler.start.y-a.y)>5){var c=this.dragHandler.start;b=Math.min(c.y,a.y);var d=Math.max(c.y,a.y),e=Math.min(c.x,a.x),a=Math.max(c.x, -a.x);b=new OpenLayers.Bounds(e,d,a,b)}else b=this.dragHandler.start.clone();this.removeBox();this.callback("done",[b])},removeBox:function(){this.map.eventsDiv.removeChild(this.zoomBox);this.boxOffsets=this.zoomBox=null;OpenLayers.Element.removeClass(this.map.eventsDiv,"olDrawBox")},activate:function(){return OpenLayers.Handler.prototype.activate.apply(this,arguments)?(this.dragHandler.activate(),!0):!1},deactivate:function(){return OpenLayers.Handler.prototype.deactivate.apply(this,arguments)?(this.dragHandler.deactivate()&& -this.zoomBox&&this.removeBox(),!0):!1},getBoxOffsets:function(){if(!this.boxOffsets){var a=document.createElement("div");a.style.position="absolute";a.style.border="1px solid black";a.style.width="3px";document.body.appendChild(a);var b=a.clientWidth==3;document.body.removeChild(a);var a=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-left-width")),c=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-right-width")),d=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-top-width")), -e=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-bottom-width"));this.boxOffsets={left:a,right:c,top:d,bottom:e,width:b===!1?a+c:0,height:b===!1?d+e:0}}return this.boxOffsets},CLASS_NAME:"OpenLayers.Handler.Box"}); -OpenLayers.Control.ZoomBox=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,out:!1,alwaysZoom:!1,draw:function(){this.handler=new OpenLayers.Handler.Box(this,{done:this.zoomBox},{keyMask:this.keyMask})},zoomBox:function(a){if(a instanceof OpenLayers.Bounds){var b;if(this.out){b=Math.abs(a.right-a.left);var c=Math.abs(a.top-a.bottom);b=Math.min(this.map.size.h/c,this.map.size.w/b);var c=this.map.getExtent(),d=this.map.getLonLatFromPixel(a.getCenterPixel()),a=d.lon-c.getWidth()/ -2*b,e=d.lon+c.getWidth()/2*b,f=d.lat-c.getHeight()/2*b;b=d.lat+c.getHeight()/2*b;b=new OpenLayers.Bounds(a,f,e,b)}else b=this.map.getLonLatFromPixel(new OpenLayers.Pixel(a.left,a.bottom)),c=this.map.getLonLatFromPixel(new OpenLayers.Pixel(a.right,a.top)),b=new OpenLayers.Bounds(b.lon,b.lat,c.lon,c.lat);c=this.map.getZoom();this.map.zoomToExtent(b);c==this.map.getZoom()&&this.alwaysZoom==!0&&this.map.zoomTo(c+(this.out?-1:1))}else this.out?this.map.setCenter(this.map.getLonLatFromPixel(a),this.map.getZoom()- -1):this.map.setCenter(this.map.getLonLatFromPixel(a),this.map.getZoom()+1)},CLASS_NAME:"OpenLayers.Control.ZoomBox"}); -OpenLayers.Control.DragPan=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:!1,interval:1,documentDrag:!1,kinetic:null,enableKinetic:!1,kineticInterval:10,draw:function(){if(this.enableKinetic){var a={interval:this.kineticInterval};typeof this.enableKinetic==="object"&&(a=OpenLayers.Util.extend(a,this.enableKinetic));this.kinetic=new OpenLayers.Kinetic(a)}this.handler=new OpenLayers.Handler.Drag(this,{move:this.panMap,done:this.panMapDone,down:this.panMapStart},{interval:this.interval, +"olDragDown");this.documentEvents=!0;OpenLayers.Event.observe(document,"mousemove",this._docMove);OpenLayers.Event.observe(document,"mouseup",this._docUp)},removeDocumentEvents:function(){OpenLayers.Element.removeClass(document.body,"olDragDown");this.documentEvents=!1;OpenLayers.Event.stopObserving(document,"mousemove",this._docMove);OpenLayers.Event.stopObserving(document,"mouseup",this._docUp)},CLASS_NAME:"OpenLayers.Handler.Drag"});OpenLayers.Handler.Box=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,boxDivClassName:"olHandlerBoxZoomBox",boxOffsets:null,initialize:function(a,b,c){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})},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);if(this.dragHandler)this.dragHandler.destroy(),this.dragHandler= +null},setMap:function(a){OpenLayers.Handler.prototype.setMap.apply(this,arguments);this.dragHandler&&this.dragHandler.setMap(a)},startBox:function(){this.callback("start",[]);this.zoomBox=OpenLayers.Util.createDiv("zoomBox",{x:-9999,y:-9999});this.zoomBox.className=this.boxDivClassName;this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE.Popup-1;this.map.viewPortDiv.appendChild(this.zoomBox);OpenLayers.Element.addClass(this.map.viewPortDiv,"olDrawBox")},moveBox:function(a){var b=this.dragHandler.start.x, +c=this.dragHandler.start.y,d=Math.abs(b-a.x),e=Math.abs(c-a.y),f=this.getBoxOffsets();this.zoomBox.style.width=d+f.width+1+"px";this.zoomBox.style.height=e+f.height+1+"px";this.zoomBox.style.left=(a.xwindow.opera.version()&&(b=-b)):a.detail&& +(b=-a.detail/3);this.delta+=b;this.interval?(window.clearTimeout(this._timeoutId),this._timeoutId=window.setTimeout(OpenLayers.Function.bind(function(){this.wheelZoom(a)},this),this.interval)):this.wheelZoom(a)}OpenLayers.Event.stop(a)}}},wheelZoom:function(a){var b=this.delta;this.delta=0;if(b){if(this.mousePosition)a.xy=this.mousePosition;if(!a.xy)a.xy=this.map.getPixelFromLonLat(this.map.getCenter());0>b?this.callback("down",[a,this.cumulative?b:-1]):this.callback("up",[a,this.cumulative?b:1])}}, +mousemove:function(a){this.mousePosition=a.xy},activate:function(a){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){var b=this.wheelListener;OpenLayers.Event.observe(window,"DOMMouseScroll",b);OpenLayers.Event.observe(window,"mousewheel",b);OpenLayers.Event.observe(document,"mousewheel",b);return!0}return!1},deactivate:function(a){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){var b=this.wheelListener;OpenLayers.Event.stopObserving(window,"DOMMouseScroll",b);OpenLayers.Event.stopObserving(window, +"mousewheel",b);OpenLayers.Event.stopObserving(document,"mousewheel",b);return!0}return!1},CLASS_NAME:"OpenLayers.Handler.MouseWheel"});OpenLayers.Control.Navigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,dragPanOptions:null,pinchZoom:null,pinchZoomOptions:null,documentDrag:!1,zoomBox:null,zoomBoxEnabled:!0,zoomWheelEnabled:!0,mouseWheelOptions:null,handleRightClicks:!1,zoomBoxKeyMask:OpenLayers.Handler.MOD_SHIFT,autoActivate:!0,initialize:function(a){this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,arguments)},destroy:function(){this.deactivate();this.dragPan&&this.dragPan.destroy();this.dragPan=null; this.zoomBox&&this.zoomBox.destroy();this.zoomBox=null;this.pinchZoom&&this.pinchZoom.destroy();this.pinchZoom=null;OpenLayers.Control.prototype.destroy.apply(this,arguments)},activate:function(){this.dragPan.activate();this.zoomWheelEnabled&&this.handlers.wheel.activate();this.handlers.click.activate();this.zoomBoxEnabled&&this.zoomBox.activate();this.pinchZoom&&this.pinchZoom.activate();return OpenLayers.Control.prototype.activate.apply(this,arguments)},deactivate:function(){this.pinchZoom&&this.pinchZoom.deactivate(); this.zoomBox.deactivate();this.dragPan.deactivate();this.handlers.click.deactivate();this.handlers.wheel.deactivate();return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},draw:function(){if(this.handleRightClicks)this.map.viewPortDiv.oncontextmenu=OpenLayers.Function.False;this.handlers.click=new OpenLayers.Handler.Click(this,{click:this.defaultClick,dblclick:this.defaultDblClick,dblrightclick:this.defaultDblRightClick},{"double":!0,stopDouble:!0});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);if(OpenLayers.Control.PinchZoom)this.pinchZoom=new OpenLayers.Control.PinchZoom(OpenLayers.Util.extend({map:this.map},this.pinchZoomOptions))},defaultClick:function(a){a.lastTouches&&a.lastTouches.length== -2&&this.map.zoomOut()},defaultDblClick:function(a){this.map.setCenter(this.map.getLonLatFromViewPortPx(a.xy),this.map.zoom+1)},defaultDblRightClick:function(a){this.map.setCenter(this.map.getLonLatFromViewPortPx(a.xy),this.map.zoom-1)},wheelChange:function(a,b){var c=this.map.getZoom(),d=this.map.getZoom()+Math.round(b),d=Math.max(d,0),d=Math.min(d,this.map.getNumZoomLevels());if(d!==c){var e=this.map.getSize(),c=e.w/2-a.xy.x,e=a.xy.y-e.h/2,f=this.map.baseLayer.getResolutionForZoom(d),g=this.map.getLonLatFromPixel(a.xy); +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);if(OpenLayers.Control.PinchZoom)this.pinchZoom=new OpenLayers.Control.PinchZoom(OpenLayers.Util.extend({map:this.map},this.pinchZoomOptions))},defaultClick:function(a){a.lastTouches&&2==a.lastTouches.length&& +this.map.zoomOut()},defaultDblClick:function(a){this.map.setCenter(this.map.getLonLatFromViewPortPx(a.xy),this.map.zoom+1)},defaultDblRightClick:function(a){this.map.setCenter(this.map.getLonLatFromViewPortPx(a.xy),this.map.zoom-1)},wheelChange:function(a,b){var c=this.map.getZoom(),d=this.map.getZoom()+Math.round(b),d=Math.max(d,0),d=Math.min(d,this.map.getNumZoomLevels());if(d!==c){var e=this.map.getSize(),c=e.w/2-a.xy.x,e=a.xy.y-e.h/2,f=this.map.baseLayer.getResolutionForZoom(d),g=this.map.getLonLatFromPixel(a.xy); this.map.setCenter(new OpenLayers.LonLat(g.lon+c*f,g.lat+e*f),d)}},wheelUp:function(a,b){this.wheelChange(a,b||1)},wheelDown:function(a,b){this.wheelChange(a,b||-1)},disableZoomBox:function(){this.zoomBoxEnabled=!1;this.zoomBox.deactivate()},enableZoomBox:function(){this.zoomBoxEnabled=!0;this.active&&this.zoomBox.activate()},disableZoomWheel:function(){this.zoomWheelEnabled=!1;this.handlers.wheel.deactivate()},enableZoomWheel:function(){this.zoomWheelEnabled=!0;this.active&&this.handlers.wheel.activate()}, -CLASS_NAME:"OpenLayers.Control.Navigation"}); -OpenLayers.Tile=OpenLayers.Class({EVENT_TYPES:["loadstart","loadend","reload","unload"],events:null,id:null,layer:null,url:null,bounds:null,size:null,position:null,isLoading:!1,initialize:function(a,b,c,d,e,f){this.layer=a;this.position=b.clone();this.bounds=c.clone();this.url=d;if(e)this.size=e.clone();this.id=OpenLayers.Util.createUniqueID("Tile_");this.events=new OpenLayers.Events(this,null,this.EVENT_TYPES);OpenLayers.Util.extend(this,f)},unload:function(){if(this.isLoading)this.isLoading=!1, -this.events.triggerEvent("unload")},destroy:function(){this.position=this.size=this.bounds=this.layer=null;this.events.destroy();this.events=null},draw:function(){this.clear();return this.shouldDraw()},shouldDraw:function(){var a=this.layer.maxExtent;return a&&this.bounds.intersectsBounds(a,!1)||this.layer.displayOutsideMaxExtent},moveTo:function(a,b,c){c==null&&(c=!0);this.bounds=a.clone();this.position=b.clone();c&&this.draw()},clear:function(){},getBoundsFromBaseLayer:function(a){var b=OpenLayers.i18n("reprojectDeprecated", -{layerName:this.layer.name});OpenLayers.Console.warn(b);b=this.layer.map.getLonLatFromLayerPx(a);a=a.clone();a.x+=this.size.w;a.y+=this.size.h;a=this.layer.map.getLonLatFromLayerPx(a);if(b.lon>a.lon)b.lon<0?b.lon=-180-(b.lon+180):a.lon=180+a.lon+180;return new OpenLayers.Bounds(b.lon,a.lat,a.lon,b.lat)},CLASS_NAME:"OpenLayers.Tile"}); -OpenLayers.Tile.BackBufferable=OpenLayers.Class(OpenLayers.Tile,{backBufferMode:null,backBufferData:null,initialize:function(){OpenLayers.Tile.prototype.initialize.apply(this,arguments);this.backBufferMode=(this.layer.singleTile&&1)|(OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS,this.layer.transitionEffect)!=-1&&2);this.backBufferData={};if(!this.size)this.size=new OpenLayers.Size(256,256)},draw:function(){var a=OpenLayers.Tile.prototype.shouldDraw.apply(this,arguments);a&&this.updateBackBuffer(); -this.clear();a||this.resetBackBuffer();return a},setBackBufferData:function(){this.backBufferData=OpenLayers.Util.extend(this.backBufferData,{bounds:this.bounds,resolution:this.layer.map.getResolution()})},updateBackBuffer:function(){var a=this.layer,b=a.map,c=this.backBufferMode,d=this.backBufferData,e=this.getTile(),f=d.tile,g=d.resolution,g=g?g/b.getResolution():1,h=e&&e.parentNode!==a.div,i=!(e&&e.childNodes.length>0),j=d.tile&&!this.isLoading;if(!(g==1?c&1:c&2)||h||i||j)this.setBackBufferData(); -else{if(!f)f=this.createBackBuffer(),a.events.register("loadend",this,this.resetBackBuffer),d.tile=f,a.div.insertBefore(f,e);a=b.getPixelFromLonLat({lon:d.bounds.left,lat:d.bounds.top});c=b.layerContainerDiv.style;b=parseInt(c.left,10);c=parseInt(c.top,10);d=f.style;d.left=a.x-b+"px";d.top=a.y-c+"px";d.width=this.size.w*g+"px";d.height=this.size.h*g+"px";return f}},resetBackBuffer:function(){this.layer.events.unregister("loadend",this,this.resetBackBuffer);this.removeBackBuffer();this.setBackBufferData()}, -removeBackBuffer:function(){var a=this.backBufferData,b=a.tile;delete a.tile;a=b&&b.parentNode;b&&a.removeChild(b)},destroy:function(){this.removeBackBuffer();this.layer.events.unregister("loadend",this,this.resetBackBuffer);this.backBufferData=null;OpenLayers.Tile.prototype.destroy.apply(this,arguments)}}); -OpenLayers.Tile.Image=OpenLayers.Class(OpenLayers.Tile.BackBufferable,{url:null,imgDiv:null,frame:null,imageReloadAttempts:null,layerAlphaHack:null,asyncRequestId:null,blankImageUrl:"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7",maxGetUrlLength:null,initialize:function(a,b,c,d,e,f){OpenLayers.Tile.BackBufferable.prototype.initialize.apply(this,arguments);this.url=d;this.frame=document.createElement("div");this.frame.style.position="absolute";this.frame.style.overflow= -"hidden";this.layerAlphaHack=this.layer.alpha&&OpenLayers.Util.alphaHack();this.maxGetUrlLength!=null&&OpenLayers.Util.extend(this,OpenLayers.Tile.Image.IFrame)},destroy:function(){if(this.frame!=null)this.clear(),this.frame=this.imgDiv=null;this.asyncRequestId=null;OpenLayers.Tile.BackBufferable.prototype.destroy.apply(this,arguments)},draw:function(){var a=OpenLayers.Tile.BackBufferable.prototype.draw.apply(this,arguments);if(a){if(this.layer!=this.layer.map.baseLayer&&this.layer.reproject)this.bounds= -this.getBoundsFromBaseLayer(this.position);this.isLoading?this.events.triggerEvent("reload"):(this.isLoading=!0,this.events.triggerEvent("loadstart"));this.positionTile();this.renderTile()}else this.unload();return a},renderTile:function(){this.layer.div.appendChild(this.frame);if(this.layer.async){var a=this.asyncRequestId=(this.asyncRequestId||0)+1;this.layer.getURLasync(this.bounds,this,"url",function(){a==this.asyncRequestId&&this.initImage()})}else this.url=this.layer.getURL(this.bounds),this.initImage()}, -positionTile:function(){var a=this.frame.style;a.left=this.position.x+"px";a.top=this.position.y+"px";a.width=this.size.w+"px";a.height=this.size.h+"px"},clear:function(){var a=this.imgDiv;if(a){OpenLayers.Event.stopObservingElement(a);this.frame.parentNode===this.layer.div&&this.layer.div.removeChild(this.frame);this.setImgSrc();if(this.layerAlphaHack===!0)a.style.filter="";OpenLayers.Element.removeClass(a,"olImageLoadError")}},createImage:function(){var a=document.createElement("img");this.imgDiv= -a;a.className="olTileImage";a.galleryImg="no";var b=a.style,c=this.layer.gutter;if(c){var d=this.layer.tileSize,e=c/d.w*100,c=c/d.h*100;b.left=-e+"%";b.top=-c+"%";b.width=2*e+100+"%";b.height=2*c+100+"%";b.position="absolute"}else b.width="100%",b.height="100%";b.display="none";this.layer.opacity<1&&OpenLayers.Util.modifyDOMElement(a,null,null,null,null,null,null,this.layer.opacity);if(this.layerAlphaHack)b.paddingTop=b.height,b.height="0";this.frame.appendChild(a);return a},initImage:function(){var a= -this.imgDiv||this.createImage();if(this.url&&a.getAttribute("src")==this.url)this.onImageLoad();else{var b=OpenLayers.Function.bind(function(){OpenLayers.Event.stopObservingElement(a);OpenLayers.Event.observe(a,"load",OpenLayers.Function.bind(this.onImageLoad,this));OpenLayers.Event.observe(a,"error",OpenLayers.Function.bind(this.onImageError,this));this.imageReloadAttempts=0;this.setImgSrc(this.url)},this);a.getAttribute("src")==this.blankImageUrl?b():(OpenLayers.Event.observe(a,"load",b),OpenLayers.Event.observe(a, -"error",b),a.src=this.blankImageUrl)}},setImgSrc:function(a){var b=this.imgDiv;b.style.display="none";if(a)b.src=a},getTile:function(){return this.frame},createBackBuffer:function(){var a=this.frame.cloneNode(!1);OpenLayers.Event.stopObservingElement(this.imgDiv);a.appendChild(this.imgDiv);this.imgDiv=null;return a},onImageLoad:function(){var a=this.imgDiv;a.style.display="";this.isLoading=!1;this.events.triggerEvent("loadend");if(this.layerAlphaHack===!0)a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+ -a.src+"', sizingMethod='scale')"},onImageError:function(){var a=this.imgDiv;a.src!=null&&(this.imageReloadAttempts++,this.imageReloadAttempts<=OpenLayers.IMAGE_RELOAD_ATTEMPTS?this.setImgSrc(this.layer.getURL(this.bounds)):(OpenLayers.Element.addClass(a,"olImageLoadError"),this.onImageLoad()))},CLASS_NAME:"OpenLayers.Tile.Image"}); -OpenLayers.Layer.WMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{service:"WMS",version:"1.1.1",request:"GetMap",styles:"",format:"image/jpeg"},reproject:!1,isBaseLayer:!0,encodeBBOX:!1,noMagic:!1,yx:{"EPSG:4326":!0},initialize:function(a,b,c,d){var e=[],c=OpenLayers.Util.upperCaseObject(c);if(parseFloat(c.VERSION)>=1.3&&!c.EXCEPTIONS)c.EXCEPTIONS="INIMAGE";e.push(a,b,c,d);OpenLayers.Layer.Grid.prototype.initialize.apply(this,e);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)); -if(!this.noMagic&&this.params.TRANSPARENT&&this.params.TRANSPARENT.toString().toLowerCase()=="true"){if(d==null||!d.isBaseLayer)this.isBaseLayer=!1;if(this.params.FORMAT=="image/jpeg")this.params.FORMAT=OpenLayers.Util.alphaHack()?"image/gif":"image/png"}},destroy:function(){OpenLayers.Layer.Grid.prototype.destroy.apply(this,arguments)},clone:function(a){a==null&&(a=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this, -[a])},reverseAxisOrder:function(){return parseFloat(this.params.VERSION)>=1.3&&!!this.yx[this.map.getProjectionObject().getCode()]},getURL:function(a){var a=this.adjustBounds(a),b=this.getImageSize(),c={},d=this.reverseAxisOrder();c.BBOX=this.encodeBBOX?a.toBBOX(null,d):a.toArray(d);c.WIDTH=b.w;c.HEIGHT=b.h;return this.getFullRequestString(c)},mergeNewParams:function(a){a=[OpenLayers.Util.upperCaseObject(a)];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,a)},getFullRequestString:function(a, -b){var c=this.map.getProjectionObject(),c=this.projection&&this.projection.equals(c)?this.projection.getCode():c.getCode(),c=c=="none"?null:c;parseFloat(this.params.VERSION)>=1.3?this.params.CRS=c:this.params.SRS=c;if(typeof this.params.TRANSPARENT=="boolean")a.TRANSPARENT=this.params.TRANSPARENT?"TRUE":"FALSE";return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments)},CLASS_NAME:"OpenLayers.Layer.WMS"}); -OpenLayers.Layer.XYZ=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,sphericalMercator:!1,zoomOffset:0,serverResolutions:null,initialize:function(a,b,c){if(c&&c.sphericalMercator||this.sphericalMercator)c=OpenLayers.Util.extend({maxExtent:new OpenLayers.Bounds(-2.003750834E7,-2.003750834E7,2.003750834E7,2.003750834E7),maxResolution:156543.03390625,numZoomLevels:19,units:"m",projection:"EPSG:900913"},c);b=b||this.url;a=a||this.name;OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a,b, -{},c])},clone:function(a){a==null&&(a=new OpenLayers.Layer.XYZ(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getURL:function(a){var a=this.getXYZ(a),b=this.url;OpenLayers.Util.isArray(b)&&(b=this.selectUrl(""+a.x+a.y+a.z,b));return OpenLayers.String.format(b,a)},getXYZ:function(a){var b=this.map.getResolution(),c=Math.round((a.left-this.maxExtent.left)/(b*this.tileSize.w)),a=Math.round((this.maxExtent.top-a.top)/(b*this.tileSize.h)),b=this.serverResolutions!= -null?OpenLayers.Util.indexOf(this.serverResolutions,b):this.map.getZoom()+this.zoomOffset,d=Math.pow(2,b);this.wrapDateLine&&(c=(c%d+d)%d);return{x:c,y:a,z:b}},setMap:function(a){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"}); -OpenLayers.Layer.OSM=OpenLayers.Class(OpenLayers.Layer.XYZ,{name:"OpenStreetMap",attribution:"Data CC-By-SA by OpenStreetMap",sphericalMercator:!0,url:"http://tile.openstreetmap.org/${z}/${x}/${y}.png",clone:function(a){a==null&&(a=new OpenLayers.Layer.OSM(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.XYZ.prototype.clone.apply(this,[a])},wrapDateLine:!0,CLASS_NAME:"OpenLayers.Layer.OSM"}); -OpenLayers.Layer.Raster=OpenLayers.Class(OpenLayers.Layer,{needsUpdate:!1,initialize:function(a){var a=a||{},b=a.data;delete a.data;OpenLayers.Layer.prototype.initialize.apply(this,[a.name,a]);this.canvas=document.createElement("canvas");this.canvas.style.position="absolute";this.div.appendChild(this.canvas);this.context=this.canvas.getContext("2d");b&&this.setData(b)},setData:function(a){this.clearData();this.data=a;a.events.register("update",this,this.onDataUpdate)},clearData:function(){this.data&& +CLASS_NAME:"OpenLayers.Control.Navigation"});OpenLayers.Layer.WMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{service:"WMS",version:"1.1.1",request:"GetMap",styles:"",format:"image/jpeg"},isBaseLayer:!0,encodeBBOX:!1,noMagic:!1,yx:{},initialize:function(a,b,c,d){var e=[],c=OpenLayers.Util.upperCaseObject(c);if(1.3<=parseFloat(c.VERSION)&&!c.EXCEPTIONS)c.EXCEPTIONS="INIMAGE";e.push(a,b,c,d);OpenLayers.Layer.Grid.prototype.initialize.apply(this,e);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)); +if(!this.noMagic&&this.params.TRANSPARENT&&"true"==this.params.TRANSPARENT.toString().toLowerCase()){if(null==d||!d.isBaseLayer)this.isBaseLayer=!1;if("image/jpeg"==this.params.FORMAT)this.params.FORMAT=OpenLayers.Util.alphaHack()?"image/gif":"image/png"}},clone:function(a){null==a&&(a=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},reverseAxisOrder:function(){var a=this.projection.getCode();return 1.3<=parseFloat(this.params.VERSION)&& +!(!this.yx[a]&&!OpenLayers.Projection.defaults[a].yx)},getURL:function(a){var a=this.adjustBounds(a),b=this.getImageSize(),c={},d=this.reverseAxisOrder();c.BBOX=this.encodeBBOX?a.toBBOX(null,d):a.toArray(d);c.WIDTH=b.w;c.HEIGHT=b.h;return this.getFullRequestString(c)},mergeNewParams:function(a){a=[OpenLayers.Util.upperCaseObject(a)];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,a)},getFullRequestString:function(a,b){var c=this.map.getProjectionObject(),c=this.projection&&this.projection.equals(c)? +this.projection.getCode():c.getCode(),c="none"==c?null:c;1.3<=parseFloat(this.params.VERSION)?this.params.CRS=c:this.params.SRS=c;if("boolean"==typeof this.params.TRANSPARENT)a.TRANSPARENT=this.params.TRANSPARENT?"TRUE":"FALSE";return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments)},CLASS_NAME:"OpenLayers.Layer.WMS"});OpenLayers.Layer.XYZ=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,sphericalMercator:!1,zoomOffset:0,serverResolutions:null,initialize:function(a,b,c){if(c&&c.sphericalMercator||this.sphericalMercator)c=OpenLayers.Util.extend({projection:"EPSG:900913",numZoomLevels:19},c);OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a||this.name,b||this.url,{},c])},clone:function(a){null==a&&(a=new OpenLayers.Layer.XYZ(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this, +[a])},getURL:function(a){var a=this.getXYZ(a),b=this.url;OpenLayers.Util.isArray(b)&&(b=this.selectUrl(""+a.x+a.y+a.z,b));return OpenLayers.String.format(b,a)},getXYZ:function(a){var b=this.getServerResolution(),c=Math.round((a.left-this.maxExtent.left)/(b*this.tileSize.w)),a=Math.round((this.maxExtent.top-a.top)/(b*this.tileSize.h)),d=this.serverResolutions||this.resolutions,b=0==this.zoomOffset?OpenLayers.Util.indexOf(d,b):this.getServerZoom()+this.zoomOffset;this.wrapDateLine&&(d=Math.pow(2,b), +c=(c%d+d)%d);return{x:c,y:a,z:b}},setMap:function(a){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"});OpenLayers.Layer.OSM=OpenLayers.Class(OpenLayers.Layer.XYZ,{name:"OpenStreetMap",url:["http://a.tile.openstreetmap.org/${z}/${x}/${y}.png","http://b.tile.openstreetmap.org/${z}/${x}/${y}.png","http://c.tile.openstreetmap.org/${z}/${x}/${y}.png"],attribution:"Data CC-By-SA by OpenStreetMap",sphericalMercator:!0,wrapDateLine:!0,tileOptions:null,initialize:function(a,b,c){OpenLayers.Layer.XYZ.prototype.initialize.apply(this,arguments);this.tileOptions=OpenLayers.Util.extend({crossOriginKeyword:"anonymous"}, +this.options&&this.options.tileOptions)},clone:function(a){null==a&&(a=new OpenLayers.Layer.OSM(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.XYZ.prototype.clone.apply(this,[a])},CLASS_NAME:"OpenLayers.Layer.OSM"});OpenLayers.Control.Zoom=OpenLayers.Class(OpenLayers.Control,{zoomInText:"+",zoomInId:"olZoomInLink",zoomOutText:"-",zoomOutId:"olZoomOutLink",draw:function(){var a=OpenLayers.Control.prototype.draw.apply(this),b=this.getOrCreateLinks(a),c=b.zoomIn,b=b.zoomOut,d=this.map.events;if(b.parentNode!==a)d=this.events,d.attachToElement(b.parentNode);d.register("buttonclick",this,this.onZoomClick);this.zoomInLink=c;this.zoomOutLink=b;return a},getOrCreateLinks:function(a){var b=document.getElementById(this.zoomInId), +c=document.getElementById(this.zoomOutId);if(!b)b=document.createElement("a"),b.href="#zoomIn",b.appendChild(document.createTextNode(this.zoomInText)),b.className="olControlZoomIn",a.appendChild(b);OpenLayers.Element.addClass(b,"olButton");if(!c)c=document.createElement("a"),c.href="#zoomOut",c.appendChild(document.createTextNode(this.zoomOutText)),c.className="olControlZoomOut",a.appendChild(c);OpenLayers.Element.addClass(c,"olButton");return{zoomIn:b,zoomOut:c}},onZoomClick:function(a){a=a.buttonElement; +a===this.zoomInLink?this.map.zoomIn():a===this.zoomOutLink&&this.map.zoomOut()},destroy:function(){this.map&&this.map.events.unregister("buttonclick",this,this.onZoomClick);delete this.zoomInLink;delete this.zoomOutLink;OpenLayers.Control.prototype.destroy.apply(this)},CLASS_NAME:"OpenLayers.Control.Zoom"});OpenLayers.Layer.Raster=OpenLayers.Class(OpenLayers.Layer,{needsUpdate:!1,initialize:function(a){var a=a||{},b=a.data;delete a.data;OpenLayers.Layer.prototype.initialize.apply(this,[a.name,a]);this.canvas=document.createElement("canvas");this.canvas.style.position="absolute";this.div.appendChild(this.canvas);this.context=this.canvas.getContext("2d");b&&this.setData(b)},setData:function(a){this.clearData();this.data=a;a.events.register("update",this,this.onDataUpdate)},clearData:function(){this.data&& (this.data.events.unregister("update",this,this.onDataUpdate),delete this.data)},moveTo:function(){this.needsUpdate=!0;OpenLayers.Layer.prototype.moveTo.apply(this,arguments);window.setTimeout(OpenLayers.Function.bind(this.afterMoveTo,this),0)},afterMoveTo:function(){if(this.needsUpdate)this.onDataUpdate()},onDataUpdate:function(){var a=this.map;if(a){var b=a.getSize(),c=this.data.numCols(),d=this.data.numRows(),a=a.layerContainerDiv.style;this.canvas.width=c;this.canvas.height=d;this.canvas.style.top= --parseInt(a.top)+"px";this.canvas.style.left=-parseInt(a.left)+"px";this.canvas.style.width=b.w+"px";this.canvas.style.height=b.h+"px";var b=this.context.createImageData(c,d),e=b.data;this.data.forEach(function(a,b){var c=4*b;a.length||(a=[a,a,a]);e[c+0]=a[0];e[c+1]=a[1];e[c+2]=a[2];e[c+3]=a.length>3?a[3]:255});this.context.putImageData(b,0,0);this.needsUpdate=!1}},CLASS_NAME:"OpenLayers.Layer.Raster"});OpenLayers.Rico=OpenLayers.Rico||{}; -OpenLayers.Rico.Color=OpenLayers.Class({initialize:function(a,b,c){this.rgb={r:a,g:b,b:c}},setRed:function(a){this.rgb.r=a},setGreen:function(a){this.rgb.g=a},setBlue:function(a){this.rgb.b=a},setHue:function(a){var b=this.asHSB();b.h=a;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,b.b)},setSaturation:function(a){var b=this.asHSB();b.s=a;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,b.b)},setBrightness:function(a){var b=this.asHSB();b.b=a;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,b.b)}, -darken:function(a){var b=this.asHSB();this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,Math.max(b.b-a,0))},brighten:function(a){var b=this.asHSB();this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,Math.min(b.b+a,1))},blend:function(a){this.rgb.r=Math.floor((this.rgb.r+a.rgb.r)/2);this.rgb.g=Math.floor((this.rgb.g+a.rgb.g)/2);this.rgb.b=Math.floor((this.rgb.b+a.rgb.b)/2)},isBright:function(){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(a){if(a.length==4)for(var b=a,a="#",c=1;c<4;c++)a+=b.charAt(c)+b.charAt(c);a.indexOf("#")==0&&(a=a.substring(1));b=a.substring(0,2);c=a.substring(2,4);a=a.substring(4,6);return new OpenLayers.Rico.Color(parseInt(b,16),parseInt(c,16),parseInt(a,16))}; -OpenLayers.Rico.Color.createColorFromBackground=function(a){var b=OpenLayers.Element.getStyle(OpenLayers.Util.getElement(a),"backgroundColor");if(b=="transparent"&&a.parentNode)return OpenLayers.Rico.Color.createColorFromBackground(a.parentNode);return b==null?new OpenLayers.Rico.Color(255,255,255):b.indexOf("rgb(")==0?(a=b.substring(4,b.length-1).split(","),new OpenLayers.Rico.Color(parseInt(a[0]),parseInt(a[1]),parseInt(a[2]))):b.indexOf("#")==0?OpenLayers.Rico.Color.createFromHex(b):new OpenLayers.Rico.Color(255, -255,255)}; -OpenLayers.Rico.Color.HSBtoRGB=function(a,b,c){var d=0,e=0,f=0;if(b==0)f=e=d=parseInt(c*255+0.5);else{var a=(a-Math.floor(a))*6,g=a-Math.floor(a),h=c*(1-b),i=c*(1-b*g),b=c*(1-b*(1-g));switch(parseInt(a)){case 0:d=c*255+0.5;e=b*255+0.5;f=h*255+0.5;break;case 1:d=i*255+0.5;e=c*255+0.5;f=h*255+0.5;break;case 2:d=h*255+0.5;e=c*255+0.5;f=b*255+0.5;break;case 3:d=h*255+0.5;e=i*255+0.5;f=c*255+0.5;break;case 4:d=b*255+0.5;e=h*255+0.5;f=c*255+0.5;break;case 5:d=c*255+0.5,e=h*255+0.5,f=i*255+0.5}}return{r:parseInt(d),g:parseInt(e), -b:parseInt(f)}};OpenLayers.Rico.Color.RGBtoHSB=function(a,b,c){var d,e=a>b?a:b;c>e&&(e=c);var f=a"+a.innerHTML+""},_roundTopCorners:function(a,b,c){for(var d=this._createCorner(c),e=0;e=0;e--)d.appendChild(this._createCornerSlice(b, -c,e,"bottom"));a.style.paddingBottom=0;a.appendChild(d)},_createCorner:function(a){var b=document.createElement("div");b.style.backgroundColor=this._isTransparent()?"transparent":a;return b},_createCornerSlice:function(a,b,c,d){var e=document.createElement("span"),f=e.style;f.backgroundColor=a;f.display="block";f.height="1px";f.overflow="hidden";f.fontSize="1px";a=this._borderColor(a,b);if(this.options.border&&c==0)f.borderTopStyle="solid",f.borderTopWidth="1px",f.borderLeftWidth="0px",f.borderRightWidth= -"0px",f.borderBottomWidth="0px",f.height="0px",f.borderColor=a;else if(a)f.borderColor=a,f.borderStyle="solid",f.borderWidth="0px 1px";if(!this.options.compact&&c==this.options.numSlices-1)f.height="2px";this._setMargin(e,c,d);this._setBorder(e,c,d);return e},_setOptions:function(a){this.options={corners:"all",color:"fromElement",bgColor:"fromParent",blend:!0,border:!1,compact:!1};OpenLayers.Util.extend(this.options,a||{});this.options.numSlices=this.options.compact?2:4;if(this._isTransparent())this.options.blend= -!1},_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(a,b){return a=="transparent"?b:this.options.border?this.options.border:this.options.blend?this._blend(b,a):""},_setMargin:function(a,b,c){b=this._marginSize(b);c=c=="top"?this._whichSideTop():this._whichSideBottom();c=="left"?(a.style.marginLeft=b+"px",a.style.marginRight="0px"):c=="right"?(a.style.marginRight=b+"px",a.style.marginLeft="0px"):(a.style.marginLeft=b+"px",a.style.marginRight=b+ -"px")},_setBorder:function(a,b,c){b=this._borderSize(b);c=c=="top"?this._whichSideTop():this._whichSideBottom();c=="left"?(a.style.borderLeftWidth=b+"px",a.style.borderRightWidth="0px"):c=="right"?(a.style.borderRightWidth=b+"px",a.style.borderLeftWidth="0px"):(a.style.borderLeftWidth=b+"px",a.style.borderRightWidth=b+"px");if(this.options.border!=!1)a.style.borderLeftWidth=b+"px",a.style.borderRightWidth=b+"px"},_marginSize:function(a){if(this._isTransparent())return 0;var b=[5,3,2,1],c=[3,2,1,0], -d=[2,1],e=[1,0];return this.options.compact&&this.options.blend?e[a]:this.options.compact?d[a]:this.options.blend?c[a]:b[a]},_borderSize:function(a){var b=[5,3,2,1],c=[2,1,1,1],d=[1,0],e=[0,2,0,0];if(this.options.compact&&(this.options.blend||this._isTransparent()))return 1;else if(this.options.compact)return d[a];else if(this.options.blend)return c[a];else if(this.options.border)return e[a];else if(this._isTransparent())return b[a];return 0},_hasString:function(a){for(var b=1;b= -0)return!0;return!1},_blend:function(a,b){var c=OpenLayers.Rico.Color.createFromHex(a);c.blend(OpenLayers.Rico.Color.createFromHex(b));return c},_background:function(a){try{return OpenLayers.Rico.Color.createColorFromBackground(a).asHex()}catch(b){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(a){return a.childNodes.length==1&&a.childNodes[0].nodeType==3}}; -OpenLayers.Control.LayerSwitcher=OpenLayers.Class(OpenLayers.Control,{roundedCorner:!0,roundedCornerColor:"darkblue",layerStates:null,layersDiv:null,baseLayersDiv:null,baseLayers:null,dataLbl:null,dataLayersDiv:null,dataLayers:null,minimizeDiv:null,maximizeDiv:null,ascending:!0,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,arguments);this.layerStates=[]},destroy:function(){OpenLayers.Event.stopObservingElement(this.div);OpenLayers.Event.stopObservingElement(this.minimizeDiv); -OpenLayers.Event.stopObservingElement(this.maximizeDiv);this.clearLayersArray("base");this.clearLayersArray("data");this.map.events.un({addlayer:this.redraw,changelayer:this.redraw,removelayer:this.redraw,changebaselayer:this.redraw,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments)},setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);this.map.events.on({addlayer:this.redraw,changelayer:this.redraw,removelayer:this.redraw,changebaselayer:this.redraw,scope:this})}, -draw:function(){OpenLayers.Control.prototype.draw.apply(this);this.loadContents();this.outsideViewport||this.minimizeControl();this.redraw();return this.div},clearLayersArray:function(a){var b=this[a+"Layers"];if(b)for(var c=0,d=b.length;c Date: Tue, 28 Aug 2012 16:47:38 -0600 Subject: [PATCH 05/36] Pixel values on events are now fractional. --- examples/raster-query.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/raster-query.js b/examples/raster-query.js index f6a73434da..60d47982fa 100644 --- a/examples/raster-query.js +++ b/examples/raster-query.js @@ -18,7 +18,7 @@ var Click = OpenLayers.Class(OpenLayers.Control, { }, trigger: function(event) { var pixel = event.xy; - pixelValues = vegData.getValue(pixel.x, pixel.y); + pixelValues = vegData.getValue(Math.round(pixel.x), Math.round(pixel.y)); selected.events.triggerEvent("update"); } }); From 746160f2c5ea795b6f29685ca67bdb9715b22cc9 Mon Sep 17 00:00:00 2001 From: tschaub Date: Tue, 28 Aug 2012 16:48:12 -0600 Subject: [PATCH 06/36] Example updates. --- examples/raster-array.html | 3 --- examples/raster-grid-layer.html | 3 --- examples/raster-grid-layer.js | 5 ----- examples/raster-magnify.html | 7 ------- examples/raster-magnify.js | 5 ----- examples/raster-operations.html | 3 --- examples/raster-operations.js | 5 ----- examples/raster-query.html | 9 +-------- examples/raster-query.js | 1 - 9 files changed, 1 insertion(+), 40 deletions(-) diff --git a/examples/raster-array.html b/examples/raster-array.html index 95d1bb4017..c6a95145a8 100644 --- a/examples/raster-array.html +++ b/examples/raster-array.html @@ -12,9 +12,6 @@ + + +

Download Raster

+
+ Raster, Grid, Download +
+

This demo shows how raster data can be downloaded.

+
+

+ Download links: +

+

+
+

+ See the raster-download.js + source for details on how this is done. +

+
+ + + diff --git a/examples/raster-download.js b/examples/raster-download.js new file mode 100644 index 0000000000..607f89a088 --- /dev/null +++ b/examples/raster-download.js @@ -0,0 +1,29 @@ +var marble = new OpenLayers.Layer.WMS( + "Blue Marble", + "/geoserver/wms", + {layers: "topp:bluemarble", format: "image/png"} +); + +var data = OpenLayers.Raster.Composite.fromLayer(marble); + +var map = new OpenLayers.Map({ + div: "map", + theme: null, + layers: [marble], + center: new OpenLayers.LonLat(0, 0), + zoom: 1 +}); + +var types = { + png: "image/png", + jpg: "image/jpeg", + gif: "image/gif" +}; + +for (var type in types) { + var link = document.getElementById(type + "-link"); + link.onmouseover = (function(link, type) {return function() { + link.href = data.toDataURL(types[type]); + }})(link, type); +} + diff --git a/lib/OpenLayers/Raster/Composite.js b/lib/OpenLayers/Raster/Composite.js index 981a24bbec..a227334cbb 100644 --- a/lib/OpenLayers/Raster/Composite.js +++ b/lib/OpenLayers/Raster/Composite.js @@ -93,6 +93,9 @@ OpenLayers.Raster.Composite.fromLayer = function(layer) { var cols = canvas.width; var offset = 4 * (col + (row * cols)); return Array.prototype.slice.apply(pixelArray, [offset, offset+4]); + }, + toDataURL: function() { + return canvas.toDataURL.apply(canvas, arguments); } }); From 6b6aa29e97945c4234466c2fb4f7456d14220eb1 Mon Sep 17 00:00:00 2001 From: tschaub Date: Tue, 28 Aug 2012 17:28:02 -0600 Subject: [PATCH 08/36] Shell for vector to raster conversion. --- examples/raster-from-vector.html | 61 ++++++++++++++++++++++++++++++ examples/raster-from-vector.js | 38 +++++++++++++++++++ lib/OpenLayers/Raster/Composite.js | 18 +++++++-- 3 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 examples/raster-from-vector.html create mode 100644 examples/raster-from-vector.js diff --git a/examples/raster-from-vector.html b/examples/raster-from-vector.html new file mode 100644 index 0000000000..88215c0af3 --- /dev/null +++ b/examples/raster-from-vector.html @@ -0,0 +1,61 @@ + + + + + + + Drag Feature Example + + + + + + + + +

Drag Feature Example

+ +
+ point, line, linestring, polygon, digitizing, geometry, draw, drag +
+ +

+ Demonstrates point, line and polygon creation and editing. +

+ +
+ +
+
    +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
+
+ +
+ + + diff --git a/examples/raster-from-vector.js b/examples/raster-from-vector.js new file mode 100644 index 0000000000..a46b10007a --- /dev/null +++ b/examples/raster-from-vector.js @@ -0,0 +1,38 @@ +var map = new OpenLayers.Map('map'); +var wms = new OpenLayers.Layer.WMS( "OpenLayers WMS", + "http://vmap0.tiles.osgeo.org/wms/vmap0?", {layers: 'basic'}); + +var vectors = new OpenLayers.Layer.Vector("Vector Layer"); + +var zones = OpenLayers.Raster.Composite.fromLayer(vectors, { + mapping: function(feature) { + return [255, 255, 255, 150]; + } +}); + +map.addLayers([wms, vectors]); +map.addControl(new OpenLayers.Control.LayerSwitcher()); + +var controls = { + polygon: new OpenLayers.Control.DrawFeature(vectors, + OpenLayers.Handler.Polygon), + drag: new OpenLayers.Control.DragFeature(vectors) +}; + +for(var key in controls) { + map.addControl(controls[key]); +} + +map.setCenter(new OpenLayers.LonLat(0, 0), 3); +document.getElementById('noneToggle').checked = true; + +function toggleControl(element) { + for(key in controls) { + var control = controls[key]; + if(element.value == key && element.checked) { + control.activate(); + } else { + control.deactivate(); + } + } +} diff --git a/lib/OpenLayers/Raster/Composite.js b/lib/OpenLayers/Raster/Composite.js index a227334cbb..22e95811d7 100644 --- a/lib/OpenLayers/Raster/Composite.js +++ b/lib/OpenLayers/Raster/Composite.js @@ -69,11 +69,23 @@ OpenLayers.Raster.Composite = OpenLayers.Class(OpenLayers.Raster.Grid, (function })()); -OpenLayers.Raster.Composite.fromLayer = function(layer) { - - if (!(layer instanceof OpenLayers.Layer.Grid)) { +OpenLayers.Raster.Composite.fromLayer = function(layer, options) { + var composite; + if (layer instanceof OpenLayers.Layer.Grid) { + composite = OpenLayers.Raster.Composite.fromGridLayer(layer); + } else if (layer instanceof OpenLayers.Layer.Vector) { + composite = OpenLayers.Raster.Composite.fromVectorLayer(layer, options); + } else { throw new Error("Only OpenLayers.Layer.Grid type layers can be used to create a raster"); } + return composite; +}; + +OpenLayers.Raster.Composite.fromVectorLayer = function(layer, options) { + return null; +}; + +OpenLayers.Raster.Composite.fromGridLayer = function(layer) { var canvas = document.createElement("canvas"); var context = canvas.getContext("2d"); From e4c85e36ea565dd1bcfc8eaf8202f26a6c5e0824 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Tue, 28 Aug 2012 22:48:54 -0600 Subject: [PATCH 09/36] Trigger featuremodified when dragging. --- lib/OpenLayers/Control/DragFeature.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/OpenLayers/Control/DragFeature.js b/lib/OpenLayers/Control/DragFeature.js index af81062e76..c28de44565 100644 --- a/lib/OpenLayers/Control/DragFeature.js +++ b/lib/OpenLayers/Control/DragFeature.js @@ -314,6 +314,7 @@ OpenLayers.Control.DragFeature = OpenLayers.Class(OpenLayers.Control, { * came from a mouseout, this may not be in the map viewport. */ doneDragging: function(pixel) { + this.layer.events.triggerEvent("featuremodified", {feature: this.feature}); this.onComplete(this.feature, pixel); }, From 0d3ffae93780bb23f471ca1b02c1f1c02578edd2 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Tue, 28 Aug 2012 22:49:34 -0600 Subject: [PATCH 10/36] Creation of raster composite from vector layer. --- examples/raster-from-vector.html | 8 +- examples/raster-from-vector.js | 31 +++++--- lib/OpenLayers/Layer/Raster.js | 1 + lib/OpenLayers/Raster/Composite.js | 124 ++++++++++++++++++++++++++++- 4 files changed, 150 insertions(+), 14 deletions(-) diff --git a/examples/raster-from-vector.html b/examples/raster-from-vector.html index 88215c0af3..653bfab7fd 100644 --- a/examples/raster-from-vector.html +++ b/examples/raster-from-vector.html @@ -4,7 +4,7 @@ - Drag Feature Example + Rasterize Feature Example @@ -24,14 +24,14 @@ -

Drag Feature Example

+

Rasterize Feature Example

- point, line, linestring, polygon, digitizing, geometry, draw, drag + raster, feature

- Demonstrates point, line and polygon creation and editing. + Demonstrates the rasterization of vector features.

diff --git a/examples/raster-from-vector.js b/examples/raster-from-vector.js index a46b10007a..36c0b4ebf2 100644 --- a/examples/raster-from-vector.js +++ b/examples/raster-from-vector.js @@ -1,29 +1,42 @@ -var map = new OpenLayers.Map('map'); -var wms = new OpenLayers.Layer.WMS( "OpenLayers WMS", - "http://vmap0.tiles.osgeo.org/wms/vmap0?", {layers: 'basic'}); +var marble = new OpenLayers.Layer.WMS( + "Blue Marble", + "http://demo.opengeo.org/geoserver/wms", + {layers: "topp:bluemarble", format: "image/png"} +); -var vectors = new OpenLayers.Layer.Vector("Vector Layer"); +var vector = new OpenLayers.Layer.Vector("Vector Features"); -var zones = OpenLayers.Raster.Composite.fromLayer(vectors, { +var composite = OpenLayers.Raster.Composite.fromLayer(vector, { mapping: function(feature) { + // return a 4 element array based on feature return [255, 255, 255, 150]; } }); -map.addLayers([wms, vectors]); +var raster = new OpenLayers.Layer.Raster({ + name: "Rasterized Features", + data: composite +}); + +var map = new OpenLayers.Map({ + div: "map", + layers: [marble, vector, raster], + center: [0, 0], + zoom: 1 +}); + map.addControl(new OpenLayers.Control.LayerSwitcher()); var controls = { - polygon: new OpenLayers.Control.DrawFeature(vectors, + polygon: new OpenLayers.Control.DrawFeature(vector, OpenLayers.Handler.Polygon), - drag: new OpenLayers.Control.DragFeature(vectors) + drag: new OpenLayers.Control.DragFeature(vector) }; for(var key in controls) { map.addControl(controls[key]); } -map.setCenter(new OpenLayers.LonLat(0, 0), 3); document.getElementById('noneToggle').checked = true; function toggleControl(element) { diff --git a/lib/OpenLayers/Layer/Raster.js b/lib/OpenLayers/Layer/Raster.js index b1aa2e8f48..de60a1425c 100644 --- a/lib/OpenLayers/Layer/Raster.js +++ b/lib/OpenLayers/Layer/Raster.js @@ -70,6 +70,7 @@ OpenLayers.Layer.Raster = OpenLayers.Class(OpenLayers.Layer, { var imageData = this.context.createImageData(cols, rows); var data = imageData.data; + // TODO: provide shortcut for canvas based composites this.data.forEach(function(value, index) { var offset = 4 * index; if (!value.length) { diff --git a/lib/OpenLayers/Raster/Composite.js b/lib/OpenLayers/Raster/Composite.js index 22e95811d7..1fe0eb3402 100644 --- a/lib/OpenLayers/Raster/Composite.js +++ b/lib/OpenLayers/Raster/Composite.js @@ -82,7 +82,128 @@ OpenLayers.Raster.Composite.fromLayer = function(layer, options) { }; OpenLayers.Raster.Composite.fromVectorLayer = function(layer, options) { - return null; + + var mapping = options && options.mapping || function(feature) { + return [255, 255, 255, 255] + }; + + var container = document.createElement("div"); + var renderer = new OpenLayers.Renderer.Canvas(container, { + hitDetection: false + }); + + var canvas = renderer.root; + var context = renderer.canvas; + + var composite = new OpenLayers.Raster.Composite({ + numCols: function() { + return canvas.width; + }, + numRows: function() { + return canvas.height; + }, + getCount: function() { + return 4; + }, + getValue: function(col, row) { + var pixelArray = getPixelArray(); + var cols = canvas.width; + var offset = 4 * (col + (row * cols)); + return Array.prototype.slice.apply(pixelArray, [offset, offset+4]); + }, + toDataURL: function() { + return canvas.toDataURL.apply(canvas, arguments); + } + }); + + var cache = {}; + function getPixelArray() { + if (!cache.pixelArray) { + var imageData = context.getImageData(0, 0, canvas.width, canvas.height); + cache.pixelArray = imageData.data; + } + return cache.pixelArray; + } + + function hex(value) { + value = Math.max(0, Math.min(255, value)); + return (3840 + value).toString(16).substring(1); + } + + var style = new OpenLayers.Style({ + stroke: false, + fillColor: "${getColor}", + fillOpacity: "${getOpacity}" + }, {context: { + getColor: function(feature) { + var rgba = mapping(feature); + return "#" + + hex(rgba[0]) + + hex(rgba[1]) + + hex(rgba[2]); + }, + getOpacity: function(feature) { + var rgba = mapping(feature); + return rgba[3] / 255; + } + }}); + + var clone = new OpenLayers.Layer.Vector(null, { + styleMap: new OpenLayers.StyleMap(style), + renderer: renderer + }); + + function triggerUpdate() { + cache = {}; + composite.events.triggerEvent("update"); + } + + function addFeatures(event) { + var features = event.features; + clone.addFeatures(features, {silent: true}); + + // features can only be added to one layer + // work around this by reassigning to original + for (var i=0, ii=features.length; i Date: Tue, 28 Aug 2012 23:05:53 -0600 Subject: [PATCH 11/36] Update raster build. --- OpenLayers.js | 561 +++++++++++++++++++---------- build/raster.cfg | 6 + examples/raster-download.html | 3 +- examples/raster-from-vector.html | 2 +- examples/raster-query.html | 2 +- lib/OpenLayers/Raster/Composite.js | 1 + 6 files changed, 382 insertions(+), 193 deletions(-) diff --git a/OpenLayers.js b/OpenLayers.js index 13cad74d98..3cfe629f60 100644 --- a/OpenLayers.js +++ b/OpenLayers.js @@ -55,59 +55,49 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ -var OpenLayers={VERSION_NUMBER:"Release 2.12-rc1",singleFile:!0,_getScriptLocation:function(){for(var a=/(^|(.*?\/))(OpenLayers.*?\.js)(\?|$)/,b=document.getElementsByTagName("script"),c,d="",e=0,f=b.length;ethis.duration&&this.stop()},CLASS_NAME:"OpenLayers.Tween"});OpenLayers.Easing={CLASS_NAME:"OpenLayers.Easing"};OpenLayers.Easing.Linear={easeIn:function(a,b,c,d){return c*a/d+b},easeOut:function(a,b,c,d){return c*a/d+b},easeInOut:function(a,b,c,d){return c*a/d+b},CLASS_NAME:"OpenLayers.Easing.Linear"}; -OpenLayers.Easing.Expo={easeIn:function(a,b,c,d){return 0==a?b:c*Math.pow(2,10*(a/d-1))+b},easeOut:function(a,b,c,d){return a==d?b+c:c*(-Math.pow(2,-10*a/d)+1)+b},easeInOut:function(a,b,c,d){return 0==a?b:a==d?b+c:1>(a/=d/2)?c/2*Math.pow(2,10*(a-1))+b:c/2*(-Math.pow(2,-10*--a)+2)+b},CLASS_NAME:"OpenLayers.Easing.Expo"}; -OpenLayers.Easing.Quad={easeIn:function(a,b,c,d){return c*(a/=d)*a+b},easeOut:function(a,b,c,d){return-c*(a/=d)*(a-2)+b},easeInOut:function(a,b,c,d){return 1>(a/=d/2)?c/2*a*a+b:-c/2*(--a*(a-2)-1)+b},CLASS_NAME:"OpenLayers.Easing.Quad"};OpenLayers.Raster.Grid=OpenLayers.Class({EVENT_TYPES:["update"],initialize:function(a){OpenLayers.Util.extend(this,a);this.events=new OpenLayers.Events(this,null,this.EVENT_TYPES)},getValue:function(){throw Error("getValue must be defined");},numCols:function(){throw Error("numCols must be defined");},numRows:function(){throw Error("numRows must be defined");},forEach:function(a){for(var b=this.numCols(),c=this.numRows(),d=0;da||a>=this.getCount())throw Error("Bad grid index.");var c=this;return new OpenLayers.Raster.Grid({numCols:function(){return c.numCols()},numRows:function(){return c.numRows()},getValue:function(d,e){return c.getValue(d,e)[a]}})},CLASS_NAME:"OpenLayers.Raster.Composite"}}()); -OpenLayers.Raster.Composite.fromLayer=function(a){var b;function c(){b=void 0;var c=a.map,h=a.tileSize,i=c.getSize();d.width=i.w;d.height=i.h;for(var i=c.getExtent(),j=a.grid,o,q,l,k=0,p=j.length;kthis.right)this.right=b.right;if(null==this.top||b.top>this.top)this.top=b.top}}},containsLonLat:function(a,b){"boolean"===typeof b&&(b={inclusive:b});var b=b||{},c=this.contains(a.lon,a.lat,b.inclusive),d=b.worldBounds;d&&!c&&(c=d.getWidth(),d=Math.round((a.lon-(d.left+d.right)/2)/c),c=this.containsLonLat({lon:a.lon-d*c,lat:a.lat},{inclusive:b.inclusive}));return c},containsPixel:function(a,b){return this.contains(a.x, -a.y,b)},contains:function(a,b,c){null==c&&(c=!0);if(null==a||null==b)return!1;var a=OpenLayers.Util.toFloat(a),b=OpenLayers.Util.toFloat(b),d=!1;return d=c?a>=this.left&&a<=this.right&&b>=this.bottom&&b<=this.top:a>this.left&&athis.bottom&&b=this.left&&a<=this.right&&b>=this.bottom&&b<=this.top:a>this.left&&athis.bottom&&b=c.bottom&&a.top<=c.top||c.top>a.bottom&&c.top=c.left&&a.left<=c.right||c.left>=a.left&&c.left<=a.right,f=a.right>=c.left&&a.right<=c.right||c.right>=a.left&&c.right<=a.right,d=(a.bottom>=c.bottom&&a.bottom<=c.top||c.bottom>=a.bottom&&c.bottom<=a.top||d)&&(e||f);if(b.worldBounds&&!d){var g=b.worldBounds,e=g.getWidth(),f=!g.containsBounds(c),g=!g.containsBounds(a);f&&!g?(a=a.add(-e,0),d=c.intersectsBounds(a, {inclusive:b.inclusive})):g&&!f&&(c=c.add(-e,0),d=a.intersectsBounds(c,{inclusive:b.inclusive}))}return d},containsBounds:function(a,b,c){null==b&&(b=!1);null==c&&(c=!0);var d=this.contains(a.left,a.bottom,c),e=this.contains(a.right,a.bottom,c),f=this.contains(a.left,a.top,c),a=this.contains(a.right,a.top,c);return b?d||e||f||a:d&&e&&f&&a},determineQuadrant:function(a){var b="",c=this.getCenterLonLat(),b=b+(a.lat=a.right&&e.right>a.right;)e=e.add(-f,0);c=e.left+c;ca.left&&e.right-d>a.right&&(e=e.add(-f,0))}return e},CLASS_NAME:"OpenLayers.Bounds"});OpenLayers.Bounds.fromString=function(a,b){var c=a.split(",");return OpenLayers.Bounds.fromArray(c,b)};OpenLayers.Bounds.fromArray=function(a,b){return!0===b?new OpenLayers.Bounds(a[1],a[0],a[3],a[2]):new OpenLayers.Bounds(a[0],a[1],a[2],a[3])}; +a.getWidth();e.left=a.right&&e.right>a.right;)e=e.add(-f,0);c=e.left+c;ca.left&&e.right-d>a.right)&&(e=e.add(-f,0))}return e},CLASS_NAME:"OpenLayers.Bounds"});OpenLayers.Bounds.fromString=function(a,b){var c=a.split(",");return OpenLayers.Bounds.fromArray(c,b)};OpenLayers.Bounds.fromArray=function(a,b){return!0===b?new OpenLayers.Bounds(a[1],a[0],a[3],a[2]):new OpenLayers.Bounds(a[0],a[1],a[2],a[3])}; OpenLayers.Bounds.fromSize=function(a){return new OpenLayers.Bounds(0,a.h,a.w,0)};OpenLayers.Bounds.oppositeQuadrant=function(a){var b;b=""+("t"==a.charAt(0)?"b":"t");return b+="l"==a.charAt(1)?"r":"l"};OpenLayers.Element={visible:function(a){return"none"!=OpenLayers.Util.getElement(a).style.display},toggle:function(){for(var a=0,b=arguments.length;aa.right;)b.lon-=a.getWidth()}return b},CLASS_NAME:"OpenLayers.LonLat"}); OpenLayers.LonLat.fromString=function(a){a=a.split(",");return new OpenLayers.LonLat(a[0],a[1])};OpenLayers.LonLat.fromArray=function(a){var b=OpenLayers.Util.isArray(a);return new OpenLayers.LonLat(b&&a[0],b&&a[1])};OpenLayers.Pixel=OpenLayers.Class({x:0,y:0,initialize:function(a,b){this.x=parseFloat(a);this.y=parseFloat(b)},toString:function(){return"x="+this.x+",y="+this.y},clone:function(){return new OpenLayers.Pixel(this.x,this.y)},equals:function(a){var b=!1;null!=a&&(b=this.x==a.x&&this.y==a.y||isNaN(this.x)&&isNaN(this.y)&&isNaN(a.x)&&isNaN(a.y));return b},distanceTo:function(a){return Math.sqrt(Math.pow(this.x-a.x,2)+Math.pow(this.y-a.y,2))},add:function(a,b){if(null==a||null==b)throw new TypeError("Pixel.add cannot receive null values"); return new OpenLayers.Pixel(this.x+a,this.y+b)},offset:function(a){var b=this.clone();a&&(b=this.add(a.x,a.y));return b},CLASS_NAME:"OpenLayers.Pixel"});OpenLayers.Size=OpenLayers.Class({w:0,h:0,initialize:function(a,b){this.w=parseFloat(a);this.h=parseFloat(b)},toString:function(){return"w="+this.w+",h="+this.h},clone:function(){return new OpenLayers.Size(this.w,this.h)},equals:function(a){var b=!1;null!=a&&(b=this.w==a.w&&this.h==a.h||isNaN(this.w)&&isNaN(this.h)&&isNaN(a.w)&&isNaN(a.h));return b},CLASS_NAME:"OpenLayers.Size"});OpenLayers.Console={log:function(){},debug:function(){},info:function(){},warn:function(){},error:function(){},userError:function(a){alert(a)},assert:function(){},dir:function(){},dirxml:function(){},trace:function(){},group:function(){},groupEnd:function(){},time:function(){},timeEnd:function(){},profile:function(){},profileEnd:function(){},count:function(){},CLASS_NAME:"OpenLayers.Console"}; -(function(){for(var a=document.getElementsByTagName("script"),b=0,c=a.length;bparseFloat(h))a.style.filter="alpha(opacity="+100*h+")",a.style.opacity=h;else if(1==parseFloat(h))a.style.filter="",a.style.opacity=""}; -OpenLayers.Util.createDiv=function(a,b,c,d,e,f,g,h){var i=document.createElement("div");if(d)i.style.backgroundImage="url("+d+")";a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="absolute");OpenLayers.Util.modifyDOMElement(i,a,b,c,e,f,g,h);return i}; -OpenLayers.Util.createImage=function(a,b,c,d,e,f,g,h){var i=document.createElement("img");a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="relative");OpenLayers.Util.modifyDOMElement(i,a,b,c,e,f,null,g);if(h)i.style.display="none",b=function(){i.style.display="";OpenLayers.Event.stopObservingElement(i)},OpenLayers.Event.observe(i,"load",b),OpenLayers.Event.observe(i,"error",b);i.style.alt=a;i.galleryImg="no";if(d)i.src=d;return i};OpenLayers.IMAGE_RELOAD_ATTEMPTS=0; +(function(){for(var a=document.getElementsByTagName("script"),b=0,c=a.length;bparseFloat(h)?(a.style.filter="alpha(opacity="+100*h+")",a.style.opacity=h):1==parseFloat(h)&&(a.style.filter="",a.style.opacity="")}; +OpenLayers.Util.createDiv=function(a,b,c,d,e,f,g,h){var i=document.createElement("div");d&&(i.style.backgroundImage="url("+d+")");a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="absolute");OpenLayers.Util.modifyDOMElement(i,a,b,c,e,f,g,h);return i}; +OpenLayers.Util.createImage=function(a,b,c,d,e,f,g,h){var i=document.createElement("img");a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="relative");OpenLayers.Util.modifyDOMElement(i,a,b,c,e,f,null,g);h&&(i.style.display="none",b=function(){i.style.display="";OpenLayers.Event.stopObservingElement(i)},OpenLayers.Event.observe(i,"load",b),OpenLayers.Event.observe(i,"error",b));i.style.alt=a;i.galleryImg="no";d&&(i.src=d);return i};OpenLayers.IMAGE_RELOAD_ATTEMPTS=0; OpenLayers.Util.alphaHackNeeded=null;OpenLayers.Util.alphaHack=function(){if(null==OpenLayers.Util.alphaHackNeeded){var a=navigator.appVersion.split("MSIE"),a=parseFloat(a[1]),b=!1;try{b=!!document.body.filters}catch(c){}OpenLayers.Util.alphaHackNeeded=b&&5.5<=a&&7>a}return OpenLayers.Util.alphaHackNeeded}; -OpenLayers.Util.modifyAlphaImageDiv=function(a,b,c,d,e,f,g,h,i){OpenLayers.Util.modifyDOMElement(a,b,c,d,f,null,null,i);b=a.childNodes[0];if(e)b.src=e;OpenLayers.Util.modifyDOMElement(b,a.id+"_innerImage",null,d,"relative",g);if(OpenLayers.Util.alphaHack()){if("none"!=a.style.display)a.style.display="inline-block";null==h&&(h="scale");a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+b.src+"', sizingMethod='"+h+"')";0<=parseFloat(a.style.opacity)&&1>parseFloat(a.style.opacity)&& -(a.style.filter+=" alpha(opacity="+100*a.style.opacity+")");b.style.filter="alpha(opacity=0)"}};OpenLayers.Util.createAlphaImageDiv=function(a,b,c,d,e,f,g,h,i){var j=OpenLayers.Util.createDiv(),i=OpenLayers.Util.createImage(null,null,null,null,null,null,null,i);i.className="olAlphaImg";j.appendChild(i);OpenLayers.Util.modifyAlphaImageDiv(j,a,b,c,d,e,f,g,h);return j};OpenLayers.Util.upperCaseObject=function(a){var b={},c;for(c in a)b[c.toUpperCase()]=a[c];return b}; -OpenLayers.Util.applyDefaults=function(a,b){var a=a||{},c="function"==typeof window.Event&&b instanceof window.Event,d;for(d in b)if(void 0===a[d]||!c&&b.hasOwnProperty&&b.hasOwnProperty(d)&&!a.hasOwnProperty(d))a[d]=b[d];if(!c&&b&&b.hasOwnProperty&&b.hasOwnProperty("toString")&&!a.hasOwnProperty("toString"))a.toString=b.toString;return a}; +OpenLayers.Util.modifyAlphaImageDiv=function(a,b,c,d,e,f,g,h,i){OpenLayers.Util.modifyDOMElement(a,b,c,d,f,null,null,i);b=a.childNodes[0];e&&(b.src=e);OpenLayers.Util.modifyDOMElement(b,a.id+"_innerImage",null,d,"relative",g);OpenLayers.Util.alphaHack()&&("none"!=a.style.display&&(a.style.display="inline-block"),null==h&&(h="scale"),a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+b.src+"', sizingMethod='"+h+"')",0<=parseFloat(a.style.opacity)&&1>parseFloat(a.style.opacity)&& +(a.style.filter+=" alpha(opacity="+100*a.style.opacity+")"),b.style.filter="alpha(opacity=0)")};OpenLayers.Util.createAlphaImageDiv=function(a,b,c,d,e,f,g,h,i){var j=OpenLayers.Util.createDiv(),i=OpenLayers.Util.createImage(null,null,null,null,null,null,null,i);i.className="olAlphaImg";j.appendChild(i);OpenLayers.Util.modifyAlphaImageDiv(j,a,b,c,d,e,f,g,h);return j};OpenLayers.Util.upperCaseObject=function(a){var b={},c;for(c in a)b[c.toUpperCase()]=a[c];return b}; +OpenLayers.Util.applyDefaults=function(a,b){var a=a||{},c="function"==typeof window.Event&&b instanceof window.Event,d;for(d in b)if(void 0===a[d]||!c&&b.hasOwnProperty&&b.hasOwnProperty(d)&&!a.hasOwnProperty(d))a[d]=b[d];!c&&(b&&b.hasOwnProperty&&b.hasOwnProperty("toString")&&!a.hasOwnProperty("toString"))&&(a.toString=b.toString);return a}; OpenLayers.Util.getParameterString=function(a){var b=[],c;for(c in a){var d=a[c];if(null!=d&&"function"!=typeof d){if("object"==typeof d&&d.constructor==Array){for(var e=[],f,g=0,h=d.length;ge&&(e="0"+e);e+="\u00b0";0<=c.indexOf("dm")&&(10>d&&(d="0"+d),e+=d+"'",0<=c.indexOf("dms")&&(10>f&&(f="0"+f),e+=f+'"'));return e="lon"==b?e+(0>a?OpenLayers.i18n("W"):OpenLayers.i18n("E")):e+(0>a?OpenLayers.i18n("S"):OpenLayers.i18n("N"))};OpenLayers.Event={observers:!1,KEY_SPACE:32,KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,element:function(a){return a.target||a.srcElement},isSingleTouch:function(a){return a.touches&&1==a.touches.length},isMultiTouch:function(a){return a.touches&&1e&&(e="0"+e);e+="\u00b0";0<=c.indexOf("dm")&&(10>d&&(d="0"+d),e+=d+"'",0<=c.indexOf("dms")&&(10>f&&(f="0"+f),e+=f+'"'));return e="lon"==b?e+(0>a?OpenLayers.i18n("W"):OpenLayers.i18n("E")):e+(0>a?OpenLayers.i18n("S"):OpenLayers.i18n("N"))};OpenLayers.Feature=OpenLayers.Class({layer:null,id:null,lonlat:null,data:null,marker:null,popupClass:null,popup:null,initialize:function(a,b,c){this.layer=a;this.lonlat=b;this.data=null!=c?c:{};this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){null!=this.layer&&null!=this.layer.map&&null!=this.popup&&this.layer.map.removePopup(this.popup);null!=this.layer&&null!=this.marker&&this.layer.removeMarker(this.marker);this.data=this.lonlat=this.id=this.layer=null;null!=this.marker&& +(this.destroyMarker(this.marker),this.marker=null);null!=this.popup&&(this.destroyPopup(this.popup),this.popup=null)},onScreen:function(){var a=!1;null!=this.layer&&null!=this.layer.map&&(a=this.layer.map.getExtent().containsLonLat(this.lonlat));return a},createMarker:function(){null!=this.lonlat&&(this.marker=new OpenLayers.Marker(this.lonlat,this.data.icon));return this.marker},destroyMarker:function(){this.marker.destroy()},createPopup:function(a){null!=this.lonlat&&(this.popup||(this.popup=new (this.popupClass? +this.popupClass:OpenLayers.Popup.Anchored)(this.id+"_popup",this.lonlat,this.data.popupSize,this.data.popupContentHTML,this.marker?this.marker.icon:null,a)),null!=this.data.overflow&&(this.popup.contentDiv.style.overflow=this.data.overflow),this.popup.feature=this);return this.popup},destroyPopup:function(){this.popup&&(this.popup.feature=null,this.popup.destroy(),this.popup=null)},CLASS_NAME:"OpenLayers.Feature"});OpenLayers.State={UNKNOWN:"Unknown",INSERT:"Insert",UPDATE:"Update",DELETE:"Delete"}; +OpenLayers.Feature.Vector=OpenLayers.Class(OpenLayers.Feature,{fid:null,geometry:null,attributes:null,bounds:null,state:null,style:null,url:null,renderIntent:"default",modified:null,initialize:function(a,b,c){OpenLayers.Feature.prototype.initialize.apply(this,[null,null,b]);this.lonlat=null;this.geometry=a?a:null;this.state=null;this.attributes={};b&&(this.attributes=OpenLayers.Util.extend(this.attributes,b));this.style=c?c:null},destroy:function(){this.layer&&(this.layer.removeFeatures(this),this.layer= +null);this.modified=this.geometry=null;OpenLayers.Feature.prototype.destroy.apply(this,arguments)},clone:function(){return new OpenLayers.Feature.Vector(this.geometry?this.geometry.clone():null,this.attributes,this.style)},onScreen:function(a){var b=!1;this.layer&&this.layer.map&&(b=this.layer.map.getExtent(),a?(a=this.geometry.getBounds(),b=b.intersectsBounds(a)):b=b.toGeometry().intersects(this.geometry));return b},getVisibility:function(){return!(this.style&&"none"==this.style.display||!this.layer|| +this.layer&&this.layer.styleMap&&"none"==this.layer.styleMap.createSymbolizer(this,this.renderIntent).display||this.layer&&!this.layer.getVisibility())},createMarker:function(){return null},destroyMarker:function(){},createPopup:function(){return null},atPoint:function(a,b,c){var d=!1;this.geometry&&(d=this.geometry.atPoint(a,b,c));return d},destroyPopup:function(){},move:function(a){if(this.layer&&this.geometry.move){var a="OpenLayers.LonLat"==a.CLASS_NAME?this.layer.getViewPortPxFromLonLat(a):a, +b=this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat()),c=this.layer.map.getResolution();this.geometry.move(c*(a.x-b.x),c*(b.y-a.y));this.layer.drawFeature(this);return b}},toState:function(a){if(a==OpenLayers.State.UPDATE)switch(this.state){case OpenLayers.State.UNKNOWN:case OpenLayers.State.DELETE:this.state=a}else if(a==OpenLayers.State.INSERT)switch(this.state){case OpenLayers.State.UNKNOWN:break;default:this.state=a}else if(a==OpenLayers.State.DELETE)switch(this.state){case OpenLayers.State.UNKNOWN:case OpenLayers.State.UPDATE:this.state= +a}else a==OpenLayers.State.UNKNOWN&&(this.state=a)},CLASS_NAME:"OpenLayers.Feature.Vector"}); +OpenLayers.Feature.Vector.style={"default":{fillColor:"#ee9900",fillOpacity:0.4,hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"#ee9900",strokeOpacity:1,strokeWidth:1,strokeLinecap:"round",strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"inherit",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},select:{fillColor:"blue",fillOpacity:0.4, +hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"blue",strokeOpacity:1,strokeWidth:2,strokeLinecap:"round",strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"pointer",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},temporary:{fillColor:"#66cccc",fillOpacity:0.2,hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"#66cccc",strokeOpacity:1, +strokeLinecap:"round",strokeWidth:2,strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"inherit",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},"delete":{display:"none"}};OpenLayers.Style=OpenLayers.Class({id:null,name:null,title:null,description:null,layerName:null,isDefault:!1,rules:null,context:null,defaultStyle:null,defaultsPerSymbolizer:!1,propertyStyles:null,initialize:function(a,b){OpenLayers.Util.extend(this,b);this.rules=[];b&&b.rules&&this.addRules(b.rules);this.setDefaultStyle(a||OpenLayers.Feature.Vector.style["default"]);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){for(var a=0,b=this.rules.length;athis.duration&&this.stop()},CLASS_NAME:"OpenLayers.Tween"});OpenLayers.Easing={CLASS_NAME:"OpenLayers.Easing"};OpenLayers.Easing.Linear={easeIn:function(a,b,c,d){return c*a/d+b},easeOut:function(a,b,c,d){return c*a/d+b},easeInOut:function(a,b,c,d){return c*a/d+b},CLASS_NAME:"OpenLayers.Easing.Linear"}; +OpenLayers.Easing.Expo={easeIn:function(a,b,c,d){return 0==a?b:c*Math.pow(2,10*(a/d-1))+b},easeOut:function(a,b,c,d){return a==d?b+c:c*(-Math.pow(2,-10*a/d)+1)+b},easeInOut:function(a,b,c,d){return 0==a?b:a==d?b+c:1>(a/=d/2)?c/2*Math.pow(2,10*(a-1))+b:c/2*(-Math.pow(2,-10*--a)+2)+b},CLASS_NAME:"OpenLayers.Easing.Expo"}; +OpenLayers.Easing.Quad={easeIn:function(a,b,c,d){return c*(a/=d)*a+b},easeOut:function(a,b,c,d){return-c*(a/=d)*(a-2)+b},easeInOut:function(a,b,c,d){return 1>(a/=d/2)?c/2*a*a+b:-c/2*(--a*(a-2)-1)+b},CLASS_NAME:"OpenLayers.Easing.Quad"};OpenLayers.Geometry=OpenLayers.Class({id:null,parent:null,bounds:null,initialize:function(){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){this.bounds=this.id=null},clone:function(){return new OpenLayers.Geometry},setBounds:function(a){a&&(this.bounds=a.clone())},clearBounds:function(){this.bounds=null;this.parent&&this.parent.clearBounds()},extendBounds:function(a){this.getBounds()?this.bounds.extend(a):this.setBounds(a)},getBounds:function(){null==this.bounds&&this.calculateBounds(); +return this.bounds},calculateBounds:function(){},distanceTo:function(){},getVertices:function(){},atPoint:function(a,b,c){var d=!1;null!=this.getBounds()&&null!=a&&(b=null!=b?b:0,c=null!=c?c:0,d=(new OpenLayers.Bounds(this.bounds.left-b,this.bounds.bottom-c,this.bounds.right+b,this.bounds.top+c)).containsLonLat(a));return d},getLength:function(){return 0},getArea:function(){return 0},getCentroid:function(){return null},toString:function(){return OpenLayers.Format&&OpenLayers.Format.WKT?OpenLayers.Format.WKT.prototype.write(new OpenLayers.Feature.Vector(this)): +Object.prototype.toString.call(this)},CLASS_NAME:"OpenLayers.Geometry"});OpenLayers.Geometry.fromWKT=function(a){var b;if(OpenLayers.Format&&OpenLayers.Format.WKT){var c=OpenLayers.Geometry.fromWKT.format;c||(c=new OpenLayers.Format.WKT,OpenLayers.Geometry.fromWKT.format=c);a=c.read(a);if(a instanceof OpenLayers.Feature.Vector)b=a.geometry;else if(OpenLayers.Util.isArray(a)){b=a.length;for(var c=Array(b),d=0;d=f&&0<=n&&1>=n)&&(d?(h=a.x1+f*h,n=a.y1+f*i,e=new OpenLayers.Geometry.Point(h,n)):e=!0));if(c)if(e){if(d){a=[a,b];b=0;a:for(;2>b;++b){f=a[b];for(i=1;3>i;++i)if(h=f["x"+i],n=f["y"+i],d=Math.sqrt(Math.pow(h-e.x,2)+Math.pow(n-e.y,2)),db;++b){h=a[b];n=a[(b+1)%2];for(i=1;3>i;++i)if(f={x:h["x"+i],y:h["y"+i]},g=OpenLayers.Geometry.distanceToSegment(f,n),g.distance=k||(1<=k?(e=g,f=h):(e+=k*i,f+=k*j));return{distance:Math.sqrt(Math.pow(e-c,2)+Math.pow(f-d,2)),x:e,y:f}};OpenLayers.Geometry.Collection=OpenLayers.Class(OpenLayers.Geometry,{components:null,componentTypes:null,initialize:function(a){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.components=[];null!=a&&this.addComponents(a)},destroy:function(){this.components.length=0;this.components=null;OpenLayers.Geometry.prototype.destroy.apply(this,arguments)},clone:function(){for(var a=eval("new "+this.CLASS_NAME+"()"),b=0,c=this.components.length;bf)break;if(!(i.x2Math.max(g,h))&&!(Math.max(j,k)h&&(i>j.y1&&ij.y2))break;e=c?{distance:e.distance,x0:e.x,y0:e.y,x1:h,y1:i}:e.distance}else if(a instanceof OpenLayers.Geometry.LineString){var g=this.getSortedSegments(),h=a.getSortedSegments(),m,l,o=h.length,p={point:!0},k=0,n=g.length;a:for(;kb.length)return this;var c=function(a,b,d,i){for(var j=0,k=0,n=b,m;nj&&(j=m,k=n)}j>i&&k!=b&&(e.push(k),c(a,b,k,i),c(a,k,d,i))},d=b.length-1,e=[];e.push(0);for(e.push(d);b[0].equals(b[d]);)d--,e.push(d);c(b,0,d,a);a=[];e.sort(function(a,b){return a-b});for(d=0;d=a)return this.components[0].clone();if(2=g&&c<=h||g>=h&&c<=g&&c>=h)){j=-1;break}}else{i=b((a-f)*((h-g)/(f-e))+h,14);if(i== +c&&(e=e&&a<=f||e>f&&a<=e&&a>=f)){j=-1;break}i<=c||g!=h&&(iMath.max(g,h))||(e=e&&af&&a=f)&&++j}return-1==j?1:!!(j&1)},intersects:function(a){var b=!1;if("OpenLayers.Geometry.Point"==a.CLASS_NAME)b=this.containsPoint(a);else if("OpenLayers.Geometry.LineString"==a.CLASS_NAME)b=a.intersects(this);else if("OpenLayers.Geometry.LinearRing"==a.CLASS_NAME)b=OpenLayers.Geometry.LineString.prototype.intersects.apply(this,[a]);else for(var c=0,d=a.components.length;c< +d&&!(b=a.components[c].intersects(this));++c);return b},getVertices:function(a){return!0===a?[]:this.components.slice(0,this.components.length-1)},CLASS_NAME:"OpenLayers.Geometry.LinearRing"});OpenLayers.Geometry.Polygon=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.LinearRing"],getArea:function(){var a=0;if(this.components&&0h.length)&&(a=this.getLocalXY(a),e=a[0],g=a[1],!isNaN(e)&&!isNaN(g))){this.canvas.lineCap="round";this.canvas.lineJoin="round";this.hitDetection&&(this.hitContext.lineCap="round",this.hitContext.lineJoin="round");if(b.graphicName in this.cachedSymbolBounds)d=this.cachedSymbolBounds[b.graphicName];else{d=new OpenLayers.Bounds;for(a=0;aa||a>=this.getCount())throw Error("Bad grid index.");var c=this;return new OpenLayers.Raster.Grid({numCols:function(){return c.numCols()},numRows:function(){return c.numRows()},getValue:function(d,e){return c.getValue(d,e)[a]}})},CLASS_NAME:"OpenLayers.Raster.Composite"}}()); +OpenLayers.Raster.Composite.fromLayer=function(a,b){var c;if(a instanceof OpenLayers.Layer.Grid)c=OpenLayers.Raster.Composite.fromGridLayer(a);else if(a instanceof OpenLayers.Layer.Vector)c=OpenLayers.Raster.Composite.fromVectorLayer(a,b);else throw Error("Only OpenLayers.Layer.Grid type layers can be used to create a raster");return c}; +OpenLayers.Raster.Composite.fromVectorLayer=function(a,b){var c;function d(a){a=Math.max(0,Math.min(255,a));return(3840+a).toString(16).substring(1)}function e(){c=void 0;n.events.triggerEvent("update")}function f(b){b=b.features;l.addFeatures(b,{silent:!0});for(var c=0,d=b.length;cb)b=0;else if(b>this.layers.length)b=this.layers.length;if(c!=b){this.layers.splice(c,1);this.layers.splice(b,0,a);for(var c=0,d=this.layers.length;c=this.minPx.x+h?Math.round(a):0;b=f<=this.maxPx.y-i&&f>=this.minPx.y+i?Math.round(b):0;if(a||b){if(!this.dragging)this.dragging=!0,this.events.triggerEvent("movestart"); -this.center=null;if(a)this.layerContainerDiv.style.left=parseInt(this.layerContainerDiv.style.left)-a+"px",this.minPx.x-=a,this.maxPx.x-=a;if(b)this.layerContainerDiv.style.top=parseInt(this.layerContainerDiv.style.top)-b+"px",this.minPx.y-=b,this.maxPx.y-=b;for(d=0,e=this.layers.length;dc)for(var d=a|0,e=b.length;dthis.restrictedExtent.getWidth()?a=new OpenLayers.LonLat(g.lon,a.lat):f.leftthis.restrictedExtent.right&&(a=a.add(this.restrictedExtent.right- -f.right,0));f.getHeight()>this.restrictedExtent.getHeight()?a=new OpenLayers.LonLat(a.lon,g.lat):f.bottomthis.restrictedExtent.top&&(a=a.add(0,this.restrictedExtent.top-f.top))}}e=e||this.isValidZoomLevel(b)&&b!=this.getZoom();f=this.isValidLonLat(a)&&!a.equals(this.center);if(e||f||d){d||this.events.triggerEvent("movestart");if(f)!e&&this.center&&this.centerLayerContainer(a),this.center=a.clone();a=e?this.getResolutionForZoom(b): -this.getResolution();if(e||null==this.layerContainerOrigin){this.layerContainerOrigin=this.getCachedCenter();this.layerContainerDiv.style.left="0px";this.layerContainerDiv.style.top="0px";var f=this.getMaxExtent({restricted:!0}),h=f.getCenterLonLat(),g=this.center.lon-h.lon,h=h.lat-this.center.lat,i=Math.round(f.getWidth()/a),j=Math.round(f.getHeight()/a);this.minPx={x:(this.size.w-i)/2-g/a,y:(this.size.h-j)/2-h/a};this.maxPx={x:this.minPx.x+Math.round(f.getWidth()/a),y:this.minPx.y+Math.round(f.getHeight()/ -a)}}if(e)this.zoom=b,this.resolution=a;a=this.getExtent();this.baseLayer.visibility&&(this.baseLayer.moveTo(a,e,c.dragging),c.dragging||this.baseLayer.events.triggerEvent("moveend",{zoomChanged:e}));a=this.baseLayer.getExtent();for(b=this.layers.length-1;0<=b;--b)if(f=this.layers[b],f!==this.baseLayer&&!f.isBaseLayer){g=f.calculateInRange();if(f.inRange!=g)(f.inRange=g)||f.display(!1),this.events.triggerEvent("changelayer",{layer:f,property:"visibility"});g&&f.visibility&&(f.moveTo(a,e,c.dragging), -c.dragging||f.events.triggerEvent("moveend",{zoomChanged:e}))}this.events.triggerEvent("move");d||this.events.triggerEvent("moveend");if(e){b=0;for(c=this.popups.length;b=this.minResolution&&a<=this.maxResolution);return a},setIsBaseLayer:function(a){if(a!=this.isBaseLayer)this.isBaseLayer= -a,null!=this.map&&this.map.events.triggerEvent("changebaselayer",{layer:this})},initResolutions:function(){var a,b,c,d={},e=!0;for(a=0,b=this.RESOLUTION_PROPERTIES.length;ab?b=0:b>this.layers.length&&(b=this.layers.length);if(c!=b){this.layers.splice(c,1);this.layers.splice(b,0,a);for(var c=0,d=this.layers.length;c=this.minPx.x+h?Math.round(a):0;b=f<=this.maxPx.y-i&&f>=this.minPx.y+i?Math.round(b):0;if(a||b){this.dragging||(this.dragging=!0,this.events.triggerEvent("movestart"));this.center=null;a&&(this.layerContainerDiv.style.left= +(this.layerContainerOriginPx.x-=a)+"px",this.minPx.x-=a,this.maxPx.x-=a);b&&(this.layerContainerDiv.style.top=(this.layerContainerOriginPx.y-=b)+"px",this.minPx.y-=b,this.maxPx.y-=b);d=0;for(e=this.layers.length;dc)if(this.fractionalZoom)a=this.getZoomForResolution(c);else for(var d=a|0,e=b.length;dthis.restrictedExtent.getWidth()?a=new OpenLayers.LonLat(g.lon,a.lat):f.leftthis.restrictedExtent.right&&(a=a.add(this.restrictedExtent.right-f.right,0));f.getHeight()>this.restrictedExtent.getHeight()?a=new OpenLayers.LonLat(a.lon,g.lat):f.bottomthis.restrictedExtent.top&&(a=a.add(0,this.restrictedExtent.top-f.top))}}e=e||this.isValidZoomLevel(b)&&b!=this.getZoom();f=this.isValidLonLat(a)&&!a.equals(this.center);if(e||f||d){d||this.events.triggerEvent("movestart");f&&(!e&&this.center&& +this.centerLayerContainer(a),this.center=a.clone());a=e?this.getResolutionForZoom(b):this.getResolution();if(e||null==this.layerContainerOrigin){this.layerContainerOrigin=this.getCachedCenter();f=this.layerContainerDiv.style;f.left="0px";f.top="0px";this.layerContainerOriginPx.x=0;this.layerContainerOriginPx.y=0;var f=this.getMaxExtent({restricted:!0}),h=f.getCenterLonLat(),g=this.center.lon-h.lon,h=h.lat-this.center.lat,i=Math.round(f.getWidth()/a),j=Math.round(f.getHeight()/a);this.minPx={x:(this.size.w- +i)/2-g/a,y:(this.size.h-j)/2-h/a};this.maxPx={x:this.minPx.x+Math.round(f.getWidth()/a),y:this.minPx.y+Math.round(f.getHeight()/a)}}e&&(this.zoom=b,this.resolution=a);a=this.getExtent();this.baseLayer.visibility&&(this.baseLayer.moveTo(a,e,c.dragging),c.dragging||this.baseLayer.events.triggerEvent("moveend",{zoomChanged:e}));a=this.baseLayer.getExtent();for(b=this.layers.length-1;0<=b;--b)if(f=this.layers[b],f!==this.baseLayer&&!f.isBaseLayer&&(g=f.calculateInRange(),f.inRange!=g&&((f.inRange=g)|| +f.display(!1),this.events.triggerEvent("changelayer",{layer:f,property:"visibility"})),g&&f.visibility))f.moveTo(a,e,c.dragging),c.dragging||f.events.triggerEvent("moveend",{zoomChanged:e});this.events.triggerEvent("move");d||this.events.triggerEvent("moveend");if(e){b=0;for(c=this.popups.length;b=this.down.xy.distanceTo(a.xy))&&this.touch&&this.down.touches.length===this.last.touches.length)for(var a=0,c=this.down.touches.length;athis.pixelTolerance){b= +!1;break}return b},getTouchDistance:function(a,b){return Math.sqrt(Math.pow(a.clientX-b.clientX,2)+Math.pow(a.clientY-b.clientY,2))},passesDblclickTolerance:function(){var a=!0;this.down&&this.first&&(a=this.down.xy.distanceTo(this.first.xy)<=this.dblclickTolerance);return a},clearTimer:function(){null!=this.timerId&&(window.clearTimeout(this.timerId),this.timerId=null);null!=this.rightclickTimerId&&(window.clearTimeout(this.rightclickTimerId),this.rightclickTimerId=null)},delayedCall:function(a){this.timerId= +null;a&&this.callback("click",[a])},getEventInfo:function(a){var b;if(a.touches){var c=a.touches.length;b=Array(c);for(var d,e=0;ethis.nbPoints&&this.points.pop()},end:function(a){for(var b,c=(new Date).getTime(),d=0,e=this.points.length,f;dthis.delay)break;b=f}if(b&&(d=(new Date).getTime()-b.tick,c=Math.sqrt(Math.pow(a.x-b.xy.x,2)+Math.pow(a.y-b.xy.y,2)),d=c/d,!(0==d||d=-this.deceleration*a+c&&(OpenLayers.Animation.stop(this.timerId),this.timerId=null,n=!0);a=k-g;m=j-h;g=k;h=j;b(a,m,n)}},this))},CLASS_NAME:"OpenLayers.Kinetic"});OpenLayers.Handler.Drag=OpenLayers.Class(OpenLayers.Handler,{started:!1,stopDown:!0,dragging:!1,touch:!1,last:null,start:null,lastMoveEvt:null,oldOnselectstart:null,interval:0,timeoutId:null,documentDrag:!1,documentEvents:null,initialize:function(a,b,c){OpenLayers.Handler.prototype.initialize.apply(this,arguments);if(!0===this.documentDrag){var d=this;this._docMove=function(a){d.mousemove({xy:{x:a.clientX,y:a.clientY},element:document})};this._docUp=function(a){d.mouseup({xy:{x:a.clientX,y:a.clientY}})}}}, +dragstart:function(a){var b=!0;this.dragging=!1;this.checkModifiers(a)&&(OpenLayers.Event.isLeftClick(a)||OpenLayers.Event.isSingleTouch(a))?(this.started=!0,this.last=this.start=a.xy,OpenLayers.Element.addClass(this.map.viewPortDiv,"olDragDown"),this.down(a),this.callback("down",[a.xy]),OpenLayers.Event.preventDefault(a),this.oldOnselectstart||(this.oldOnselectstart=document.onselectstart?document.onselectstart:OpenLayers.Function.True),document.onselectstart=OpenLayers.Function.False,b=!this.stopDown): +(this.started=!1,this.last=this.start=null);return b},dragmove:function(a){this.lastMoveEvt=a;if(this.started&&!this.timeoutId&&(a.xy.x!=this.last.x||a.xy.y!=this.last.y))!0===this.documentDrag&&this.documentEvents&&(a.element===document?(this.adjustXY(a),this.setEvent(a)):this.removeDocumentEvents()),0=this.map.Z_INDEX_BASE.Feature?this.layer.setZIndex(a):this.map.setLayerZIndex(this.layer,this.map.getLayerIndex(this.layer))},CLASS_NAME:"OpenLayers.Handler.Feature"});OpenLayers.Control.DragFeature=OpenLayers.Class(OpenLayers.Control,{geometryTypes:null,onStart:function(){},onDrag:function(){},onComplete:function(){},onEnter:function(){},onLeave:function(){},documentDrag:!1,layer:null,feature:null,dragCallbacks:{},featureCallbacks:{},lastPixel:null,initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);this.layer=a;this.handlers={drag:new OpenLayers.Handler.Drag(this,OpenLayers.Util.extend({down:this.downFeature,move:this.moveFeature, +up:this.upFeature,out:this.cancel,done:this.doneDragging},this.dragCallbacks),{documentDrag:this.documentDrag}),feature:new OpenLayers.Handler.Feature(this,this.layer,OpenLayers.Util.extend({click:this.clickFeature,clickout:this.clickoutFeature,over:this.overFeature,out:this.outFeature},this.featureCallbacks),{geometryTypes:this.geometryTypes})}},clickFeature:function(a){this.handlers.feature.touch&&(!this.over&&this.overFeature(a))&&(this.handlers.drag.dragstart(this.handlers.feature.evt),this.handlers.drag.stopDown= +!1)},clickoutFeature:function(a){this.handlers.feature.touch&&this.over&&(this.outFeature(a),this.handlers.drag.stopDown=!0)},destroy:function(){this.layer=null;OpenLayers.Control.prototype.destroy.apply(this,[])},activate:function(){return this.handlers.feature.activate()&&OpenLayers.Control.prototype.activate.apply(this,arguments)},deactivate:function(){this.handlers.drag.deactivate();this.handlers.feature.deactivate();this.feature=null;this.dragging=!1;this.lastPixel=null;OpenLayers.Element.removeClass(this.map.viewPortDiv, +this.displayClass+"Over");return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},overFeature:function(a){var b=!1;this.handlers.drag.dragging?this.over=this.feature.id==a.id?!0:!1:(this.feature=a,this.handlers.drag.activate(),this.over=b=!0,OpenLayers.Element.addClass(this.map.viewPortDiv,this.displayClass+"Over"),this.onEnter(a));return b},downFeature:function(a){this.lastPixel=a;this.onStart(this.feature,a)},moveFeature:function(a){var b=this.map.getResolution();this.feature.geometry.move(b* +(a.x-this.lastPixel.x),b*(this.lastPixel.y-a.y));this.layer.drawFeature(this.feature);this.lastPixel=a;this.onDrag(this.feature,a)},upFeature:function(){this.over||this.handlers.drag.deactivate()},doneDragging:function(a){this.layer.events.triggerEvent("featuremodified",{feature:this.feature});this.onComplete(this.feature,a)},outFeature:function(a){this.handlers.drag.dragging?this.feature.id==a.id&&(this.over=!1):(this.over=!1,this.handlers.drag.deactivate(),OpenLayers.Element.removeClass(this.map.viewPortDiv, +this.displayClass+"Over"),this.onLeave(a),this.feature=null)},cancel:function(){this.handlers.drag.deactivate();this.over=!1},setMap:function(a){this.handlers.drag.setMap(a);this.handlers.feature.setMap(a);OpenLayers.Control.prototype.setMap.apply(this,arguments)},CLASS_NAME:"OpenLayers.Control.DragFeature"});OpenLayers.Handler.Point=OpenLayers.Class(OpenLayers.Handler,{point:null,layer:null,multi:!1,citeCompliant:!1,mouseDown:!1,stoppedDown:null,lastDown:null,lastUp:null,persist:!1,stopDown:!1,stopUp:!1,layerOptions:null,pixelTolerance:5,touch:!1,lastTouchPx:null,initialize:function(a,b,c){if(!c||!c.layerOptions||!c.layerOptions.styleMap)this.style=OpenLayers.Util.extend(OpenLayers.Feature.Vector.style["default"],{});OpenLayers.Handler.prototype.initialize.apply(this,arguments)},activate:function(){if(!OpenLayers.Handler.prototype.activate.apply(this, +arguments))return!1;var a=OpenLayers.Util.extend({displayInLayerSwitcher:!1,calculateInRange:OpenLayers.Function.True,wrapDateLine:this.citeCompliant},this.layerOptions);this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,a);this.map.addLayer(this.layer);return!0},createFeature:function(a){a=this.layer.getLonLatFromViewPortPx(a);a=new OpenLayers.Geometry.Point(a.lon,a.lat);this.point=new OpenLayers.Feature.Vector(a);this.callback("create",[this.point.geometry,this.point]);this.point.geometry.clearBounds(); +this.layer.addFeatures([this.point],{silent:!0})},deactivate:function(){if(!OpenLayers.Handler.prototype.deactivate.apply(this,arguments))return!1;this.cancel();null!=this.layer.map&&(this.destroyFeature(!0),this.layer.destroy(!1));this.layer=null;this.touch=!1;return!0},destroyFeature:function(a){this.layer&&(a||!this.persist)&&this.layer.destroyFeatures();this.point=null},destroyPersistedFeature:function(){var a=this.layer;a&&1c&&(d=!1);return d},CLASS_NAME:"OpenLayers.Handler.Point"});OpenLayers.Layer=OpenLayers.Class({id:null,name:null,div:null,opacity:1,alwaysInRange:null,RESOLUTION_PROPERTIES:"scales resolutions maxScale minScale maxResolution minResolution numZoomLevels maxZoomLevel".split(" "),events:null,map:null,isBaseLayer:!1,alpha:!1,displayInLayerSwitcher:!0,visibility:!0,attribution:null,inRange:!1,imageSize:null,options:null,eventListeners:null,gutter:0,projection:null,units:null,scales:null,resolutions:null,maxExtent:null,minExtent:null,maxResolution:null,minResolution:null, +numZoomLevels:null,minScale:null,maxScale:null,displayOutsideMaxExtent:!1,wrapDateLine:!1,metadata:null,initialize:function(a,b){this.metadata={};b=OpenLayers.Util.extend({},b);null!=this.alwaysInRange&&(b.alwaysInRange=this.alwaysInRange);this.addOptions(b);this.name=a;if(null==this.id&&(this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_"),this.div=OpenLayers.Util.createDiv(this.id),this.div.style.width="100%",this.div.style.height="100%",this.div.dir="ltr",this.events=new OpenLayers.Events(this, +this.div),this.eventListeners instanceof Object))this.events.on(this.eventListeners)},destroy:function(a){null==a&&(a=!0);null!=this.map&&this.map.removeLayer(this,a);this.options=this.div=this.name=this.map=this.projection=null;this.events&&(this.eventListeners&&this.events.un(this.eventListeners),this.events.destroy());this.events=this.eventListeners=null},clone:function(a){null==a&&(a=new OpenLayers.Layer(this.name,this.getOptions()));OpenLayers.Util.applyDefaults(a,this);a.map=null;return a}, +getOptions:function(){var a={},b;for(b in this.options)a[b]=this[b];return a},setName:function(a){a!=this.name&&(this.name=a,null!=this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"name"}))},addOptions:function(a,b){null==this.options&&(this.options={});if(a&&("string"==typeof a.projection&&(a.projection=new OpenLayers.Projection(a.projection)),a.projection&&OpenLayers.Util.applyDefaults(a,OpenLayers.Projection.defaults[a.projection.getCode()]),a.maxExtent&&!(a.maxExtent instanceof +OpenLayers.Bounds)&&(a.maxExtent=new OpenLayers.Bounds(a.maxExtent)),a.minExtent&&!(a.minExtent instanceof OpenLayers.Bounds)))a.minExtent=new OpenLayers.Bounds(a.minExtent);OpenLayers.Util.extend(this.options,a);OpenLayers.Util.extend(this,a);this.projection&&this.projection.getUnits()&&(this.units=this.projection.getUnits());if(this.map){var c=this.map.getResolution(),d=this.RESOLUTION_PROPERTIES.concat(["projection","units","minExtent","maxExtent"]),e;for(e in a)if(a.hasOwnProperty(e)&&0<=OpenLayers.Util.indexOf(d, +e)){this.initResolutions();b&&this.map.baseLayer===this&&(this.map.setCenter(this.map.getCenter(),this.map.getZoomForResolution(c),!1,!0),this.map.events.triggerEvent("changebaselayer",{layer:this}));break}}},onMapResize:function(){},redraw:function(){var a=!1;if(this.map){this.inRange=this.calculateInRange();var b=this.getExtent();b&&(this.inRange&&this.visibility)&&(this.moveTo(b,!0,!1),this.events.triggerEvent("moveend",{zoomChanged:!0}),a=!0)}return a},moveTo:function(){var a=this.visibility; +this.isBaseLayer||(a=a&&this.inRange);this.display(a)},moveByPx:function(){},setMap:function(a){null==this.map&&(this.map=a,this.maxExtent=this.maxExtent||this.map.maxExtent,this.minExtent=this.minExtent||this.map.minExtent,this.projection=this.projection||this.map.projection,"string"==typeof this.projection&&(this.projection=new OpenLayers.Projection(this.projection)),this.units=this.projection.getUnits()||this.units||this.map.units,this.initResolutions(),this.isBaseLayer||(this.inRange=this.calculateInRange(), +this.div.style.display=this.visibility&&this.inRange?"":"none"),this.setTileSize())},afterAdd:function(){},removeMap:function(){},getImageSize:function(){return this.imageSize||this.tileSize},setTileSize:function(a){this.tileSize=a=a?a:this.tileSize?this.tileSize:this.map.getTileSize();this.gutter&&(this.imageSize=new OpenLayers.Size(a.w+2*this.gutter,a.h+2*this.gutter))},getVisibility:function(){return this.visibility},setVisibility:function(a){a!=this.visibility&&(this.visibility=a,this.display(a), +this.redraw(),null!=this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"visibility"}),this.events.triggerEvent("visibilitychanged"))},display:function(a){a!=("none"!=this.div.style.display)&&(this.div.style.display=a&&this.calculateInRange()?"block":"none")},calculateInRange:function(){var a=!1;this.alwaysInRange?a=!0:this.map&&(a=this.map.getResolution(),a=a>=this.minResolution&&a<=this.maxResolution);return a},setIsBaseLayer:function(a){a!=this.isBaseLayer&&(this.isBaseLayer= +a,null!=this.map&&this.map.events.triggerEvent("changebaselayer",{layer:this}))},initResolutions:function(){var a,b,c,d={},e=!0;a=0;for(b=this.RESOLUTION_PROPERTIES.length;a=a||"number"!==typeof d&&"number"!==typeof c)){b=Array(a);var e=2;"number"==typeof c&&"number"==typeof d&&(e=Math.pow(d/c,1/(a-1)));var f;if("number"===typeof d)for(f=0;f=a&&(f=h,e=c),h<=a){g=h;break}c=f-g;c=0f)break;f=e}else if(this.resolutions[c]=a&&(f=h,e=c),h<=a){g=h;break}c=f-g;c=0f)break;f=e}else if(this.resolutions[c]this.layer.opacity)a.filter="alpha(opacity="+100*this.layer.opacity+")";a.position="absolute";if(this.layerAlphaHack)a.paddingTop= -a.height,a.height="0",a.width="100%";if(this.frame)a.width="100%",a.height="100%",this.frame.appendChild(this.imgDiv)}return this.imgDiv},initImage:function(){this.events.triggerEvent(this._loadEvent);var a=this.getImage();if(this.url&&a.getAttribute("src")==this.url)this.onImageLoad();else{var b=OpenLayers.Function.bind(function(){OpenLayers.Event.stopObservingElement(a);OpenLayers.Event.observe(a,"load",OpenLayers.Function.bind(this.onImageLoad,this));OpenLayers.Event.observe(a,"error",OpenLayers.Function.bind(this.onImageError, -this));this.imageReloadAttempts=0;this.setImgSrc(this.url)},this);a.getAttribute("src")==this.blankImageUrl?b():(OpenLayers.Event.observe(a,"load",b),OpenLayers.Event.observe(a,"error",b),this.crossOriginKeyword&&a.removeAttribute("crossorigin"),a.src=this.blankImageUrl)}},setImgSrc:function(a){var b=this.imgDiv;b.style.visibility="hidden";b.style.opacity=0;if(a)this.crossOriginKeyword&&("data:"!==a.substr(0,5)?b.setAttribute("crossorigin",this.crossOriginKeyword):b.removeAttribute("crossorigin")), -b.src=a},getTile:function(){return this.frame?this.frame:this.getImage()},createBackBuffer:function(){if(this.imgDiv&&!this.isLoading){var a;this.frame?(a=this.frame.cloneNode(!1),a.appendChild(this.imgDiv)):a=this.imgDiv;this.imgDiv=null;return a}},onImageLoad:function(){var a=this.imgDiv;OpenLayers.Event.stopObservingElement(a);a.style.visibility="inherit";a.style.opacity=this.layer.opacity;this.isLoading=!1;this.canvasContext=null;this.events.triggerEvent("loadend");if(7>parseFloat(navigator.appVersion.split("MSIE")[1])&& -this.layer&&this.layer.div){var b=document.createElement("span");b.style.display="none";var c=this.layer.div;c.appendChild(b);window.setTimeout(function(){b.parentNode===c&&b.parentNode.removeChild(b)},0)}if(!0===this.layerAlphaHack)a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+a.src+"', sizingMethod='scale')"},onImageError:function(){var a=this.imgDiv;null!=a.src&&(this.imageReloadAttempts++,this.imageReloadAttempts<=OpenLayers.IMAGE_RELOAD_ATTEMPTS?this.setImgSrc(this.layer.getURL(this.bounds)): -(OpenLayers.Element.addClass(a,"olImageLoadError"),this.events.triggerEvent("loaderror"),this.onImageLoad()))},getCanvasContext:function(){if(OpenLayers.CANVAS_SUPPORTED&&this.imgDiv&&!this.isLoading){if(!this.canvasContext){var a=document.createElement("canvas");a.width=this.size.w;a.height=this.size.h;this.canvasContext=a.getContext("2d");this.canvasContext.drawImage(this.imgDiv,0,0)}return this.canvasContext}},CLASS_NAME:"OpenLayers.Tile.Image"});OpenLayers.Layer.Grid=OpenLayers.Class(OpenLayers.Layer.HTTPRequest,{tileSize:null,tileOriginCorner:"bl",tileOrigin:null,tileOptions:null,tileClass:OpenLayers.Tile.Image,grid:null,singleTile:!1,ratio:1.5,buffer:0,transitionEffect:null,numLoadingTiles:0,tileLoadingDelay:85,serverResolutions:null,moveTimerId:null,deferMoveGriddedTiles:null,tileQueueId:null,tileQueue:null,loading:!1,backBuffer:null,gridResolution:null,backBufferResolution:null,backBufferLonLat:null,backBufferTimerId:null,removeBackBufferDelay:null, -className:null,initialize:function(a,b,c,d){OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,arguments);this.grid=[];this.tileQueue=[];if(null===this.removeBackBufferDelay)this.removeBackBufferDelay=this.singleTile?0:2500;if(null===this.className)this.className=this.singleTile?"olLayerGridSingleTile":"olLayerGrid";if(!OpenLayers.Animation.isNative)this.deferMoveGriddedTiles=OpenLayers.Function.bind(function(){this.moveGriddedTiles(!0);this.moveTimerId=null},this)},setMap:function(a){OpenLayers.Layer.HTTPRequest.prototype.setMap.call(this, -a);OpenLayers.Element.addClass(this.div,this.className)},removeMap:function(){if(null!==this.moveTimerId)window.clearTimeout(this.moveTimerId),this.moveTimerId=null;this.clearTileQueue();if(null!==this.backBufferTimerId)window.clearTimeout(this.backBufferTimerId),this.backBufferTimerId=null},destroy:function(){this.removeBackBuffer();this.clearGrid();this.tileSize=this.grid=null;OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this,arguments)},clearGrid:function(){this.clearTileQueue();if(this.grid){for(var a= -0,b=this.grid.length;aa){a=c;break}if(-1===b)throw"no appropriate resolution in serverResolutions";}return a},getServerZoom:function(){return this.map.getZoomForResolution(this.getServerResolution())},transformDiv:function(a){this.div.style.width=100*a+"%";this.div.style.height=100*a+"%";var b=this.map.getSize(),c=parseInt(this.map.layerContainerDiv.style.left,10),d=(parseInt(this.map.layerContainerDiv.style.top,10)-b.h/2)*(a-1);this.div.style.left=(c-b.w/2)*(a-1)+"%";this.div.style.top= -d+"%"},getResolutionScale:function(){return parseInt(this.div.style.width,10)/100},applyBackBuffer:function(a){null!==this.backBufferTimerId&&this.removeBackBuffer();var b=this.backBuffer;if(!b){b=this.createBackBuffer();if(!b)return;this.div.insertBefore(b,this.div.firstChild);this.backBuffer=b;var c=this.grid[0][0].bounds;this.backBufferLonLat={lon:c.left,lat:c.top};this.backBufferResolution=this.gridResolution}var c=b.style,d=this.backBufferResolution/a;c.width=100*d+"%";c.height=100*d+"%";a=this.getViewPortPxFromLonLat(this.backBufferLonLat, -a);c=parseInt(this.map.layerContainerDiv.style.left,10);d=parseInt(this.map.layerContainerDiv.style.top,10);b.style.left=Math.round(a.x-c)+"%";b.style.top=Math.round(a.y-d)+"%"},createBackBuffer:function(){var a;if(0=a.bottom-j*this.buffer||l-e*(a-1))this.shiftColumn(!0);else if(c<-e*a)this.shiftColumn(!1);else if(d>-f*(a-1))this.shiftRow(!0);else if(d<-f*a)this.shiftRow(!1);else break}},shiftRow:function(a){for(var b=this.grid,c=b[a?0:this.grid.length-1],d=this.getServerResolution(),e=a?-this.tileSize.h:this.tileSize.h,d=d*-e,f=a?b.pop():b.shift(),g=0,h=c.length;ga;)for(var c=this.grid.pop(),d=0,e=c.length;d -b;){d=0;for(e=this.grid.length;d=this.down.xy.distanceTo(a.xy))&&this.touch&&this.down.touches.length===this.last.touches.length)for(var a=0,c=this.down.touches.length;athis.pixelTolerance){b= -!1;break}return b},getTouchDistance:function(a,b){return Math.sqrt(Math.pow(a.clientX-b.clientX,2)+Math.pow(a.clientY-b.clientY,2))},passesDblclickTolerance:function(){var a=!0;this.down&&this.first&&(a=this.down.xy.distanceTo(this.first.xy)<=this.dblclickTolerance);return a},clearTimer:function(){if(null!=this.timerId)window.clearTimeout(this.timerId),this.timerId=null;if(null!=this.rightclickTimerId)window.clearTimeout(this.rightclickTimerId),this.rightclickTimerId=null},delayedCall:function(a){this.timerId= -null;a&&this.callback("click",[a])},getEventInfo:function(a){var b;if(a.touches){var c=a.touches.length;b=Array(c);for(var d,e=0;ethis.nbPoints&&this.points.pop()},end:function(a){for(var b,c=(new Date).getTime(),d=0,e=this.points.length,f;dthis.delay)break;b=f}if(b&&(d=(new Date).getTime()-b.tick,c=Math.sqrt(Math.pow(a.x-b.xy.x,2)+Math.pow(a.y-b.xy.y,2)),d=c/d,!(0==d||d=-this.deceleration*a+c)OpenLayers.Animation.stop(this.timerId),this.timerId=null,q=!0;a=o-g;l=j-h;g=o;h=j;b(a,l,q)}},this))},CLASS_NAME:"OpenLayers.Kinetic"});OpenLayers.Events.buttonclick=OpenLayers.Class({target:null,events:"mousedown,mouseup,click,dblclick,touchstart,touchmove,touchend,keydown".split(","),startRegEx:/^mousedown|touchstart$/,cancelRegEx:/^touchmove$/,completeRegEx:/^mouseup|touchend$/,initialize:function(a){this.target=a;for(a=this.events.length-1;0<=a;--a)this.target.register(this.events[a],this,this.buttonClick,{extension:!0})},destroy:function(){for(var a=this.events.length-1;0<=a;--a)this.target.unregister(this.events[a],this,this.buttonClick); -delete this.target},getPressedButton:function(a){var b=3,c;do{if(OpenLayers.Element.hasClass(a,"olButton")){c=a;break}a=a.parentNode}while(0<--b&&a);return c},buttonClick:function(a){var b=!0,c=OpenLayers.Event.element(a);if(c&&(OpenLayers.Event.isLeftClick(a)||!~a.type.indexOf("mouse")))if(c=this.getPressedButton(c)){if("keydown"===a.type)switch(a.keyCode){case OpenLayers.Event.KEY_RETURN:case OpenLayers.Event.KEY_SPACE:this.target.triggerEvent("buttonclick",{buttonElement:c}),OpenLayers.Event.stop(a), -b=!1}else this.startEvt&&(this.completeRegEx.test(a.type)&&(b=OpenLayers.Util.pagePosition(c),this.target.triggerEvent("buttonclick",{buttonElement:c,buttonXY:{x:this.startEvt.clientX-b[0],y:this.startEvt.clientY-b[1]}})),this.cancelRegEx.test(a.type)&&delete this.startEvt,OpenLayers.Event.stop(a),b=!1);if(this.startRegEx.test(a.type))this.startEvt=a,OpenLayers.Event.stop(a),b=!1}else delete this.startEvt;return b}});OpenLayers.Handler.Drag=OpenLayers.Class(OpenLayers.Handler,{started:!1,stopDown:!0,dragging:!1,touch:!1,last:null,start:null,lastMoveEvt:null,oldOnselectstart:null,interval:0,timeoutId:null,documentDrag:!1,documentEvents:null,initialize:function(a,b,c){OpenLayers.Handler.prototype.initialize.apply(this,arguments);if(!0===this.documentDrag){var d=this;this._docMove=function(a){d.mousemove({xy:{x:a.clientX,y:a.clientY},element:document})};this._docUp=function(a){d.mouseup({xy:{x:a.clientX,y:a.clientY}})}}}, -dragstart:function(a){var b=!0;this.dragging=!1;if(this.checkModifiers(a)&&(OpenLayers.Event.isLeftClick(a)||OpenLayers.Event.isSingleTouch(a))){this.started=!0;this.last=this.start=a.xy;OpenLayers.Element.addClass(this.map.viewPortDiv,"olDragDown");this.down(a);this.callback("down",[a.xy]);OpenLayers.Event.stop(a);if(!this.oldOnselectstart)this.oldOnselectstart=document.onselectstart?document.onselectstart:OpenLayers.Function.True;document.onselectstart=OpenLayers.Function.False;b=!this.stopDown}else this.started= -!1,this.last=this.start=null;return b},dragmove:function(a){this.lastMoveEvt=a;if(this.started&&!this.timeoutId&&(a.xy.x!=this.last.x||a.xy.y!=this.last.y)){!0===this.documentDrag&&this.documentEvents&&(a.element===document?(this.adjustXY(a),this.setEvent(a)):this.removeDocumentEvents());if(0this.layer.opacity&&(a.filter="alpha(opacity="+100*this.layer.opacity+")");a.position="absolute";this.layerAlphaHack&&(a.paddingTop=a.height,a.height="0",a.width="100%");this.frame&&this.frame.appendChild(this.imgDiv)}return this.imgDiv},initImage:function(){this.events.triggerEvent(this._loadEvent);var a=this.getImage();if(this.url&&a.getAttribute("src")==this.url)this.onImageLoad(); +else{var b=OpenLayers.Function.bind(function(){OpenLayers.Event.stopObservingElement(a);OpenLayers.Event.observe(a,"load",OpenLayers.Function.bind(this.onImageLoad,this));OpenLayers.Event.observe(a,"error",OpenLayers.Function.bind(this.onImageError,this));this.imageReloadAttempts=0;this.setImgSrc(this.url)},this);a.getAttribute("src")==this.blankImageUrl?b():(OpenLayers.Event.observe(a,"load",b),OpenLayers.Event.observe(a,"error",b),this.crossOriginKeyword&&a.removeAttribute("crossorigin"),a.src= +this.blankImageUrl)}},setImgSrc:function(a){var b=this.imgDiv;a?(b.style.visibility="hidden",b.style.opacity=0,this.crossOriginKeyword&&("data:"!==a.substr(0,5)?b.setAttribute("crossorigin",this.crossOriginKeyword):b.removeAttribute("crossorigin")),b.src=a):(this.imgDiv=null,b.parentNode&&b.parentNode.removeChild(b))},getTile:function(){return this.frame?this.frame:this.getImage()},createBackBuffer:function(){if(this.imgDiv&&!this.isLoading){var a;this.frame?(a=this.frame.cloneNode(!1),a.appendChild(this.imgDiv)): +a=this.imgDiv;this.imgDiv=null;return a}},onImageLoad:function(){var a=this.imgDiv;OpenLayers.Event.stopObservingElement(a);a.style.visibility="inherit";a.style.opacity=this.layer.opacity;this.isLoading=!1;this.canvasContext=null;this.events.triggerEvent("loadend");!0===this.layerAlphaHack&&(a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+a.src+"', sizingMethod='scale')")},onImageError:function(){var a=this.imgDiv;null!=a.src&&(this.imageReloadAttempts++,this.imageReloadAttempts<= +OpenLayers.IMAGE_RELOAD_ATTEMPTS?this.setImgSrc(this.layer.getURL(this.bounds)):(OpenLayers.Element.addClass(a,"olImageLoadError"),this.events.triggerEvent("loaderror"),this.onImageLoad()))},getCanvasContext:function(){if(OpenLayers.CANVAS_SUPPORTED&&this.imgDiv&&!this.isLoading){if(!this.canvasContext){var a=document.createElement("canvas");a.width=this.size.w;a.height=this.size.h;this.canvasContext=a.getContext("2d");this.canvasContext.drawImage(this.imgDiv,0,0)}return this.canvasContext}},CLASS_NAME:"OpenLayers.Tile.Image"});OpenLayers.Layer.Grid=OpenLayers.Class(OpenLayers.Layer.HTTPRequest,{tileSize:null,tileOriginCorner:"bl",tileOrigin:null,tileOptions:null,tileClass:OpenLayers.Tile.Image,grid:null,singleTile:!1,ratio:1.5,buffer:0,transitionEffect:null,numLoadingTiles:0,tileLoadingDelay:85,serverResolutions:null,moveTimerId:null,deferMoveGriddedTiles:null,tileQueueId:null,tileQueue:null,loading:!1,backBuffer:null,gridResolution:null,backBufferResolution:null,backBufferLonLat:null,backBufferTimerId:null,removeBackBufferDelay:null, +className:null,initialize:function(a,b,c,d){OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,arguments);this.grid=[];this.tileQueue=[];null===this.removeBackBufferDelay&&(this.removeBackBufferDelay=this.singleTile?0:2500);null===this.className&&(this.className=this.singleTile?"olLayerGridSingleTile":"olLayerGrid");OpenLayers.Animation.isNative||(this.deferMoveGriddedTiles=OpenLayers.Function.bind(function(){this.moveGriddedTiles(true);this.moveTimerId=null},this))},setMap:function(a){OpenLayers.Layer.HTTPRequest.prototype.setMap.call(this, +a);OpenLayers.Element.addClass(this.div,this.className)},removeMap:function(){null!==this.moveTimerId&&(window.clearTimeout(this.moveTimerId),this.moveTimerId=null);this.clearTileQueue();null!==this.backBufferTimerId&&(window.clearTimeout(this.backBufferTimerId),this.backBufferTimerId=null)},destroy:function(){this.removeBackBuffer();this.clearGrid();this.tileSize=this.grid=null;OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this,arguments)},clearGrid:function(){this.clearTileQueue();if(this.grid){for(var a= +0,b=this.grid.length;ab)break;b=d;f=e}a=f}return a},getServerZoom:function(){var a=this.getServerResolution();return this.serverResolutions? +OpenLayers.Util.indexOf(this.serverResolutions,a):this.map.getZoomForResolution(a)+(this.zoomOffset||0)},applyBackBuffer:function(a){null!==this.backBufferTimerId&&this.removeBackBuffer();var b=this.backBuffer;if(!b){b=this.createBackBuffer();if(!b)return;this.div.insertBefore(b,this.div.firstChild);this.backBuffer=b;var c=this.grid[0][0].bounds;this.backBufferLonLat={lon:c.left,lat:c.top};this.backBufferResolution=this.gridResolution}for(var c=this.backBufferResolution/a,d=b.childNodes,e,f=d.length- +1;0<=f;--f)e=d[f],e.style.top=(c*e._i*e._h|0)+"px",e.style.left=(c*e._j*e._w|0)+"px",e.style.width=Math.round(c*e._w)+"px",e.style.height=Math.round(c*e._h)+"px";a=this.getViewPortPxFromLonLat(this.backBufferLonLat,a);c=this.map.layerContainerOriginPx.y;b.style.left=Math.round(a.x-this.map.layerContainerOriginPx.x)+"px";b.style.top=Math.round(a.y-c)+"px"},createBackBuffer:function(){var a;if(0= +a.bottom-n*this.buffer||o-d.w*(a-1))this.shiftColumn(!0,d);else if(c<-d.w*a)this.shiftColumn(!1,d);else if(b>-d.h*(a-1))this.shiftRow(!0,d);else if(b<-d.h*a)this.shiftRow(!1,d);else break}},shiftRow:function(a,b){for(var c=this.grid, +d=c[a?0:this.grid.length-1],e=a?-1:1,f=this.getServerResolution()*-e*this.tileSize.h,g=a?c.pop():c.shift(),h=0,i=d.length;ha;){var e=this.grid.pop();c=0;for(d=e.length;cb;)e=this.grid[c],f=e.pop(),this.destroyTile(f)},onMapResize:function(){this.singleTile&&(this.clearGrid(),this.setTileSize())},getTileBounds:function(a){var b=this.maxExtent,c=this.getResolution(),d=c*this.tileSize.w,c=c*this.tileSize.h, +e=this.getLonLatFromViewPortPx(a),a=b.left+d*Math.floor((e.lon-b.left)/d),b=b.bottom+c*Math.floor((e.lat-b.bottom)/c);return new OpenLayers.Bounds(a,b,a+d,b+c)},CLASS_NAME:"OpenLayers.Layer.Grid"});OpenLayers.Handler.Box=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,boxDivClassName:"olHandlerBoxZoomBox",boxOffsets:null,initialize:function(a,b,c){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})},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);this.dragHandler&&(this.dragHandler.destroy(),this.dragHandler= +null)},setMap:function(a){OpenLayers.Handler.prototype.setMap.apply(this,arguments);this.dragHandler&&this.dragHandler.setMap(a)},startBox:function(){this.callback("start",[]);this.zoomBox=OpenLayers.Util.createDiv("zoomBox",{x:-9999,y:-9999});this.zoomBox.className=this.boxDivClassName;this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE.Popup-1;this.map.viewPortDiv.appendChild(this.zoomBox);OpenLayers.Element.addClass(this.map.viewPortDiv,"olDrawBox")},moveBox:function(a){var b=this.dragHandler.start.x, c=this.dragHandler.start.y,d=Math.abs(b-a.x),e=Math.abs(c-a.y),f=this.getBoxOffsets();this.zoomBox.style.width=d+f.width+1+"px";this.zoomBox.style.height=e+f.height+1+"px";this.zoomBox.style.left=(a.xwindow.opera.version()&&(b=-b)):a.detail&& -(b=-a.detail/3);this.delta+=b;this.interval?(window.clearTimeout(this._timeoutId),this._timeoutId=window.setTimeout(OpenLayers.Function.bind(function(){this.wheelZoom(a)},this),this.interval)):this.wheelZoom(a)}OpenLayers.Event.stop(a)}}},wheelZoom:function(a){var b=this.delta;this.delta=0;if(b){if(this.mousePosition)a.xy=this.mousePosition;if(!a.xy)a.xy=this.map.getPixelFromLonLat(this.map.getCenter());0>b?this.callback("down",[a,this.cumulative?b:-1]):this.callback("up",[a,this.cumulative?b:1])}}, -mousemove:function(a){this.mousePosition=a.xy},activate:function(a){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){var b=this.wheelListener;OpenLayers.Event.observe(window,"DOMMouseScroll",b);OpenLayers.Event.observe(window,"mousewheel",b);OpenLayers.Event.observe(document,"mousewheel",b);return!0}return!1},deactivate:function(a){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){var b=this.wheelListener;OpenLayers.Event.stopObserving(window,"DOMMouseScroll",b);OpenLayers.Event.stopObserving(window, -"mousewheel",b);OpenLayers.Event.stopObserving(document,"mousewheel",b);return!0}return!1},CLASS_NAME:"OpenLayers.Handler.MouseWheel"});OpenLayers.Control.Navigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,dragPanOptions:null,pinchZoom:null,pinchZoomOptions:null,documentDrag:!1,zoomBox:null,zoomBoxEnabled:!0,zoomWheelEnabled:!0,mouseWheelOptions:null,handleRightClicks:!1,zoomBoxKeyMask:OpenLayers.Handler.MOD_SHIFT,autoActivate:!0,initialize:function(a){this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,arguments)},destroy:function(){this.deactivate();this.dragPan&&this.dragPan.destroy();this.dragPan=null; +animate:!1})})}this.panned=!1}},CLASS_NAME:"OpenLayers.Control.DragPan"});OpenLayers.Handler.MouseWheel=OpenLayers.Class(OpenLayers.Handler,{wheelListener:null,interval:0,delta:0,cumulative:!0,initialize:function(a,b,c){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.wheelListener=OpenLayers.Function.bindAsEventListener(this.onWheelEvent,this)},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);this.wheelListener=null},onWheelEvent:function(a){if(this.map&&this.checkModifiers(a)){for(var b=!1,c=!1,d=!1,e=OpenLayers.Event.element(a);null!= +e&&!d&&!b;){if(!b)try{var f,b=(f=e.currentStyle?e.currentStyle.overflow:document.defaultView.getComputedStyle(e,null).getPropertyValue("overflow"))&&"auto"==f||"scroll"==f}catch(g){}if(!c&&(c=OpenLayers.Element.hasClass(e,"olScrollable"),!c))for(var d=0,h=this.map.layers.length;db?this.callback("down",[a,this.cumulative?b:-1]):this.callback("up",[a,this.cumulative?b:1]))},activate:function(a){if(OpenLayers.Handler.prototype.activate.apply(this, +arguments)){var b=this.wheelListener;OpenLayers.Event.observe(window,"DOMMouseScroll",b);OpenLayers.Event.observe(window,"mousewheel",b);OpenLayers.Event.observe(document,"mousewheel",b);return!0}return!1},deactivate:function(a){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){var b=this.wheelListener;OpenLayers.Event.stopObserving(window,"DOMMouseScroll",b);OpenLayers.Event.stopObserving(window,"mousewheel",b);OpenLayers.Event.stopObserving(document,"mousewheel",b);return!0}return!1}, +CLASS_NAME:"OpenLayers.Handler.MouseWheel"});OpenLayers.Control.Navigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,dragPanOptions:null,pinchZoom:null,pinchZoomOptions:null,documentDrag:!1,zoomBox:null,zoomBoxEnabled:!0,zoomWheelEnabled:!0,mouseWheelOptions:null,handleRightClicks:!1,zoomBoxKeyMask:OpenLayers.Handler.MOD_SHIFT,autoActivate:!0,initialize:function(a){this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,arguments)},destroy:function(){this.deactivate();this.dragPan&&this.dragPan.destroy();this.dragPan=null; this.zoomBox&&this.zoomBox.destroy();this.zoomBox=null;this.pinchZoom&&this.pinchZoom.destroy();this.pinchZoom=null;OpenLayers.Control.prototype.destroy.apply(this,arguments)},activate:function(){this.dragPan.activate();this.zoomWheelEnabled&&this.handlers.wheel.activate();this.handlers.click.activate();this.zoomBoxEnabled&&this.zoomBox.activate();this.pinchZoom&&this.pinchZoom.activate();return OpenLayers.Control.prototype.activate.apply(this,arguments)},deactivate:function(){this.pinchZoom&&this.pinchZoom.deactivate(); -this.zoomBox.deactivate();this.dragPan.deactivate();this.handlers.click.deactivate();this.handlers.wheel.deactivate();return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},draw:function(){if(this.handleRightClicks)this.map.viewPortDiv.oncontextmenu=OpenLayers.Function.False;this.handlers.click=new OpenLayers.Handler.Click(this,{click:this.defaultClick,dblclick:this.defaultDblClick,dblrightclick:this.defaultDblRightClick},{"double":!0,stopDouble:!0});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);if(OpenLayers.Control.PinchZoom)this.pinchZoom=new OpenLayers.Control.PinchZoom(OpenLayers.Util.extend({map:this.map},this.pinchZoomOptions))},defaultClick:function(a){a.lastTouches&&2==a.lastTouches.length&& -this.map.zoomOut()},defaultDblClick:function(a){this.map.setCenter(this.map.getLonLatFromViewPortPx(a.xy),this.map.zoom+1)},defaultDblRightClick:function(a){this.map.setCenter(this.map.getLonLatFromViewPortPx(a.xy),this.map.zoom-1)},wheelChange:function(a,b){var c=this.map.getZoom(),d=this.map.getZoom()+Math.round(b),d=Math.max(d,0),d=Math.min(d,this.map.getNumZoomLevels());if(d!==c){var e=this.map.getSize(),c=e.w/2-a.xy.x,e=a.xy.y-e.h/2,f=this.map.baseLayer.getResolutionForZoom(d),g=this.map.getLonLatFromPixel(a.xy); -this.map.setCenter(new OpenLayers.LonLat(g.lon+c*f,g.lat+e*f),d)}},wheelUp:function(a,b){this.wheelChange(a,b||1)},wheelDown:function(a,b){this.wheelChange(a,b||-1)},disableZoomBox:function(){this.zoomBoxEnabled=!1;this.zoomBox.deactivate()},enableZoomBox:function(){this.zoomBoxEnabled=!0;this.active&&this.zoomBox.activate()},disableZoomWheel:function(){this.zoomWheelEnabled=!1;this.handlers.wheel.deactivate()},enableZoomWheel:function(){this.zoomWheelEnabled=!0;this.active&&this.handlers.wheel.activate()}, -CLASS_NAME:"OpenLayers.Control.Navigation"});OpenLayers.Layer.WMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{service:"WMS",version:"1.1.1",request:"GetMap",styles:"",format:"image/jpeg"},isBaseLayer:!0,encodeBBOX:!1,noMagic:!1,yx:{},initialize:function(a,b,c,d){var e=[],c=OpenLayers.Util.upperCaseObject(c);if(1.3<=parseFloat(c.VERSION)&&!c.EXCEPTIONS)c.EXCEPTIONS="INIMAGE";e.push(a,b,c,d);OpenLayers.Layer.Grid.prototype.initialize.apply(this,e);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)); -if(!this.noMagic&&this.params.TRANSPARENT&&"true"==this.params.TRANSPARENT.toString().toLowerCase()){if(null==d||!d.isBaseLayer)this.isBaseLayer=!1;if("image/jpeg"==this.params.FORMAT)this.params.FORMAT=OpenLayers.Util.alphaHack()?"image/gif":"image/png"}},clone:function(a){null==a&&(a=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},reverseAxisOrder:function(){var a=this.projection.getCode();return 1.3<=parseFloat(this.params.VERSION)&& +this.zoomBox.deactivate();this.dragPan.deactivate();this.handlers.click.deactivate();this.handlers.wheel.deactivate();return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},draw:function(){this.handleRightClicks&&(this.map.viewPortDiv.oncontextmenu=OpenLayers.Function.False);this.handlers.click=new OpenLayers.Handler.Click(this,{click:this.defaultClick,dblclick:this.defaultDblClick,dblrightclick:this.defaultDblRightClick},{"double":!0,stopDouble:!0});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);OpenLayers.Control.PinchZoom&&(this.pinchZoom=new OpenLayers.Control.PinchZoom(OpenLayers.Util.extend({map:this.map},this.pinchZoomOptions)))},defaultClick:function(a){a.lastTouches&&2==a.lastTouches.length&& +this.map.zoomOut()},defaultDblClick:function(a){this.map.setCenter(this.map.getLonLatFromViewPortPx(a.xy),this.map.zoom+1)},defaultDblRightClick:function(a){this.map.setCenter(this.map.getLonLatFromViewPortPx(a.xy),this.map.zoom-1)},wheelChange:function(a,b){this.map.fractionalZoom||(b=Math.round(b));var c=this.map.getZoom(),d=this.map.getZoom()+b,d=Math.max(d,0),d=Math.min(d,this.map.getNumZoomLevels());if(d!==c){var e=this.map.getSize(),c=e.w/2-a.xy.x,e=a.xy.y-e.h/2,f=this.map.baseLayer.getResolutionForZoom(d), +g=this.map.getLonLatFromPixel(a.xy);this.map.setCenter(new OpenLayers.LonLat(g.lon+c*f,g.lat+e*f),d)}},wheelUp:function(a,b){this.wheelChange(a,b||1)},wheelDown:function(a,b){this.wheelChange(a,b||-1)},disableZoomBox:function(){this.zoomBoxEnabled=!1;this.zoomBox.deactivate()},enableZoomBox:function(){this.zoomBoxEnabled=!0;this.active&&this.zoomBox.activate()},disableZoomWheel:function(){this.zoomWheelEnabled=!1;this.handlers.wheel.deactivate()},enableZoomWheel:function(){this.zoomWheelEnabled=!0; +this.active&&this.handlers.wheel.activate()},CLASS_NAME:"OpenLayers.Control.Navigation"});OpenLayers.Layer.WMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{service:"WMS",version:"1.1.1",request:"GetMap",styles:"",format:"image/jpeg"},isBaseLayer:!0,encodeBBOX:!1,noMagic:!1,yx:{},initialize:function(a,b,c,d){var e=[],c=OpenLayers.Util.upperCaseObject(c);1.3<=parseFloat(c.VERSION)&&!c.EXCEPTIONS&&(c.EXCEPTIONS="INIMAGE");e.push(a,b,c,d);OpenLayers.Layer.Grid.prototype.initialize.apply(this,e);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)); +if(!this.noMagic&&this.params.TRANSPARENT&&"true"==this.params.TRANSPARENT.toString().toLowerCase()){if(null==d||!d.isBaseLayer)this.isBaseLayer=!1;"image/jpeg"==this.params.FORMAT&&(this.params.FORMAT=OpenLayers.Util.alphaHack()?"image/gif":"image/png")}},clone:function(a){null==a&&(a=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},reverseAxisOrder:function(){var a=this.projection.getCode();return 1.3<=parseFloat(this.params.VERSION)&& !(!this.yx[a]&&!OpenLayers.Projection.defaults[a].yx)},getURL:function(a){var a=this.adjustBounds(a),b=this.getImageSize(),c={},d=this.reverseAxisOrder();c.BBOX=this.encodeBBOX?a.toBBOX(null,d):a.toArray(d);c.WIDTH=b.w;c.HEIGHT=b.h;return this.getFullRequestString(c)},mergeNewParams:function(a){a=[OpenLayers.Util.upperCaseObject(a)];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,a)},getFullRequestString:function(a,b){var c=this.map.getProjectionObject(),c=this.projection&&this.projection.equals(c)? -this.projection.getCode():c.getCode(),c="none"==c?null:c;1.3<=parseFloat(this.params.VERSION)?this.params.CRS=c:this.params.SRS=c;if("boolean"==typeof this.params.TRANSPARENT)a.TRANSPARENT=this.params.TRANSPARENT?"TRUE":"FALSE";return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments)},CLASS_NAME:"OpenLayers.Layer.WMS"});OpenLayers.Layer.XYZ=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,sphericalMercator:!1,zoomOffset:0,serverResolutions:null,initialize:function(a,b,c){if(c&&c.sphericalMercator||this.sphericalMercator)c=OpenLayers.Util.extend({projection:"EPSG:900913",numZoomLevels:19},c);OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a||this.name,b||this.url,{},c])},clone:function(a){null==a&&(a=new OpenLayers.Layer.XYZ(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this, -[a])},getURL:function(a){var a=this.getXYZ(a),b=this.url;OpenLayers.Util.isArray(b)&&(b=this.selectUrl(""+a.x+a.y+a.z,b));return OpenLayers.String.format(b,a)},getXYZ:function(a){var b=this.getServerResolution(),c=Math.round((a.left-this.maxExtent.left)/(b*this.tileSize.w)),a=Math.round((this.maxExtent.top-a.top)/(b*this.tileSize.h)),d=this.serverResolutions||this.resolutions,b=0==this.zoomOffset?OpenLayers.Util.indexOf(d,b):this.getServerZoom()+this.zoomOffset;this.wrapDateLine&&(d=Math.pow(2,b), -c=(c%d+d)%d);return{x:c,y:a,z:b}},setMap:function(a){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"});OpenLayers.Layer.OSM=OpenLayers.Class(OpenLayers.Layer.XYZ,{name:"OpenStreetMap",url:["http://a.tile.openstreetmap.org/${z}/${x}/${y}.png","http://b.tile.openstreetmap.org/${z}/${x}/${y}.png","http://c.tile.openstreetmap.org/${z}/${x}/${y}.png"],attribution:"Data CC-By-SA by OpenStreetMap",sphericalMercator:!0,wrapDateLine:!0,tileOptions:null,initialize:function(a,b,c){OpenLayers.Layer.XYZ.prototype.initialize.apply(this,arguments);this.tileOptions=OpenLayers.Util.extend({crossOriginKeyword:"anonymous"}, -this.options&&this.options.tileOptions)},clone:function(a){null==a&&(a=new OpenLayers.Layer.OSM(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.XYZ.prototype.clone.apply(this,[a])},CLASS_NAME:"OpenLayers.Layer.OSM"});OpenLayers.Control.Zoom=OpenLayers.Class(OpenLayers.Control,{zoomInText:"+",zoomInId:"olZoomInLink",zoomOutText:"-",zoomOutId:"olZoomOutLink",draw:function(){var a=OpenLayers.Control.prototype.draw.apply(this),b=this.getOrCreateLinks(a),c=b.zoomIn,b=b.zoomOut,d=this.map.events;if(b.parentNode!==a)d=this.events,d.attachToElement(b.parentNode);d.register("buttonclick",this,this.onZoomClick);this.zoomInLink=c;this.zoomOutLink=b;return a},getOrCreateLinks:function(a){var b=document.getElementById(this.zoomInId), -c=document.getElementById(this.zoomOutId);if(!b)b=document.createElement("a"),b.href="#zoomIn",b.appendChild(document.createTextNode(this.zoomInText)),b.className="olControlZoomIn",a.appendChild(b);OpenLayers.Element.addClass(b,"olButton");if(!c)c=document.createElement("a"),c.href="#zoomOut",c.appendChild(document.createTextNode(this.zoomOutText)),c.className="olControlZoomOut",a.appendChild(c);OpenLayers.Element.addClass(c,"olButton");return{zoomIn:b,zoomOut:c}},onZoomClick:function(a){a=a.buttonElement; -a===this.zoomInLink?this.map.zoomIn():a===this.zoomOutLink&&this.map.zoomOut()},destroy:function(){this.map&&this.map.events.unregister("buttonclick",this,this.onZoomClick);delete this.zoomInLink;delete this.zoomOutLink;OpenLayers.Control.prototype.destroy.apply(this)},CLASS_NAME:"OpenLayers.Control.Zoom"});OpenLayers.Layer.Raster=OpenLayers.Class(OpenLayers.Layer,{needsUpdate:!1,initialize:function(a){var a=a||{},b=a.data;delete a.data;OpenLayers.Layer.prototype.initialize.apply(this,[a.name,a]);this.canvas=document.createElement("canvas");this.canvas.style.position="absolute";this.div.appendChild(this.canvas);this.context=this.canvas.getContext("2d");b&&this.setData(b)},setData:function(a){this.clearData();this.data=a;a.events.register("update",this,this.onDataUpdate)},clearData:function(){this.data&& +this.projection.getCode():c.getCode(),c="none"==c?null:c;1.3<=parseFloat(this.params.VERSION)?this.params.CRS=c:this.params.SRS=c;"boolean"==typeof this.params.TRANSPARENT&&(a.TRANSPARENT=this.params.TRANSPARENT?"TRUE":"FALSE");return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments)},CLASS_NAME:"OpenLayers.Layer.WMS"});OpenLayers.StyleMap=OpenLayers.Class({styles:null,extendDefault:!0,initialize:function(a,b){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"])};if(a instanceof OpenLayers.Style)this.styles["default"]=a,this.styles.select=a,this.styles.temporary=a,this.styles["delete"]= +a;else if("object"==typeof a)for(var c in a)if(a[c]instanceof OpenLayers.Style)this.styles[c]=a[c];else if("object"==typeof a[c])this.styles[c]=new OpenLayers.Style(a[c]);else{this.styles["default"]=new OpenLayers.Style(a);this.styles.select=new OpenLayers.Style(a);this.styles.temporary=new OpenLayers.Style(a);this.styles["delete"]=new OpenLayers.Style(a);break}OpenLayers.Util.extend(this,b)},destroy:function(){for(var a in this.styles)this.styles[a].destroy();this.styles=null},createSymbolizer:function(a, +b){a||(a=new OpenLayers.Feature.Vector);this.styles[b]||(b="default");a.renderIntent=b;var c={};this.extendDefault&&"default"!=b&&(c=this.styles["default"].createSymbolizer(a));return OpenLayers.Util.extend(c,this.styles[b].createSymbolizer(a))},addUniqueValueRules:function(a,b,c,d){var e=[],f;for(f in c)e.push(new OpenLayers.Rule({symbolizer:c[f],context:d,filter:new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO,property:b,value:f})}));this.styles[a].addRules(e)},CLASS_NAME:"OpenLayers.StyleMap"});OpenLayers.Layer.Vector=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:!1,isFixed:!1,features:null,filter:null,selectedFeatures:null,unrenderedFeatures:null,reportError:!0,style:null,styleMap:null,strategies:null,protocol:null,renderers:["SVG","VML","Canvas"],renderer:null,rendererOptions:null,geometryType:null,drawn:!1,ratio:1,initialize:function(a,b){OpenLayers.Layer.prototype.initialize.apply(this,arguments);(!this.renderer||!this.renderer.supported())&&this.assignRenderer();if(!this.renderer|| +!this.renderer.supported())this.renderer=null,this.displayError();this.styleMap||(this.styleMap=new OpenLayers.StyleMap);this.features=[];this.selectedFeatures=[];this.unrenderedFeatures={};if(this.strategies)for(var c=0,d=this.strategies.length;cOpenStreetMap",sphericalMercator:!0,wrapDateLine:!0,tileOptions:null,initialize:function(a,b,c){OpenLayers.Layer.XYZ.prototype.initialize.apply(this,arguments);this.tileOptions=OpenLayers.Util.extend({crossOriginKeyword:"anonymous"}, +this.options&&this.options.tileOptions)},clone:function(a){null==a&&(a=new OpenLayers.Layer.OSM(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.XYZ.prototype.clone.apply(this,[a])},CLASS_NAME:"OpenLayers.Layer.OSM"});OpenLayers.Handler.Path=OpenLayers.Class(OpenLayers.Handler.Point,{line:null,maxVertices:null,doubleTouchTolerance:20,freehand:!1,freehandToggle:"shiftKey",timerId:null,redoStack:null,createFeature:function(a){a=this.layer.getLonLatFromViewPortPx(a);a=new OpenLayers.Geometry.Point(a.lon,a.lat);this.point=new OpenLayers.Feature.Vector(a);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:!0})},destroyFeature:function(a){OpenLayers.Handler.Point.prototype.destroyFeature.call(this,a);this.line=null},destroyPersistedFeature:function(){var a=this.layer;a&&2this.maxZIndex&&(this.maxZIndex=b)},getNextElement:function(a){a+=1;if(aa.left&&f.righta.left&&f.left=-this.MAX_PIXEL&&a<=this.MAX_PIXEL&&b>=-this.MAX_PIXEL&&b<=this.MAX_PIXEL},setExtent:function(a,b){var c=OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,arguments),d=this.getResolution(),e=-a.left/d,d=a.top/d;if(b)return this.left=e,this.top=d,this.rendererRoot.setAttributeNS(null, +"viewBox","0 0 "+this.size.w+" "+this.size.h),this.translate(this.xOffset,0),!0;(e=this.translate(e-this.left+this.xOffset,d-this.top))||this.setExtent(a,!0);return c&&e},translate:function(a,b){if(this.inValidRange(a,b,!0)){var c="";if(a||b)c="translate("+a+","+b+")";this.root.setAttributeNS(null,"transform",c);this.translationParameters={x:a,y:b};return!0}return!1},setSize:function(a){OpenLayers.Renderer.prototype.setSize.apply(this,arguments);this.rendererRoot.setAttributeNS(null,"width",this.size.w); +this.rendererRoot.setAttributeNS(null,"height",this.size.h)},getNodeType:function(a,b){var c=null;switch(a.CLASS_NAME){case "OpenLayers.Geometry.Point":c=b.externalGraphic?"image":this.isComplexSymbol(b.graphicName)?"svg":"circle";break;case "OpenLayers.Geometry.Rectangle":c="rect";break;case "OpenLayers.Geometry.LineString":c="polyline";break;case "OpenLayers.Geometry.LinearRing":c="polygon";break;case "OpenLayers.Geometry.Polygon":case "OpenLayers.Geometry.Curve":c="path"}return c},setStyle:function(a, +b,c){var b=b||a._style,c=c||a._options,d=b.title||b.graphicTitle;if(d){a.setAttributeNS(null,"title",d);var e=a.getElementsByTagName("title");0i;)f.removeChild(f.lastChild); +for(var j=0;jd)i=(c-g)/(h-f),h=0>h?-d:d,c=g+(h-f)*i;if(c<-e||c>e)i=(h-f)/(c-g),c=0>c?-e:e,h=f+(c-g)*i;return h+","+c},getShortString:function(a){var b=this.getResolution(),c=(a.x-this.featureDx)/b+this.left,a=this.top-a.y/b;return this.inValidRange(c,a)?c+","+a:!1},getPosition:function(a){return{x:parseFloat(a.getAttributeNS(null,"cx")),y:parseFloat(a.getAttributeNS(null,"cy"))}},importSymbol:function(a){this.defs|| +(this.defs=this.createDefs());var b=this.container.id+"-"+a,c=document.getElementById(b);if(null!=c)return c;var d=OpenLayers.Renderer.symbol[a];if(!d)throw Error(a+" is not a valid symbol name");var a=this.nodeFactory(b,"symbol"),e=this.nodeFactory(null,"polygon");a.appendChild(e);for(var c=new OpenLayers.Bounds(Number.MAX_VALUE,Number.MAX_VALUE,0,0),f=[],g,h,i=0;i - - + - + diff --git a/examples/raster-query.html b/examples/raster-query.html index e733cefde3..bc76a0db14 100644 --- a/examples/raster-query.html +++ b/examples/raster-query.html @@ -7,7 +7,7 @@ - + + + +

Download PDF

+
+ Raster, PDF, Download +
+

This demo shows how raster data can be downloaded as a PDF.

+
+

+ + + +

+
+

+ See the raster-pdf.js + source for details on how this is done. +

+
+ + + diff --git a/examples/raster-pdf.js b/examples/raster-pdf.js new file mode 100644 index 0000000000..c11ad56b7d --- /dev/null +++ b/examples/raster-pdf.js @@ -0,0 +1,28 @@ +var marble = new OpenLayers.Layer.WMS( + "Blue Marble", + "/geoserver/wms", + {layers: "topp:bluemarble", format: "image/png"} +); + +var data = OpenLayers.Raster.Composite.fromLayer(marble); + +var map = new OpenLayers.Map({ + div: "map", + theme: null, + layers: [marble], + center: new OpenLayers.LonLat(0, 0), + zoom: 1 +}); + +var link = document.getElementById("pdf-link"); + +link.onmouseover = function() { + var title = document.getElementById("map-title").value; + var doc = new jsPDF("landscape"); + doc.text(20, 20, title); + + var imgData = data.toDataURL("image/jpeg").slice("data:image/jpeg;base64,".length); + doc.addImage(atob(imgData), "JPEG", 20, 30, 256, 128); + + link.href = doc.output("datauristring"); +} From 41db5a0b3a29ddb80eacf0063df358698bf3fe61 Mon Sep 17 00:00:00 2001 From: tschaub Date: Thu, 30 Aug 2012 18:00:06 -0600 Subject: [PATCH 13/36] Simple stats example. --- examples/raster-stats.html | 37 +++++++++++++++++++++++++ examples/raster-stats.js | 44 ++++++++++++++++++++++++++++++ lib/OpenLayers/Raster/Composite.js | 8 +++++- 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 examples/raster-stats.html create mode 100644 examples/raster-stats.js diff --git a/examples/raster-stats.html b/examples/raster-stats.html new file mode 100644 index 0000000000..503b6e5ac3 --- /dev/null +++ b/examples/raster-stats.html @@ -0,0 +1,37 @@ + + + + + + + OpenLayers Raster Stats + + + + + +

OpenLayers Raster Stats

+
+ This example demonstrates how statistics can be generated from raster data. +
+
+ Raster, Statistics +
+
+ +
+

+ See the raster-stats.js source for + detail on generating statistics from raster data. +

+
+ + + diff --git a/examples/raster-stats.js b/examples/raster-stats.js new file mode 100644 index 0000000000..154d2997c7 --- /dev/null +++ b/examples/raster-stats.js @@ -0,0 +1,44 @@ +var nlcd = new OpenLayers.Layer.WMS( + "Land Cover", + "/geoserver/wms", + {layers: "usgs:nlcd", format: "image/png8"} +); + +var data = OpenLayers.Raster.Composite.fromLayer(nlcd); + +var pending; +function deferredStats() { + if (pending) { + window.clearTimeout(pending); + } + pending = window.setTimeout(generateStats, 900); +} + +var stats = {}; +function generateStats() { + stats = {}; + data.forEach(function(pixel) { + var rgb = pixel.slice(0, 3).join(","); + if (rgb in stats) { + stats[rgb] += 1; + } else { + stats[rgb] = 0; + } + }); + var txt = "RGB\tCount\n"; + for (var rgb in stats) { + txt += rgb + "\t" + stats[rgb] + "\n"; + } + document.getElementById("stats").value = txt; +} + +data.events.on({update: deferredStats}); + +var map = new OpenLayers.Map({ + div: "map", + projection: "EPSG:900913", + layers: [nlcd], + center: [-8606289, 4714070], + zoom: 11 +}); + diff --git a/lib/OpenLayers/Raster/Composite.js b/lib/OpenLayers/Raster/Composite.js index 10c62fb276..c30d078d69 100644 --- a/lib/OpenLayers/Raster/Composite.js +++ b/lib/OpenLayers/Raster/Composite.js @@ -156,7 +156,9 @@ OpenLayers.Raster.Composite.fromVectorLayer = function(layer, options) { function triggerUpdate() { cache = {}; - composite.events.triggerEvent("update"); + window.setTimeout(function() { + composite.events.triggerEvent("update"); + }, 0); } function addFeatures(event) { @@ -242,6 +244,10 @@ OpenLayers.Raster.Composite.fromGridLayer = function(layer) { return cache.pixelArray; } + function deferredUpdate() { + window.setTimeout(update, 0); + } + function update() { cache = {}; var map = layer.map; From 0673143c3278a7231e4b3add3f79ba0b31e31571 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Thu, 30 Aug 2012 22:45:31 -0600 Subject: [PATCH 14/36] Raster stats table. --- examples/raster-stats.html | 26 ++++++++++++++--- examples/raster-stats.js | 60 +++++++++++++++++++++++++++++++------- 2 files changed, 72 insertions(+), 14 deletions(-) diff --git a/examples/raster-stats.html b/examples/raster-stats.html index 503b6e5ac3..fa6bf038a8 100644 --- a/examples/raster-stats.html +++ b/examples/raster-stats.html @@ -9,10 +9,18 @@ @@ -25,7 +33,16 @@

OpenLayers Raster Stats

Raster, Statistics
- +
+
+ + + + + + +
Area (sq. m)Land Cover
areacover
+

See the raster-stats.js source for @@ -33,5 +50,6 @@

OpenLayers Raster Stats

+ diff --git a/examples/raster-stats.js b/examples/raster-stats.js index 154d2997c7..0665e24233 100644 --- a/examples/raster-stats.js +++ b/examples/raster-stats.js @@ -1,7 +1,8 @@ var nlcd = new OpenLayers.Layer.WMS( "Land Cover", "/geoserver/wms", - {layers: "usgs:nlcd", format: "image/png8"} + {layers: "usgs:nlcd", format: "image/png8"}, + {singleTile: true} ); var data = OpenLayers.Raster.Composite.fromLayer(nlcd); @@ -11,25 +12,65 @@ function deferredStats() { if (pending) { window.clearTimeout(pending); } - pending = window.setTimeout(generateStats, 900); + pending = window.setTimeout(generateStats, 200); } +var classes = { + "255,255,255": "Background", + "0,0,0": "Background", // 0 + "73,109,163": "Open Water", // 11 + "224,204,204": "Developed, Open Space", // 21 + "219,153,130": "Developed, Low Intensity", // 22 + "242,0,0": "Developed, Medium Intensity", // 23 + "170,0,0": "Developed, High Intensity", // 24 + "181,175,163": "Barren Land (Rock/Sand/Clay)", // 31 + "107,170,102": "Deciduous Forest", // 41 + "28,102,51": "Evergreen Forest", // 42 + "186,204,145": "Mixed Forest", // 43 + "165,140,48": "Dwarf Scrub", // 51 + "209,186,130": "Shrub/Scrub", // 52 + "229,229,193": "Grassland/Herbaceous", // 71 + "201,201,119": "Sedge/Herbaceous", // 72 + "221,216,60": "Pasture/Hay", // 81 + "173,112,40": "Cultivated Crops", // 82 + "186,216,237": "Woody Wetlands", // 90 + "112,163,191": "Emergent Herbaceous Wetlands" // 95 +}; + var stats = {}; function generateStats() { stats = {}; + var area = Math.pow(map.getResolution(), 2); data.forEach(function(pixel) { var rgb = pixel.slice(0, 3).join(","); - if (rgb in stats) { - stats[rgb] += 1; + var cls = classes[rgb] || rgb + if (cls in stats) { + stats[cls] += area; } else { - stats[rgb] = 0; + stats[cls] = area; } }); - var txt = "RGB\tCount\n"; - for (var rgb in stats) { - txt += rgb + "\t" + stats[rgb] + "\n"; + var txt = "Area (sq. m)\tLand Cover\n"; + for (var cls in stats) { + txt += Math.round(stats[cls]) + "\t\t" + cls + "\n"; + } + displayStats(stats); +} + +var template = new jugl.Template("template"); +var target = document.getElementById("stats"); +function displayStats(stats) { + var entries = []; + for (var cls in stats) { + entries.push([stats[cls], cls]); } - document.getElementById("stats").value = txt; + entries.sort(function(a, b) {return b[0]-a[0]}); + target.innerHTML = ""; + template.process({ + context: {entries: entries}, + clone: true, + parent: target + }); } data.events.on({update: deferredStats}); @@ -41,4 +82,3 @@ var map = new OpenLayers.Map({ center: [-8606289, 4714070], zoom: 11 }); - From 6fd21f99cd262f79d3c6cd4230d057e25aa92552 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Fri, 31 Aug 2012 00:29:11 -0600 Subject: [PATCH 15/36] Build lib for stats example. --- OpenLayers.js | 8 ++++---- examples/raster-stats.html | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/OpenLayers.js b/OpenLayers.js index 3cfe629f60..b2e0ce4934 100644 --- a/OpenLayers.js +++ b/OpenLayers.js @@ -205,10 +205,10 @@ this.redraw()},redraw:function(){if(!this.locked){var a=this.root.height,b=this. a[b],this.drawText(f[0].geometry.getCentroid(),f[1])}},CLASS_NAME:"OpenLayers.Renderer.Canvas"});OpenLayers.Renderer.Canvas.LABEL_ALIGN={l:"left",r:"right",t:"top",b:"bottom"};OpenLayers.Renderer.Canvas.LABEL_FACTOR={l:0,r:-1,t:0,b:-1};OpenLayers.Renderer.Canvas.drawImageScaleFactor=null;OpenLayers.Raster.Composite=OpenLayers.Class(OpenLayers.Raster.Grid,function(){var a;return{initialize:function(b){b.grids&&(a=b.grids,delete b.grids);OpenLayers.Raster.Grid.prototype.initialize.apply(this,[b]);if(a)for(var b=0,c=a.length;ba||a>=this.getCount())throw Error("Bad grid index.");var c=this;return new OpenLayers.Raster.Grid({numCols:function(){return c.numCols()},numRows:function(){return c.numRows()},getValue:function(d,e){return c.getValue(d,e)[a]}})},CLASS_NAME:"OpenLayers.Raster.Composite"}}()); OpenLayers.Raster.Composite.fromLayer=function(a,b){var c;if(a instanceof OpenLayers.Layer.Grid)c=OpenLayers.Raster.Composite.fromGridLayer(a);else if(a instanceof OpenLayers.Layer.Vector)c=OpenLayers.Raster.Composite.fromVectorLayer(a,b);else throw Error("Only OpenLayers.Layer.Grid type layers can be used to create a raster");return c}; -OpenLayers.Raster.Composite.fromVectorLayer=function(a,b){var c;function d(a){a=Math.max(0,Math.min(255,a));return(3840+a).toString(16).substring(1)}function e(){c=void 0;n.events.triggerEvent("update")}function f(b){b=b.features;l.addFeatures(b,{silent:!0});for(var c=0,d=b.length;cOpenLayers Raster Stats detail on generating statistics from raster data.

- + From d38fdbc46a794f7ef49cb766f037c771c20e75b9 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Fri, 31 Aug 2012 01:04:15 -0600 Subject: [PATCH 16/36] Update after tileload and move sequence complete. --- OpenLayers.js | 32 +++++++++++++++--------------- examples/raster-stats.js | 29 +++++++++------------------ lib/OpenLayers/Raster/Composite.js | 9 ++++----- 3 files changed, 29 insertions(+), 41 deletions(-) diff --git a/OpenLayers.js b/OpenLayers.js index b2e0ce4934..218fc3c4a1 100644 --- a/OpenLayers.js +++ b/OpenLayers.js @@ -91,10 +91,10 @@ OpenLayers.Util.getParameterString=function(a){var b=[],c;for(c in a){var d=a[c] OpenLayers.Util.getImagesLocation=function(){return OpenLayers.ImgPath||OpenLayers._getScriptLocation()+"img/"};OpenLayers.Util.getImageLocation=function(a){return OpenLayers.Util.getImagesLocation()+a};OpenLayers.Util.Try=function(){for(var a=null,b=0,c=arguments.length;bf)break;if(!(i.x2Math.max(g,h))&&!(Math.max(j,k)h&&(i>j.y1&&ij.y2))break;e=c?{distance:e.distance,x0:e.x,y0:e.y,x1:h,y1:i}:e.distance}else if(a instanceof OpenLayers.Geometry.LineString){var g=this.getSortedSegments(),h=a.getSortedSegments(),m,l,o=h.length,p={point:!0},k=0,n=g.length;a:for(;kh&&(i>j.y1&&ij.y2))break;e=c?{distance:e.distance,x0:e.x,y0:e.y,x1:h,y1:i}:e.distance}else if(a instanceof OpenLayers.Geometry.LineString){var g=this.getSortedSegments(),h=a.getSortedSegments(),m,l,o=h.length,q={point:!0},k=0,n=g.length;a:for(;kb.length)return this;var c=function(a,b,d,i){for(var j=0,k=0,n=b,m;nj&&(j=m,k=n)}j>i&&k!=b&&(e.push(k),c(a,b,k,i),c(a,k,d,i))},d=b.length-1,e=[];e.push(0);for(e.push(d);b[0].equals(b[d]);)d--,e.push(d);c(b,0,d,a);a=[];e.sort(function(a,b){return a-b});for(d=0;da||a>=this.getCount())throw Error("Bad grid index.");var c=this;return new OpenLayers.Raster.Grid({numCols:function(){return c.numCols()},numRows:function(){return c.numRows()},getValue:function(d,e){return c.getValue(d,e)[a]}})},CLASS_NAME:"OpenLayers.Raster.Composite"}}()); -OpenLayers.Raster.Composite.fromLayer=function(a,b){var c;if(a instanceof OpenLayers.Layer.Grid)c=OpenLayers.Raster.Composite.fromGridLayer(a);else if(a instanceof OpenLayers.Layer.Vector)c=OpenLayers.Raster.Composite.fromVectorLayer(a,b);else throw Error("Only OpenLayers.Layer.Grid type layers can be used to create a raster");return c}; +OpenLayers.Raster.Composite.fromLayer=function(a,b){var c;if(a instanceof OpenLayers.Layer.Grid)c=OpenLayers.Raster.Composite.fromGridLayer(a);else if(a instanceof OpenLayers.Layer.Vector)c=OpenLayers.Raster.Composite.fromVectorLayer(a,b);else throw Error("Only Grid or Vector type layers can be used to create a raster");return c}; OpenLayers.Raster.Composite.fromVectorLayer=function(a,b){var c;function d(a){a=Math.max(0,Math.min(255,a));return(3840+a).toString(16).substring(1)}function e(){c=void 0;window.setTimeout(function(){n.events.triggerEvent("update")},0)}function f(b){b=b.features;l.addFeatures(b,{silent:!0});for(var c=0,d=b.length;c= +new OpenLayers.LonLat(a[b[0]],a[b[1]]);return a},initGriddedTiles:function(a){this.clearTileQueue();var b=this.map.getSize(),c=this.getTileOrigin(),d=this.map.getResolution(),e=this.getServerResolution(),f=d/e,d=this.tileSize.w/f,f=this.tileSize.h/f,g=Math.ceil(b.h/f)+2*this.buffer+1,b=Math.ceil(b.w/d)+2*this.buffer+1,c=this.calculateGridLayout(a,c,e),e=Math.round(c.tileoffsetx),h=Math.round(c.tileoffsety),i=c.tileoffsetlon,j=c.tileoffsetlat,k=c.tilelon,n=c.tilelat,m=e,l=i,o=0,q=this.map.layerContainerOriginPx.x, +p=this.map.layerContainerOriginPx.y,c=[],r=this.map.getCenter();do{var s=this.grid[o++];s||(s=[],this.grid.push(s));var i=l,e=m,t=0;do{var v=new OpenLayers.Bounds(i,j,i+k,j+n),u=e,u=u-q,w=h,w=w-p,w=new OpenLayers.Pixel(u,w);(u=s[t++])?u.moveTo(v,w,!1):(u=this.addTile(v,w),this.addTileMonitoringHooks(u),s.push(u));v=v.getCenterLonLat();c.push({tile:u,distance:Math.pow(v.lon-r.lon,2)+Math.pow(v.lat-r.lat,2)});i+=k;e+=Math.round(d)}while(i<=a.right+k*this.buffer||t= a.bottom-n*this.buffer||o Date: Mon, 3 Sep 2012 18:25:24 -0600 Subject: [PATCH 17/36] Example updates. --- examples/raster-operations.html | 1 - examples/raster-stats.js | 35 +++++- examples/raster-zonal-stats.html | 74 ++++++++++++ examples/raster-zonal-stats.js | 186 +++++++++++++++++++++++++++++++ 4 files changed, 293 insertions(+), 3 deletions(-) create mode 100644 examples/raster-zonal-stats.html create mode 100644 examples/raster-zonal-stats.js diff --git a/examples/raster-operations.html b/examples/raster-operations.html index 2403d9dca4..5d7567bd64 100644 --- a/examples/raster-operations.html +++ b/examples/raster-operations.html @@ -7,7 +7,6 @@ - diff --git a/examples/raster-stats.js b/examples/raster-stats.js index fa3fc0016f..b5065a6b27 100644 --- a/examples/raster-stats.js +++ b/examples/raster-stats.js @@ -1,18 +1,49 @@ +var streets = new OpenLayers.Layer.XYZ( + "OpenStreetMap", + [ + "http://otile1.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png", + "http://otile2.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png", + "http://otile3.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png", + "http://otile4.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png" + ], + { + attribution: "Tiles by MapQuest, Open Street Map and contributors, CC-BY-SA ", + transitionEffect: "resize" + } +); + +var imagery = new OpenLayers.Layer.XYZ( + "Imagery", + [ + "http://oatile1.mqcdn.com/naip/${z}/${x}/${y}.png", + "http://oatile2.mqcdn.com/naip/${z}/${x}/${y}.png", + "http://oatile3.mqcdn.com/naip/${z}/${x}/${y}.png", + "http://oatile4.mqcdn.com/naip/${z}/${x}/${y}.png" + ], + { + attribution: "Tiles by MapQuest ", + transitionEffect: "resize" + } +); + + var nlcd = new OpenLayers.Layer.WMS( "Land Cover", "/geoserver/wms", {layers: "usgs:nlcd", format: "image/png8"}, - {singleTile: true} + {singleTile: true, isBaseLayer: false} ); var map = new OpenLayers.Map({ div: "map", projection: "EPSG:900913", - layers: [nlcd], + layers: [streets, imagery, nlcd], center: [-8606289, 4714070], zoom: 11 }); +map.addControl(new OpenLayers.Control.LayerSwitcher()); + var data = OpenLayers.Raster.Composite.fromLayer(nlcd); var classes = { diff --git a/examples/raster-zonal-stats.html b/examples/raster-zonal-stats.html new file mode 100644 index 0000000000..69fbb43f37 --- /dev/null +++ b/examples/raster-zonal-stats.html @@ -0,0 +1,74 @@ + + + + + + + OpenLayers Raster Zonal Stats + + + + + + + + +

OpenLayers Raster Zonal Stats

+
+ This example demonstrates how statistics can be generated from raster data. +
+
+ Raster, Statistics +
+
+
+ min elevation: +
+
+
+
+ + + + + + +
Area (sq. m)Land Cover
areacover
+
+
+

+ See the raster-zonal-stats.js source for + detail on generating statistics from raster data. +

+
+ + + + diff --git a/examples/raster-zonal-stats.js b/examples/raster-zonal-stats.js new file mode 100644 index 0000000000..01992ee511 --- /dev/null +++ b/examples/raster-zonal-stats.js @@ -0,0 +1,186 @@ +var op = OpenLayers.Raster.Operation; + +var streets = new OpenLayers.Layer.XYZ( + "OpenStreetMap", + [ + "http://otile1.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png", + "http://otile2.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png", + "http://otile3.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png", + "http://otile4.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png" + ], + { + attribution: "Tiles by MapQuest, Open Street Map and contributors, CC-BY-SA ", + transitionEffect: "resize" + } +); + +var imagery = new OpenLayers.Layer.XYZ( + "Imagery", + [ + "http://oatile1.mqcdn.com/naip/${z}/${x}/${y}.png", + "http://oatile2.mqcdn.com/naip/${z}/${x}/${y}.png", + "http://oatile3.mqcdn.com/naip/${z}/${x}/${y}.png", + "http://oatile4.mqcdn.com/naip/${z}/${x}/${y}.png" + ], + { + attribution: "Tiles by MapQuest ", + transitionEffect: "resize" + } +); + + +var ned = new OpenLayers.Layer.WMS( + "Elevation", + "/geoserver/wms", + {layers: "usgs:ned", format: "image/png", transparent: true}, + {singleTile: true, isBaseLayer: false, visibility: false} +); + +var nlcd = new OpenLayers.Layer.WMS( + "Land Cover", + "/geoserver/wms", + {layers: "usgs:nlcd", format: "image/png8", transparent: true}, + {singleTile: true, isBaseLayer: false, visibility: false} +); + +var map = new OpenLayers.Map({ + div: "map", + projection: "EPSG:900913", + layers: [streets, imagery, ned, nlcd], + center: [-8606289, 4714070], + zoom: 11 +}); + +/** + * The NED dataset is symbolized by a color ramp that maps the following + * elevations to corresponding RGB values. This operation is used to + * invert the mapping - returning elevations in meters for a pixel RGB array. + * + * -20m : 0, 0, 0 + * 400m : 0, 0, 255 + * 820m : 0, 255, 255 + * 1240m : 255, 255, 255 + * + * Transparent pixels are areas of no data (grid value will be NaN). + */ +var getElevation = op.create(function(rgba) { + var elevation = NaN, + delta = 420, + min = -20; + + if (rgba[3] == 255) { + elevation = (delta * (rgba[0] + rgba[1] + rgba[2]) / 255) + min; + } + return elevation; +}); + +/** + * This operation is used to transform an elevation grid into a grid + * with values representing an elevation zone. + * + * 0: e < 250m + * 1: 250m <= e < 500m + * 2: e >= 500m + * + * Areas of no data will have NaN value. + */ +var getZone = op.create(function(elevation) { + var e = elevation[0], + zone = NaN; + if (!isNaN(e)) { + if (e < 250) { + zone = 0; + } else if (e < 500) { + zone = 1; + } else { + zone = 2; + } + } + return zone; +}; + +var zones = getZone(getElevation(OpenLayers.Raster.Composite.fromLayer(ned))); + +var classes = { + "255,255,255": "Background", + "0,0,0": "Background", // 0 + "73,109,163": "Open Water", // 11 + "224,204,204": "Developed, Open Space", // 21 + "219,153,130": "Developed, Low Intensity", // 22 + "242,0,0": "Developed, Medium Intensity", // 23 + "170,0,0": "Developed, High Intensity", // 24 + "181,175,163": "Barren Land (Rock/Sand/Clay)", // 31 + "107,170,102": "Deciduous Forest", // 41 + "28,102,51": "Evergreen Forest", // 42 + "186,204,145": "Mixed Forest", // 43 + "165,140,48": "Dwarf Scrub", // 51 + "209,186,130": "Shrub/Scrub", // 52 + "229,229,193": "Grassland/Herbaceous", // 71 + "201,201,119": "Sedge/Herbaceous", // 72 + "221,216,60": "Pasture/Hay", // 81 + "173,112,40": "Cultivated Crops", // 82 + "186,216,237": "Woody Wetlands", // 90 + "112,163,191": "Emergent Herbaceous Wetlands" // 95 +}; + +var getCover = op.create(function(pixel) { + var rgb = pixel.slice(0, 3).join(","); + var cover = classes[rgb] || rgb; +}); + +var landcover = getCover(OpenLayers.Raster.Composite.fromLayer(nlcd)); + +var getZoneCover = op.create(function(zonesPixel, coverPixel) { + return [zonesPixel[0], coverPixel[0]]; +}); + +var zoneCover = getZoneCover(zones, landcover); + +var stats = {}; +function generateStats() { + stats = {}; + var area = Math.pow(map.getResolution(), 2); + zoneCover.forEach(function(pixel) { + var rgb = pixel.slice(0, 3).join(","); + var cls = classes[rgb] || rgb + if (cls in stats) { + stats[cls] += area; + } else { + stats[cls] = area; + } + }); + displayStats(stats); +} + +var template = new jugl.Template("template"); +var target = document.getElementById("stats"); +function displayStats(stats) { + var entries = []; + for (var cls in stats) { + entries.push([stats[cls], cls]); + } + entries.sort(function(a, b) {return b[0]-a[0]}); + target.innerHTML = ""; + template.process({ + context: {entries: entries}, + clone: true, + parent: target + }); +} + +landcover.events.on({update: generateStats}); + +var Click = OpenLayers.Class(OpenLayers.Control, { + autoActivate: true, + initialize: function(options) { + OpenLayers.Control.prototype.initialize.apply(this, arguments); + this.handler = new OpenLayers.Handler.Click(this, {click: this.trigger}); + }, + trigger: function(event) { + var xy = event.xy; + pixel = elevation.getValue(Math.round(xy.x), Math.round(xy.y)); + console.log(pixel); + } +}); +map.addControl(new Click()); +map.addControl(new OpenLayers.Control.LayerSwitcher()); From 6cadf767b4ae498cf776cec7607c728e62b6b253 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Mon, 3 Sep 2012 22:34:54 -0600 Subject: [PATCH 18/36] Zonal stats update. --- OpenLayers.js | 4 +- examples/raster-zonal-stats.html | 29 +++++--- examples/raster-zonal-stats.js | 105 ++++++++++++++++------------- lib/OpenLayers/Raster/Operation.js | 6 +- 4 files changed, 80 insertions(+), 64 deletions(-) diff --git a/OpenLayers.js b/OpenLayers.js index 218fc3c4a1..45d076bd0e 100644 --- a/OpenLayers.js +++ b/OpenLayers.js @@ -211,8 +211,8 @@ h(a);return"#"+d(a[0])+d(a[1])+d(a[2])},getOpacity:function(a){return h(a)[3]/25 null,g)});return n}; OpenLayers.Raster.Composite.fromGridLayer=function(a){var b;function c(){window.setTimeout(d,0)}function d(){b=void 0;var c=a.map,d=a.tileSize,j=c.getSize();e.width=j.w;e.height=j.h;for(var j=c.getExtent(),k=a.grid,n,m,l,o=0,q=k.length;oOpenLayers Raster Zonal Stats - - - + + +

OpenLayers Raster Mask

+
+ This example demonstrates how generate a raster mask from vector data. +
+
+ Raster, Vector, Mask +
+
+
+
+ + + + + + +
Area (sq. m)Land Cover
areacover
+
+
+

+ Click on the map to select a census tract. The landcover stats will be + displayed for the selected tracts. +

+ See the raster-mask.js source for + detail on generating a mask for raster data from vector features. +

+
+ + + + diff --git a/examples/raster-mask.js b/examples/raster-mask.js new file mode 100644 index 0000000000..306f763433 --- /dev/null +++ b/examples/raster-mask.js @@ -0,0 +1,201 @@ +var fromLayer = OpenLayers.Raster.Composite.fromLayer; +var op = OpenLayers.Raster.Operation; + +var streets = new OpenLayers.Layer.XYZ( + "OpenStreetMap", + [ + "http://otile1.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png", + "http://otile2.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png", + "http://otile3.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png", + "http://otile4.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png" + ], + { + attribution: "Tiles by MapQuest, Open Street Map and contributors, CC-BY-SA ", + transitionEffect: "resize" + } +); + +var imagery = new OpenLayers.Layer.XYZ( + "Imagery", + [ + "http://oatile1.mqcdn.com/naip/${z}/${x}/${y}.png", + "http://oatile2.mqcdn.com/naip/${z}/${x}/${y}.png", + "http://oatile3.mqcdn.com/naip/${z}/${x}/${y}.png", + "http://oatile4.mqcdn.com/naip/${z}/${x}/${y}.png" + ], + { + attribution: "Tiles by MapQuest ", + transitionEffect: "resize" + } +); + + +var nlcd = new OpenLayers.Layer.WMS( + "Land Cover", + "/geoserver/wms", + {layers: "usgs:nlcd", format: "image/png8"}, + {singleTile: true, isBaseLayer: false} +); + + +var tracts = new OpenLayers.Layer.Vector("Census Tracts", { + strategies: [new OpenLayers.Strategy.BBOX()], + projection: new OpenLayers.Projection("EPSG:900913"), + protocol: new OpenLayers.Protocol.WFS({ + url: "/geoserver/wfs", + version: "1.1.0", + featureNS: "http://www.usgs.gov/#opengeo", + srsName: "EPSG:900913", + featureType: "tracts" + }), + styleMap: new OpenLayers.StyleMap({ + "default": new OpenLayers.Style({ + stroke: false, + fillOpacity: 0.01 + }), + "select": new OpenLayers.Style({ + fillColor: "#66ccff", + fillOpacity: 0.5, + stroke: true, + strokeColor: "#3399ff", + strokeWidth: 2 + }) + }) +}); + +var select = new OpenLayers.Control.SelectFeature(tracts, { + autoActivate: true, + toggle: true, + multipleKey: "shiftKey" +}); + +var getIds = op.create(function(pixel) { + var id = null; + if (!!pixel[3]) { + id = (256 * 256 * pixel[2]) + ((256 * pixel[1]) + pixel[0]); + } + return [id]; +}); + +var rasterTracts = fromLayer(tracts, { + mapping: function(feature) { + // TODO: handle this mapping in the factory + var id = Number(feature.fid.split(".").pop()); + var r = id % 256; + var g = Math.floor(id / 256) % 256; + var b = Math.floor(id / (256 * 256)); + if (b > 255) { + throw new Error("Id overflow"); + } + return [r, g, b, 255]; + } +}); + +var tractIds = getIds(rasterTracts); + +var map = new OpenLayers.Map({ + div: "map", + projection: "EPSG:900913", + layers: [streets, imagery, nlcd, tracts], + controls: [ + select, + new OpenLayers.Control.Zoom(), + new OpenLayers.Control.Navigation(), + new OpenLayers.Control.LayerSwitcher() + ], + center: [-8606289, 4714070], + zoom: 11 +}); + +var classes = { + "255,255,255": null, + "0,0,0": null, // 0 + "73,109,163": "Open Water", // 11 + "224,204,204": "Developed, Open Space", // 21 + "219,153,130": "Developed, Low Intensity", // 22 + "242,0,0": "Developed, Medium Intensity", // 23 + "170,0,0": "Developed, High Intensity", // 24 + "181,175,163": "Barren Land (Rock/Sand/Clay)", // 31 + "107,170,102": "Deciduous Forest", // 41 + "28,102,51": "Evergreen Forest", // 42 + "186,204,145": "Mixed Forest", // 43 + "165,140,48": "Dwarf Scrub", // 51 + "209,186,130": "Shrub/Scrub", // 52 + "229,229,193": "Grassland/Herbaceous", // 71 + "201,201,119": "Sedge/Herbaceous", // 72 + "221,216,60": "Pasture/Hay", // 81 + "173,112,40": "Cultivated Crops", // 82 + "186,216,237": "Woody Wetlands", // 90 + "112,163,191": "Emergent Herbaceous Wetlands" // 95 +}; + +var getCover = op.create(function(pixel) { + var rgb = pixel.slice(0, 3).join(","); + return [classes[rgb] || rgb]; +}); + +var landcover = getCover(fromLayer(nlcd)); + +function generateStats() { + var stats = {}; + var area = Math.pow(map.getResolution(), 2); + var selected = {}; + var some = false; + for (var i=0, ii=tracts.selectedFeatures.length; i Date: Tue, 4 Sep 2012 16:32:52 -0600 Subject: [PATCH 20/36] Namespace to match. --- examples/raster-mask.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/raster-mask.js b/examples/raster-mask.js index 306f763433..3bf7973e88 100644 --- a/examples/raster-mask.js +++ b/examples/raster-mask.js @@ -44,7 +44,7 @@ var tracts = new OpenLayers.Layer.Vector("Census Tracts", { protocol: new OpenLayers.Protocol.WFS({ url: "/geoserver/wfs", version: "1.1.0", - featureNS: "http://www.usgs.gov/#opengeo", + featureNS: "http://www.usgs.gov/", srsName: "EPSG:900913", featureType: "tracts" }), From 77cd1ebc6dcba20dde96e7581f1b0e918d7a4ca2 Mon Sep 17 00:00:00 2001 From: tschaub Date: Tue, 4 Sep 2012 17:04:24 -0600 Subject: [PATCH 21/36] New signature for forEach. Compressed build. --- OpenLayers.js | 38894 +------------------------------ lib/OpenLayers/Layer/Raster.js | 3 +- 2 files changed, 584 insertions(+), 38313 deletions(-) diff --git a/OpenLayers.js b/OpenLayers.js index 39294c87bf..54753b2772 100644 --- a/OpenLayers.js +++ b/OpenLayers.js @@ -55,38315 +55,585 @@ * 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-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -var OpenLayers = { - /** - * Constant: VERSION_NUMBER - */ - VERSION_NUMBER: "Release 2.13 dev", - - /** - * Constant: singleFile - * TODO: remove this in 3.0 when we stop supporting build profiles that - * include OpenLayers.js - */ - singleFile: true, - - /** - * Method: _getScriptLocation - * Return the path to this script. This is also implemented in - * OpenLayers.js - * - * Returns: - * {String} Path to this script - */ - _getScriptLocation: (function() { - var r = new RegExp("(^|(.*?\\/))(OpenLayers[^\\/]*?\\.js)(\\?|$)"), - s = document.getElementsByTagName('script'), - src, m, l = ""; - for(var i=0, len=s.length; i - * - * (end code) - * - * Please remember that when your OpenLayers script is not named - * "OpenLayers.js" you will have to make sure that the default theme is - * loaded into the page by including an appropriate -tag, - * e.g.: - * - * (code) - * - * (end code) - */ - ImgPath : '' -}; -/* ====================================================================== - OpenLayers/BaseTypes.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/SingleFile.js - */ - -/** - * Header: OpenLayers Base Types - * OpenLayers custom string, number and function functions are described here. - */ - -/** - * Namespace: OpenLayers.String - * Contains convenience functions for string manipulation. - */ -OpenLayers.String = { - - /** - * APIFunction: startsWith - * Test whether a string starts with another string. - * - * Parameters: - * str - {String} The string to test. - * sub - {String} The substring to look for. - * - * Returns: - * {Boolean} The first string starts with the second. - */ - startsWith: function(str, sub) { - return (str.indexOf(sub) == 0); - }, - - /** - * APIFunction: contains - * Test whether a string contains another string. - * - * Parameters: - * str - {String} The string to test. - * sub - {String} The substring to look for. - * - * Returns: - * {Boolean} The first string contains the second. - */ - contains: function(str, sub) { - return (str.indexOf(sub) != -1); - }, - - /** - * APIFunction: trim - * Removes leading and trailing whitespace characters from a string. - * - * Parameters: - * str - {String} The (potentially) space padded string. This string is not - * modified. - * - * Returns: - * {String} A trimmed version of the string with all leading and - * trailing spaces removed. - */ - trim: function(str) { - return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); - }, - - /** - * APIFunction: camelize - * Camel-case a hyphenated string. - * Ex. "chicken-head" becomes "chickenHead", and - * "-chicken-head" becomes "ChickenHead". - * - * Parameters: - * str - {String} The string to be camelized. The original is not modified. - * - * Returns: - * {String} The string, camelized - */ - camelize: function(str) { - var oStringList = str.split('-'); - var camelizedString = oStringList[0]; - for (var i=1, len=oStringList.length; i replacement = context[a]; - // 1 -> replacement = context[a][b]; - // 2 -> replacement = context[a][b][c]; - var subs = match.split(/\.+/); - for (var i=0; i< subs.length; i++) { - if (i == 0) { - replacement = context; - } - - replacement = replacement[subs[i]]; - } - - if(typeof replacement == "function") { - replacement = args ? - replacement.apply(null, args) : - replacement(); - } - - // If replacement is undefined, return the string 'undefined'. - // This is a workaround for a bugs in browsers not properly - // dealing with non-participating groups in regular expressions: - // http://blog.stevenlevithan.com/archives/npcg-javascript - if (typeof replacement == 'undefined') { - return 'undefined'; - } else { - return replacement; - } - }; - - return template.replace(OpenLayers.String.tokenRegEx, replacer); - }, - - /** - * Property: tokenRegEx - * Used to find tokens in a string. - * Examples: ${a}, ${a.b.c}, ${a-b}, ${5} - */ - tokenRegEx: /\$\{([\w.]+?)\}/g, - - /** - * Property: numberRegEx - * Used to test strings as numbers. - */ - numberRegEx: /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/, - - /** - * APIFunction: isNumeric - * Determine whether a string contains only a numeric value. - * - * Examples: - * (code) - * OpenLayers.String.isNumeric("6.02e23") // true - * OpenLayers.String.isNumeric("12 dozen") // false - * OpenLayers.String.isNumeric("4") // true - * OpenLayers.String.isNumeric(" 4 ") // false - * (end) - * - * Returns: - * {Boolean} String contains only a number. - */ - isNumeric: function(value) { - return OpenLayers.String.numberRegEx.test(value); - }, - - /** - * APIFunction: numericIf - * Converts a string that appears to be a numeric value into a number. - * - * Parameters: - * value - {String} - * trimWhitespace - {Boolean} - * - * Returns: - * {Number|String} a Number if the passed value is a number, a String - * otherwise. - */ - numericIf: function(value, trimWhitespace) { - var originalValue = value; - if (trimWhitespace === true && value != null && value.replace) { - value = value.replace(/^\s*|\s*$/g, ""); - } - return OpenLayers.String.isNumeric(value) ? parseFloat(value) : originalValue; - } - -}; - -/** - * Namespace: OpenLayers.Number - * Contains convenience functions for manipulating numbers. - */ -OpenLayers.Number = { - - /** - * Property: decimalSeparator - * Decimal separator to use when formatting numbers. - */ - decimalSeparator: ".", - - /** - * Property: thousandsSeparator - * Thousands separator to use when formatting numbers. - */ - thousandsSeparator: ",", - - /** - * APIFunction: limitSigDigs - * Limit the number of significant digits on a float. - * - * Parameters: - * num - {Float} - * sig - {Integer} - * - * Returns: - * {Float} The number, rounded to the specified number of significant - * digits. - */ - limitSigDigs: function(num, sig) { - var fig = 0; - if (sig > 0) { - fig = parseFloat(num.toPrecision(sig)); - } - return fig; - }, - - /** - * APIFunction: format - * Formats a number for output. - * - * Parameters: - * num - {Float} - * dec - {Integer} Number of decimal places to round to. - * Defaults to 0. Set to null to leave decimal places unchanged. - * tsep - {String} Thousands separator. - * Default is ",". - * dsep - {String} Decimal separator. - * Default is ".". - * - * Returns: - * {String} A string representing the formatted number. - */ - format: function(num, dec, tsep, dsep) { - dec = (typeof dec != "undefined") ? dec : 0; - tsep = (typeof tsep != "undefined") ? tsep : - OpenLayers.Number.thousandsSeparator; - dsep = (typeof dsep != "undefined") ? dsep : - OpenLayers.Number.decimalSeparator; - - if (dec != null) { - num = parseFloat(num.toFixed(dec)); - } - - var parts = num.toString().split("."); - if (parts.length == 1 && dec == null) { - // integer where we do not want to touch the decimals - dec = 0; - } - - var integer = parts[0]; - if (tsep) { - var thousands = /(-?[0-9]+)([0-9]{3})/; - while(thousands.test(integer)) { - integer = integer.replace(thousands, "$1" + tsep + "$2"); - } - } - - var str; - if (dec == 0) { - str = integer; - } else { - var rem = parts.length > 1 ? parts[1] : "0"; - if (dec != null) { - rem = rem + new Array(dec - rem.length + 1).join("0"); - } - str = integer + dsep + rem; - } - return str; - } -}; - -/** - * Namespace: OpenLayers.Function - * Contains convenience functions for function manipulation. - */ -OpenLayers.Function = { - /** - * APIFunction: bind - * Bind a function to an object. Method to easily create closures with - * 'this' altered. - * - * Parameters: - * func - {Function} Input function. - * object - {Object} The object to bind to the input function (as this). - * - * Returns: - * {Function} A closure with 'this' set to the passed in object. - */ - bind: function(func, object) { - // create a reference to all arguments past the second one - var args = Array.prototype.slice.apply(arguments, [2]); - return function() { - // Push on any additional arguments from the actual function call. - // These will come after those sent to the bind call. - var newArgs = args.concat( - Array.prototype.slice.apply(arguments, [0]) - ); - return func.apply(object, newArgs); - }; - }, - - /** - * APIFunction: bindAsEventListener - * Bind a function to an object, and configure it to receive the event - * object as first parameter when called. - * - * Parameters: - * func - {Function} Input function to serve as an event listener. - * object - {Object} A reference to this. - * - * Returns: - * {Function} - */ - bindAsEventListener: function(func, object) { - return function(event) { - return func.call(object, event || window.event); - }; - }, - - /** - * APIFunction: False - * A simple function to that just does "return false". We use this to - * avoid attaching anonymous functions to DOM event handlers, which - * causes "issues" on IE<8. - * - * Usage: - * document.onclick = OpenLayers.Function.False; - * - * Returns: - * {Boolean} - */ - False : function() { - return false; - }, - - /** - * APIFunction: True - * A simple function to that just does "return true". We use this to - * avoid attaching anonymous functions to DOM event handlers, which - * causes "issues" on IE<8. - * - * Usage: - * document.onclick = OpenLayers.Function.True; - * - * Returns: - * {Boolean} - */ - True : function() { - return true; - }, - - /** - * APIFunction: Void - * A reusable function that returns ``undefined``. - * - * Returns: - * {undefined} - */ - Void: function() {} - -}; - -/** - * Namespace: OpenLayers.Array - * Contains convenience functions for array manipulation. - */ -OpenLayers.Array = { - - /** - * APIMethod: filter - * Filter an array. Provides the functionality of the - * Array.prototype.filter extension to the ECMA-262 standard. Where - * available, Array.prototype.filter will be used. - * - * Based on well known example from http://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Array/filter - * - * Parameters: - * array - {Array} The array to be filtered. This array is not mutated. - * Elements added to this array by the callback will not be visited. - * callback - {Function} A function that is called for each element in - * the array. If this function returns true, the element will be - * included in the return. The function will be called with three - * arguments: the element in the array, the index of that element, and - * the array itself. If the optional caller parameter is specified - * the callback will be called with this set to caller. - * caller - {Object} Optional object to be set as this when the callback - * is called. - * - * Returns: - * {Array} An array of elements from the passed in array for which the - * callback returns true. - */ - filter: function(array, callback, caller) { - var selected = []; - if (Array.prototype.filter) { - selected = array.filter(callback, caller); - } else { - var len = array.length; - if (typeof callback != "function") { - throw new TypeError(); - } - for(var i=0; i 1) { - var newArgs = [C, P].concat( - Array.prototype.slice.call(arguments).slice(1, len-1), F); - OpenLayers.inherit.apply(null, newArgs); - } else { - C.prototype = F; - } - return C; -}; - -/** - * Function: OpenLayers.inherit - * - * Parameters: - * C - {Object} the class that inherits - * P - {Object} the superclass to inherit from - * - * In addition to the mandatory C and P parameters, an arbitrary number of - * objects can be passed, which will extend C. - */ -OpenLayers.inherit = function(C, P) { - var F = function() {}; - F.prototype = P.prototype; - C.prototype = new F; - var i, l, o; - for(i=2, l=arguments.length; i} A cached center location. This should not be - * accessed directly. Use instead. - */ - centerLonLat: null, - - /** - * Constructor: OpenLayers.Bounds - * Construct a new bounds object. Coordinates can either be passed as four - * arguments, or as a single argument. - * - * Parameters (four arguments): - * left - {Number} The left bounds of the box. Note that for width - * calculations, this is assumed to be less than the right value. - * bottom - {Number} The bottom bounds of the box. Note that for height - * calculations, this is assumed to be more than the top value. - * right - {Number} The right bounds. - * top - {Number} The top bounds. - * - * Parameters (single argument): - * bounds - {Array(Number)} [left, bottom, right, top] - */ - initialize: function(left, bottom, right, top) { - if (OpenLayers.Util.isArray(left)) { - top = left[3]; - right = left[2]; - bottom = left[1]; - left = left[0]; - } - if (left != null) { - this.left = OpenLayers.Util.toFloat(left); - } - if (bottom != null) { - this.bottom = OpenLayers.Util.toFloat(bottom); - } - if (right != null) { - this.right = OpenLayers.Util.toFloat(right); - } - if (top != null) { - this.top = OpenLayers.Util.toFloat(top); - } - }, - - /** - * Method: clone - * Create a cloned instance of this bounds. - * - * Returns: - * {} A fresh copy of the bounds - */ - clone:function() { - return new OpenLayers.Bounds(this.left, this.bottom, - this.right, this.top); - }, - - /** - * Method: equals - * Test a two bounds for equivalence. - * - * Parameters: - * bounds - {} - * - * Returns: - * {Boolean} The passed-in bounds object has the same left, - * right, top, bottom components as this. Note that if bounds - * passed in is null, returns false. - */ - equals:function(bounds) { - var equals = false; - if (bounds != null) { - equals = ((this.left == bounds.left) && - (this.right == bounds.right) && - (this.top == bounds.top) && - (this.bottom == bounds.bottom)); - } - return equals; - }, - - /** - * APIMethod: toString - * Returns a string representation of the bounds object. - * - * Returns: - * {String} String representation of bounds object. - */ - toString:function() { - return [this.left, this.bottom, this.right, this.top].join(","); - }, - - /** - * APIMethod: toArray - * Returns an array representation of the bounds object. - * - * Returns an array of left, bottom, right, top properties, or -- when the - * optional parameter is true -- an array of the bottom, left, top, - * right properties. - * - * Parameters: - * reverseAxisOrder - {Boolean} Should we reverse the axis order? - * - * Returns: - * {Array} array of left, bottom, right, top - */ - toArray: function(reverseAxisOrder) { - if (reverseAxisOrder === true) { - return [this.bottom, this.left, this.top, this.right]; - } else { - return [this.left, this.bottom, this.right, this.top]; - } - }, - - /** - * APIMethod: toBBOX - * Returns a boundingbox-string representation of the bounds object. - * - * Parameters: - * decimal - {Integer} How many significant digits in the bbox coords? - * Default is 6 - * reverseAxisOrder - {Boolean} Should we reverse the axis order? - * - * Returns: - * {String} Simple String representation of bounds object. - * (e.g. "5,42,10,45") - */ - toBBOX:function(decimal, reverseAxisOrder) { - if (decimal== null) { - decimal = 6; - } - var mult = Math.pow(10, decimal); - var xmin = Math.round(this.left * mult) / mult; - var ymin = Math.round(this.bottom * mult) / mult; - var xmax = Math.round(this.right * mult) / mult; - var ymax = Math.round(this.top * mult) / mult; - if (reverseAxisOrder === true) { - return ymin + "," + xmin + "," + ymax + "," + xmax; - } else { - return xmin + "," + ymin + "," + xmax + "," + ymax; - } - }, - - /** - * APIMethod: toGeometry - * Create a new polygon geometry based on this bounds. - * - * Returns: - * {} A new polygon with the coordinates - * of this bounds. - */ - toGeometry: function() { - return new OpenLayers.Geometry.Polygon([ - new OpenLayers.Geometry.LinearRing([ - new OpenLayers.Geometry.Point(this.left, this.bottom), - new OpenLayers.Geometry.Point(this.right, this.bottom), - new OpenLayers.Geometry.Point(this.right, this.top), - new OpenLayers.Geometry.Point(this.left, this.top) - ]) - ]); - }, - - /** - * APIMethod: getWidth - * Returns the width of the bounds. - * - * Returns: - * {Float} The width of the bounds (right minus left). - */ - getWidth:function() { - return (this.right - this.left); - }, - - /** - * APIMethod: getHeight - * Returns the height of the bounds. - * - * Returns: - * {Float} The height of the bounds (top minus bottom). - */ - getHeight:function() { - return (this.top - this.bottom); - }, - - /** - * APIMethod: getSize - * Returns an object of the bounds. - * - * Returns: - * {} The size of the bounds. - */ - getSize:function() { - return new OpenLayers.Size(this.getWidth(), this.getHeight()); - }, - - /** - * APIMethod: getCenterPixel - * Returns the object which represents the center of the - * bounds. - * - * Returns: - * {} The center of the bounds in pixel space. - */ - getCenterPixel:function() { - return new OpenLayers.Pixel( (this.left + this.right) / 2, - (this.bottom + this.top) / 2); - }, - - /** - * APIMethod: getCenterLonLat - * Returns the object which represents the center of the - * bounds. - * - * Returns: - * {} The center of the bounds in map space. - */ - getCenterLonLat:function() { - if(!this.centerLonLat) { - this.centerLonLat = new OpenLayers.LonLat( - (this.left + this.right) / 2, (this.bottom + this.top) / 2 - ); - } - return this.centerLonLat; - }, - - /** - * APIMethod: scale - * Scales the bounds around a pixel or lonlat. Note that the new - * bounds may return non-integer properties, even if a pixel - * is passed. - * - * Parameters: - * ratio - {Float} - * origin - { or } - * Default is center. - * - * Returns: - * {} A new bounds that is scaled by ratio - * from origin. - */ - scale: function(ratio, origin){ - if(origin == null){ - origin = this.getCenterLonLat(); - } - - var origx,origy; - - // get origin coordinates - if(origin.CLASS_NAME == "OpenLayers.LonLat"){ - origx = origin.lon; - origy = origin.lat; - } else { - origx = origin.x; - origy = origin.y; - } - - var left = (this.left - origx) * ratio + origx; - var bottom = (this.bottom - origy) * ratio + origy; - var right = (this.right - origx) * ratio + origx; - var top = (this.top - origy) * ratio + origy; - - return new OpenLayers.Bounds(left, bottom, right, top); - }, - - /** - * APIMethod: add - * Shifts the coordinates of the bound by the given horizontal and vertical - * deltas. - * - * (start code) - * var bounds = new OpenLayers.Bounds(0, 0, 10, 10); - * bounds.toString(); - * // => "0,0,10,10" - * - * bounds.add(-1.5, 4).toString(); - * // => "-1.5,4,8.5,14" - * (end) - * - * This method will throw a TypeError if it is passed null as an argument. - * - * Parameters: - * x - {Float} horizontal delta - * y - {Float} vertical delta - * - * Returns: - * {} A new bounds whose coordinates are the same as - * this, but shifted by the passed-in x and y values. - */ - add:function(x, y) { - if ( (x == null) || (y == null) ) { - throw new TypeError('Bounds.add cannot receive null values'); - } - return new OpenLayers.Bounds(this.left + x, this.bottom + y, - this.right + x, this.top + y); - }, - - /** - * APIMethod: extend - * Extend the bounds to include the , - * or specified. - * - * Please note that this function assumes that left < right and - * bottom < top. - * - * Parameters: - * object - {, or - * } The object to be included in the new bounds - * object. - */ - extend:function(object) { - var bounds = null; - if (object) { - // clear cached center location - switch(object.CLASS_NAME) { - case "OpenLayers.LonLat": - bounds = new OpenLayers.Bounds(object.lon, object.lat, - object.lon, object.lat); - break; - case "OpenLayers.Geometry.Point": - bounds = new OpenLayers.Bounds(object.x, object.y, - object.x, object.y); - break; - - case "OpenLayers.Bounds": - bounds = object; - break; - } - - if (bounds) { - this.centerLonLat = null; - if ( (this.left == null) || (bounds.left < this.left)) { - this.left = bounds.left; - } - if ( (this.bottom == null) || (bounds.bottom < this.bottom) ) { - this.bottom = bounds.bottom; - } - if ( (this.right == null) || (bounds.right > this.right) ) { - this.right = bounds.right; - } - if ( (this.top == null) || (bounds.top > this.top) ) { - this.top = bounds.top; - } - } - } - }, - - /** - * APIMethod: containsLonLat - * Returns whether the bounds object contains the given . - * - * Parameters: - * ll - {|Object} OpenLayers.LonLat or an - * object with a 'lon' and 'lat' properties. - * options - {Object} Optional parameters - * - * Acceptable options: - * inclusive - {Boolean} Whether or not to include the border. - * Default is true. - * worldBounds - {} If a worldBounds is provided, the - * ll will be considered as contained if it exceeds the world bounds, - * but can be wrapped around the dateline so it is contained by this - * bounds. - * - * Returns: - * {Boolean} The passed-in lonlat is within this bounds. - */ - containsLonLat: function(ll, options) { - if (typeof options === "boolean") { - options = {inclusive: options}; - } - options = options || {}; - var contains = this.contains(ll.lon, ll.lat, options.inclusive), - worldBounds = options.worldBounds; - if (worldBounds && !contains) { - var worldWidth = worldBounds.getWidth(); - var worldCenterX = (worldBounds.left + worldBounds.right) / 2; - var worldsAway = Math.round((ll.lon - worldCenterX) / worldWidth); - contains = this.containsLonLat({ - lon: ll.lon - worldsAway * worldWidth, - lat: ll.lat - }, {inclusive: options.inclusive}); - } - return contains; - }, - - /** - * APIMethod: containsPixel - * Returns whether the bounds object contains the given . - * - * Parameters: - * px - {} - * inclusive - {Boolean} Whether or not to include the border. Default is - * true. - * - * Returns: - * {Boolean} The passed-in pixel is within this bounds. - */ - containsPixel:function(px, inclusive) { - return this.contains(px.x, px.y, inclusive); - }, - - /** - * APIMethod: contains - * Returns whether the bounds object contains the given x and y. - * - * Parameters: - * x - {Float} - * y - {Float} - * inclusive - {Boolean} Whether or not to include the border. Default is - * true. - * - * Returns: - * {Boolean} Whether or not the passed-in coordinates are within this - * bounds. - */ - contains:function(x, y, inclusive) { - //set default - if (inclusive == null) { - inclusive = true; - } - - if (x == null || y == null) { - return false; - } - - x = OpenLayers.Util.toFloat(x); - y = OpenLayers.Util.toFloat(y); - - var contains = false; - if (inclusive) { - contains = ((x >= this.left) && (x <= this.right) && - (y >= this.bottom) && (y <= this.top)); - } else { - contains = ((x > this.left) && (x < this.right) && - (y > this.bottom) && (y < this.top)); - } - return contains; - }, - - /** - * APIMethod: intersectsBounds - * Determine whether the target bounds intersects this bounds. Bounds are - * considered intersecting if any of their edges intersect or if one - * bounds contains the other. - * - * Parameters: - * bounds - {} The target bounds. - * options - {Object} Optional parameters. - * - * Acceptable options: - * inclusive - {Boolean} Treat coincident borders as intersecting. Default - * is true. If false, bounds that do not overlap but only touch at the - * border will not be considered as intersecting. - * worldBounds - {} If a worldBounds is provided, two - * bounds will be considered as intersecting if they intersect when - * shifted to within the world bounds. This applies only to bounds that - * cross or are completely outside the world bounds. - * - * Returns: - * {Boolean} The passed-in bounds object intersects this bounds. - */ - intersectsBounds:function(bounds, options) { - if (typeof options === "boolean") { - options = {inclusive: options}; - } - options = options || {}; - if (options.worldBounds) { - var self = this.wrapDateLine(options.worldBounds); - bounds = bounds.wrapDateLine(options.worldBounds); - } else { - self = this; - } - if (options.inclusive == null) { - options.inclusive = true; - } - var intersects = false; - var mightTouch = ( - self.left == bounds.right || - self.right == bounds.left || - self.top == bounds.bottom || - self.bottom == bounds.top - ); - - // if the two bounds only touch at an edge, and inclusive is false, - // then the bounds don't *really* intersect. - if (options.inclusive || !mightTouch) { - // otherwise, if one of the boundaries even partially contains another, - // inclusive of the edges, then they do intersect. - var inBottom = ( - ((bounds.bottom >= self.bottom) && (bounds.bottom <= self.top)) || - ((self.bottom >= bounds.bottom) && (self.bottom <= bounds.top)) - ); - var inTop = ( - ((bounds.top >= self.bottom) && (bounds.top <= self.top)) || - ((self.top > bounds.bottom) && (self.top < bounds.top)) - ); - var inLeft = ( - ((bounds.left >= self.left) && (bounds.left <= self.right)) || - ((self.left >= bounds.left) && (self.left <= bounds.right)) - ); - var inRight = ( - ((bounds.right >= self.left) && (bounds.right <= self.right)) || - ((self.right >= bounds.left) && (self.right <= bounds.right)) - ); - intersects = ((inBottom || inTop) && (inLeft || inRight)); - } - // document me - if (options.worldBounds && !intersects) { - var world = options.worldBounds; - var width = world.getWidth(); - var selfCrosses = !world.containsBounds(self); - var boundsCrosses = !world.containsBounds(bounds); - if (selfCrosses && !boundsCrosses) { - bounds = bounds.add(-width, 0); - intersects = self.intersectsBounds(bounds, {inclusive: options.inclusive}); - } else if (boundsCrosses && !selfCrosses) { - self = self.add(-width, 0); - intersects = bounds.intersectsBounds(self, {inclusive: options.inclusive}); - } - } - return intersects; - }, - - /** - * APIMethod: containsBounds - * Returns whether the bounds object contains the given . - * - * bounds - {} The target bounds. - * partial - {Boolean} If any of the target corners is within this bounds - * consider the bounds contained. Default is false. If false, the - * entire target bounds must be contained within this bounds. - * inclusive - {Boolean} Treat shared edges as contained. Default is - * true. - * - * Returns: - * {Boolean} The passed-in bounds object is contained within this bounds. - */ - containsBounds:function(bounds, partial, inclusive) { - if (partial == null) { - partial = false; - } - if (inclusive == null) { - inclusive = true; - } - var bottomLeft = this.contains(bounds.left, bounds.bottom, inclusive); - var bottomRight = this.contains(bounds.right, bounds.bottom, inclusive); - var topLeft = this.contains(bounds.left, bounds.top, inclusive); - var topRight = this.contains(bounds.right, bounds.top, inclusive); - - return (partial) ? (bottomLeft || bottomRight || topLeft || topRight) - : (bottomLeft && bottomRight && topLeft && topRight); - }, - - /** - * APIMethod: determineQuadrant - * Returns the the quadrant ("br", "tr", "tl", "bl") in which the given - * lies. - * - * Parameters: - * lonlat - {} - * - * Returns: - * {String} The quadrant ("br" "tr" "tl" "bl") of the bounds in which the - * coordinate lies. - */ - determineQuadrant: function(lonlat) { - - var quadrant = ""; - var center = this.getCenterLonLat(); - - quadrant += (lonlat.lat < center.lat) ? "b" : "t"; - quadrant += (lonlat.lon < center.lon) ? "l" : "r"; - - return quadrant; - }, - - /** - * APIMethod: transform - * Transform the Bounds object from source to dest. - * - * Parameters: - * source - {} Source projection. - * dest - {} Destination projection. - * - * Returns: - * {} Itself, for use in chaining operations. - */ - transform: function(source, dest) { - // clear cached center location - this.centerLonLat = null; - var ll = OpenLayers.Projection.transform( - {'x': this.left, 'y': this.bottom}, source, dest); - var lr = OpenLayers.Projection.transform( - {'x': this.right, 'y': this.bottom}, source, dest); - var ul = OpenLayers.Projection.transform( - {'x': this.left, 'y': this.top}, source, dest); - var ur = OpenLayers.Projection.transform( - {'x': this.right, 'y': this.top}, source, dest); - this.left = Math.min(ll.x, ul.x); - this.bottom = Math.min(ll.y, lr.y); - this.right = Math.max(lr.x, ur.x); - this.top = Math.max(ul.y, ur.y); - return this; - }, - - /** - * APIMethod: wrapDateLine - * Wraps the bounds object around the dateline. - * - * Parameters: - * maxExtent - {} - * options - {Object} Some possible options are: - * - * Allowed Options: - * leftTolerance - {float} Allow for a margin of error - * with the 'left' value of this - * bound. - * Default is 0. - * rightTolerance - {float} Allow for a margin of error - * with the 'right' value of - * this bound. - * Default is 0. - * - * Returns: - * {} A copy of this bounds, but wrapped around the - * "dateline" (as specified by the borders of - * maxExtent). Note that this function only returns - * a different bounds value if this bounds is - * *entirely* outside of the maxExtent. If this - * bounds straddles the dateline (is part in/part - * out of maxExtent), the returned bounds will always - * cross the left edge of the given maxExtent. - *. - */ - wrapDateLine: function(maxExtent, options) { - options = options || {}; - - var leftTolerance = options.leftTolerance || 0; - var rightTolerance = options.rightTolerance || 0; - - var newBounds = this.clone(); - - if (maxExtent) { - var width = maxExtent.getWidth(); - - //shift right? - while (newBounds.left < maxExtent.left && - newBounds.right - rightTolerance <= maxExtent.left ) { - newBounds = newBounds.add(width, 0); - } - - //shift left? - while (newBounds.left + leftTolerance >= maxExtent.right && - newBounds.right > maxExtent.right ) { - newBounds = newBounds.add(-width, 0); - } - - // crosses right only? force left - var newLeft = newBounds.left + leftTolerance; - if (newLeft < maxExtent.right && newLeft > maxExtent.left && - newBounds.right - rightTolerance > maxExtent.right) { - newBounds = newBounds.add(-width, 0); - } - } - - return newBounds; - }, - - CLASS_NAME: "OpenLayers.Bounds" -}); - -/** - * APIFunction: fromString - * Alternative constructor that builds a new OpenLayers.Bounds from a - * parameter string. - * - * (begin code) - * OpenLayers.Bounds.fromString("5,42,10,45"); - * // => equivalent to ... - * new OpenLayers.Bounds(5, 42, 10, 45); - * (end) - * - * Parameters: - * str - {String} Comma-separated bounds string. (e.g. "5,42,10,45") - * reverseAxisOrder - {Boolean} Does the string use reverse axis order? - * - * Returns: - * {} New bounds object built from the - * passed-in String. - */ -OpenLayers.Bounds.fromString = function(str, reverseAxisOrder) { - var bounds = str.split(","); - return OpenLayers.Bounds.fromArray(bounds, reverseAxisOrder); -}; - -/** - * APIFunction: fromArray - * Alternative constructor that builds a new OpenLayers.Bounds from an array. - * - * (begin code) - * OpenLayers.Bounds.fromArray( [5, 42, 10, 45] ); - * // => equivalent to ... - * new OpenLayers.Bounds(5, 42, 10, 45); - * (end) - * - * Parameters: - * bbox - {Array(Float)} Array of bounds values (e.g. [5,42,10,45]) - * reverseAxisOrder - {Boolean} Does the array use reverse axis order? - * - * Returns: - * {} New bounds object built from the passed-in Array. - */ -OpenLayers.Bounds.fromArray = function(bbox, reverseAxisOrder) { - return reverseAxisOrder === true ? - new OpenLayers.Bounds(bbox[1], bbox[0], bbox[3], bbox[2]) : - new OpenLayers.Bounds(bbox[0], bbox[1], bbox[2], bbox[3]); -}; - -/** - * APIFunction: fromSize - * Alternative constructor that builds a new OpenLayers.Bounds from a size. - * - * (begin code) - * OpenLayers.Bounds.fromSize( new OpenLayers.Size(10, 20) ); - * // => equivalent to ... - * new OpenLayers.Bounds(0, 20, 10, 0); - * (end) - * - * Parameters: - * size - { or Object} or an object with - * both 'w' and 'h' properties. - * - * Returns: - * {} New bounds object built from the passed-in size. - */ -OpenLayers.Bounds.fromSize = function(size) { - return new OpenLayers.Bounds(0, - size.h, - size.w, - 0); -}; - -/** - * Function: oppositeQuadrant - * Get the opposite quadrant for a given quadrant string. - * - * (begin code) - * OpenLayers.Bounds.oppositeQuadrant( "tl" ); - * // => "br" - * - * OpenLayers.Bounds.oppositeQuadrant( "tr" ); - * // => "bl" - * (end) - * - * Parameters: - * quadrant - {String} two character quadrant shortstring - * - * Returns: - * {String} The opposing quadrant ("br" "tr" "tl" "bl"). For Example, if - * you pass in "bl" it returns "tr", if you pass in "br" it - * returns "tl", etc. - */ -OpenLayers.Bounds.oppositeQuadrant = function(quadrant) { - var opp = ""; - - opp += (quadrant.charAt(0) == 't') ? 'b' : 't'; - opp += (quadrant.charAt(1) == 'l') ? 'r' : 'l'; - - return opp; -}; -/* ====================================================================== - OpenLayers/BaseTypes/Element.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Util.js - * @requires OpenLayers/BaseTypes.js - */ - -/** - * Namespace: OpenLayers.Element - */ -OpenLayers.Element = { - - /** - * APIFunction: visible - * - * Parameters: - * element - {DOMElement} - * - * Returns: - * {Boolean} Is the element visible? - */ - visible: function(element) { - return OpenLayers.Util.getElement(element).style.display != 'none'; - }, - - /** - * APIFunction: toggle - * Toggle the visibility of element(s) passed in - * - * Parameters: - * element - {DOMElement} Actually user can pass any number of elements - */ - toggle: function() { - for (var i=0, len=arguments.length; i"lon=5,lat=42") - */ - toString:function() { - return ("lon=" + this.lon + ",lat=" + this.lat); - }, - - /** - * APIMethod: toShortString - * - * Returns: - * {String} Shortened String representation of OpenLayers.LonLat object. - * (e.g. "5, 42") - */ - toShortString:function() { - return (this.lon + ", " + this.lat); - }, - - /** - * APIMethod: clone - * - * Returns: - * {} New OpenLayers.LonLat object with the same lon - * and lat values - */ - clone:function() { - return new OpenLayers.LonLat(this.lon, this.lat); - }, - - /** - * APIMethod: add - * - * Parameters: - * lon - {Float} - * lat - {Float} - * - * Returns: - * {} A new OpenLayers.LonLat object with the lon and - * lat passed-in added to this's. - */ - add:function(lon, lat) { - if ( (lon == null) || (lat == null) ) { - throw new TypeError('LonLat.add cannot receive null values'); - } - return new OpenLayers.LonLat(this.lon + OpenLayers.Util.toFloat(lon), - this.lat + OpenLayers.Util.toFloat(lat)); - }, - - /** - * APIMethod: equals - * - * Parameters: - * ll - {} - * - * Returns: - * {Boolean} Boolean value indicating whether the passed-in - * object has the same lon and lat - * components as this. - * Note: if ll passed in is null, returns false - */ - equals:function(ll) { - var equals = false; - if (ll != null) { - equals = ((this.lon == ll.lon && this.lat == ll.lat) || - (isNaN(this.lon) && isNaN(this.lat) && isNaN(ll.lon) && isNaN(ll.lat))); - } - return equals; - }, - - /** - * APIMethod: transform - * Transform the LonLat object from source to dest. This transformation is - * *in place*: if you want a *new* lonlat, use .clone() first. - * - * Parameters: - * source - {} Source projection. - * dest - {} Destination projection. - * - * Returns: - * {} Itself, for use in chaining operations. - */ - transform: function(source, dest) { - var point = OpenLayers.Projection.transform( - {'x': this.lon, 'y': this.lat}, source, dest); - this.lon = point.x; - this.lat = point.y; - return this; - }, - - /** - * APIMethod: wrapDateLine - * - * Parameters: - * maxExtent - {} - * - * Returns: - * {} A copy of this lonlat, but wrapped around the - * "dateline" (as specified by the borders of - * maxExtent) - */ - wrapDateLine: function(maxExtent) { - - var newLonLat = this.clone(); - - if (maxExtent) { - //shift right? - while (newLonLat.lon < maxExtent.left) { - newLonLat.lon += maxExtent.getWidth(); - } - - //shift left? - while (newLonLat.lon > maxExtent.right) { - newLonLat.lon -= maxExtent.getWidth(); - } - } - - return newLonLat; - }, - - CLASS_NAME: "OpenLayers.LonLat" -}); - -/** - * Function: fromString - * Alternative constructor that builds a new from a - * parameter string - * - * Parameters: - * str - {String} Comma-separated Lon,Lat coordinate string. - * (e.g. "5,40") - * - * Returns: - * {} New object built from the - * passed-in String. - */ -OpenLayers.LonLat.fromString = function(str) { - var pair = str.split(","); - return new OpenLayers.LonLat(pair[0], pair[1]); -}; - -/** - * Function: fromArray - * Alternative constructor that builds a new from an - * array of two numbers that represent lon- and lat-values. - * - * Parameters: - * arr - {Array(Float)} Array of lon/lat values (e.g. [5,-42]) - * - * Returns: - * {} New object built from the - * passed-in array. - */ -OpenLayers.LonLat.fromArray = function(arr) { - var gotArr = OpenLayers.Util.isArray(arr), - lon = gotArr && arr[0], - lat = gotArr && arr[1]; - return new OpenLayers.LonLat(lon, lat); -}; -/* ====================================================================== - OpenLayers/BaseTypes/Pixel.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/BaseTypes/Class.js - */ - -/** - * Class: OpenLayers.Pixel - * This class represents a screen coordinate, in x and y coordinates - */ -OpenLayers.Pixel = OpenLayers.Class({ - - /** - * APIProperty: x - * {Number} The x coordinate - */ - x: 0.0, - - /** - * APIProperty: y - * {Number} The y coordinate - */ - y: 0.0, - - /** - * Constructor: OpenLayers.Pixel - * Create a new OpenLayers.Pixel instance - * - * Parameters: - * x - {Number} The x coordinate - * y - {Number} The y coordinate - * - * Returns: - * An instance of OpenLayers.Pixel - */ - initialize: function(x, y) { - this.x = parseFloat(x); - this.y = parseFloat(y); - }, - - /** - * Method: toString - * Cast this object into a string - * - * Returns: - * {String} The string representation of Pixel. ex: "x=200.4,y=242.2" - */ - toString:function() { - return ("x=" + this.x + ",y=" + this.y); - }, - - /** - * APIMethod: clone - * Return a clone of this pixel object - * - * Returns: - * {} A clone pixel - */ - clone:function() { - return new OpenLayers.Pixel(this.x, this.y); - }, - - /** - * APIMethod: equals - * Determine whether one pixel is equivalent to another - * - * Parameters: - * px - {|Object} An OpenLayers.Pixel or an object with - * a 'x' and 'y' properties. - * - * Returns: - * {Boolean} The point passed in as parameter is equal to this. Note that - * if px passed in is null, returns false. - */ - equals:function(px) { - var equals = false; - if (px != null) { - equals = ((this.x == px.x && this.y == px.y) || - (isNaN(this.x) && isNaN(this.y) && isNaN(px.x) && isNaN(px.y))); - } - return equals; - }, - - /** - * APIMethod: distanceTo - * Returns the distance to the pixel point passed in as a parameter. - * - * Parameters: - * px - {} - * - * Returns: - * {Float} The pixel point passed in as parameter to calculate the - * distance to. - */ - distanceTo:function(px) { - return Math.sqrt( - Math.pow(this.x - px.x, 2) + - Math.pow(this.y - px.y, 2) - ); - }, - - /** - * APIMethod: add - * - * Parameters: - * x - {Integer} - * y - {Integer} - * - * Returns: - * {} A new Pixel with this pixel's x&y augmented by the - * values passed in. - */ - add:function(x, y) { - if ( (x == null) || (y == null) ) { - throw new TypeError('Pixel.add cannot receive null values'); - } - return new OpenLayers.Pixel(this.x + x, this.y + y); - }, - - /** - * APIMethod: offset - * - * Parameters - * px - {|Object} An OpenLayers.Pixel or an object with - * a 'x' and 'y' properties. - * - * Returns: - * {} A new Pixel with this pixel's x&y augmented by the - * x&y values of the pixel passed in. - */ - offset:function(px) { - var newPx = this.clone(); - if (px) { - newPx = this.add(px.x, px.y); - } - return newPx; - }, - - CLASS_NAME: "OpenLayers.Pixel" -}); -/* ====================================================================== - OpenLayers/BaseTypes/Size.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/BaseTypes/Class.js - */ - -/** - * Class: OpenLayers.Size - * Instances of this class represent a width/height pair - */ -OpenLayers.Size = OpenLayers.Class({ - - /** - * APIProperty: w - * {Number} width - */ - w: 0.0, - - /** - * APIProperty: h - * {Number} height - */ - h: 0.0, - - - /** - * Constructor: OpenLayers.Size - * Create an instance of OpenLayers.Size - * - * Parameters: - * w - {Number} width - * h - {Number} height - */ - initialize: function(w, h) { - this.w = parseFloat(w); - this.h = parseFloat(h); - }, - - /** - * Method: toString - * Return the string representation of a size object - * - * Returns: - * {String} The string representation of OpenLayers.Size object. - * (e.g. "w=55,h=66") - */ - toString:function() { - return ("w=" + this.w + ",h=" + this.h); - }, - - /** - * APIMethod: clone - * Create a clone of this size object - * - * Returns: - * {} A new OpenLayers.Size object with the same w and h - * values - */ - clone:function() { - return new OpenLayers.Size(this.w, this.h); - }, - - /** - * - * APIMethod: equals - * Determine where this size is equal to another - * - * Parameters: - * sz - {|Object} An OpenLayers.Size or an object with - * a 'w' and 'h' properties. - * - * Returns: - * {Boolean} The passed in size has the same h and w properties as this one. - * Note that if sz passed in is null, returns false. - */ - equals:function(sz) { - var equals = false; - if (sz != null) { - equals = ((this.w == sz.w && this.h == sz.h) || - (isNaN(this.w) && isNaN(this.h) && isNaN(sz.w) && isNaN(sz.h))); - } - return equals; - }, - - CLASS_NAME: "OpenLayers.Size" -}); -/* ====================================================================== - OpenLayers/Console.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/BaseTypes/Class.js - */ - -/** - * Namespace: OpenLayers.Console - * The OpenLayers.Console namespace is used for debugging and error logging. - * If the Firebug Lite (../Firebug/firebug.js) is included before this script, - * calls to OpenLayers.Console methods will get redirected to window.console. - * This makes use of the Firebug extension where available and allows for - * cross-browser debugging Firebug style. - * - * Note: - * Note that behavior will differ with the Firebug extention and Firebug Lite. - * Most notably, the Firebug Lite console does not currently allow for - * hyperlinks to code or for clicking on object to explore their properties. - * - */ -OpenLayers.Console = { - /** - * Create empty functions for all console methods. The real value of these - * properties will be set if Firebug Lite (../Firebug/firebug.js script) is - * included. We explicitly require the Firebug Lite script to trigger - * functionality of the OpenLayers.Console methods. - */ - - /** - * APIFunction: log - * Log an object in the console. The Firebug Lite console logs string - * representation of objects. Given multiple arguments, they will - * be cast to strings and logged with a space delimiter. If the first - * argument is a string with printf-like formatting, subsequent arguments - * will be used in string substitution. Any additional arguments (beyond - * the number substituted in a format string) will be appended in a space- - * delimited line. - * - * Parameters: - * object - {Object} - */ - log: function() {}, - - /** - * APIFunction: debug - * Writes a message to the console, including a hyperlink to the line - * where it was called. - * - * May be called with multiple arguments as with OpenLayers.Console.log(). - * - * Parameters: - * object - {Object} - */ - debug: function() {}, - - /** - * APIFunction: info - * Writes a message to the console with the visual "info" icon and color - * coding and a hyperlink to the line where it was called. - * - * May be called with multiple arguments as with OpenLayers.Console.log(). - * - * Parameters: - * object - {Object} - */ - info: function() {}, - - /** - * APIFunction: warn - * Writes a message to the console with the visual "warning" icon and - * color coding and a hyperlink to the line where it was called. - * - * May be called with multiple arguments as with OpenLayers.Console.log(). - * - * Parameters: - * object - {Object} - */ - warn: function() {}, - - /** - * APIFunction: error - * Writes a message to the console with the visual "error" icon and color - * coding and a hyperlink to the line where it was called. - * - * May be called with multiple arguments as with OpenLayers.Console.log(). - * - * Parameters: - * object - {Object} - */ - error: function() {}, - - /** - * APIFunction: userError - * A single interface for showing error messages to the user. The default - * behavior is a Javascript alert, though this can be overridden by - * reassigning OpenLayers.Console.userError to a different function. - * - * Expects a single error message - * - * Parameters: - * error - {Object} - */ - userError: function(error) { - alert(error); - }, - - /** - * APIFunction: assert - * Tests that an expression is true. If not, it will write a message to - * the console and throw an exception. - * - * May be called with multiple arguments as with OpenLayers.Console.log(). - * - * Parameters: - * object - {Object} - */ - assert: function() {}, - - /** - * APIFunction: dir - * Prints an interactive listing of all properties of the object. This - * looks identical to the view that you would see in the DOM tab. - * - * Parameters: - * object - {Object} - */ - dir: function() {}, - - /** - * APIFunction: dirxml - * Prints the XML source tree of an HTML or XML element. This looks - * identical to the view that you would see in the HTML tab. You can click - * on any node to inspect it in the HTML tab. - * - * Parameters: - * object - {Object} - */ - dirxml: function() {}, - - /** - * APIFunction: trace - * Prints an interactive stack trace of JavaScript execution at the point - * where it is called. The stack trace details the functions on the stack, - * as well as the values that were passed as arguments to each function. - * You can click each function to take you to its source in the Script tab, - * and click each argument value to inspect it in the DOM or HTML tabs. - * - */ - trace: function() {}, - - /** - * APIFunction: group - * Writes a message to the console and opens a nested block to indent all - * future messages sent to the console. Call OpenLayers.Console.groupEnd() - * to close the block. - * - * May be called with multiple arguments as with OpenLayers.Console.log(). - * - * Parameters: - * object - {Object} - */ - group: function() {}, - - /** - * APIFunction: groupEnd - * Closes the most recently opened block created by a call to - * OpenLayers.Console.group - */ - groupEnd: function() {}, - - /** - * APIFunction: time - * Creates a new timer under the given name. Call - * OpenLayers.Console.timeEnd(name) - * with the same name to stop the timer and print the time elapsed. - * - * Parameters: - * name - {String} - */ - time: function() {}, - - /** - * APIFunction: timeEnd - * Stops a timer created by a call to OpenLayers.Console.time(name) and - * writes the time elapsed. - * - * Parameters: - * name - {String} - */ - timeEnd: function() {}, - - /** - * APIFunction: profile - * Turns on the JavaScript profiler. The optional argument title would - * contain the text to be printed in the header of the profile report. - * - * This function is not currently implemented in Firebug Lite. - * - * Parameters: - * title - {String} Optional title for the profiler - */ - profile: function() {}, - - /** - * APIFunction: profileEnd - * Turns off the JavaScript profiler and prints its report. - * - * This function is not currently implemented in Firebug Lite. - */ - profileEnd: function() {}, - - /** - * APIFunction: count - * Writes the number of times that the line of code where count was called - * was executed. The optional argument title will print a message in - * addition to the number of the count. - * - * This function is not currently implemented in Firebug Lite. - * - * Parameters: - * title - {String} Optional title to be printed with count - */ - count: function() {}, - - CLASS_NAME: "OpenLayers.Console" -}; - -/** - * Execute an anonymous function to extend the OpenLayers.Console namespace - * if the firebug.js script is included. This closure is used so that the - * "scripts" and "i" variables don't pollute the global namespace. - */ -(function() { - /** - * If Firebug Lite is included (before this script), re-route all - * OpenLayers.Console calls to the console object. - */ - var scripts = document.getElementsByTagName("script"); - for(var i=0, len=scripts.length; i method to set this value and the method to - * retrieve it. - */ - code: null, - - /** - * APIProperty: defaultCode - * {String} Default language to use when a specific language can't be - * found. Default is "en". - */ - defaultCode: "en", - - /** - * APIFunction: getCode - * Get the current language code. - * - * Returns: - * {String} The current language code. - */ - getCode: function() { - if(!OpenLayers.Lang.code) { - OpenLayers.Lang.setCode(); - } - return OpenLayers.Lang.code; - }, - - /** - * APIFunction: setCode - * Set the language code for string translation. This code is used by - * the method. - * - * Parameters: - * code - {String} These codes follow the IETF recommendations at - * http://www.ietf.org/rfc/rfc3066.txt. If no value is set, the - * browser's language setting will be tested. If no - * dictionary exists for the code, the - * will be used. - */ - setCode: function(code) { - var lang; - if(!code) { - code = (OpenLayers.BROWSER_NAME == "msie") ? - navigator.userLanguage : navigator.language; - } - var parts = code.split('-'); - parts[0] = parts[0].toLowerCase(); - if(typeof OpenLayers.Lang[parts[0]] == "object") { - lang = parts[0]; - } - - // check for regional extensions - if(parts[1]) { - var testLang = parts[0] + '-' + parts[1].toUpperCase(); - if(typeof OpenLayers.Lang[testLang] == "object") { - lang = testLang; - } - } - if(!lang) { - OpenLayers.Console.warn( - 'Failed to find OpenLayers.Lang.' + parts.join("-") + - ' dictionary, falling back to default language' - ); - lang = OpenLayers.Lang.defaultCode; - } - - OpenLayers.Lang.code = lang; - }, - - /** - * APIMethod: translate - * Looks up a key from a dictionary based on the current language string. - * The value of will be used to determine the appropriate - * dictionary. Dictionaries are stored in . - * - * Parameters: - * key - {String} The key for an i18n string value in the dictionary. - * context - {Object} Optional context to be used with - * . - * - * Returns: - * {String} A internationalized string. - */ - translate: function(key, context) { - var dictionary = OpenLayers.Lang[OpenLayers.Lang.getCode()]; - var message = dictionary && dictionary[key]; - if(!message) { - // Message not found, fall back to message key - message = key; - } - if(context) { - message = OpenLayers.String.format(message, context); - } - return message; - } - -}; - - -/** - * APIMethod: OpenLayers.i18n - * Alias for . Looks up a key from a dictionary - * based on the current language string. The value of - * will be used to determine the appropriate - * dictionary. Dictionaries are stored in . - * - * Parameters: - * key - {String} The key for an i18n string value in the dictionary. - * context - {Object} Optional context to be used with - * . - * - * Returns: - * {String} A internationalized string. - */ -OpenLayers.i18n = OpenLayers.Lang.translate; -/* ====================================================================== - OpenLayers/Util.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/BaseTypes.js - * @requires OpenLayers/BaseTypes/Bounds.js - * @requires OpenLayers/BaseTypes/Element.js - * @requires OpenLayers/BaseTypes/LonLat.js - * @requires OpenLayers/BaseTypes/Pixel.js - * @requires OpenLayers/BaseTypes/Size.js - * @requires OpenLayers/Lang.js - */ - -/** - * Namespace: Util - */ -OpenLayers.Util = OpenLayers.Util || {}; - -/** - * Function: getElement - * This is the old $() from prototype - * - * Parameters: - * e - {String or DOMElement or Window} - * - * Returns: - * {Array(DOMElement) or DOMElement} - */ -OpenLayers.Util.getElement = function() { - var elements = []; - - for (var i=0, len=arguments.length; i= 0; i--) { - if(array[i] == item) { - array.splice(i,1); - //break;more than once?? - } - } - return array; -}; - -/** - * Function: indexOf - * Seems to exist already in FF, but not in MOZ. - * - * Parameters: - * array - {Array} - * obj - {*} - * - * Returns: - * {Integer} The index at which the first object was found in the array. - * If not found, returns -1. - */ -OpenLayers.Util.indexOf = function(array, obj) { - // use the build-in function if available. - if (typeof array.indexOf == "function") { - return array.indexOf(obj); - } else { - for (var i = 0, len = array.length; i < len; i++) { - if (array[i] == obj) { - return i; - } - } - return -1; - } -}; - - -/** - * Property: dotless - * {RegExp} - * Compiled regular expression to match dots ("."). This is used for replacing - * dots in identifiers. Because object identifiers are frequently used for - * DOM element identifiers by the library, we avoid using dots to make for - * more sensible CSS selectors. - * - * TODO: Use a module pattern to avoid bloating the API with stuff like this. - */ -OpenLayers.Util.dotless = /\./g; - -/** - * Function: modifyDOMElement - * - * Modifies many properties of a DOM element all at once. Passing in - * null to an individual parameter will avoid setting the attribute. - * - * Parameters: - * element - {DOMElement} DOM element to modify. - * id - {String} The element id attribute to set. Note that dots (".") will be - * replaced with underscore ("_") in setting the element id. - * px - {|Object} The element left and top position, - * OpenLayers.Pixel or an object with - * a 'x' and 'y' properties. - * sz - {|Object} The element width and height, - * OpenLayers.Size or an object with a - * 'w' and 'h' properties. - * position - {String} The position attribute. eg: absolute, - * relative, etc. - * border - {String} The style.border attribute. eg: - * solid black 2px - * overflow - {String} The style.overview attribute. - * opacity - {Float} Fractional value (0.0 - 1.0) - */ -OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position, - border, overflow, opacity) { - - if (id) { - element.id = id.replace(OpenLayers.Util.dotless, "_"); - } - if (px) { - element.style.left = px.x + "px"; - element.style.top = px.y + "px"; - } - if (sz) { - element.style.width = sz.w + "px"; - element.style.height = sz.h + "px"; - } - if (position) { - element.style.position = position; - } - if (border) { - element.style.border = border; - } - if (overflow) { - element.style.overflow = overflow; - } - if (parseFloat(opacity) >= 0.0 && parseFloat(opacity) < 1.0) { - element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')'; - element.style.opacity = opacity; - } else if (parseFloat(opacity) == 1.0) { - element.style.filter = ''; - element.style.opacity = ''; - } -}; - -/** - * Function: createDiv - * Creates a new div and optionally set some standard attributes. - * Null may be passed to each parameter if you do not wish to - * set a particular attribute. - * Note - zIndex is NOT set on the resulting div. - * - * Parameters: - * id - {String} An identifier for this element. If no id is - * passed an identifier will be created - * automatically. Note that dots (".") will be replaced with - * underscore ("_") when generating ids. - * px - {|Object} The element left and top position, - * OpenLayers.Pixel or an object with - * a 'x' and 'y' properties. - * sz - {|Object} The element width and height, - * OpenLayers.Size or an object with a - * 'w' and 'h' properties. - * imgURL - {String} A url pointing to an image to use as a - * background image. - * position - {String} The style.position value. eg: absolute, - * relative etc. - * border - {String} The the style.border value. - * eg: 2px solid black - * overflow - {String} The style.overflow value. Eg. hidden - * opacity - {Float} Fractional value (0.0 - 1.0) - * - * Returns: - * {DOMElement} A DOM Div created with the specified attributes. - */ -OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position, - border, overflow, opacity) { - - var dom = document.createElement('div'); - - if (imgURL) { - dom.style.backgroundImage = 'url(' + imgURL + ')'; - } - - //set generic properties - if (!id) { - id = OpenLayers.Util.createUniqueID("OpenLayersDiv"); - } - if (!position) { - position = "absolute"; - } - OpenLayers.Util.modifyDOMElement(dom, id, px, sz, position, - border, overflow, opacity); - - return dom; -}; - -/** - * Function: createImage - * Creates an img element with specific attribute values. - * - * Parameters: - * id - {String} The id field for the img. If none assigned one will be - * automatically generated. - * px - {|Object} The element left and top position, - * OpenLayers.Pixel or an object with - * a 'x' and 'y' properties. - * sz - {|Object} The element width and height, - * OpenLayers.Size or an object with a - * 'w' and 'h' properties. - * imgURL - {String} The url to use as the image source. - * position - {String} The style.position value. - * border - {String} The border to place around the image. - * opacity - {Float} Fractional value (0.0 - 1.0) - * delayDisplay - {Boolean} If true waits until the image has been - * loaded. - * - * Returns: - * {DOMElement} A DOM Image created with the specified attributes. - */ -OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border, - opacity, delayDisplay) { - - var image = document.createElement("img"); - - //set generic properties - if (!id) { - id = OpenLayers.Util.createUniqueID("OpenLayersDiv"); - } - if (!position) { - position = "relative"; - } - OpenLayers.Util.modifyDOMElement(image, id, px, sz, position, - border, null, opacity); - - if (delayDisplay) { - image.style.display = "none"; - function display() { - image.style.display = ""; - OpenLayers.Event.stopObservingElement(image); - } - OpenLayers.Event.observe(image, "load", display); - OpenLayers.Event.observe(image, "error", display); - } - - //set special properties - image.style.alt = id; - image.galleryImg = "no"; - if (imgURL) { - image.src = imgURL; - } - - return image; -}; - -/** - * Property: IMAGE_RELOAD_ATTEMPTS - * {Integer} How many times should we try to reload an image before giving up? - * Default is 0 - */ -OpenLayers.IMAGE_RELOAD_ATTEMPTS = 0; - -/** - * Property: alphaHackNeeded - * {Boolean} true if the png alpha hack is necessary and possible, false otherwise. - */ -OpenLayers.Util.alphaHackNeeded = null; - -/** - * Function: alphaHack - * Checks whether it's necessary (and possible) to use the png alpha - * hack which allows alpha transparency for png images under Internet - * Explorer. - * - * Returns: - * {Boolean} true if the png alpha hack is necessary and possible, false otherwise. - */ -OpenLayers.Util.alphaHack = function() { - if (OpenLayers.Util.alphaHackNeeded == null) { - var arVersion = navigator.appVersion.split("MSIE"); - var version = parseFloat(arVersion[1]); - var filter = false; - - // IEs4Lin dies when trying to access document.body.filters, because - // the property is there, but requires a DLL that can't be provided. This - // means that we need to wrap this in a try/catch so that this can - // continue. - - try { - filter = !!(document.body.filters); - } catch (e) {} - - OpenLayers.Util.alphaHackNeeded = (filter && - (version >= 5.5) && (version < 7)); - } - return OpenLayers.Util.alphaHackNeeded; -}; - -/** - * Function: modifyAlphaImageDiv - * - * Parameters: - * div - {DOMElement} Div containing Alpha-adjusted Image - * id - {String} - * px - {|Object} OpenLayers.Pixel or an object with - * a 'x' and 'y' properties. - * sz - {|Object} OpenLayers.Size or an object with - * a 'w' and 'h' properties. - * imgURL - {String} - * position - {String} - * border - {String} - * sizing - {String} 'crop', 'scale', or 'image'. Default is "scale" - * opacity - {Float} Fractional value (0.0 - 1.0) - */ -OpenLayers.Util.modifyAlphaImageDiv = function(div, id, px, sz, imgURL, - position, border, sizing, - opacity) { - - OpenLayers.Util.modifyDOMElement(div, id, px, sz, position, - null, null, opacity); - - var img = div.childNodes[0]; - - if (imgURL) { - img.src = imgURL; - } - OpenLayers.Util.modifyDOMElement(img, div.id + "_innerImage", null, sz, - "relative", border); - - if (OpenLayers.Util.alphaHack()) { - if(div.style.display != "none") { - div.style.display = "inline-block"; - } - if (sizing == null) { - sizing = "scale"; - } - - div.style.filter = "progid:DXImageTransform.Microsoft" + - ".AlphaImageLoader(src='" + img.src + "', " + - "sizingMethod='" + sizing + "')"; - if (parseFloat(div.style.opacity) >= 0.0 && - parseFloat(div.style.opacity) < 1.0) { - div.style.filter += " alpha(opacity=" + div.style.opacity * 100 + ")"; - } - - img.style.filter = "alpha(opacity=0)"; - } -}; - -/** - * Function: createAlphaImageDiv - * - * Parameters: - * id - {String} - * px - {|Object} OpenLayers.Pixel or an object with - * a 'x' and 'y' properties. - * sz - {|Object} OpenLayers.Size or an object with - * a 'w' and 'h' properties. - * imgURL - {String} - * position - {String} - * border - {String} - * sizing - {String} 'crop', 'scale', or 'image'. Default is "scale" - * opacity - {Float} Fractional value (0.0 - 1.0) - * delayDisplay - {Boolean} If true waits until the image has been - * loaded. - * - * Returns: - * {DOMElement} A DOM Div created with a DOM Image inside it. If the hack is - * needed for transparency in IE, it is added. - */ -OpenLayers.Util.createAlphaImageDiv = function(id, px, sz, imgURL, - position, border, sizing, - opacity, delayDisplay) { - - var div = OpenLayers.Util.createDiv(); - var img = OpenLayers.Util.createImage(null, null, null, null, null, null, - null, delayDisplay); - img.className = "olAlphaImg"; - div.appendChild(img); - - OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL, position, - border, sizing, opacity); - - return div; -}; - - -/** - * Function: upperCaseObject - * Creates a new hashtable and copies over all the keys from the - * passed-in object, but storing them under an uppercased - * version of the key at which they were stored. - * - * Parameters: - * object - {Object} - * - * Returns: - * {Object} A new Object with all the same keys but uppercased - */ -OpenLayers.Util.upperCaseObject = function (object) { - var uObject = {}; - for (var key in object) { - uObject[key.toUpperCase()] = object[key]; - } - return uObject; -}; - -/** - * Function: applyDefaults - * Takes an object and copies any properties that don't exist from - * another properties, by analogy with OpenLayers.Util.extend() from - * Prototype.js. - * - * Parameters: - * to - {Object} The destination object. - * from - {Object} The source object. Any properties of this object that - * are undefined in the to object will be set on the to object. - * - * Returns: - * {Object} A reference to the to object. Note that the to argument is modified - * in place and returned by this function. - */ -OpenLayers.Util.applyDefaults = function (to, from) { - to = to || {}; - /* - * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative - * prototype object" when calling hawOwnProperty if the source object is an - * instance of window.Event. - */ - var fromIsEvt = typeof window.Event == "function" - && from instanceof window.Event; - - for (var key in from) { - if (to[key] === undefined || - (!fromIsEvt && from.hasOwnProperty - && from.hasOwnProperty(key) && !to.hasOwnProperty(key))) { - to[key] = from[key]; - } - } - /** - * IE doesn't include the toString property when iterating over an object's - * properties with the for(property in object) syntax. Explicitly check if - * the source has its own toString property. - */ - if(!fromIsEvt && from && from.hasOwnProperty - && from.hasOwnProperty('toString') && !to.hasOwnProperty('toString')) { - to.toString = from.toString; - } - - return to; -}; - -/** - * Function: getParameterString - * - * Parameters: - * params - {Object} - * - * Returns: - * {String} A concatenation of the properties of an object in - * http parameter notation. - * (ex. "key1=value1&key2=value2&key3=value3") - * If a parameter is actually a list, that parameter will then - * be set to a comma-seperated list of values (foo,bar) instead - * of being URL escaped (foo%3Abar). - */ -OpenLayers.Util.getParameterString = function(params) { - var paramsArray = []; - - for (var key in params) { - var value = params[key]; - if ((value != null) && (typeof value != 'function')) { - var encodedValue; - if (typeof value == 'object' && value.constructor == Array) { - /* value is an array; encode items and separate with "," */ - var encodedItemArray = []; - var item; - for (var itemIndex=0, len=value.length; itemIndex} (or any object with both .lat, .lon properties) - * p2 - {} (or any object with both .lat, .lon properties) - * - * Returns: - * {Float} The distance (in km) between the two input points as measured on an - * ellipsoid. Note that the input point objects must be in geographic - * coordinates (decimal degrees) and the return distance is in kilometers. - */ -OpenLayers.Util.distVincenty = function(p1, p2) { - var ct = OpenLayers.Util.VincentyConstants; - var a = ct.a, b = ct.b, f = ct.f; - - var L = OpenLayers.Util.rad(p2.lon - p1.lon); - var U1 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p1.lat))); - var U2 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p2.lat))); - var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1); - var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2); - var lambda = L, lambdaP = 2*Math.PI; - var iterLimit = 20; - while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0) { - var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda); - var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) + - (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda)); - if (sinSigma==0) { - return 0; // co-incident points - } - var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda; - var sigma = Math.atan2(sinSigma, cosSigma); - var alpha = Math.asin(cosU1 * cosU2 * sinLambda / sinSigma); - var cosSqAlpha = Math.cos(alpha) * Math.cos(alpha); - var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha; - var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha)); - lambdaP = lambda; - lambda = L + (1-C) * f * Math.sin(alpha) * - (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM))); - } - if (iterLimit==0) { - return NaN; // formula failed to converge - } - var uSq = cosSqAlpha * (a*a - b*b) / (b*b); - var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq))); - var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq))); - var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)- - B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM))); - var s = b*A*(sigma-deltaSigma); - var d = s.toFixed(3)/1000; // round to 1mm precision - return d; -}; - -/** - * APIFunction: destinationVincenty - * Calculate destination point given start point lat/long (numeric degrees), - * bearing (numeric degrees) & distance (in m). - * Adapted from Chris Veness work, see - * http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html - * - * Parameters: - * lonlat - {} (or any object with both .lat, .lon - * properties) The start point. - * brng - {Float} The bearing (degrees). - * dist - {Float} The ground distance (meters). - * - * Returns: - * {} The destination point. - */ -OpenLayers.Util.destinationVincenty = function(lonlat, brng, dist) { - var u = OpenLayers.Util; - var ct = u.VincentyConstants; - var a = ct.a, b = ct.b, f = ct.f; - - var lon1 = lonlat.lon; - var lat1 = lonlat.lat; - - var s = dist; - var alpha1 = u.rad(brng); - var sinAlpha1 = Math.sin(alpha1); - var cosAlpha1 = Math.cos(alpha1); - - var tanU1 = (1-f) * Math.tan(u.rad(lat1)); - var cosU1 = 1 / Math.sqrt((1 + tanU1*tanU1)), sinU1 = tanU1*cosU1; - var sigma1 = Math.atan2(tanU1, cosAlpha1); - var sinAlpha = cosU1 * sinAlpha1; - var cosSqAlpha = 1 - sinAlpha*sinAlpha; - var uSq = cosSqAlpha * (a*a - b*b) / (b*b); - var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq))); - var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq))); - - var sigma = s / (b*A), sigmaP = 2*Math.PI; - while (Math.abs(sigma-sigmaP) > 1e-12) { - var cos2SigmaM = Math.cos(2*sigma1 + sigma); - var sinSigma = Math.sin(sigma); - var cosSigma = Math.cos(sigma); - var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)- - B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM))); - sigmaP = sigma; - sigma = s / (b*A) + deltaSigma; - } - - var tmp = sinU1*sinSigma - cosU1*cosSigma*cosAlpha1; - var lat2 = Math.atan2(sinU1*cosSigma + cosU1*sinSigma*cosAlpha1, - (1-f)*Math.sqrt(sinAlpha*sinAlpha + tmp*tmp)); - var lambda = Math.atan2(sinSigma*sinAlpha1, cosU1*cosSigma - sinU1*sinSigma*cosAlpha1); - var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha)); - var L = lambda - (1-C) * f * sinAlpha * - (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM))); - - var revAz = Math.atan2(sinAlpha, -tmp); // final bearing - - return new OpenLayers.LonLat(lon1+u.deg(L), u.deg(lat2)); -}; - -/** - * Function: getParameters - * Parse the parameters from a URL or from the current page itself into a - * JavaScript Object. Note that parameter values with commas are separated - * out into an Array. - * - * Parameters: - * url - {String} Optional url used to extract the query string. - * If url is null or is not supplied, query string is taken - * from the page location. - * - * 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 === null || url === undefined) ? window.location.href : url; - - //parse out parameters portion of url string - var paramsString = ""; - if (OpenLayers.String.contains(url, '?')) { - var start = url.indexOf('?') + 1; - var end = OpenLayers.String.contains(url, "#") ? - url.indexOf('#') : url.length; - paramsString = url.substring(start, end); - } - - var parameters = {}; - var pairs = paramsString.split(/[&;]/); - for(var i=0, len=pairs.length; i 1.0) ? (1.0 / scale) - : scale; - return normScale; -}; - -/** - * Function: getResolutionFromScale - * - * Parameters: - * scale - {Float} - * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable. - * Default is degrees - * - * Returns: - * {Float} The corresponding resolution given passed-in scale and unit - * parameters. If the given scale is falsey, the returned resolution will - * be undefined. - */ -OpenLayers.Util.getResolutionFromScale = function (scale, units) { - var resolution; - if (scale) { - if (units == null) { - units = "degrees"; - } - var normScale = OpenLayers.Util.normalizeScale(scale); - resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units] - * OpenLayers.DOTS_PER_INCH); - } - return resolution; -}; - -/** - * Function: getScaleFromResolution - * - * Parameters: - * resolution - {Float} - * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable. - * Default is degrees - * - * Returns: - * {Float} The corresponding scale given passed-in resolution and unit - * parameters. - */ -OpenLayers.Util.getScaleFromResolution = function (resolution, units) { - - if (units == null) { - units = "degrees"; - } - - var scale = resolution * OpenLayers.INCHES_PER_UNIT[units] * - OpenLayers.DOTS_PER_INCH; - return scale; -}; - -/** - * Function: pagePosition - * Calculates the position of an element on the page (see - * http://code.google.com/p/doctype/wiki/ArticlePageOffset) - * - * OpenLayers.Util.pagePosition is based on Yahoo's getXY method, which is - * Copyright (c) 2006, Yahoo! Inc. - * All rights reserved. - * - * Redistribution and use of this software in source and binary forms, with or - * without modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of Yahoo! Inc. nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission of Yahoo! Inc. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * Parameters: - * forElement - {DOMElement} - * - * Returns: - * {Array} two item array, Left value then Top value. - */ -OpenLayers.Util.pagePosition = function(forElement) { - // NOTE: If element is hidden (display none or disconnected or any the - // ancestors are hidden) we get (0,0) by default but we still do the - // accumulation of scroll position. - - var pos = [0, 0]; - var viewportElement = OpenLayers.Util.getViewportElement(); - if (!forElement || forElement == window || forElement == viewportElement) { - // viewport is always at 0,0 as that defined the coordinate system for - // this function - this avoids special case checks in the code below - return pos; - } - - // Gecko browsers normally use getBoxObjectFor to calculate the position. - // When invoked for an element with an implicit absolute position though it - // can be off by one. Therefore the recursive implementation is used in - // those (relatively rare) cases. - var BUGGY_GECKO_BOX_OBJECT = - OpenLayers.IS_GECKO && document.getBoxObjectFor && - OpenLayers.Element.getStyle(forElement, 'position') == 'absolute' && - (forElement.style.top == '' || forElement.style.left == ''); - - var parent = null; - var box; - - if (forElement.getBoundingClientRect) { // IE - box = forElement.getBoundingClientRect(); - var scrollTop = viewportElement.scrollTop; - var scrollLeft = viewportElement.scrollLeft; - - pos[0] = box.left + scrollLeft; - pos[1] = box.top + scrollTop; - - } else if (document.getBoxObjectFor && !BUGGY_GECKO_BOX_OBJECT) { // gecko - // Gecko ignores the scroll values for ancestors, up to 1.9. See: - // https://bugzilla.mozilla.org/show_bug.cgi?id=328881 and - // https://bugzilla.mozilla.org/show_bug.cgi?id=330619 - - box = document.getBoxObjectFor(forElement); - var vpBox = document.getBoxObjectFor(viewportElement); - pos[0] = box.screenX - vpBox.screenX; - pos[1] = box.screenY - vpBox.screenY; - - } else { // safari/opera - pos[0] = forElement.offsetLeft; - pos[1] = forElement.offsetTop; - parent = forElement.offsetParent; - if (parent != forElement) { - while (parent) { - pos[0] += parent.offsetLeft; - pos[1] += parent.offsetTop; - parent = parent.offsetParent; - } - } - - var browser = OpenLayers.BROWSER_NAME; - - // opera & (safari absolute) incorrectly account for body offsetTop - if (browser == "opera" || (browser == "safari" && - OpenLayers.Element.getStyle(forElement, 'position') == 'absolute')) { - pos[1] -= document.body.offsetTop; - } - - // accumulate the scroll positions for everything but the body element - parent = forElement.offsetParent; - while (parent && parent != document.body) { - pos[0] -= parent.scrollLeft; - // see https://bugs.opera.com/show_bug.cgi?id=249965 - if (browser != "opera" || parent.tagName != 'TR') { - pos[1] -= parent.scrollTop; - } - parent = parent.offsetParent; - } - } - - return pos; -}; - -/** - * Function: getViewportElement - * Returns die viewport element of the document. The viewport element is - * usually document.documentElement, except in IE,where it is either - * document.body or document.documentElement, depending on the document's - * compatibility mode (see - * http://code.google.com/p/doctype/wiki/ArticleClientViewportElement) - * - * Returns: - * {DOMElement} - */ -OpenLayers.Util.getViewportElement = function() { - var viewportElement = arguments.callee.viewportElement; - if (viewportElement == undefined) { - viewportElement = (OpenLayers.BROWSER_NAME == "msie" && - document.compatMode != 'CSS1Compat') ? document.body : - document.documentElement; - arguments.callee.viewportElement = viewportElement; - } - return viewportElement; -}; - -/** - * Function: isEquivalentUrl - * Test two URLs for equivalence. - * - * Setting 'ignoreCase' allows for case-independent comparison. - * - * Comparison is based on: - * - Protocol - * - Host (evaluated without the port) - * - Port (set 'ignorePort80' to ignore "80" values) - * - Hash ( set 'ignoreHash' to disable) - * - Pathname (for relative <-> absolute comparison) - * - Arguments (so they can be out of order) - * - * Parameters: - * url1 - {String} - * url2 - {String} - * options - {Object} Allows for customization of comparison: - * 'ignoreCase' - Default is True - * 'ignorePort80' - Default is True - * 'ignoreHash' - Default is True - * - * Returns: - * {Boolean} Whether or not the two URLs are equivalent - */ -OpenLayers.Util.isEquivalentUrl = function(url1, url2, options) { - options = options || {}; - - OpenLayers.Util.applyDefaults(options, { - ignoreCase: true, - ignorePort80: true, - ignoreHash: true - }); - - var urlObj1 = OpenLayers.Util.createUrlObject(url1, options); - var urlObj2 = OpenLayers.Util.createUrlObject(url2, options); - - //compare all keys except for "args" (treated below) - for(var key in urlObj1) { - if(key !== "args") { - if(urlObj1[key] != urlObj2[key]) { - return false; - } - } - } - - // compare search args - irrespective of order - for(var key in urlObj1.args) { - if(urlObj1.args[key] != urlObj2.args[key]) { - return false; - } - delete urlObj2.args[key]; - } - // urlObj2 shouldn't have any args left - for(var key in urlObj2.args) { - return false; - } - - return true; -}; - -/** - * Function: createUrlObject - * - * Parameters: - * url - {String} - * options - {Object} A hash of options. - * - * Valid options: - * ignoreCase - {Boolean} lowercase url, - * ignorePort80 - {Boolean} don't include explicit port if port is 80, - * ignoreHash - {Boolean} Don't include part of url after the hash (#). - * - * 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 - // - // This is a workaround for Internet Explorer where - // window.location.pathname has a leading "/", but - // a.pathname has no leading "/". - urlObject.pathname = (a.pathname.charAt(0) == "/") ? a.pathname : "/" + a.pathname; - - return urlObject; -}; - -/** - * Function: removeTail - * Takes a url and removes everything after the ? and # - * - * Parameters: - * url - {String} The url to process - * - * Returns: - * {String} The string with all queryString and Hash removed - */ -OpenLayers.Util.removeTail = function(url) { - var head = null; - - var qMark = url.indexOf("?"); - var hashMark = url.indexOf("#"); - - if (qMark == -1) { - head = (hashMark != -1) ? url.substr(0,hashMark) : url; - } else { - head = (hashMark != -1) ? url.substr(0,Math.min(qMark, hashMark)) - : url.substr(0, qMark); - } - return head; -}; - -/** - * Constant: IS_GECKO - * {Boolean} True if the userAgent reports the browser to use the Gecko engine - */ -OpenLayers.IS_GECKO = (function() { - var ua = navigator.userAgent.toLowerCase(); - return ua.indexOf("webkit") == -1 && ua.indexOf("gecko") != -1; -})(); - -/** - * Constant: CANVAS_SUPPORTED - * {Boolean} True if canvas 2d is supported. - */ -OpenLayers.CANVAS_SUPPORTED = (function() { - var elem = document.createElement('canvas'); - return !!(elem.getContext && elem.getContext('2d')); -})(); - -/** - * Constant: BROWSER_NAME - * {String} - * A substring of the navigator.userAgent property. Depending on the userAgent - * property, this will be the empty string or one of the following: - * * "opera" -- Opera - * * "msie" -- Internet Explorer - * * "safari" -- Safari - * * "firefox" -- Firefox - * * "mozilla" -- Mozilla - */ -OpenLayers.BROWSER_NAME = (function() { - var name = ""; - var ua = navigator.userAgent.toLowerCase(); - if (ua.indexOf("opera") != -1) { - name = "opera"; - } else if (ua.indexOf("msie") != -1) { - name = "msie"; - } else if (ua.indexOf("safari") != -1) { - name = "safari"; - } else if (ua.indexOf("mozilla") != -1) { - if (ua.indexOf("firefox") != -1) { - name = "firefox"; - } else { - name = "mozilla"; - } - } - return name; -})(); - -/** - * Function: getBrowserName - * - * Returns: - * {String} A string which specifies which is the current - * browser in which we are running. - * - * Currently-supported browser detection and codes: - * * 'opera' -- Opera - * * 'msie' -- Internet Explorer - * * 'safari' -- Safari - * * 'firefox' -- Firefox - * * 'mozilla' -- Mozilla - * - * If we are unable to property identify the browser, we - * return an empty string. - */ -OpenLayers.Util.getBrowserName = function() { - return OpenLayers.BROWSER_NAME; -}; - -/** - * Method: getRenderedDimensions - * Renders the contentHTML offscreen to determine actual dimensions for - * popup sizing. As we need layout to determine dimensions the content - * is rendered -9999px to the left and absolute to ensure the - * scrollbars do not flicker - * - * Parameters: - * contentHTML - * size - {} If either the 'w' or 'h' properties is - * specified, we fix that dimension of the div to be measured. This is - * useful in the case where we have a limit in one dimension and must - * therefore meaure the flow in the other dimension. - * options - {Object} - * - * Allowed Options: - * displayClass - {String} Optional parameter. A CSS class name(s) string - * to provide the CSS context of the rendered content. - * containerElement - {DOMElement} Optional parameter. Insert the HTML to - * this node instead of the body root when calculating dimensions. - * - * Returns: - * {} - */ -OpenLayers.Util.getRenderedDimensions = function(contentHTML, size, options) { - - var w, h; - - // create temp container div with restricted size - var container = document.createElement("div"); - container.style.visibility = "hidden"; - - var containerElement = (options && options.containerElement) - ? options.containerElement : document.body; - - // Opera and IE7 can't handle a node with position:aboslute if it inherits - // position:absolute from a parent. - var parentHasPositionAbsolute = false; - var superContainer = null; - var parent = containerElement; - while (parent && parent.tagName.toLowerCase()!="body") { - var parentPosition = OpenLayers.Element.getStyle(parent, "position"); - if(parentPosition == "absolute") { - parentHasPositionAbsolute = true; - break; - } else if (parentPosition && parentPosition != "static") { - break; - } - parent = parent.parentNode; - } - if(parentHasPositionAbsolute && (containerElement.clientHeight === 0 || - containerElement.clientWidth === 0) ){ - superContainer = document.createElement("div"); - superContainer.style.visibility = "hidden"; - superContainer.style.position = "absolute"; - superContainer.style.overflow = "visible"; - superContainer.style.width = document.body.clientWidth + "px"; - superContainer.style.height = document.body.clientHeight + "px"; - superContainer.appendChild(container); - } - container.style.position = "absolute"; - - //fix a dimension, if specified. - if (size) { - if (size.w) { - w = size.w; - container.style.width = w + "px"; - } else if (size.h) { - h = size.h; - container.style.height = h + "px"; - } - } - - //add css classes, if specified - if (options && options.displayClass) { - container.className = options.displayClass; - } - - // create temp content div and assign content - var content = document.createElement("div"); - content.innerHTML = contentHTML; - - // we need overflow visible when calculating the size - content.style.overflow = "visible"; - if (content.childNodes) { - for (var i=0, l=content.childNodes.length; i= 60) { - coordinateseconds -= 60; - coordinateminutes += 1; - if( coordinateminutes >= 60) { - coordinateminutes -= 60; - coordinatedegrees += 1; - } - } - - if( coordinatedegrees < 10 ) { - coordinatedegrees = "0" + coordinatedegrees; - } - var str = coordinatedegrees + "\u00B0"; - - if (dmsOption.indexOf('dm') >= 0) { - if( coordinateminutes < 10 ) { - coordinateminutes = "0" + coordinateminutes; - } - str += coordinateminutes + "'"; - - if (dmsOption.indexOf('dms') >= 0) { - if( coordinateseconds < 10 ) { - coordinateseconds = "0" + coordinateseconds; - } - str += coordinateseconds + '"'; - } - } - - if (axis == "lon") { - str += coordinate < 0 ? OpenLayers.i18n("W") : OpenLayers.i18n("E"); - } else { - str += coordinate < 0 ? OpenLayers.i18n("S") : OpenLayers.i18n("N"); - } - return str; -}; - -/* ====================================================================== - OpenLayers/Events.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/Util.js - */ - -/** - * Namespace: OpenLayers.Event - * Utility functions for event handling. - */ -OpenLayers.Event = { - - /** - * Property: observers - * {Object} A hashtable cache of the event observers. Keyed by - * element._eventCacheID - */ - observers: false, - - /** - * Constant: KEY_SPACE - * {int} - */ - KEY_SPACE: 32, - - /** - * Constant: KEY_BACKSPACE - * {int} - */ - KEY_BACKSPACE: 8, - - /** - * Constant: KEY_TAB - * {int} - */ - KEY_TAB: 9, - - /** - * Constant: KEY_RETURN - * {int} - */ - KEY_RETURN: 13, - - /** - * Constant: KEY_ESC - * {int} - */ - KEY_ESC: 27, - - /** - * Constant: KEY_LEFT - * {int} - */ - KEY_LEFT: 37, - - /** - * Constant: KEY_UP - * {int} - */ - KEY_UP: 38, - - /** - * Constant: KEY_RIGHT - * {int} - */ - KEY_RIGHT: 39, - - /** - * Constant: KEY_DOWN - * {int} - */ - KEY_DOWN: 40, - - /** - * Constant: KEY_DELETE - * {int} - */ - KEY_DELETE: 46, - - - /** - * Method: element - * Cross browser event element detection. - * - * Parameters: - * event - {Event} - * - * Returns: - * {DOMElement} The element that caused the event - */ - element: function(event) { - return event.target || event.srcElement; - }, - - /** - * Method: isSingleTouch - * Determine whether event was caused by a single touch - * - * Parameters: - * event - {Event} - * - * Returns: - * {Boolean} - */ - isSingleTouch: function(event) { - return event.touches && event.touches.length == 1; - }, - - /** - * Method: isMultiTouch - * Determine whether event was caused by a multi touch - * - * Parameters: - * event - {Event} - * - * Returns: - * {Boolean} - */ - isMultiTouch: function(event) { - return event.touches && event.touches.length > 1; - }, - - /** - * Method: isLeftClick - * Determine whether event was caused by a left click. - * - * Parameters: - * event - {Event} - * - * Returns: - * {Boolean} - */ - isLeftClick: function(event) { - return (((event.which) && (event.which == 1)) || - ((event.button) && (event.button == 1))); - }, - - /** - * Method: isRightClick - * Determine whether event was caused by a right mouse click. - * - * Parameters: - * event - {Event} - * - * Returns: - * {Boolean} - */ - isRightClick: function(event) { - return (((event.which) && (event.which == 3)) || - ((event.button) && (event.button == 2))); - }, - - /** - * Method: stop - * Stops an event from propagating. - * - * Parameters: - * event - {Event} - * allowDefault - {Boolean} If true, we stop the event chain but - * still allow the default browser behaviour (text selection, - * radio-button clicking, etc). Default is false. - */ - stop: function(event, allowDefault) { - - if (!allowDefault) { - OpenLayers.Event.preventDefault(event); - } - - if (event.stopPropagation) { - event.stopPropagation(); - } else { - event.cancelBubble = true; - } - }, - - /** - * Method: preventDefault - * Cancels the event if it is cancelable, without stopping further - * propagation of the event. - * - * Parameters: - * event - {Event} - */ - preventDefault: function(event) { - if (event.preventDefault) { - event.preventDefault(); - } else { - event.returnValue = false; - } - }, - - /** - * Method: findElement - * - * Parameters: - * event - {Event} - * tagName - {String} - * - * Returns: - * {DOMElement} The first node with the given tagName, starting from the - * node the event was triggered on and traversing the DOM upwards - */ - findElement: function(event, tagName) { - var element = OpenLayers.Event.element(event); - while (element.parentNode && (!element.tagName || - (element.tagName.toUpperCase() != tagName.toUpperCase()))){ - element = element.parentNode; - } - return element; - }, - - /** - * Method: observe - * - * Parameters: - * elementParam - {DOMElement || String} - * name - {String} - * observer - {function} - * useCapture - {Boolean} - */ - observe: function(elementParam, name, observer, useCapture) { - var element = OpenLayers.Util.getElement(elementParam); - useCapture = useCapture || false; - - if (name == 'keypress' && - (navigator.appVersion.match(/Konqueror|Safari|KHTML/) - || element.attachEvent)) { - name = 'keydown'; - } - - //if observers cache has not yet been created, create it - if (!this.observers) { - this.observers = {}; - } - - //if not already assigned, make a new unique cache ID - if (!element._eventCacheID) { - var idPrefix = "eventCacheID_"; - if (element.id) { - idPrefix = element.id + "_" + idPrefix; - } - element._eventCacheID = OpenLayers.Util.createUniqueID(idPrefix); - } - - var cacheID = element._eventCacheID; - - //if there is not yet a hash entry for this element, add one - if (!this.observers[cacheID]) { - this.observers[cacheID] = []; - } - - //add a new observer to this element's list - this.observers[cacheID].push({ - 'element': element, - 'name': name, - 'observer': observer, - 'useCapture': useCapture - }); - - //add the actual browser event listener - if (element.addEventListener) { - element.addEventListener(name, observer, useCapture); - } else if (element.attachEvent) { - element.attachEvent('on' + name, observer); - } - }, - - /** - * Method: stopObservingElement - * Given the id of an element to stop observing, cycle through the - * element's cached observers, calling stopObserving on each one, - * skipping those entries which can no longer be removed. - * - * parameters: - * elementParam - {DOMElement || String} - */ - stopObservingElement: function(elementParam) { - var element = OpenLayers.Util.getElement(elementParam); - var cacheID = element._eventCacheID; - - this._removeElementObservers(OpenLayers.Event.observers[cacheID]); - }, - - /** - * Method: _removeElementObservers - * - * Parameters: - * elementObservers - {Array(Object)} Array of (element, name, - * observer, usecapture) objects, - * taken directly from hashtable - */ - _removeElementObservers: function(elementObservers) { - if (elementObservers) { - for(var i = elementObservers.length-1; i >= 0; i--) { - var entry = elementObservers[i]; - OpenLayers.Event.stopObserving.apply(this, [ - entry.element, entry.name, entry.observer, entry.useCapture - ]); - } - } - }, - - /** - * Method: stopObserving - * - * Parameters: - * elementParam - {DOMElement || String} - * name - {String} - * observer - {function} - * useCapture - {Boolean} - * - * Returns: - * {Boolean} Whether or not the event observer was removed - */ - stopObserving: function(elementParam, name, observer, useCapture) { - useCapture = useCapture || false; - - var element = OpenLayers.Util.getElement(elementParam); - var cacheID = element._eventCacheID; - - if (name == 'keypress') { - if ( navigator.appVersion.match(/Konqueror|Safari|KHTML/) || - element.detachEvent) { - name = 'keydown'; - } - } - - // find element's entry in this.observers cache and remove it - var foundEntry = false; - var elementObservers = OpenLayers.Event.observers[cacheID]; - if (elementObservers) { - - // find the specific event type in the element's list - var i=0; - while(!foundEntry && i < elementObservers.length) { - var cacheEntry = elementObservers[i]; - - if ((cacheEntry.name == name) && - (cacheEntry.observer == observer) && - (cacheEntry.useCapture == useCapture)) { - - elementObservers.splice(i, 1); - if (elementObservers.length == 0) { - delete OpenLayers.Event.observers[cacheID]; - } - foundEntry = true; - break; - } - i++; - } - } - - //actually remove the event listener from browser - if (foundEntry) { - if (element.removeEventListener) { - element.removeEventListener(name, observer, useCapture); - } else if (element && element.detachEvent) { - element.detachEvent('on' + name, observer); - } - } - return foundEntry; - }, - - /** - * Method: unloadCache - * Cycle through all the element entries in the events cache and call - * stopObservingElement on each. - */ - unloadCache: function() { - // check for OpenLayers.Event before checking for observers, because - // OpenLayers.Event may be undefined in IE if no map instance was - // created - if (OpenLayers.Event && OpenLayers.Event.observers) { - for (var cacheID in OpenLayers.Event.observers) { - var elementObservers = OpenLayers.Event.observers[cacheID]; - OpenLayers.Event._removeElementObservers.apply(this, - [elementObservers]); - } - OpenLayers.Event.observers = false; - } - }, - - CLASS_NAME: "OpenLayers.Event" -}; - -/* prevent memory leaks in IE */ -OpenLayers.Event.observe(window, 'unload', OpenLayers.Event.unloadCache, false); - -/** - * Class: OpenLayers.Events - */ -OpenLayers.Events = OpenLayers.Class({ - - /** - * Constant: BROWSER_EVENTS - * {Array(String)} supported events - */ - BROWSER_EVENTS: [ - "mouseover", "mouseout", - "mousedown", "mouseup", "mousemove", - "click", "dblclick", "rightclick", "dblrightclick", - "resize", "focus", "blur", - "touchstart", "touchmove", "touchend", - "keydown" - ], - - /** - * Property: listeners - * {Object} Hashtable of Array(Function): events listener functions - */ - listeners: null, - - /** - * Property: object - * {Object} the code object issuing application events - */ - object: null, - - /** - * Property: element - * {DOMElement} the DOM element receiving browser events - */ - element: null, - - /** - * Property: eventHandler - * {Function} bound event handler attached to elements - */ - eventHandler: null, - - /** - * APIProperty: fallThrough - * {Boolean} - */ - fallThrough: null, - - /** - * APIProperty: includeXY - * {Boolean} Should the .xy property automatically be created for browser - * mouse events? In general, this should be false. If it is true, then - * mouse events will automatically generate a '.xy' property on the - * event object that is passed. (Prior to OpenLayers 2.7, this was true - * by default.) Otherwise, you can call the getMousePosition on the - * relevant events handler on the object available via the 'evt.object' - * property of the evt object. So, for most events, you can call: - * function named(evt) { - * this.xy = this.object.events.getMousePosition(evt) - * } - * - * This option typically defaults to false for performance reasons: - * when creating an events object whose primary purpose is to manage - * relatively positioned mouse events within a div, it may make - * sense to set it to true. - * - * This option is also used to control whether the events object caches - * offsets. If this is false, it will not: the reason for this is that - * it is only expected to be called many times if the includeXY property - * is set to true. If you set this to true, you are expected to clear - * the offset cache manually (using this.clearMouseCache()) if: - * the border of the element changes - * the location of the element in the page changes - */ - includeXY: false, - - /** - * APIProperty: extensions - * {Object} Event extensions registered with this instance. Keys are - * event types, values are {OpenLayers.Events.*} extension instances or - * {Boolean} for events that an instantiated extension provides in - * addition to the one it was created for. - * - * Extensions create an event in addition to browser events, which usually - * fires when a sequence of browser events is completed. Extensions are - * automatically instantiated when a listener is registered for an event - * provided by an extension. - * - * Extensions are created in the namespace using - * , and named after the event they provide. - * The constructor receives the target instance as - * argument. Extensions that need to capture browser events before they - * propagate can register their listeners events using , with - * {extension: true} as 4th argument. - * - * If an extension creates more than one event, an alias for each event - * type should be created and reference the same class. The constructor - * should set a reference in the target's extensions registry to itself. - * - * Below is a minimal extension that provides the "foostart" and "fooend" - * event types, which replace the native "click" event type if clicked on - * an element with the css class "foo": - * - * (code) - * OpenLayers.Events.foostart = OpenLayers.Class({ - * initialize: function(target) { - * this.target = target; - * this.target.register("click", this, this.doStuff, {extension: true}); - * // only required if extension provides more than one event type - * this.target.extensions["foostart"] = true; - * this.target.extensions["fooend"] = true; - * }, - * destroy: function() { - * var target = this.target; - * target.unregister("click", this, this.doStuff); - * delete this.target; - * // only required if extension provides more than one event type - * delete target.extensions["foostart"]; - * delete target.extensions["fooend"]; - * }, - * doStuff: function(evt) { - * var propagate = true; - * if (OpenLayers.Event.element(evt).className === "foo") { - * propagate = false; - * var target = this.target; - * target.triggerEvent("foostart"); - * window.setTimeout(function() { - * target.triggerEvent("fooend"); - * }, 1000); - * } - * return propagate; - * } - * }); - * // only required if extension provides more than one event type - * OpenLayers.Events.fooend = OpenLayers.Events.foostart; - * (end) - * - */ - extensions: null, - - /** - * Property: extensionCount - * {Object} Keys are event types (like in ), values are the - * number of extension listeners for each event type. - */ - extensionCount: null, - - /** - * Method: clearMouseListener - * A version of that is bound to this instance so that - * it can be used with and - * . - */ - clearMouseListener: null, - - /** - * Constructor: OpenLayers.Events - * Construct an OpenLayers.Events object. - * - * Parameters: - * object - {Object} The js object to which this Events object is being added - * element - {DOMElement} A dom element to respond to browser events - * eventTypes - {Array(String)} Deprecated. Array of custom application - * events. A listener may be registered for any named event, regardless - * of the values provided here. - * fallThrough - {Boolean} Allow events to fall through after these have - * been handled? - * options - {Object} Options for the events object. - */ - initialize: function (object, element, eventTypes, fallThrough, options) { - OpenLayers.Util.extend(this, options); - this.object = object; - this.fallThrough = fallThrough; - this.listeners = {}; - this.extensions = {}; - this.extensionCount = {}; - - // if a dom element is specified, add a listeners list - // for browser events on the element and register them - if (element != null) { - this.attachToElement(element); - } - }, - - /** - * APIMethod: destroy - */ - destroy: function () { - for (var e in this.extensions) { - if (typeof this.extensions[e] !== "boolean") { - this.extensions[e].destroy(); - } - } - this.extensions = null; - if (this.element) { - OpenLayers.Event.stopObservingElement(this.element); - if(this.element.hasScrollEvent) { - OpenLayers.Event.stopObserving( - window, "scroll", this.clearMouseListener - ); - } - } - this.element = null; - - this.listeners = null; - this.object = null; - this.fallThrough = null; - this.eventHandler = null; - }, - - /** - * APIMethod: addEventType - * Deprecated. Any event can be triggered without adding it first. - * - * Parameters: - * eventName - {String} - */ - addEventType: function(eventName) { - }, - - /** - * Method: attachToElement - * - * Parameters: - * element - {HTMLDOMElement} a DOM element to attach browser events to - */ - attachToElement: function (element) { - if (this.element) { - OpenLayers.Event.stopObservingElement(this.element); - } else { - // keep a bound copy of handleBrowserEvent() so that we can - // pass the same function to both Event.observe() and .stopObserving() - this.eventHandler = OpenLayers.Function.bindAsEventListener( - this.handleBrowserEvent, this - ); - - // to be used with observe and stopObserving - this.clearMouseListener = OpenLayers.Function.bind( - this.clearMouseCache, this - ); - } - this.element = element; - for (var i = 0, len = this.BROWSER_EVENTS.length; i < len; i++) { - // register the event cross-browser - OpenLayers.Event.observe( - element, this.BROWSER_EVENTS[i], this.eventHandler - ); - } - // disable dragstart in IE so that mousedown/move/up works normally - OpenLayers.Event.observe(element, "dragstart", OpenLayers.Event.stop); - }, - - /** - * APIMethod: on - * Convenience method for registering listeners with a common scope. - * Internally, this method calls as shown in the examples - * below. - * - * Example use: - * (code) - * // register a single listener for the "loadstart" event - * events.on({"loadstart": loadStartListener}); - * - * // this is equivalent to the following - * events.register("loadstart", undefined, loadStartListener); - * - * // register multiple listeners to be called with the same `this` object - * events.on({ - * "loadstart": loadStartListener, - * "loadend": loadEndListener, - * scope: object - * }); - * - * // this is equivalent to the following - * events.register("loadstart", object, loadStartListener); - * events.register("loadend", object, loadEndListener); - * (end) - * - * Parameters: - * object - {Object} - */ - on: function(object) { - for(var type in object) { - if(type != "scope" && object.hasOwnProperty(type)) { - this.register(type, object.scope, object[type]); - } - } - }, - - /** - * APIMethod: register - * Register an event on the events object. - * - * When the event is triggered, the 'func' function will be called, in the - * context of 'obj'. Imagine we were to register an event, specifying an - * OpenLayers.Bounds Object as 'obj'. When the event is triggered, the - * context in the callback function will be our Bounds object. This means - * that within our callback function, we can access the properties and - * methods of the Bounds object through the "this" variable. So our - * callback could execute something like: - * : leftStr = "Left: " + this.left; - * - * or - * - * : centerStr = "Center: " + this.getCenterLonLat(); - * - * Parameters: - * type - {String} Name of the event to register - * obj - {Object} The object to bind the context to for the callback#. - * If no object is specified, default is the Events's 'object' property. - * func - {Function} The callback function. If no callback is - * specified, this function does nothing. - * priority - {Boolean|Object} If true, adds the new listener to the - * *front* of the events queue instead of to the end. - * - * Valid options for priority: - * extension - {Boolean} If true, then the event will be registered as - * extension event. Extension events are handled before all other - * events. - */ - register: function (type, obj, func, priority) { - if (type in OpenLayers.Events && !this.extensions[type]) { - this.extensions[type] = new OpenLayers.Events[type](this); - } - if (func != null) { - if (obj == null) { - obj = this.object; - } - var listeners = this.listeners[type]; - if (!listeners) { - listeners = []; - this.listeners[type] = listeners; - this.extensionCount[type] = 0; - } - var listener = {obj: obj, func: func}; - if (priority) { - listeners.splice(this.extensionCount[type], 0, listener); - if (typeof priority === "object" && priority.extension) { - this.extensionCount[type]++; - } - } else { - listeners.push(listener); - } - } - }, - - /** - * APIMethod: registerPriority - * Same as register() but adds the new listener to the *front* of the - * events queue instead of to the end. - * - * TODO: get rid of this in 3.0 - Decide whether listeners should be - * called in the order they were registered or in reverse order. - * - * - * Parameters: - * type - {String} Name of the event to register - * obj - {Object} The object to bind the context to for the callback#. - * If no object is specified, default is the Events's - * 'object' property. - * func - {Function} The callback function. If no callback is - * specified, this function does nothing. - */ - registerPriority: function (type, obj, func) { - this.register(type, obj, func, true); - }, - - /** - * APIMethod: un - * Convenience method for unregistering listeners with a common scope. - * Internally, this method calls as shown in the examples - * below. - * - * Example use: - * (code) - * // unregister a single listener for the "loadstart" event - * events.un({"loadstart": loadStartListener}); - * - * // this is equivalent to the following - * events.unregister("loadstart", undefined, loadStartListener); - * - * // unregister multiple listeners with the same `this` object - * events.un({ - * "loadstart": loadStartListener, - * "loadend": loadEndListener, - * scope: object - * }); - * - * // this is equivalent to the following - * events.unregister("loadstart", object, loadStartListener); - * events.unregister("loadend", object, loadEndListener); - * (end) - */ - un: function(object) { - for(var type in object) { - if(type != "scope" && object.hasOwnProperty(type)) { - this.unregister(type, object.scope, object[type]); - } - } - }, - - /** - * APIMethod: unregister - * - * Parameters: - * type - {String} - * obj - {Object} If none specified, defaults to this.object - * func - {Function} - */ - unregister: function (type, obj, func) { - if (obj == null) { - obj = this.object; - } - var listeners = this.listeners[type]; - if (listeners != null) { - for (var i=0, len=listeners.length; i} The current xy coordinate of the mouse, adjusted - * for offsets - */ - getMousePosition: function (evt) { - if (!this.includeXY) { - this.clearMouseCache(); - } else if (!this.element.hasScrollEvent) { - OpenLayers.Event.observe(window, "scroll", this.clearMouseListener); - this.element.hasScrollEvent = true; - } - - if (!this.element.scrolls) { - var viewportElement = OpenLayers.Util.getViewportElement(); - this.element.scrolls = [ - viewportElement.scrollLeft, - viewportElement.scrollTop - ]; - } - - if (!this.element.lefttop) { - this.element.lefttop = [ - (document.documentElement.clientLeft || 0), - (document.documentElement.clientTop || 0) - ]; - } - - if (!this.element.offsets) { - this.element.offsets = OpenLayers.Util.pagePosition(this.element); - } - - return new OpenLayers.Pixel( - (evt.clientX + this.element.scrolls[0]) - this.element.offsets[0] - - this.element.lefttop[0], - (evt.clientY + this.element.scrolls[1]) - this.element.offsets[1] - - this.element.lefttop[1] - ); - }, - - CLASS_NAME: "OpenLayers.Events" -}); -/* ====================================================================== - OpenLayers/Events/buttonclick.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Events.js - */ - -/** - * Class: OpenLayers.Events.buttonclick - * Extension event type for handling buttons on top of a dom element. This - * event type fires "buttonclick" on its when a button was - * clicked. Buttons are detected by the "olButton" class. - * - * This event type makes sure that button clicks do not interfere with other - * events that are registered on the same . - * - * Event types provided by this extension: - * - *buttonclick* Triggered when a button is clicked. Listeners receive an - * object with a *buttonElement* property referencing the dom element of - * the clicked button, and an *buttonXY* property with the click position - * relative to the button. - */ -OpenLayers.Events.buttonclick = OpenLayers.Class({ - - /** - * Property: target - * {} The events instance that the buttonclick event will - * be triggered on. - */ - target: null, - - /** - * Property: events - * {Array} Events to observe and conditionally stop from propagating when - * an element with the olButton class (or its olAlphaImg child) is - * clicked. - */ - events: [ - 'mousedown', 'mouseup', 'click', 'dblclick', - 'touchstart', 'touchmove', 'touchend', 'keydown' - ], - - /** - * Property: startRegEx - * {RegExp} Regular expression to test Event.type for events that start - * a buttonclick sequence. - */ - startRegEx: /^mousedown|touchstart$/, - - /** - * Property: cancelRegEx - * {RegExp} Regular expression to test Event.type for events that cancel - * a buttonclick sequence. - */ - cancelRegEx: /^touchmove$/, - - /** - * Property: completeRegEx - * {RegExp} Regular expression to test Event.type for events that complete - * a buttonclick sequence. - */ - completeRegEx: /^mouseup|touchend$/, - - /** - * Property: startEvt - * {Event} The event that started the click sequence - */ - - /** - * Constructor: OpenLayers.Events.buttonclick - * Construct a buttonclick event type. Applications are not supposed to - * create instances of this class - they are created on demand by - * instances. - * - * Parameters: - * target - {} The events instance that the buttonclick - * event will be triggered on. - */ - initialize: function(target) { - this.target = target; - for (var i=this.events.length-1; i>=0; --i) { - this.target.register(this.events[i], this, this.buttonClick, { - extension: true - }); - } - }, - - /** - * Method: destroy - */ - destroy: function() { - for (var i=this.events.length-1; i>=0; --i) { - this.target.unregister(this.events[i], this, this.buttonClick); - } - delete this.target; - }, - - /** - * Method: getPressedButton - * Get the pressed button, if any. Returns undefined if no button - * was pressed. - * - * Arguments: - * element - {DOMElement} The event target. - * - * Returns: - * {DOMElement} The button element, or undefined. - */ - getPressedButton: function(element) { - var depth = 3, // limit the search depth - button; - do { - if(OpenLayers.Element.hasClass(element, "olButton")) { - // hit! - button = element; - break; - } - element = element.parentNode; - } while(--depth > 0 && element); - return button; - }, - - /** - * Method: ignore - * Check for event target elements that should be ignored by OpenLayers. - * - * Parameters: - * element - {DOMElement} The event target. - */ - ignore: function(element) { - var depth = 3, - ignore = false; - do { - if (element.nodeName.toLowerCase() === 'a') { - ignore = true; - break; - } - element = element.parentNode; - } while (--depth > 0 && element); - return ignore; - }, - - /** - * Method: buttonClick - * Check if a button was clicked, and fire the buttonclick event - * - * Parameters: - * evt - {Event} - */ - buttonClick: function(evt) { - var propagate = true, - element = OpenLayers.Event.element(evt); - if (element && (OpenLayers.Event.isLeftClick(evt) || !~evt.type.indexOf("mouse"))) { - // was a button pressed? - var button = this.getPressedButton(element); - if (button) { - if (evt.type === "keydown") { - switch (evt.keyCode) { - case OpenLayers.Event.KEY_RETURN: - case OpenLayers.Event.KEY_SPACE: - this.target.triggerEvent("buttonclick", { - buttonElement: button - }); - OpenLayers.Event.stop(evt); - propagate = false; - break; - } - } else if (this.startEvt) { - if (this.completeRegEx.test(evt.type)) { - var pos = OpenLayers.Util.pagePosition(button); - this.target.triggerEvent("buttonclick", { - buttonElement: button, - buttonXY: { - x: this.startEvt.clientX - pos[0], - y: this.startEvt.clientY - pos[1] - } - }); - } - if (this.cancelRegEx.test(evt.type)) { - delete this.startEvt; - } - OpenLayers.Event.stop(evt); - propagate = false; - } - if (this.startRegEx.test(evt.type)) { - this.startEvt = evt; - OpenLayers.Event.stop(evt); - propagate = false; - } - } else { - propagate = !this.ignore(OpenLayers.Event.element(evt)); - delete this.startEvt; - } - } - return propagate; - } - -}); -/* ====================================================================== - OpenLayers/Format.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/BaseTypes/Class.js - * @requires OpenLayers/Util.js - */ - -/** - * Class: OpenLayers.Format - * Base class for format reading/writing a variety of formats. Subclasses - * of OpenLayers.Format are expected to have read and write methods. - */ -OpenLayers.Format = OpenLayers.Class({ - - /** - * Property: options - * {Object} A reference to options passed to the constructor. - */ - options: null, - - /** - * APIProperty: externalProjection - * {} When passed a externalProjection and - * internalProjection, the format will reproject the geometries it - * reads or writes. The externalProjection is the projection used by - * the content which is passed into read or which comes out of write. - * In order to reproject, a projection transformation function for the - * specified projections must be available. This support may be - * provided via proj4js or via a custom transformation function. See - * {} for more information on - * custom transformations. - */ - externalProjection: null, - - /** - * APIProperty: internalProjection - * {} When passed a externalProjection and - * internalProjection, the format will reproject the geometries it - * reads or writes. The internalProjection is the projection used by - * the geometries which are returned by read or which are passed into - * write. In order to reproject, a projection transformation function - * for the specified projections must be available. This support may be - * provided via proj4js or via a custom transformation function. See - * {} for more information on - * custom transformations. - */ - internalProjection: null, - - /** - * APIProperty: data - * {Object} When is true, this is the parsed string sent to - * . - */ - data: null, - - /** - * APIProperty: keepData - * {Object} Maintain a reference () to the most recently read data. - * Default is false. - */ - keepData: false, - - /** - * Constructor: OpenLayers.Format - * Instances of this class are not useful. See one of the subclasses. - * - * Parameters: - * options - {Object} An optional object with properties to set on the - * format - * - * Valid options: - * keepData - {Boolean} If true, upon , the data property will be - * set to the parsed object (e.g. the json or xml object). - * - * Returns: - * An instance of OpenLayers.Format - */ - initialize: function(options) { - OpenLayers.Util.extend(this, options); - this.options = options; - }, - - /** - * APIMethod: destroy - * Clean up. - */ - destroy: function() { - }, - - /** - * Method: read - * Read data from a string, and return an object whose type depends on the - * subclass. - * - * Parameters: - * data - {string} Data to read/parse. - * - * Returns: - * Depends on the subclass - */ - read: function(data) { - throw new Error('Read not implemented.'); - }, - - /** - * Method: write - * Accept an object, and return a string. - * - * Parameters: - * object - {Object} Object to be serialized - * - * Returns: - * {String} A string representation of the object. - */ - write: function(object) { - throw new Error('Write not implemented.'); - }, - - CLASS_NAME: "OpenLayers.Format" -}); -/* ====================================================================== - OpenLayers/Format/XML.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Format.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 document. - * The DOM creation and traversing methods exposed here all mimic the - * W3C XML DOM methods. Create a new parser with the - * constructor. - * - * Inherits from: - * - - */ -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 - * 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 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 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 document - * 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. - * - * 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: - * 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 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), 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 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. - * - * 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 on the instance. On other browsers, this will - * either return an existing or create a new shared document (see - * ). - * - * Returns: - * {XMLDocument} - */ - getXMLDoc: function() { - if (!OpenLayers.Format.XML.document && !this.xmldom) { - if (document.implementation && document.implementation.createDocument) { - OpenLayers.Format.XML.document = - document.implementation.createDocument("", "", null); - } else if (!this.xmldom && window.ActiveXObject) { - this.xmldom = new ActiveXObject("Microsoft.XMLDOM"); - } - } - return OpenLayers.Format.XML.document || this.xmldom; - }, - - 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 -); - -/** - * Property: OpenLayers.Format.XML.document - * {XMLDocument} XML document to reuse for creating non-HTML compliant nodes, - * like document.createCDATASection. - */ -OpenLayers.Format.XML.document = null; -/* ====================================================================== - OpenLayers/Format/WFST.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Format.js - */ - -/** - * Function: OpenLayers.Format.WFST - * Used to create a versioned WFS protocol. Default version is 1.0.0. - * - * Returns: - * {} 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); -}; - -/** - * Constant: OpenLayers.Format.WFST.DEFAULTS - * {Object} Default properties for the WFST format. - */ -OpenLayers.Format.WFST.DEFAULTS = { - "version": "1.0.0" -}; -/* ====================================================================== - OpenLayers/Feature.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/BaseTypes/Class.js - * @requires OpenLayers/Util.js - */ - -/** - * Class: OpenLayers.Feature - * Features are combinations of geography and attributes. The OpenLayers.Feature - * class specifically combines a marker and a lonlat. - */ -OpenLayers.Feature = OpenLayers.Class({ - - /** - * Property: layer - * {} - */ - layer: null, - - /** - * Property: id - * {String} - */ - id: null, - - /** - * Property: lonlat - * {} - */ - lonlat: null, - - /** - * Property: data - * {Object} - */ - data: null, - - /** - * Property: marker - * {} - */ - marker: null, - - /** - * APIProperty: popupClass - * {} The class which will be used to instantiate - * a new Popup. Default is . - */ - popupClass: null, - - /** - * Property: popup - * {} - */ - popup: null, - - /** - * Constructor: OpenLayers.Feature - * Constructor for features. - * - * Parameters: - * layer - {} - * lonlat - {} - * data - {Object} - * - * Returns: - * {} - */ - initialize: function(layer, lonlat, data) { - this.layer = layer; - this.lonlat = lonlat; - this.data = (data != null) ? data : {}; - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); - }, - - /** - * Method: destroy - * nullify references to prevent circular references and memory leaks - */ - destroy: function() { - - //remove the popup from the map - if ((this.layer != null) && (this.layer.map != null)) { - if (this.popup != null) { - this.layer.map.removePopup(this.popup); - } - } - // remove the marker from the layer - if (this.layer != null && this.marker != null) { - this.layer.removeMarker(this.marker); - } - - this.layer = null; - this.id = null; - this.lonlat = null; - this.data = null; - if (this.marker != null) { - this.destroyMarker(this.marker); - this.marker = null; - } - if (this.popup != null) { - this.destroyPopup(this.popup); - this.popup = null; - } - }, - - /** - * Method: onScreen - * - * Returns: - * {Boolean} Whether or not the feature is currently visible on screen - * (based on its 'lonlat' property) - */ - onScreen:function() { - - var onScreen = false; - if ((this.layer != null) && (this.layer.map != null)) { - var screenBounds = this.layer.map.getExtent(); - onScreen = screenBounds.containsLonLat(this.lonlat); - } - return onScreen; - }, - - - /** - * Method: createMarker - * Based on the data associated with the Feature, create and return a marker object. - * - * Returns: - * {} A Marker Object created from the 'lonlat' and 'icon' properties - * set in this.data. If no 'lonlat' is set, returns null. If no - * 'icon' is set, OpenLayers.Marker() will load the default image. - * - * Note - this.marker is set to return value - * - */ - createMarker: function() { - - if (this.lonlat != null) { - this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon); - } - return this.marker; - }, - - /** - * Method: destroyMarker - * Destroys marker. - * If user overrides the createMarker() function, s/he should be able - * to also specify an alternative function for destroying it - */ - destroyMarker: function() { - this.marker.destroy(); - }, - - /** - * Method: createPopup - * Creates a popup object created from the 'lonlat', 'popupSize', - * and 'popupContentHTML' properties set in this.data. It uses - * this.marker.icon as default anchor. - * - * If no 'lonlat' is set, returns null. - * If no this.marker has been created, no anchor is sent. - * - * Note - the returned popup object is 'owned' by the feature, so you - * cannot use the popup's destroy method to discard the popup. - * Instead, you must use the feature's destroyPopup - * - * Note - this.popup is set to return value - * - * Parameters: - * closeBox - {Boolean} create popup with closebox or not - * - * Returns: - * {} Returns the created popup, which is also set - * as 'popup' property of this feature. Will be of whatever type - * specified by this feature's 'popupClass' property, but must be - * of type . - * - */ - createPopup: function(closeBox) { - - if (this.lonlat != null) { - if (!this.popup) { - var anchor = (this.marker) ? this.marker.icon : null; - var popupClass = this.popupClass ? - this.popupClass : OpenLayers.Popup.Anchored; - this.popup = new popupClass(this.id + "_popup", - this.lonlat, - this.data.popupSize, - this.data.popupContentHTML, - anchor, - closeBox); - } - if (this.data.overflow != null) { - this.popup.contentDiv.style.overflow = this.data.overflow; - } - - this.popup.feature = this; - } - return this.popup; - }, - - - /** - * Method: destroyPopup - * Destroys the popup created via createPopup. - * - * As with the marker, if user overrides the createPopup() function, s/he - * should also be able to override the destruction - */ - destroyPopup: function() { - if (this.popup) { - this.popup.feature = null; - this.popup.destroy(); - this.popup = null; - } - }, - - CLASS_NAME: "OpenLayers.Feature" -}); -/* ====================================================================== - OpenLayers/Feature/Vector.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -// TRASH THIS -OpenLayers.State = { - /** states */ - UNKNOWN: 'Unknown', - INSERT: 'Insert', - UPDATE: 'Update', - DELETE: 'Delete' -}; - -/** - * @requires OpenLayers/Feature.js - * @requires OpenLayers/Util.js - */ - -/** - * Class: OpenLayers.Feature.Vector - * Vector features use the OpenLayers.Geometry classes as geometry description. - * They have an 'attributes' property, which is the data object, and a 'style' - * property, the default values of which are defined in the - * objects. - * - * Inherits from: - * - - */ -OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, { - - /** - * Property: fid - * {String} - */ - fid: null, - - /** - * APIProperty: geometry - * {} - */ - geometry: null, - - /** - * APIProperty: attributes - * {Object} This object holds arbitrary, serializable properties that - * describe the feature. - */ - attributes: null, - - /** - * Property: bounds - * {} The box bounding that feature's geometry, that - * property can be set by an object when - * deserializing the feature, so in most cases it represents an - * information set by the server. - */ - bounds: null, - - /** - * Property: state - * {String} - */ - state: null, - - /** - * APIProperty: style - * {Object} - */ - style: null, - - /** - * APIProperty: url - * {String} If this property is set it will be taken into account by - * {} when upadting or deleting the feature. - */ - url: null, - - /** - * Property: renderIntent - * {String} rendering intent currently being used - */ - renderIntent: "default", - - /** - * APIProperty: modified - * {Object} An object with the originals of the geometry and attributes of - * the feature, if they were changed. Currently this property is only read - * by , and written by - * , which sets the geometry property. - * Applications can set the originals of modified attributes in the - * attributes property. Note that applications have to check if this - * object and the attributes property is already created before using it. - * After a change made with ModifyFeature, this object could look like - * - * (code) - * { - * geometry: >Object - * } - * (end) - * - * When an application has made changes to feature attributes, it could - * have set the attributes to something like this: - * - * (code) - * { - * attributes: { - * myAttribute: "original" - * } - * } - * (end) - * - * Note that only checks for truthy values in - * *modified.geometry* and the attribute names in *modified.attributes*, - * but it is recommended to set the original values (and not just true) as - * attribute value, so applications could use this information to undo - * changes. - */ - modified: null, - - /** - * Constructor: OpenLayers.Feature.Vector - * Create a vector feature. - * - * Parameters: - * geometry - {} The geometry that this feature - * represents. - * attributes - {Object} An optional object that will be mapped to the - * property. - * style - {Object} An optional style object. - */ - initialize: function(geometry, attributes, style) { - OpenLayers.Feature.prototype.initialize.apply(this, - [null, null, attributes]); - this.lonlat = null; - this.geometry = geometry ? geometry : null; - this.state = null; - this.attributes = {}; - if (attributes) { - this.attributes = OpenLayers.Util.extend(this.attributes, - attributes); - } - this.style = style ? style : null; - }, - - /** - * Method: destroy - * nullify references to prevent circular references and memory leaks - */ - destroy: function() { - if (this.layer) { - this.layer.removeFeatures(this); - this.layer = null; - } - - this.geometry = null; - this.modified = null; - OpenLayers.Feature.prototype.destroy.apply(this, arguments); - }, - - /** - * Method: clone - * Create a clone of this vector feature. Does not set any non-standard - * properties. - * - * Returns: - * {} An exact clone of this vector feature. - */ - clone: function () { - return new OpenLayers.Feature.Vector( - this.geometry ? this.geometry.clone() : null, - this.attributes, - this.style); - }, - - /** - * Method: onScreen - * Determine whether the feature is within the map viewport. This method - * tests for an intersection between the geometry and the viewport - * bounds. If a more effecient but less precise geometry bounds - * intersection is desired, call the method with the boundsOnly - * parameter true. - * - * Parameters: - * boundsOnly - {Boolean} Only test whether a feature's bounds intersects - * the viewport bounds. Default is false. If false, the feature's - * geometry must intersect the viewport for onScreen to return true. - * - * Returns: - * {Boolean} The feature is currently visible on screen (optionally - * based on its bounds if boundsOnly is true). - */ - onScreen:function(boundsOnly) { - var onScreen = false; - if(this.layer && this.layer.map) { - var screenBounds = this.layer.map.getExtent(); - if(boundsOnly) { - var featureBounds = this.geometry.getBounds(); - onScreen = screenBounds.intersectsBounds(featureBounds); - } else { - var screenPoly = screenBounds.toGeometry(); - onScreen = screenPoly.intersects(this.geometry); - } - } - return onScreen; - }, - - /** - * Method: getVisibility - * Determine whether the feature is displayed or not. It may not displayed - * because: - * - its style display property is set to 'none', - * - it doesn't belong to any layer, - * - the styleMap creates a symbolizer with display property set to 'none' - * for it, - * - the layer which it belongs to is not visible. - * - * Returns: - * {Boolean} The feature is currently displayed. - */ - getVisibility: function() { - return !(this.style && this.style.display == 'none' || - !this.layer || - this.layer && this.layer.styleMap && - this.layer.styleMap.createSymbolizer(this, this.renderIntent).display == 'none' || - this.layer && !this.layer.getVisibility()); - }, - - /** - * Method: createMarker - * HACK - we need to decide if all vector features should be able to - * create markers - * - * Returns: - * {} For now just returns null - */ - createMarker: function() { - return null; - }, - - /** - * Method: destroyMarker - * HACK - we need to decide if all vector features should be able to - * delete markers - * - * If user overrides the createMarker() function, s/he should be able - * to also specify an alternative function for destroying it - */ - destroyMarker: function() { - // pass - }, - - /** - * Method: createPopup - * HACK - we need to decide if all vector features should be able to - * create popups - * - * Returns: - * {} For now just returns null - */ - createPopup: function() { - return null; - }, - - /** - * Method: atPoint - * Determins whether the feature intersects with the specified location. - * - * Parameters: - * lonlat - {|Object} OpenLayers.LonLat or an - * object with a 'lon' and 'lat' properties. - * toleranceLon - {float} Optional tolerance in Geometric Coords - * toleranceLat - {float} Optional tolerance in Geographic Coords - * - * Returns: - * {Boolean} Whether or not the feature is at the specified location - */ - atPoint: function(lonlat, toleranceLon, toleranceLat) { - var atPoint = false; - if(this.geometry) { - atPoint = this.geometry.atPoint(lonlat, toleranceLon, - toleranceLat); - } - return atPoint; - }, - - /** - * Method: destroyPopup - * HACK - we need to decide if all vector features should be able to - * delete popups - */ - destroyPopup: function() { - // pass - }, - - /** - * Method: move - * Moves the feature and redraws it at its new location - * - * Parameters: - * location - { or } the - * location to which to move the feature. - */ - move: function(location) { - - if(!this.layer || !this.geometry.move){ - //do nothing if no layer or immoveable geometry - return undefined; - } - - var pixel; - if (location.CLASS_NAME == "OpenLayers.LonLat") { - pixel = this.layer.getViewPortPxFromLonLat(location); - } else { - pixel = location; - } - - var lastPixel = this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat()); - var res = this.layer.map.getResolution(); - this.geometry.move(res * (pixel.x - lastPixel.x), - res * (lastPixel.y - pixel.y)); - this.layer.drawFeature(this); - return lastPixel; - }, - - /** - * Method: toState - * Sets the new state - * - * Parameters: - * state - {String} - */ - toState: function(state) { - if (state == OpenLayers.State.UPDATE) { - switch (this.state) { - case OpenLayers.State.UNKNOWN: - case OpenLayers.State.DELETE: - this.state = state; - break; - case OpenLayers.State.UPDATE: - case OpenLayers.State.INSERT: - break; - } - } else if (state == OpenLayers.State.INSERT) { - switch (this.state) { - case OpenLayers.State.UNKNOWN: - break; - default: - this.state = state; - break; - } - } else if (state == OpenLayers.State.DELETE) { - switch (this.state) { - case OpenLayers.State.INSERT: - // the feature should be destroyed - break; - case OpenLayers.State.DELETE: - break; - case OpenLayers.State.UNKNOWN: - case OpenLayers.State.UPDATE: - this.state = state; - break; - } - } else if (state == OpenLayers.State.UNKNOWN) { - this.state = state; - } - }, - - CLASS_NAME: "OpenLayers.Feature.Vector" -}); - - -/** - * Constant: OpenLayers.Feature.Vector.style - * OpenLayers features can have a number of style attributes. The 'default' - * style will typically be used if no other style is specified. These - * styles correspond for the most part, to the styling properties defined - * by the SVG standard. - * Information on fill properties: http://www.w3.org/TR/SVG/painting.html#FillProperties - * Information on stroke properties: http://www.w3.org/TR/SVG/painting.html#StrokeProperties - * - * Symbolizer properties: - * fill - {Boolean} Set to false if no fill is desired. - * fillColor - {String} Hex fill color. Default is "#ee9900". - * fillOpacity - {Number} Fill opacity (0-1). Default is 0.4 - * stroke - {Boolean} Set to false if no stroke is desired. - * strokeColor - {String} Hex stroke color. Default is "#ee9900". - * strokeOpacity - {Number} Stroke opacity (0-1). Default is 1. - * strokeWidth - {Number} Pixel stroke width. Default is 1. - * strokeLinecap - {String} Stroke cap type. Default is "round". [butt | round | square] - * strokeDashstyle - {String} Stroke dash style. Default is "solid". [dot | dash | dashdot | longdash | longdashdot | solid] - * graphic - {Boolean} Set to false if no graphic is desired. - * pointRadius - {Number} Pixel point radius. Default is 6. - * pointerEvents - {String} Default is "visiblePainted". - * cursor - {String} Default is "". - * externalGraphic - {String} Url to an external graphic that will be used for rendering points. - * graphicWidth - {Number} Pixel width for sizing an external graphic. - * graphicHeight - {Number} Pixel height for sizing an external graphic. - * graphicOpacity - {Number} Opacity (0-1) for an external graphic. - * graphicXOffset - {Number} Pixel offset along the positive x axis for displacing an external graphic. - * graphicYOffset - {Number} Pixel offset along the positive y axis for displacing an external graphic. - * rotation - {Number} For point symbolizers, this is the rotation of a graphic in the clockwise direction about its center point (or any point off center as specified by graphicXOffset and graphicYOffset). - * graphicZIndex - {Number} The integer z-index value to use in rendering. - * graphicName - {String} Named graphic to use when rendering points. Supported values include "circle" (default), - * "square", "star", "x", "cross", "triangle". - * graphicTitle - {String} Tooltip when hovering over a feature. *deprecated*, use title instead - * title - {String} Tooltip when hovering over a feature. Not supported by the canvas renderer. - * backgroundGraphic - {String} Url to a graphic to be used as the background under an externalGraphic. - * backgroundGraphicZIndex - {Number} The integer z-index value to use in rendering the background graphic. - * backgroundXOffset - {Number} The x offset (in pixels) for the background graphic. - * backgroundYOffset - {Number} The y offset (in pixels) for the background graphic. - * backgroundHeight - {Number} The height of the background graphic. If not provided, the graphicHeight will be used. - * backgroundWidth - {Number} The width of the background width. If not provided, the graphicWidth will be used. - * label - {String} The text for an optional label. For browsers that use the canvas renderer, this requires either - * fillText or mozDrawText to be available. - * labelAlign - {String} Label alignment. This specifies the insertion point relative to the text. It is a string - * composed of two characters. The first character is for the horizontal alignment, the second for the vertical - * alignment. Valid values for horizontal alignment: "l"=left, "c"=center, "r"=right. Valid values for vertical - * alignment: "t"=top, "m"=middle, "b"=bottom. Example values: "lt", "cm", "rb". Default is "cm". - * labelXOffset - {Number} Pixel offset along the positive x axis for displacing the label. Not supported by the canvas renderer. - * labelYOffset - {Number} Pixel offset along the positive y axis for displacing the label. Not supported by the canvas renderer. - * labelSelect - {Boolean} If set to true, labels will be selectable using SelectFeature or similar controls. - * Default is false. - * labelOutlineColor - {String} The color of the label outline. Default is 'white'. Only supported by the canvas & SVG renderers. - * labelOutlineWidth - {Number} The width of the label outline. Default is 3, set to 0 or null to disable. Only supported by the canvas & SVG renderers. - * fontColor - {String} The font color for the label, to be provided like CSS. - * fontOpacity - {Number} Opacity (0-1) for the label - * fontFamily - {String} The font family for the label, to be provided like in CSS. - * fontSize - {String} The font size for the label, to be provided like in CSS. - * fontStyle - {String} The font style for the label, to be provided like in CSS. - * fontWeight - {String} The font weight for the label, to be provided like in CSS. - * display - {String} Symbolizers will have no effect if display is set to "none". All other values have no effect. - */ -OpenLayers.Feature.Vector.style = { - 'default': { - fillColor: "#ee9900", - fillOpacity: 0.4, - hoverFillColor: "white", - hoverFillOpacity: 0.8, - strokeColor: "#ee9900", - strokeOpacity: 1, - strokeWidth: 1, - strokeLinecap: "round", - strokeDashstyle: "solid", - hoverStrokeColor: "red", - hoverStrokeOpacity: 1, - hoverStrokeWidth: 0.2, - pointRadius: 6, - hoverPointRadius: 1, - hoverPointUnit: "%", - pointerEvents: "visiblePainted", - cursor: "inherit", - fontColor: "#000000", - labelAlign: "cm", - labelOutlineColor: "white", - labelOutlineWidth: 3 - }, - 'select': { - fillColor: "blue", - fillOpacity: 0.4, - hoverFillColor: "white", - hoverFillOpacity: 0.8, - strokeColor: "blue", - strokeOpacity: 1, - strokeWidth: 2, - strokeLinecap: "round", - strokeDashstyle: "solid", - hoverStrokeColor: "red", - hoverStrokeOpacity: 1, - hoverStrokeWidth: 0.2, - pointRadius: 6, - hoverPointRadius: 1, - hoverPointUnit: "%", - pointerEvents: "visiblePainted", - cursor: "pointer", - fontColor: "#000000", - labelAlign: "cm", - labelOutlineColor: "white", - labelOutlineWidth: 3 - - }, - 'temporary': { - fillColor: "#66cccc", - fillOpacity: 0.2, - hoverFillColor: "white", - hoverFillOpacity: 0.8, - strokeColor: "#66cccc", - strokeOpacity: 1, - strokeLinecap: "round", - strokeWidth: 2, - strokeDashstyle: "solid", - hoverStrokeColor: "red", - hoverStrokeOpacity: 1, - hoverStrokeWidth: 0.2, - pointRadius: 6, - hoverPointRadius: 1, - hoverPointUnit: "%", - pointerEvents: "visiblePainted", - cursor: "inherit", - fontColor: "#000000", - labelAlign: "cm", - labelOutlineColor: "white", - labelOutlineWidth: 3 - - }, - 'delete': { - display: "none" - } -}; -/* ====================================================================== - OpenLayers/Style.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/BaseTypes/Class.js - * @requires OpenLayers/Util.js - * @requires OpenLayers/Feature/Vector.js - */ - -/** - * Class: OpenLayers.Style - * This class represents a UserStyle obtained - * from a SLD, containing styling rules. - */ -OpenLayers.Style = OpenLayers.Class({ - - /** - * Property: id - * {String} A unique id for this session. - */ - id: null, - - /** - * APIProperty: name - * {String} - */ - name: null, - - /** - * Property: title - * {String} Title of this style (set if included in SLD) - */ - title: null, - - /** - * Property: description - * {String} Description of this style (set if abstract is included in SLD) - */ - description: null, - - /** - * APIProperty: layerName - * {} name of the layer that this style belongs to, usually - * according to the NamedLayer attribute of an SLD document. - */ - layerName: null, - - /** - * APIProperty: isDefault - * {Boolean} - */ - isDefault: false, - - /** - * Property: rules - * {Array()} - */ - rules: null, - - /** - * APIProperty: context - * {Object} An optional object with properties that symbolizers' property - * values should be evaluated against. If no context is specified, - * feature.attributes will be used - */ - context: null, - - /** - * Property: defaultStyle - * {Object} hash of style properties to use as default for merging - * rule-based style symbolizers onto. If no rules are defined, - * createSymbolizer will return this style. If is set to - * true, the defaultStyle will only be taken into account if there are - * rules defined. - */ - defaultStyle: null, - - /** - * Property: defaultsPerSymbolizer - * {Boolean} If set to true, the will extend the symbolizer - * of every rule. Properties of the will also be used to set - * missing symbolizer properties if the symbolizer has stroke, fill or - * graphic set to true. Default is false. - */ - defaultsPerSymbolizer: false, - - /** - * Property: propertyStyles - * {Hash of Boolean} cache of style properties that need to be parsed for - * propertyNames. Property names are keys, values won't be used. - */ - propertyStyles: null, - - - /** - * Constructor: OpenLayers.Style - * Creates a UserStyle. - * - * Parameters: - * style - {Object} Optional hash of style properties that will be - * used as default style for this style object. This style - * applies if no rules are specified. Symbolizers defined in - * rules will extend this default style. - * options - {Object} An optional object with properties to set on the - * style. - * - * Valid options: - * rules - {Array()} List of rules to be added to the - * style. - * - * Returns: - * {} - */ - initialize: function(style, options) { - - OpenLayers.Util.extend(this, options); - this.rules = []; - if(options && options.rules) { - this.addRules(options.rules); - } - - // use the default style from OpenLayers.Feature.Vector if no style - // was given in the constructor - this.setDefaultStyle(style || - OpenLayers.Feature.Vector.style["default"]); - - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); - }, - - /** - * APIMethod: destroy - * nullify references to prevent circular references and memory leaks - */ - destroy: function() { - for (var i=0, len=this.rules.length; i} feature to evaluate rules for - * - * Returns: - * {Object} symbolizer hash - */ - createSymbolizer: function(feature) { - var style = this.defaultsPerSymbolizer ? {} : this.createLiterals( - OpenLayers.Util.extend({}, this.defaultStyle), feature); - - var rules = this.rules; - - var rule, context; - var elseRules = []; - var appliedRules = false; - for(var i=0, len=rules.length; i 0) { - appliedRules = true; - for(var i=0, len=elseRules.length; i 0 && appliedRules == false) { - style.display = "none"; - } - - if (style.label != null && typeof style.label !== "string") { - style.label = String(style.label); - } - - return style; - }, - - /** - * Method: applySymbolizer - * - * Parameters: - * rule - {} - * style - {Object} - * feature - {} - * - * Returns: - * {Object} A style with new symbolizer applied. - */ - applySymbolizer: function(rule, style, feature) { - var symbolizerPrefix = feature.geometry ? - this.getSymbolizerPrefix(feature.geometry) : - OpenLayers.Style.SYMBOLIZER_PREFIXES[0]; - - var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer; - - if(this.defaultsPerSymbolizer === true) { - var defaults = this.defaultStyle; - OpenLayers.Util.applyDefaults(symbolizer, { - pointRadius: defaults.pointRadius - }); - if(symbolizer.stroke === true || symbolizer.graphic === true) { - OpenLayers.Util.applyDefaults(symbolizer, { - strokeWidth: defaults.strokeWidth, - strokeColor: defaults.strokeColor, - strokeOpacity: defaults.strokeOpacity, - strokeDashstyle: defaults.strokeDashstyle, - strokeLinecap: defaults.strokeLinecap - }); - } - if(symbolizer.fill === true || symbolizer.graphic === true) { - OpenLayers.Util.applyDefaults(symbolizer, { - fillColor: defaults.fillColor, - fillOpacity: defaults.fillOpacity - }); - } - if(symbolizer.graphic === true) { - OpenLayers.Util.applyDefaults(symbolizer, { - pointRadius: this.defaultStyle.pointRadius, - externalGraphic: this.defaultStyle.externalGraphic, - graphicName: this.defaultStyle.graphicName, - graphicOpacity: this.defaultStyle.graphicOpacity, - graphicWidth: this.defaultStyle.graphicWidth, - graphicHeight: this.defaultStyle.graphicHeight, - graphicXOffset: this.defaultStyle.graphicXOffset, - graphicYOffset: this.defaultStyle.graphicYOffset - }); - } - } - - // merge the style with the current style - return this.createLiterals( - OpenLayers.Util.extend(style, symbolizer), feature); - }, - - /** - * Method: createLiterals - * creates literals for all style properties that have an entry in - * . - * - * Parameters: - * style - {Object} style to create literals for. Will be modified - * inline. - * feature - {Object} - * - * Returns: - * {Object} the modified style - */ - createLiterals: function(style, feature) { - var context = OpenLayers.Util.extend({}, feature.attributes || feature.data); - OpenLayers.Util.extend(context, this.context); - - for (var i in this.propertyStyles) { - style[i] = OpenLayers.Style.createLiteral(style[i], context, feature, i); - } - return style; - }, - - /** - * Method: findPropertyStyles - * Looks into all rules for this style and the defaultStyle to collect - * all the style hash property names containing ${...} strings that have - * to be replaced using the createLiteral method before returning them. - * - * Returns: - * {Object} hash of property names that need createLiteral parsing. The - * name of the property is the key, and the value is true; - */ - findPropertyStyles: function() { - var propertyStyles = {}; - - // check the default style - var style = this.defaultStyle; - this.addPropertyStyles(propertyStyles, style); - - // walk through all rules to check for properties in their symbolizer - var rules = this.rules; - var symbolizer, value; - for (var i=0, len=rules.length; i)} - */ - addRules: function(rules) { - Array.prototype.push.apply(this.rules, rules); - this.propertyStyles = this.findPropertyStyles(); - }, - - /** - * APIMethod: setDefaultStyle - * Sets the default style for this style object. - * - * Parameters: - * style - {Object} Hash of style properties - */ - setDefaultStyle: function(style) { - this.defaultStyle = style; - this.propertyStyles = this.findPropertyStyles(); - }, - - /** - * Method: getSymbolizerPrefix - * Returns the correct symbolizer prefix according to the - * geometry type of the passed geometry - * - * Parameters: - * geometry - {} - * - * Returns: - * {String} key of the according symbolizer - */ - getSymbolizerPrefix: function(geometry) { - var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES; - for (var i=0, len=prefixes.length; i} Clone of this style. - */ - clone: function() { - var options = OpenLayers.Util.extend({}, this); - // clone rules - if(this.rules) { - options.rules = []; - for(var i=0, len=this.rules.length; i} optional feature to pass to - * for evaluating functions in the - * context. - * property - {String} optional, name of the property for which the literal is - * being created for evaluating functions in the context. - * - * Returns: - * {String} the parsed value. In the example of the value parameter above, the - * result would be "foo valueOfBar", assuming that the passed feature has an - * attribute named "bar" with the value "valueOfBar". - */ -OpenLayers.Style.createLiteral = function(value, context, feature, property) { - if (typeof value == "string" && value.indexOf("${") != -1) { - value = OpenLayers.String.format(value, context, [feature, property]); - value = (isNaN(value) || !value) ? value : parseFloat(value); - } - return value; -}; - -/** - * Constant: OpenLayers.Style.SYMBOLIZER_PREFIXES - * {Array} prefixes of the sld symbolizers. These are the - * same as the main geometry types - */ -OpenLayers.Style.SYMBOLIZER_PREFIXES = ['Point', 'Line', 'Polygon', 'Text', - 'Raster']; -/* ====================================================================== - OpenLayers/Filter.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/BaseTypes/Class.js - * @requires OpenLayers/Util.js - * @requires OpenLayers/Style.js - */ - -/** - * Class: OpenLayers.Filter - * This class represents an OGC Filter. - */ -OpenLayers.Filter = OpenLayers.Class({ - - /** - * Constructor: OpenLayers.Filter - * This class represents a generic filter. - * - * Parameters: - * options - {Object} Optional object whose properties will be set on the - * instance. - * - * Returns: - * {} - */ - initialize: function(options) { - OpenLayers.Util.extend(this, options); - }, - - /** - * APIMethod: destroy - * Remove reference to anything added. - */ - destroy: function() { - }, - - /** - * APIMethod: evaluate - * Evaluates this filter in a specific context. Instances or subclasses - * are supposed to override this method. - * - * Parameters: - * context - {Object} Context to use in evaluating the filter. If a vector - * feature is provided, the feature.attributes will be used as context. - * - * Returns: - * {Boolean} The filter applies. - */ - evaluate: function(context) { - return true; - }, - - /** - * APIMethod: clone - * Clones this filter. Should be implemented by subclasses. - * - * Returns: - * {} Clone of this filter. - */ - clone: function() { - return null; - }, - - /** - * APIMethod: toString - * - * Returns: - * {String} Include in your build to get a CQL - * representation of the filter returned. Otherwise "[Object object]" - * will be returned. - */ - toString: function() { - var string; - if (OpenLayers.Format && OpenLayers.Format.CQL) { - string = OpenLayers.Format.CQL.prototype.write(this); - } else { - string = Object.prototype.toString.call(this); - } - return string; - }, - - CLASS_NAME: "OpenLayers.Filter" -}); -/* ====================================================================== - OpenLayers/Filter/Spatial.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Filter.js - */ - -/** - * Class: OpenLayers.Filter.Spatial - * This class represents a spatial filter. - * Currently implemented: BBOX, DWithin and Intersects - * - * Inherits from: - * - - */ -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 - * { || } 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: - * {} - */ - - /** - * Method: evaluate - * Evaluates this filter for a specific feature. - * - * Parameters: - * feature - {} 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: - throw new Error('evaluate is not implemented for this filter type.'); - } - return intersect; - }, - - /** - * APIMethod: clone - * Clones this filter. - * - * Returns: - * {} 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/Filter/FeatureId.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/Filter.js - */ - -/** - * Class: OpenLayers.Filter.FeatureId - * This class represents a ogc:FeatureId Filter, as being used for rule-based SLD - * styling - * - * Inherits from: - * - - */ -OpenLayers.Filter.FeatureId = OpenLayers.Class(OpenLayers.Filter, { - - /** - * APIProperty: fids - * {Array(String)} Feature Ids to evaluate this rule against. - * To be passed inside the params object. - */ - fids: null, - - /** - * Property: type - * {String} Type to identify this filter. - */ - type: "FID", - - /** - * Constructor: OpenLayers.Filter.FeatureId - * Creates an ogc:FeatureId rule. - * - * Parameters: - * options - {Object} An optional object with properties to set on the - * rule - * - * Returns: - * {} - */ - initialize: function(options) { - this.fids = []; - OpenLayers.Filter.prototype.initialize.apply(this, [options]); - }, - - /** - * APIMethod: evaluate - * evaluates this rule for a specific feature - * - * Parameters: - * 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 - */ - evaluate: function(feature) { - for (var i=0, len=this.fids.length; i} 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/Format/WFST/v1.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Format/XML.js - * @requires OpenLayers/Format/WFST.js - * @requires OpenLayers/Filter/Spatial.js - * @requires OpenLayers/Filter/FeatureId.js - */ - -/** - * Class: OpenLayers.Format.WFST.v1 - * Superclass for WFST parsers. - * - * Inherits from: - * - - */ -OpenLayers.Format.WFST.v1 = OpenLayers.Class(OpenLayers.Format.XML, { - - /** - * Property: namespaces - * {Object} Mapping of namespace aliases to namespace URIs. - */ - 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", - ows: "http://www.opengis.net/ows" - }, - - /** - * Property: defaultPrefix - */ - defaultPrefix: "wfs", - - /** - * Property: version - * {String} WFS version number. - */ - version: null, - - /** - * Property: schemaLocation - * {String} Schema location for a particular minor version. - */ - schemaLocations: null, - - /** - * APIProperty: srsName - * {String} URI for spatial reference system. - */ - srsName: null, - - /** - * APIProperty: extractAttributes - * {Boolean} Extract attributes from GML. Default is true. - */ - extractAttributes: true, - - /** - * 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 - * or - * 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 { - srsName = this.srsName; - } - } - return srsName; - }, - - /** - * 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: - * 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: - * {Array | Object} Output depending on the output option. - */ - 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, true); - } - if(obj.features && options.output === "features") { - obj = obj.features; - } - return obj; - }, - - /** - * 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": { - "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()} A list of features. See - * below for a more detailed description of the influence of the - * feature's *modified* property. - * options - {Object} - * - * feature.modified rules: - * If a feature has a modified property set, the following checks will be - * made before a feature's geometry or attribute is included in an Update - * transaction: - * - *modified* is not set at all: The geometry and all attributes will be - * included. - * - *modified.geometry* is set (null or a geometry): The geometry will be - * included. If *modified.attributes* is not set, all attributes will - * be included. - * - *modified.attributes* is set: Only the attributes set (i.e. to null or - * a value) in *modified.attributes* will be included. - * If *modified.geometry* is not set, the geometry will not be included. - * - * Valid options include: - * - *multi* {Boolean} If set to true, geometries will be casted to - * Multi geometries before writing. - * - * Returns: - * {String} A serialized WFS transaction. - */ - write: function(features, options) { - var node = this.writeNode("wfs:Transaction", { - features:features, - options: options - }); - 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, - handle: options && options.handle, - 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} - */ - setFilterProperty: function(filter) { - if(filter.filters) { - for(var i=0, len=filter.filters.length; i - */ -OpenLayers.Format.OGCExceptionReport = OpenLayers.Class(OpenLayers.Format.XML, { - - /** - * Property: namespaces - * {Object} Mapping of namespace aliases to namespace URIs. - */ - namespaces: { - ogc: "http://www.opengis.net/ogc" - }, - - /** - * Property: regExes - * Compiled regular expressions for manipulating strings. - */ - regExes: { - trimSpace: (/^\s*|\s*$/g), - removeSpace: (/\s*/g), - splitSpace: (/\s+/), - trimComma: (/\s*,\s*/g) - }, - - /** - * Property: defaultPrefix - */ - defaultPrefix: "ogc", - - /** - * Constructor: OpenLayers.Format.OGCExceptionReport - * Create a new parser for OGC exception reports. - * - * Parameters: - * options - {Object} An optional object whose properties will be set on - * this instance. - */ - - /** - * APIMethod: read - * Read OGC exception report data from a string, and return an object with - * information about the exceptions. - * - * Parameters: - * data - {String} or {DOMElement} data to read/parse. - * - * Returns: - * {Object} Information about the exceptions that occurred. - */ - read: function(data) { - var result; - if(typeof data == "string") { - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); - } - var root = data.documentElement; - var exceptionInfo = {exceptionReport: null}; - if (root) { - this.readChildNodes(data, exceptionInfo); - if (exceptionInfo.exceptionReport === null) { - // fall-back to OWSCommon since this is a common output format for exceptions - // we cannot easily use the ows readers directly since they differ for 1.0 and 1.1 - exceptionInfo = new OpenLayers.Format.OWSCommon().read(data); - } - } - return exceptionInfo; - }, - - /** - * 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": { - "ServiceExceptionReport": function(node, obj) { - obj.exceptionReport = {exceptions: []}; - this.readChildNodes(node, obj.exceptionReport); - }, - "ServiceException": function(node, exceptionReport) { - var exception = { - code: node.getAttribute("code"), - locator: node.getAttribute("locator"), - text: this.getChildValue(node) - }; - exceptionReport.exceptions.push(exception); - } - } - }, - - CLASS_NAME: "OpenLayers.Format.OGCExceptionReport" - -}); -/* ====================================================================== - OpenLayers/Format/XML/VersionedOGC.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Format/XML.js - * @requires OpenLayers/Format/OGCExceptionReport.js - */ - -/** - * Class: OpenLayers.Format.XML.VersionedOGC - * Base class for versioned formats, i.e. a format which supports multiple - * versions. - * - * Inherits from: - * - - */ -OpenLayers.Format.XML.VersionedOGC = OpenLayers.Class(OpenLayers.Format.XML, { - - /** - * APIProperty: defaultVersion - * {String} Version number to assume if none found. - */ - defaultVersion: null, - - /** - * APIProperty: version - * {String} Specify a version string if one is known. - */ - version: null, - - /** - * APIProperty: profile - * {String} If provided, use a custom profile. - */ - profile: null, - - /** - * APIProperty: errorProperty - * {String} Which property of the returned object to check for in order to - * determine whether or not parsing has failed. In the case that the - * errorProperty is undefined on the returned object, the document will be - * run through an OGCExceptionReport parser. - */ - errorProperty: null, - - /** - * Property: name - * {String} The name of this parser, this is the part of the CLASS_NAME - * except for "OpenLayers.Format." - */ - name: null, - - /** - * APIProperty: stringifyOutput - * {Boolean} If true, write will return a string otherwise a DOMElement. - * Default is false. - */ - stringifyOutput: false, - - /** - * Property: parser - * {Object} Instance of the versioned parser. Cached for multiple read and - * write calls of the same version. - */ - parser: null, - - /** - * Constructor: OpenLayers.Format.XML.VersionedOGC. - * Constructor. - * - * Parameters: - * options - {Object} Optional object whose properties will be set on - * the object. - */ - initialize: function(options) { - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); - var className = this.CLASS_NAME; - this.name = className.substring(className.lastIndexOf(".")+1); - }, - - /** - * Method: getVersion - * Returns the version to use. Subclasses can override this function - * if a different version detection is needed. - * - * Parameters: - * root - {DOMElement} - * options - {Object} Optional configuration object. - * - * Returns: - * {String} The version to use. - */ - getVersion: function(root, options) { - var version; - // read - if (root) { - version = this.version; - if(!version) { - version = root.getAttribute("version"); - if(!version) { - version = this.defaultVersion; - } - } - } else { // write - version = (options && options.version) || - this.version || this.defaultVersion; - } - return version; - }, - - /** - * Method: getParser - * Get an instance of the cached parser if available, otherwise create one. - * - * Parameters: - * version - {String} - * - * Returns: - * {} - */ - getParser: function(version) { - version = version || this.defaultVersion; - var profile = this.profile ? "_" + this.profile : ""; - if(!this.parser || this.parser.VERSION != version) { - var format = OpenLayers.Format[this.name][ - "v" + version.replace(/\./g, "_") + profile - ]; - if(!format) { - throw "Can't find a " + this.name + " parser for version " + - version + profile; - } - this.parser = new format(this.options); - } - return this.parser; - }, - - /** - * APIMethod: write - * Write a document. - * - * Parameters: - * obj - {Object} An object representing the document. - * options - {Object} Optional configuration object. - * - * Returns: - * {String} The document as a string - */ - write: function(obj, options) { - var version = this.getVersion(null, options); - this.parser = this.getParser(version); - var root = this.parser.write(obj, options); - if (this.stringifyOutput === false) { - return root; - } else { - return OpenLayers.Format.XML.prototype.write.apply(this, [root]); - } - }, - - /** - * APIMethod: read - * Read a doc and return an object representing the document. - * - * Parameters: - * data - {String | DOMElement} Data to read. - * options - {Object} Options for the reader. - * - * Returns: - * {Object} An object representing the document. - */ - read: function(data, options) { - if(typeof data == "string") { - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); - } - var root = data.documentElement; - var version = this.getVersion(root); - this.parser = this.getParser(version); - var obj = this.parser.read(data, options); - if (this.errorProperty !== null && obj[this.errorProperty] === undefined) { - // an error must have happened, so parse it and report back - var format = new OpenLayers.Format.OGCExceptionReport(); - obj.error = format.read(data); - } - obj.version = version; - return obj; - }, - - CLASS_NAME: "OpenLayers.Format.XML.VersionedOGC" -}); -/* ====================================================================== - OpenLayers/Filter/Logical.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/Filter.js - */ - -/** - * Class: OpenLayers.Filter.Logical - * This class represents ogc:And, ogc:Or and ogc:Not rules. - * - * Inherits from: - * - - */ -OpenLayers.Filter.Logical = OpenLayers.Class(OpenLayers.Filter, { - - /** - * APIProperty: filters - * {Array()} 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). - * - * Parameters: - * options - {Object} An optional object with properties to set on the - * filter. - * - * Returns: - * {} - */ - 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); - }, - - /** - * 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) { - var i, len; - switch(this.type) { - case OpenLayers.Filter.Logical.AND: - for (i=0, len=this.filters.length; i} Clone of this filter. - */ - clone: function() { - var filters = []; - for(var i=0, len=this.filters.length; i - */ -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. - * - * Parameters: - * options - {Object} An optional object with properties to set on the - * rule - * - * Returns: - * {} - */ - initialize: function(options) { - OpenLayers.Filter.prototype.initialize.apply(this, [options]); - // since matchCase on PropertyIsLike is not schema compliant, we only - // want to use this if explicitly asked for - if (this.type === OpenLayers.Filter.Comparison.LIKE - && options.matchCase === undefined) { - this.matchCase = null; - } - }, - - /** - * 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]; - 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; - } - 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 "." - * escapeChar - {Char} escape character in the above value, default is - * "!" - * - * Returns: - * {String} regular expression string - */ - value2regex: function(wildCard, singleChar, escapeChar) { - if (wildCard == ".") { - throw new Error("'.' is an unsupported wildCard character for " + - "OpenLayers.Filter.Comparison"); - } - - - // 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 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: - * {} 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/Format/Filter.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Format/XML/VersionedOGC.js - * @requires OpenLayers/Filter/FeatureId.js - * @requires OpenLayers/Filter/Logical.js - * @requires OpenLayers/Filter/Comparison.js - */ - -/** - * Class: OpenLayers.Format.Filter - * Read/Write ogc:Filter. Create a new instance with the - * constructor. - * - * Inherits from: - * - - */ -OpenLayers.Format.Filter = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { - - /** - * APIProperty: defaultVersion - * {String} Version number to assume if none found. Default is "1.0.0". - */ - defaultVersion: "1.0.0", - - /** - * APIMethod: write - * Write an ogc:Filter given a filter object. - * - * Parameters: - * filter - {} An filter. - * options - {Object} Optional configuration object. - * - * Returns: - * {Elment} An ogc:Filter element node. - */ - - /** - * APIMethod: read - * Read and Filter doc and return an object representing the Filter. - * - * Parameters: - * data - {String | DOMElement} Data to read. - * - * Returns: - * {} A filter object. - */ - - CLASS_NAME: "OpenLayers.Format.Filter" -}); -/* ====================================================================== - OpenLayers/Filter/Function.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Filter.js - */ - -/** - * Class: OpenLayers.Filter.Function - * This class represents a filter function. - * We are using this class for creation of complex - * filters that can contain filter functions as values. - * Nesting function as other functions parameter is supported. - * - * Inherits from: - * - - */ -OpenLayers.Filter.Function = OpenLayers.Class(OpenLayers.Filter, { - - /** - * APIProperty: name - * {String} Name of the function. - */ - name: null, - - /** - * APIProperty: params - * {Array( || String || Number)} Function parameters - * For now support only other Functions, String or Number - */ - params: null, - - /** - * Constructor: OpenLayers.Filter.Function - * Creates a filter function. - * - * Parameters: - * options - {Object} An optional object with properties to set on the - * function. - * - * Returns: - * {} - */ - - CLASS_NAME: "OpenLayers.Filter.Function" -}); - -/* ====================================================================== - OpenLayers/Format/Filter/v1.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ -/** - * @requires OpenLayers/Format/Filter.js - * @requires OpenLayers/Format/XML.js - * @requires OpenLayers/Filter/Function.js - */ - -/** - * Class: OpenLayers.Format.Filter.v1 - * Superclass for Filter version 1 parsers. - * - * Inherits from: - * - - */ -OpenLayers.Format.Filter.v1 = OpenLayers.Class(OpenLayers.Format.XML, { - - /** - * Property: namespaces - * {Object} Mapping of namespace aliases to namespace URIs. - */ - 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", - - /** - * 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 - * constructor instead. - * - * 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]); - }, - - /** - * Method: read - * - * Parameters: - * data - {DOMElement} A Filter document element. - * - * Returns: - * {} A filter object. - */ - read: function(data) { - var obj = {}; - this.readers.ogc["Filter"].apply(this, [data, obj]); - return obj.filter; - }, - - /** - * 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": { - "_expression": function(node) { - // only the simplest of ogc:expression handled - // "some text and an attribute"} - var obj, value = ""; - for(var child=node.firstChild; child; child=child.nextSibling) { - switch(child.nodeType) { - case 1: - obj = this.readNode(child); - if (obj.property) { - value += "${" + obj.property + "}"; - } else if (obj.value !== undefined) { - value += obj.value; - } - break; - case 3: // text node - case 4: // cdata section - value += child.nodeValue; - } - } - return value; - }, - "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), true); - }, - "PropertyName": function(node, filter) { - filter.property = this.getChildValue(node); - }, - "LowerBoundary": function(node, filter) { - filter.lowerBoundary = OpenLayers.String.numericIf( - this.readers.ogc._expression.call(this, node), true); - }, - "UpperBoundary": function(node, filter) { - filter.upperBoundary = OpenLayers.String.numericIf( - this.readers.ogc._expression.call(this, node), true); - }, - "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"); - }, - "Function": function(node, obj) { - //TODO write decoder for it - return; - } - } - }, - - /** - * Method: readSpatial - * - * Read a {} 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: - * {} 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: writeOgcExpression - * Limited support for writing OGC expressions. Currently it supports - * ( || String || Number) - * - * Parameters: - * value - ( || String || Number) - * node - {DOMElement} A parent DOM element - * - * Returns: - * {DOMElement} Updated node element. - */ - writeOgcExpression: function(value, node) { - if(value instanceof OpenLayers.Filter.Function){ - var child = this.writeNode("Function", value, node); - node.appendChild(child); - } else { - this.writeNode("Literal", value, node); - } - return node; - }, - - /** - * Method: write - * - * Parameters: - * filter - {} A filter object. - * - * Returns: - * {DOMElement} An ogc:Filter element. - */ - write: function(filter) { - return this.writers.ogc["Filter"].apply(this, [filter]); - }, - - /** - * Method: writeFeatureIdNodes - * - * Parameters: - * filter - {": "PropertyIsGreaterThan", - "<=": "PropertyIsLessThanOrEqualTo", - ">=": "PropertyIsGreaterThanOrEqualTo", - "..": "PropertyIsBetween", - "~": "PropertyIsLike", - "BBOX": "BBOX", - "DWITHIN": "DWITHIN", - "WITHIN": "WITHIN", - "CONTAINS": "CONTAINS", - "INTERSECTS": "INTERSECTS", - "FID": "FeatureId" - }, - - CLASS_NAME: "OpenLayers.Format.Filter.v1" - -}); -/* ====================================================================== - OpenLayers/Geometry.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/BaseTypes/Class.js - */ - -/** - * Class: OpenLayers.Geometry - * A Geometry is a description of a geographic object. Create an instance of - * this class with the constructor. This is a base class, - * typical geometry types are described by subclasses of this class. - * - * Note that if you use the method, you must - * explicitly include the OpenLayers.Format.WKT in your build. - */ -OpenLayers.Geometry = OpenLayers.Class({ - - /** - * Property: id - * {String} A unique identifier for this geometry. - */ - id: null, - - /** - * Property: parent - * {}This is set when a Geometry is added as component - * of another geometry - */ - parent: null, - - /** - * Property: bounds - * {} The bounds of this geometry - */ - bounds: null, - - /** - * Constructor: OpenLayers.Geometry - * Creates a geometry object. - */ - initialize: function() { - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME+ "_"); - }, - - /** - * Method: destroy - * Destroy this geometry. - */ - destroy: function() { - this.id = null; - this.bounds = null; - }, - - /** - * APIMethod: clone - * Create a clone of this geometry. Does not set any non-standard - * properties of the cloned geometry. - * - * Returns: - * {} An exact clone of this geometry. - */ - clone: function() { - return new OpenLayers.Geometry(); - }, - - /** - * Method: setBounds - * Set the bounds for this Geometry. - * - * Parameters: - * bounds - {} - */ - setBounds: function(bounds) { - if (bounds) { - this.bounds = bounds.clone(); - } - }, - - /** - * Method: clearBounds - * Nullify this components bounds and that of its parent as well. - */ - clearBounds: function() { - this.bounds = null; - if (this.parent) { - this.parent.clearBounds(); - } - }, - - /** - * Method: extendBounds - * Extend the existing bounds to include the new bounds. - * If geometry's bounds is not yet set, then set a new Bounds. - * - * Parameters: - * newBounds - {} - */ - extendBounds: function(newBounds){ - var bounds = this.getBounds(); - if (!bounds) { - this.setBounds(newBounds); - } else { - this.bounds.extend(newBounds); - } - }, - - /** - * APIMethod: getBounds - * Get the bounds for this Geometry. If bounds is not set, it - * is calculated again, this makes queries faster. - * - * Returns: - * {} - */ - getBounds: function() { - if (this.bounds == null) { - this.calculateBounds(); - } - return this.bounds; - }, - - /** - * APIMethod: calculateBounds - * Recalculate the bounds for the geometry. - */ - calculateBounds: function() { - // - // This should be overridden by subclasses. - // - }, - - /** - * APIMethod: distanceTo - * Calculate the closest distance between two geometries (on the x-y plane). - * - * Parameters: - * geometry - {} The target geometry. - * options - {Object} Optional properties for configuring the distance - * calculation. - * - * Valid options depend on the specific geometry type. - * - * Returns: - * {Number | Object} The distance between this geometry and the target. - * If details is true, the return will be an object with distance, - * x0, y0, x1, and x2 properties. The x0 and y0 properties represent - * the coordinates of the closest point on this geometry. The x1 and y1 - * properties represent the coordinates of the closest point on the - * target geometry. - */ - distanceTo: function(geometry, options) { - }, - - /** - * APIMethod: getVertices - * Return a list of all points in this geometry. - * - * Parameters: - * nodes - {Boolean} For lines, only return vertices that are - * endpoints. If false, for lines, only vertices that are not - * endpoints will be returned. If not provided, all vertices will - * be returned. - * - * Returns: - * {Array} A list of all vertices in the geometry. - */ - getVertices: function(nodes) { - }, - - /** - * Method: atPoint - * Note - This is only an approximation based on the bounds of the - * geometry. - * - * Parameters: - * lonlat - {|Object} OpenLayers.LonLat or an - * object with a 'lon' and 'lat' properties. - * toleranceLon - {float} Optional tolerance in Geometric Coords - * toleranceLat - {float} Optional tolerance in Geographic Coords - * - * Returns: - * {Boolean} Whether or not the geometry is at the specified location - */ - atPoint: function(lonlat, toleranceLon, toleranceLat) { - var atPoint = false; - var bounds = this.getBounds(); - if ((bounds != null) && (lonlat != null)) { - - var dX = (toleranceLon != null) ? toleranceLon : 0; - var dY = (toleranceLat != null) ? toleranceLat : 0; - - var toleranceBounds = - new OpenLayers.Bounds(this.bounds.left - dX, - this.bounds.bottom - dY, - this.bounds.right + dX, - this.bounds.top + dY); - - atPoint = toleranceBounds.containsLonLat(lonlat); - } - return atPoint; - }, - - /** - * Method: getLength - * Calculate the length of this geometry. This method is defined in - * subclasses. - * - * Returns: - * {Float} The length of the collection by summing its parts - */ - getLength: function() { - //to be overridden by geometries that actually have a length - // - return 0.0; - }, - - /** - * Method: getArea - * Calculate the area of this geometry. This method is defined in subclasses. - * - * Returns: - * {Float} The area of the collection by summing its parts - */ - getArea: function() { - //to be overridden by geometries that actually have an area - // - return 0.0; - }, - - /** - * APIMethod: getCentroid - * Calculate the centroid of this geometry. This method is defined in subclasses. - * - * Returns: - * {} The centroid of the collection - */ - getCentroid: function() { - return null; - }, - - /** - * Method: toString - * Returns a text representation of the geometry. If the WKT format is - * included in a build, this will be the Well-Known Text - * representation. - * - * Returns: - * {String} String representation of this geometry. - */ - toString: function() { - var string; - if (OpenLayers.Format && OpenLayers.Format.WKT) { - string = OpenLayers.Format.WKT.prototype.write( - new OpenLayers.Feature.Vector(this) - ); - } else { - string = Object.prototype.toString.call(this); - } - return string; - }, - - CLASS_NAME: "OpenLayers.Geometry" -}); - -/** - * Function: OpenLayers.Geometry.fromWKT - * Generate a geometry given a Well-Known Text string. For this method to - * work, you must include the OpenLayers.Format.WKT in your build - * explicitly. - * - * Parameters: - * wkt - {String} A string representing the geometry in Well-Known Text. - * - * Returns: - * {} A geometry of the appropriate class. - */ -OpenLayers.Geometry.fromWKT = function(wkt) { - var geom; - if (OpenLayers.Format && OpenLayers.Format.WKT) { - var format = OpenLayers.Geometry.fromWKT.format; - if (!format) { - format = new OpenLayers.Format.WKT(); - OpenLayers.Geometry.fromWKT.format = format; - } - var result = format.read(wkt); - if (result instanceof OpenLayers.Feature.Vector) { - geom = result.geometry; - } else if (OpenLayers.Util.isArray(result)) { - var len = result.length; - var components = new Array(len); - for (var i=0; i= seg2.x1 || seg2.x2 >= seg1.x1. In those - * obvious cases where there is no intersection, the function should - * not be called. - * - * Parameters: - * seg1 - {Object} Object representing a segment with properties x1, y1, x2, - * and y2. The start point is represented by x1 and y1. The end point - * is represented by x2 and y2. Start and end are ordered so that x1 < x2. - * seg2 - {Object} Object representing a segment with properties x1, y1, x2, - * and y2. The start point is represented by x1 and y1. The end point - * is represented by x2 and y2. Start and end are ordered so that x1 < x2. - * options - {Object} Optional properties for calculating the intersection. - * - * Valid options: - * point - {Boolean} Return the intersection point. If false, the actual - * intersection point will not be calculated. If true and the segments - * intersect, the intersection point will be returned. If true and - * the segments do not intersect, false will be returned. If true and - * the segments are coincident, true will be returned. - * tolerance - {Number} If a non-null value is provided, if the segments are - * within the tolerance distance, this will be considered an intersection. - * In addition, if the point option is true and the calculated intersection - * is within the tolerance distance of an end point, the endpoint will be - * returned instead of the calculated intersection. Further, if the - * intersection is within the tolerance of endpoints on both segments, or - * if two segment endpoints are within the tolerance distance of eachother - * (but no intersection is otherwise calculated), an endpoint on the - * first segment provided will be returned. - * - * Returns: - * {Boolean | } The two segments intersect. - * If the point argument is true, the return will be the intersection - * point or false if none exists. If point is true and the segments - * are coincident, return will be true (and the instersection is equal - * to the shorter segment). - */ -OpenLayers.Geometry.segmentsIntersect = function(seg1, seg2, options) { - var point = options && options.point; - var tolerance = options && options.tolerance; - var intersection = false; - var x11_21 = seg1.x1 - seg2.x1; - var y11_21 = seg1.y1 - seg2.y1; - var x12_11 = seg1.x2 - seg1.x1; - var y12_11 = seg1.y2 - seg1.y1; - var y22_21 = seg2.y2 - seg2.y1; - var x22_21 = seg2.x2 - seg2.x1; - var d = (y22_21 * x12_11) - (x22_21 * y12_11); - var n1 = (x22_21 * y11_21) - (y22_21 * x11_21); - var n2 = (x12_11 * y11_21) - (y12_11 * x11_21); - if(d == 0) { - // parallel - if(n1 == 0 && n2 == 0) { - // coincident - intersection = true; - } - } else { - var along1 = n1 / d; - var along2 = n2 / d; - if(along1 >= 0 && along1 <= 1 && along2 >=0 && along2 <= 1) { - // intersect - if(!point) { - intersection = true; - } else { - // calculate the intersection point - var x = seg1.x1 + (along1 * x12_11); - var y = seg1.y1 + (along1 * y12_11); - intersection = new OpenLayers.Geometry.Point(x, y); - } - } - } - if(tolerance) { - var dist; - if(intersection) { - if(point) { - var segs = [seg1, seg2]; - var seg, x, y; - // check segment endpoints for proximity to intersection - // set intersection to first endpoint within the tolerance - outer: for(var i=0; i<2; ++i) { - seg = segs[i]; - for(var j=1; j<3; ++j) { - x = seg["x" + j]; - y = seg["y" + j]; - dist = Math.sqrt( - Math.pow(x - intersection.x, 2) + - Math.pow(y - intersection.y, 2) - ); - if(dist < tolerance) { - intersection.x = x; - intersection.y = y; - break outer; - } - } - } - - } - } else { - // no calculated intersection, but segments could be within - // the tolerance of one another - var segs = [seg1, seg2]; - var source, target, x, y, p, result; - // check segment endpoints for proximity to intersection - // set intersection to first endpoint within the tolerance - outer: for(var i=0; i<2; ++i) { - source = segs[i]; - target = segs[(i+1)%2]; - for(var j=1; j<3; ++j) { - p = {x: source["x"+j], y: source["y"+j]}; - result = OpenLayers.Geometry.distanceToSegment(p, target); - if(result.distance < tolerance) { - if(point) { - intersection = new OpenLayers.Geometry.Point(p.x, p.y); - } else { - intersection = true; - } - break outer; - } - } - } - } - } - return intersection; -}; - -/** - * Function: OpenLayers.Geometry.distanceToSegment - * - * Parameters: - * point - {Object} An object with x and y properties representing the - * point coordinates. - * segment - {Object} An object with x1, y1, x2, and y2 properties - * representing endpoint coordinates. - * - * Returns: - * {Object} An object with distance, x, and y properties. The distance - * will be the shortest distance between the input point and segment. - * The x and y properties represent the coordinates along the segment - * where the shortest distance meets the segment. - */ -OpenLayers.Geometry.distanceToSegment = function(point, segment) { - var x0 = point.x; - var y0 = point.y; - var x1 = segment.x1; - var y1 = segment.y1; - var x2 = segment.x2; - var y2 = segment.y2; - var dx = x2 - x1; - var dy = y2 - y1; - var along = ((dx * (x0 - x1)) + (dy * (y0 - y1))) / - (Math.pow(dx, 2) + Math.pow(dy, 2)); - var x, y; - if(along <= 0.0) { - x = x1; - y = y1; - } else if(along >= 1.0) { - x = x2; - y = y2; - } else { - x = x1 + along * dx; - y = y1 + along * dy; - } - return { - distance: Math.sqrt(Math.pow(x - x0, 2) + Math.pow(y - y0, 2)), - x: x, y: y - }; -}; -/* ====================================================================== - OpenLayers/Geometry/Point.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Geometry.js - */ - -/** - * Class: OpenLayers.Geometry.Point - * Point geometry class. - * - * Inherits from: - * - - */ -OpenLayers.Geometry.Point = OpenLayers.Class(OpenLayers.Geometry, { - - /** - * APIProperty: x - * {float} - */ - x: null, - - /** - * APIProperty: y - * {float} - */ - y: null, - - /** - * Constructor: OpenLayers.Geometry.Point - * Construct a point geometry. - * - * Parameters: - * x - {float} - * y - {float} - * - */ - initialize: function(x, y) { - OpenLayers.Geometry.prototype.initialize.apply(this, arguments); - - this.x = parseFloat(x); - this.y = parseFloat(y); - }, - - /** - * APIMethod: clone - * - * Returns: - * {} An exact clone of this OpenLayers.Geometry.Point - */ - clone: function(obj) { - if (obj == null) { - obj = new OpenLayers.Geometry.Point(this.x, this.y); - } - - // catch any randomly tagged-on properties - OpenLayers.Util.applyDefaults(obj, this); - - return obj; - }, - - /** - * Method: calculateBounds - * Create a new Bounds based on the lon/lat - */ - calculateBounds: function () { - this.bounds = new OpenLayers.Bounds(this.x, this.y, - this.x, this.y); - }, - - /** - * APIMethod: distanceTo - * Calculate the closest distance between two geometries (on the x-y plane). - * - * Parameters: - * geometry - {} The target geometry. - * options - {Object} Optional properties for configuring the distance - * calculation. - * - * Valid options: - * details - {Boolean} Return details from the distance calculation. - * Default is false. - * edge - {Boolean} Calculate the distance from this geometry to the - * nearest edge of the target geometry. Default is true. If true, - * calling distanceTo from a geometry that is wholly contained within - * the target will result in a non-zero distance. If false, whenever - * geometries intersect, calling distanceTo will return 0. If false, - * details cannot be returned. - * - * Returns: - * {Number | Object} The distance between this geometry and the target. - * If details is true, the return will be an object with distance, - * x0, y0, x1, and x2 properties. The x0 and y0 properties represent - * the coordinates of the closest point on this geometry. The x1 and y1 - * properties represent the coordinates of the closest point on the - * target geometry. - */ - distanceTo: function(geometry, options) { - var edge = !(options && options.edge === false); - var details = edge && options && options.details; - var distance, x0, y0, x1, y1, result; - if(geometry instanceof OpenLayers.Geometry.Point) { - x0 = this.x; - y0 = this.y; - x1 = geometry.x; - y1 = geometry.y; - distance = Math.sqrt(Math.pow(x0 - x1, 2) + Math.pow(y0 - y1, 2)); - result = !details ? - distance : {x0: x0, y0: y0, x1: x1, y1: y1, distance: distance}; - } else { - result = geometry.distanceTo(this, options); - if(details) { - // switch coord order since this geom is target - result = { - x0: result.x1, y0: result.y1, - x1: result.x0, y1: result.y0, - distance: result.distance - }; - } - } - return result; - }, - - /** - * APIMethod: equals - * Determine whether another geometry is equivalent to this one. Geometries - * are considered equivalent if all components have the same coordinates. - * - * Parameters: - * geom - {} The geometry to test. - * - * Returns: - * {Boolean} The supplied geometry is equivalent to this geometry. - */ - equals: function(geom) { - var equals = false; - if (geom != null) { - equals = ((this.x == geom.x && this.y == geom.y) || - (isNaN(this.x) && isNaN(this.y) && isNaN(geom.x) && isNaN(geom.y))); - } - return equals; - }, - - /** - * Method: toShortString - * - * Returns: - * {String} Shortened String representation of Point object. - * (ex. "5, 42") - */ - toShortString: function() { - return (this.x + ", " + this.y); - }, - - /** - * APIMethod: move - * Moves a geometry by the given displacement along positive x and y axes. - * This modifies the position of the geometry and clears the cached - * bounds. - * - * Parameters: - * x - {Float} Distance to move geometry in positive x direction. - * y - {Float} Distance to move geometry in positive y direction. - */ - move: function(x, y) { - this.x = this.x + x; - this.y = this.y + y; - this.clearBounds(); - }, - - /** - * APIMethod: rotate - * Rotate a point around another. - * - * Parameters: - * angle - {Float} Rotation angle in degrees (measured counterclockwise - * from the positive x-axis) - * origin - {} Center point for the rotation - */ - rotate: function(angle, origin) { - angle *= Math.PI / 180; - var radius = this.distanceTo(origin); - var theta = angle + Math.atan2(this.y - origin.y, this.x - origin.x); - this.x = origin.x + (radius * Math.cos(theta)); - this.y = origin.y + (radius * Math.sin(theta)); - this.clearBounds(); - }, - - /** - * APIMethod: getCentroid - * - * Returns: - * {} The centroid of the collection - */ - getCentroid: function() { - return new OpenLayers.Geometry.Point(this.x, this.y); - }, - - /** - * APIMethod: resize - * Resize a point relative to some origin. For points, this has the effect - * of scaling a vector (from the origin to the point). This method is - * more useful on geometry collection subclasses. - * - * Parameters: - * scale - {Float} Ratio of the new distance from the origin to the old - * distance from the origin. A scale of 2 doubles the - * distance between the point and origin. - * origin - {} Point of origin for resizing - * ratio - {Float} Optional x:y ratio for resizing. Default ratio is 1. - * - * Returns: - * {} - The current geometry. - */ - resize: function(scale, origin, ratio) { - ratio = (ratio == undefined) ? 1 : ratio; - this.x = origin.x + (scale * ratio * (this.x - origin.x)); - this.y = origin.y + (scale * (this.y - origin.y)); - this.clearBounds(); - return this; - }, - - /** - * APIMethod: intersects - * Determine if the input geometry intersects this one. - * - * Parameters: - * geometry - {} Any type of geometry. - * - * Returns: - * {Boolean} The input geometry intersects this one. - */ - intersects: function(geometry) { - var intersect = false; - if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { - intersect = this.equals(geometry); - } else { - intersect = geometry.intersects(this); - } - return intersect; - }, - - /** - * APIMethod: transform - * Translate the x,y properties of the point from source to dest. - * - * Parameters: - * source - {} - * dest - {} - * - * Returns: - * {} - */ - transform: function(source, dest) { - if ((source && dest)) { - OpenLayers.Projection.transform( - this, source, dest); - this.bounds = null; - } - return this; - }, - - /** - * APIMethod: getVertices - * Return a list of all points in this geometry. - * - * Parameters: - * nodes - {Boolean} For lines, only return vertices that are - * endpoints. If false, for lines, only vertices that are not - * endpoints will be returned. If not provided, all vertices will - * be returned. - * - * Returns: - * {Array} A list of all vertices in the geometry. - */ - getVertices: function(nodes) { - return [this]; - }, - - CLASS_NAME: "OpenLayers.Geometry.Point" -}); -/* ====================================================================== - OpenLayers/Geometry/Collection.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Geometry.js - */ - -/** - * Class: OpenLayers.Geometry.Collection - * A Collection is exactly what it sounds like: A collection of different - * Geometries. These are stored in the local parameter (which - * can be passed as a parameter to the constructor). - * - * As new geometries are added to the collection, they are NOT cloned. - * When removing geometries, they need to be specified by reference (ie you - * have to pass in the *exact* geometry to be removed). - * - * The and functions here merely iterate through - * the components, summing their respective areas and lengths. - * - * Create a new instance with the constructor. - * - * Inherits from: - * - - */ -OpenLayers.Geometry.Collection = OpenLayers.Class(OpenLayers.Geometry, { - - /** - * APIProperty: components - * {Array()} The component parts of this geometry - */ - components: null, - - /** - * Property: componentTypes - * {Array(String)} An array of class names representing the types of - * components that the collection can include. A null value means the - * component types are not restricted. - */ - componentTypes: null, - - /** - * Constructor: OpenLayers.Geometry.Collection - * Creates a Geometry Collection -- a list of geoms. - * - * Parameters: - * components - {Array()} Optional array of geometries - * - */ - initialize: function (components) { - OpenLayers.Geometry.prototype.initialize.apply(this, arguments); - this.components = []; - if (components != null) { - this.addComponents(components); - } - }, - - /** - * APIMethod: destroy - * Destroy this geometry. - */ - destroy: function () { - this.components.length = 0; - this.components = null; - OpenLayers.Geometry.prototype.destroy.apply(this, arguments); - }, - - /** - * APIMethod: clone - * Clone this geometry. - * - * Returns: - * {} An exact clone of this collection - */ - clone: function() { - var geometry = eval("new " + this.CLASS_NAME + "()"); - for(var i=0, len=this.components.length; i)} An array of geometries to add - */ - addComponents: function(components){ - if(!(OpenLayers.Util.isArray(components))) { - components = [components]; - } - for(var i=0, len=components.length; i} A geometry to add - * index - {int} Optional index into the array to insert the component - * - * Returns: - * {Boolean} The component geometry was successfully added - */ - addComponent: function(component, index) { - var added = false; - if(component) { - if(this.componentTypes == null || - (OpenLayers.Util.indexOf(this.componentTypes, - component.CLASS_NAME) > -1)) { - - if(index != null && (index < this.components.length)) { - var components1 = this.components.slice(0, index); - var components2 = this.components.slice(index, - this.components.length); - components1.push(component); - this.components = components1.concat(components2); - } else { - this.components.push(component); - } - component.parent = this; - this.clearBounds(); - added = true; - } - } - return added; - }, - - /** - * APIMethod: removeComponents - * Remove components from this geometry. - * - * Parameters: - * components - {Array()} The components to be removed - * - * Returns: - * {Boolean} A component was removed. - */ - removeComponents: function(components) { - var removed = false; - - if(!(OpenLayers.Util.isArray(components))) { - components = [components]; - } - for(var i=components.length-1; i>=0; --i) { - removed = this.removeComponent(components[i]) || removed; - } - return removed; - }, - - /** - * Method: removeComponent - * Remove a component from this geometry. - * - * Parameters: - * component - {} - * - * Returns: - * {Boolean} The component was removed. - */ - removeComponent: function(component) { - - OpenLayers.Util.removeItem(this.components, component); - - // clearBounds() so that it gets recalculated on the next call - // to this.getBounds(); - this.clearBounds(); - return true; - }, - - /** - * APIMethod: getLength - * Calculate the length of this geometry - * - * Returns: - * {Float} The length of the geometry - */ - getLength: function() { - var length = 0.0; - for (var i=0, len=this.components.length; i. - * - * Returns: - * {Float} The area of the collection by summing its parts - */ - getArea: function() { - var area = 0.0; - for (var i=0, len=this.components.length; i} The spatial reference system - * for the geometry coordinates. If not provided, Geographic/WGS84 is - * assumed. - * - * Reference: - * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for - * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion - * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409 - * - * Returns: - * {float} The approximate geodesic area of the geometry in square meters. - */ - getGeodesicArea: function(projection) { - var area = 0.0; - for(var i=0, len=this.components.length; i} The centroid of the collection - */ - getCentroid: function(weighted) { - if (!weighted) { - return this.components.length && this.components[0].getCentroid(); - } - var len = this.components.length; - if (!len) { - return false; - } - - var areas = []; - var centroids = []; - var areaSum = 0; - var minArea = Number.MAX_VALUE; - var component; - for (var i=0; i 0) ? area : minArea; - centroids.push(centroid); - } - len = areas.length; - if (areaSum === 0) { - // all the components in this collection have 0 area - // probably a collection of points -- weight all the points the same - for (var i=0; i} The spatial reference system - * for the geometry coordinates. If not provided, Geographic/WGS84 is - * assumed. - * - * Returns: - * {Float} The appoximate geodesic length of the geometry in meters. - */ - getGeodesicLength: function(projection) { - var length = 0.0; - for(var i=0, len=this.components.length; i} Center point for the rotation - */ - rotate: function(angle, origin) { - for(var i=0, len=this.components.length; i} Point of origin for resizing - * ratio - {Float} Optional x:y ratio for resizing. Default ratio is 1. - * - * Returns: - * {} - The current geometry. - */ - resize: function(scale, origin, ratio) { - for(var i=0; i} The target geometry. - * options - {Object} Optional properties for configuring the distance - * calculation. - * - * Valid options: - * details - {Boolean} Return details from the distance calculation. - * Default is false. - * edge - {Boolean} Calculate the distance from this geometry to the - * nearest edge of the target geometry. Default is true. If true, - * calling distanceTo from a geometry that is wholly contained within - * the target will result in a non-zero distance. If false, whenever - * geometries intersect, calling distanceTo will return 0. If false, - * details cannot be returned. - * - * Returns: - * {Number | Object} The distance between this geometry and the target. - * If details is true, the return will be an object with distance, - * x0, y0, x1, and y1 properties. The x0 and y0 properties represent - * the coordinates of the closest point on this geometry. The x1 and y1 - * properties represent the coordinates of the closest point on the - * target geometry. - */ - distanceTo: function(geometry, options) { - var edge = !(options && options.edge === false); - var details = edge && options && options.details; - var result, best, distance; - var min = Number.POSITIVE_INFINITY; - for(var i=0, len=this.components.length; i} The geometry to test. - * - * Returns: - * {Boolean} The supplied geometry is equivalent to this geometry. - */ - equals: function(geometry) { - var equivalent = true; - if(!geometry || !geometry.CLASS_NAME || - (this.CLASS_NAME != geometry.CLASS_NAME)) { - equivalent = false; - } else if(!(OpenLayers.Util.isArray(geometry.components)) || - (geometry.components.length != this.components.length)) { - equivalent = false; - } else { - for(var i=0, len=this.components.length; i} - * dest - {} - * - * Returns: - * {} - */ - transform: function(source, dest) { - if (source && dest) { - for (var i=0, len=this.components.length; i} Any type of geometry. - * - * Returns: - * {Boolean} The input geometry intersects this one. - */ - intersects: function(geometry) { - var intersect = false; - for(var i=0, len=this.components.length; i constructor. - * - * Inherits from: - * - - * - - */ -OpenLayers.Geometry.MultiPoint = OpenLayers.Class( - OpenLayers.Geometry.Collection, { - - /** - * Property: componentTypes - * {Array(String)} An array of class names representing the types of - * components that the collection can include. A null value means the - * component types are not restricted. - */ - componentTypes: ["OpenLayers.Geometry.Point"], - - /** - * Constructor: OpenLayers.Geometry.MultiPoint - * Create a new MultiPoint Geometry - * - * Parameters: - * components - {Array()} - * - * Returns: - * {} - */ - - /** - * APIMethod: addPoint - * Wrapper for - * - * Parameters: - * point - {} Point to be added - * index - {Integer} Optional index - */ - addPoint: function(point, index) { - this.addComponent(point, index); - }, - - /** - * APIMethod: removePoint - * Wrapper for - * - * Parameters: - * point - {} Point to be removed - */ - removePoint: function(point){ - this.removeComponent(point); - }, - - CLASS_NAME: "OpenLayers.Geometry.MultiPoint" -}); -/* ====================================================================== - OpenLayers/Geometry/Curve.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Geometry/MultiPoint.js - */ - -/** - * Class: OpenLayers.Geometry.Curve - * A Curve is a MultiPoint, whose points are assumed to be connected. To - * this end, we provide a "getLength()" function, which iterates through - * the points, summing the distances between them. - * - * Inherits: - * - - */ -OpenLayers.Geometry.Curve = OpenLayers.Class(OpenLayers.Geometry.MultiPoint, { - - /** - * Property: componentTypes - * {Array(String)} An array of class names representing the types of - * components that the collection can include. A null - * value means the component types are not restricted. - */ - componentTypes: ["OpenLayers.Geometry.Point"], - - /** - * Constructor: OpenLayers.Geometry.Curve - * - * Parameters: - * point - {Array()} - */ - - /** - * APIMethod: getLength - * - * Returns: - * {Float} The length of the curve - */ - getLength: function() { - var length = 0.0; - if ( this.components && (this.components.length > 1)) { - for(var i=1, len=this.components.length; i} The spatial reference system - * for the geometry coordinates. If not provided, Geographic/WGS84 is - * assumed. - * - * Returns: - * {Float} The appoximate geodesic length of the geometry in meters. - */ - getGeodesicLength: function(projection) { - var geom = this; // so we can work with a clone if needed - if(projection) { - var gg = new OpenLayers.Projection("EPSG:4326"); - if(!gg.equals(projection)) { - geom = this.clone().transform(projection, gg); - } - } - var length = 0.0; - if(geom.components && (geom.components.length > 1)) { - var p1, p2; - for(var i=1, len=geom.components.length; i - */ -OpenLayers.Geometry.LineString = OpenLayers.Class(OpenLayers.Geometry.Curve, { - - /** - * Constructor: OpenLayers.Geometry.LineString - * Create a new LineString geometry - * - * Parameters: - * points - {Array()} An array of points used to - * generate the linestring - * - */ - - /** - * APIMethod: removeComponent - * Only allows removal of a point if there are three or more points in - * the linestring. (otherwise the result would be just a single point) - * - * Parameters: - * point - {} The point to be removed - * - * Returns: - * {Boolean} The component was removed. - */ - removeComponent: function(point) { - var removed = this.components && (this.components.length > 2); - if (removed) { - OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, - arguments); - } - return removed; - }, - - /** - * APIMethod: intersects - * Test for instersection between two geometries. This is a cheapo - * implementation of the Bently-Ottmann algorigithm. It doesn't - * really keep track of a sweep line data structure. It is closer - * to the brute force method, except that segments are sorted and - * potential intersections are only calculated when bounding boxes - * intersect. - * - * Parameters: - * geometry - {} - * - * Returns: - * {Boolean} The input geometry intersects this geometry. - */ - intersects: function(geometry) { - var intersect = false; - var type = geometry.CLASS_NAME; - if(type == "OpenLayers.Geometry.LineString" || - type == "OpenLayers.Geometry.LinearRing" || - type == "OpenLayers.Geometry.Point") { - var segs1 = this.getSortedSegments(); - var segs2; - if(type == "OpenLayers.Geometry.Point") { - segs2 = [{ - x1: geometry.x, y1: geometry.y, - x2: geometry.x, y2: geometry.y - }]; - } else { - segs2 = geometry.getSortedSegments(); - } - var seg1, seg1x1, seg1x2, seg1y1, seg1y2, - seg2, seg2y1, seg2y2; - // sweep right - outer: for(var i=0, len=segs1.length; i seg1x2) { - // seg1 still left of seg2 - break; - } - if(seg2.x2 < seg1x1) { - // seg2 still left of seg1 - continue; - } - seg2y1 = seg2.y1; - seg2y2 = seg2.y2; - if(Math.min(seg2y1, seg2y2) > Math.max(seg1y1, seg1y2)) { - // seg2 above seg1 - continue; - } - if(Math.max(seg2y1, seg2y2) < Math.min(seg1y1, seg1y2)) { - // seg2 below seg1 - continue; - } - if(OpenLayers.Geometry.segmentsIntersect(seg1, seg2)) { - intersect = true; - break outer; - } - } - } - } else { - intersect = geometry.intersects(this); - } - return intersect; - }, - - /** - * Method: getSortedSegments - * - * Returns: - * {Array} An array of segment objects. Segment objects have properties - * x1, y1, x2, and y2. The start point is represented by x1 and y1. - * The end point is represented by x2 and y2. Start and end are - * ordered so that x1 < x2. - */ - getSortedSegments: function() { - var numSeg = this.components.length - 1; - var segments = new Array(numSeg), point1, point2; - for(var i=0; i 0) { - // sort intersections along segment - var xDir = seg.x1 < seg.x2 ? 1 : -1; - var yDir = seg.y1 < seg.y2 ? 1 : -1; - result = { - lines: lines, - points: intersections.sort(function(p1, p2) { - return (xDir * p1.x - xDir * p2.x) || (yDir * p1.y - yDir * p2.y); - }) - }; - } - return result; - }, - - /** - * Method: split - * Use this geometry (the source) to attempt to split a target geometry. - * - * Parameters: - * target - {} The target geometry. - * options - {Object} Properties of this object will be used to determine - * how the split is conducted. - * - * Valid options: - * mutual - {Boolean} Split the source geometry in addition to the target - * geometry. Default is false. - * edge - {Boolean} Allow splitting when only edges intersect. Default is - * true. If false, a vertex on the source must be within the tolerance - * distance of the intersection to be considered a split. - * tolerance - {Number} If a non-null value is provided, intersections - * within the tolerance distance of an existing vertex on the source - * will be assumed to occur at the vertex. - * - * Returns: - * {Array} A list of geometries (of this same type as the target) that - * result from splitting the target with the source geometry. The - * source and target geometry will remain unmodified. If no split - * results, null will be returned. If mutual is true and a split - * results, return will be an array of two arrays - the first will be - * all geometries that result from splitting the source geometry and - * the second will be all geometries that result from splitting the - * target geometry. - */ - split: function(target, options) { - var results = null; - var mutual = options && options.mutual; - var sourceSplit, targetSplit, sourceParts, targetParts; - if(target instanceof OpenLayers.Geometry.LineString) { - var verts = this.getVertices(); - var vert1, vert2, seg, splits, lines, point; - var points = []; - sourceParts = []; - for(var i=0, stop=verts.length-2; i<=stop; ++i) { - vert1 = verts[i]; - vert2 = verts[i+1]; - seg = { - x1: vert1.x, y1: vert1.y, - x2: vert2.x, y2: vert2.y - }; - targetParts = targetParts || [target]; - if(mutual) { - points.push(vert1.clone()); - } - for(var j=0; j 0) { - lines.unshift(j, 1); - Array.prototype.splice.apply(targetParts, lines); - j += lines.length - 2; - } - if(mutual) { - for(var k=0, len=splits.points.length; k 0 && points.length > 0) { - points.push(vert2.clone()); - sourceParts.push(new OpenLayers.Geometry.LineString(points)); - } - } else { - results = target.splitWith(this, options); - } - if(targetParts && targetParts.length > 1) { - targetSplit = true; - } else { - targetParts = []; - } - if(sourceParts && sourceParts.length > 1) { - sourceSplit = true; - } else { - sourceParts = []; - } - if(targetSplit || sourceSplit) { - if(mutual) { - results = [sourceParts, targetParts]; - } else { - results = targetParts; - } - } - return results; - }, - - /** - * Method: splitWith - * Split this geometry (the target) with the given geometry (the source). - * - * Parameters: - * geometry - {} A geometry used to split this - * geometry (the source). - * options - {Object} Properties of this object will be used to determine - * how the split is conducted. - * - * Valid options: - * mutual - {Boolean} Split the source geometry in addition to the target - * geometry. Default is false. - * edge - {Boolean} Allow splitting when only edges intersect. Default is - * true. If false, a vertex on the source must be within the tolerance - * distance of the intersection to be considered a split. - * tolerance - {Number} If a non-null value is provided, intersections - * within the tolerance distance of an existing vertex on the source - * will be assumed to occur at the vertex. - * - * Returns: - * {Array} A list of geometries (of this same type as the target) that - * result from splitting the target with the source geometry. The - * source and target geometry will remain unmodified. If no split - * results, null will be returned. If mutual is true and a split - * results, return will be an array of two arrays - the first will be - * all geometries that result from splitting the source geometry and - * the second will be all geometries that result from splitting the - * target geometry. - */ - splitWith: function(geometry, options) { - return geometry.split(this, options); - - }, - - /** - * APIMethod: getVertices - * Return a list of all points in this geometry. - * - * Parameters: - * nodes - {Boolean} For lines, only return vertices that are - * endpoints. If false, for lines, only vertices that are not - * endpoints will be returned. If not provided, all vertices will - * be returned. - * - * Returns: - * {Array} A list of all vertices in the geometry. - */ - getVertices: function(nodes) { - var vertices; - if(nodes === true) { - vertices = [ - this.components[0], - this.components[this.components.length-1] - ]; - } else if (nodes === false) { - vertices = this.components.slice(1, this.components.length-1); - } else { - vertices = this.components.slice(); - } - return vertices; - }, - - /** - * APIMethod: distanceTo - * Calculate the closest distance between two geometries (on the x-y plane). - * - * Parameters: - * geometry - {} The target geometry. - * options - {Object} Optional properties for configuring the distance - * calculation. - * - * Valid options: - * details - {Boolean} Return details from the distance calculation. - * Default is false. - * edge - {Boolean} Calculate the distance from this geometry to the - * nearest edge of the target geometry. Default is true. If true, - * calling distanceTo from a geometry that is wholly contained within - * the target will result in a non-zero distance. If false, whenever - * geometries intersect, calling distanceTo will return 0. If false, - * details cannot be returned. - * - * Returns: - * {Number | Object} The distance between this geometry and the target. - * If details is true, the return will be an object with distance, - * x0, y0, x1, and x2 properties. The x0 and y0 properties represent - * the coordinates of the closest point on this geometry. The x1 and y1 - * properties represent the coordinates of the closest point on the - * target geometry. - */ - distanceTo: function(geometry, options) { - var edge = !(options && options.edge === false); - var details = edge && options && options.details; - var result, best = {}; - var min = Number.POSITIVE_INFINITY; - if(geometry instanceof OpenLayers.Geometry.Point) { - var segs = this.getSortedSegments(); - var x = geometry.x; - var y = geometry.y; - var seg; - for(var i=0, len=segs.length; i x && ((y > seg.y1 && y < seg.y2) || (y < seg.y1 && y > seg.y2))) { - break; - } - } - } - if(details) { - best = { - distance: best.distance, - x0: best.x, y0: best.y, - x1: x, y1: y - }; - } else { - best = best.distance; - } - } else if(geometry instanceof OpenLayers.Geometry.LineString) { - var segs0 = this.getSortedSegments(); - var segs1 = geometry.getSortedSegments(); - var seg0, seg1, intersection, x0, y0; - var len1 = segs1.length; - var interOptions = {point: true}; - outer: for(var i=0, len=segs0.length; i maxDistance) { - maxDistance = distance; - indexFarthest = index; - } - } - - if (maxDistance > tolerance && indexFarthest != firstPoint) { - //Add the largest point that exceeds the tolerance - pointIndexsToKeep.push(indexFarthest); - douglasPeuckerReduction(points, firstPoint, indexFarthest, tolerance); - douglasPeuckerReduction(points, indexFarthest, lastPoint, tolerance); - } - }; - - /** - * Private function calculating the perpendicular distance - * TODO: check whether OpenLayers.Geometry.LineString::distanceTo() is faster or slower - */ - var perpendicularDistance = function(point1, point2, point){ - //Area = |(1/2)(x1y2 + x2y3 + x3y1 - x2y1 - x3y2 - x1y3)| *Area of triangle - //Base = v((x1-x2)²+(x1-x2)²) *Base of Triangle* - //Area = .5*Base*H *Solve for height - //Height = Area/.5/Base - - var area = Math.abs(0.5 * (point1.x * point2.y + point2.x * point.y + point.x * point1.y - point2.x * point1.y - point.x * point2.y - point1.x * point.y)); - var bottom = Math.sqrt(Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2)); - var height = area / bottom * 2; - - return height; - }; - - var firstPoint = 0; - var lastPoint = points.length - 1; - var pointIndexsToKeep = []; - - //Add the first and last index to the keepers - pointIndexsToKeep.push(firstPoint); - pointIndexsToKeep.push(lastPoint); - - //The first and the last point cannot be the same - while (points[firstPoint].equals(points[lastPoint])) { - lastPoint--; - //Addition: the first point not equal to first point in the LineString is kept as well - pointIndexsToKeep.push(lastPoint); - } - - douglasPeuckerReduction(points, firstPoint, lastPoint, tolerance); - var returnPoints = []; - pointIndexsToKeep.sort(compareNumbers); - for (var index = 0; index < pointIndexsToKeep.length; index++) { - returnPoints.push(points[pointIndexsToKeep[index]]); - } - return new OpenLayers.Geometry.LineString(returnPoints); - - } - else { - return this; - } - }, - - CLASS_NAME: "OpenLayers.Geometry.LineString" -}); -/* ====================================================================== - OpenLayers/Geometry/MultiLineString.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Geometry/Collection.js - * @requires OpenLayers/Geometry/LineString.js - */ - -/** - * Class: OpenLayers.Geometry.MultiLineString - * A MultiLineString is a geometry with multiple - * components. - * - * Inherits from: - * - - * - - */ -OpenLayers.Geometry.MultiLineString = OpenLayers.Class( - OpenLayers.Geometry.Collection, { - - /** - * Property: componentTypes - * {Array(String)} An array of class names representing the types of - * components that the collection can include. A null value means the - * component types are not restricted. - */ - componentTypes: ["OpenLayers.Geometry.LineString"], - - /** - * Constructor: OpenLayers.Geometry.MultiLineString - * Constructor for a MultiLineString Geometry. - * - * Parameters: - * components - {Array()} - * - */ - - /** - * Method: split - * Use this geometry (the source) to attempt to split a target geometry. - * - * Parameters: - * geometry - {} The target geometry. - * options - {Object} Properties of this object will be used to determine - * how the split is conducted. - * - * Valid options: - * mutual - {Boolean} Split the source geometry in addition to the target - * geometry. Default is false. - * edge - {Boolean} Allow splitting when only edges intersect. Default is - * true. If false, a vertex on the source must be within the tolerance - * distance of the intersection to be considered a split. - * tolerance - {Number} If a non-null value is provided, intersections - * within the tolerance distance of an existing vertex on the source - * will be assumed to occur at the vertex. - * - * Returns: - * {Array} A list of geometries (of this same type as the target) that - * result from splitting the target with the source geometry. The - * source and target geometry will remain unmodified. If no split - * results, null will be returned. If mutual is true and a split - * results, return will be an array of two arrays - the first will be - * all geometries that result from splitting the source geometry and - * the second will be all geometries that result from splitting the - * target geometry. - */ - split: function(geometry, options) { - var results = null; - var mutual = options && options.mutual; - var splits, sourceLine, sourceLines, sourceSplit, targetSplit; - var sourceParts = []; - var targetParts = [geometry]; - for(var i=0, len=this.components.length; i 1) { - sourceSplit = true; - } else { - sourceParts = []; - } - if(targetParts && targetParts.length > 1) { - targetSplit = true; - } else { - targetParts = []; - } - if(sourceSplit || targetSplit) { - if(mutual) { - results = [sourceParts, targetParts]; - } else { - results = targetParts; - } - } - return results; - }, - - /** - * Method: splitWith - * Split this geometry (the target) with the given geometry (the source). - * - * Parameters: - * geometry - {} A geometry used to split this - * geometry (the source). - * options - {Object} Properties of this object will be used to determine - * how the split is conducted. - * - * Valid options: - * mutual - {Boolean} Split the source geometry in addition to the target - * geometry. Default is false. - * edge - {Boolean} Allow splitting when only edges intersect. Default is - * true. If false, a vertex on the source must be within the tolerance - * distance of the intersection to be considered a split. - * tolerance - {Number} If a non-null value is provided, intersections - * within the tolerance distance of an existing vertex on the source - * will be assumed to occur at the vertex. - * - * Returns: - * {Array} A list of geometries (of this same type as the target) that - * result from splitting the target with the source geometry. The - * source and target geometry will remain unmodified. If no split - * results, null will be returned. If mutual is true and a split - * results, return will be an array of two arrays - the first will be - * all geometries that result from splitting the source geometry and - * the second will be all geometries that result from splitting the - * target geometry. - */ - splitWith: function(geometry, options) { - var results = null; - var mutual = options && options.mutual; - var splits, targetLine, sourceLines, sourceSplit, targetSplit, sourceParts, targetParts; - if(geometry instanceof OpenLayers.Geometry.LineString) { - targetParts = []; - sourceParts = [geometry]; - for(var i=0, len=this.components.length; i 1) { - sourceSplit = true; - } else { - sourceParts = []; - } - if(targetParts && targetParts.length > 1) { - targetSplit = true; - } else { - targetParts = []; - } - if(sourceSplit || targetSplit) { - if(mutual) { - results = [sourceParts, targetParts]; - } else { - results = targetParts; - } - } - return results; - }, - - CLASS_NAME: "OpenLayers.Geometry.MultiLineString" -}); -/* ====================================================================== - OpenLayers/Geometry/LinearRing.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Geometry/LineString.js - */ - -/** - * Class: OpenLayers.Geometry.LinearRing - * - * A Linear Ring is a special LineString which is closed. It closes itself - * automatically on every addPoint/removePoint by adding a copy of the first - * point as the last point. - * - * Also, as it is the first in the line family to close itself, a getArea() - * function is defined to calculate the enclosed area of the linearRing - * - * Inherits: - * - - */ -OpenLayers.Geometry.LinearRing = OpenLayers.Class( - OpenLayers.Geometry.LineString, { - - /** - * Property: componentTypes - * {Array(String)} An array of class names representing the types of - * components that the collection can include. A null - * value means the component types are not restricted. - */ - componentTypes: ["OpenLayers.Geometry.Point"], - - /** - * Constructor: OpenLayers.Geometry.LinearRing - * Linear rings are constructed with an array of points. This array - * can represent a closed or open ring. If the ring is open (the last - * point does not equal the first point), the constructor will close - * the ring. If the ring is already closed (the last point does equal - * the first point), it will be left closed. - * - * Parameters: - * points - {Array()} points - */ - - /** - * APIMethod: addComponent - * Adds a point to geometry components. If the point is to be added to - * the end of the components array and it is the same as the last point - * already in that array, the duplicate point is not added. This has - * the effect of closing the ring if it is not already closed, and - * doing the right thing if it is already closed. This behavior can - * be overridden by calling the method with a non-null index as the - * second argument. - * - * Parameters: - * point - {} - * index - {Integer} Index into the array to insert the component - * - * Returns: - * {Boolean} Was the Point successfully added? - */ - addComponent: function(point, index) { - var added = false; - - //remove last point - var lastPoint = this.components.pop(); - - // given an index, add the point - // without an index only add non-duplicate points - if(index != null || !point.equals(lastPoint)) { - added = OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, - arguments); - } - - //append copy of first point - var firstPoint = this.components[0]; - OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, - [firstPoint]); - - return added; - }, - - /** - * APIMethod: removeComponent - * Removes a point from geometry components. - * - * Parameters: - * point - {} - * - * Returns: - * {Boolean} The component was removed. - */ - removeComponent: function(point) { - var removed = this.components && (this.components.length > 3); - if (removed) { - //remove last point - this.components.pop(); - - //remove our point - OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, - arguments); - //append copy of first point - var firstPoint = this.components[0]; - OpenLayers.Geometry.Collection.prototype.addComponent.apply(this, - [firstPoint]); - } - return removed; - }, - - /** - * APIMethod: move - * Moves a geometry by the given displacement along positive x and y axes. - * This modifies the position of the geometry and clears the cached - * bounds. - * - * Parameters: - * x - {Float} Distance to move geometry in positive x direction. - * y - {Float} Distance to move geometry in positive y direction. - */ - move: function(x, y) { - for(var i = 0, len=this.components.length; i} Center point for the rotation - */ - rotate: function(angle, origin) { - for(var i=0, len=this.components.length; i} Point of origin for resizing - * ratio - {Float} Optional x:y ratio for resizing. Default ratio is 1. - * - * Returns: - * {} - The current geometry. - */ - resize: function(scale, origin, ratio) { - for(var i=0, len=this.components.length; i} - * dest - {} - * - * Returns: - * {} - */ - transform: function(source, dest) { - if (source && dest) { - for (var i=0, len=this.components.length; i} The centroid of the collection - */ - getCentroid: function() { - if (this.components) { - var len = this.components.length; - if (len > 0 && len <= 2) { - return this.components[0].clone(); - } else if (len > 2) { - var sumX = 0.0; - var sumY = 0.0; - var x0 = this.components[0].x; - var y0 = this.components[0].y; - var area = -1 * this.getArea(); - if (area != 0) { - for (var i = 0; i < len - 1; i++) { - var b = this.components[i]; - var c = this.components[i+1]; - sumX += (b.x + c.x - 2 * x0) * ((b.x - x0) * (c.y - y0) - (c.x - x0) * (b.y - y0)); - sumY += (b.y + c.y - 2 * y0) * ((b.x - x0) * (c.y - y0) - (c.x - x0) * (b.y - y0)); - } - var x = x0 + sumX / (6 * area); - var y = y0 + sumY / (6 * area); - } else { - for (var i = 0; i < len - 1; i++) { - sumX += this.components[i].x; - sumY += this.components[i].y; - } - var x = sumX / (len - 1); - var y = sumY / (len - 1); - } - return new OpenLayers.Geometry.Point(x, y); - } else { - return null; - } - } - }, - - /** - * APIMethod: getArea - * Note - The area is positive if the ring is oriented CW, otherwise - * it will be negative. - * - * Returns: - * {Float} The signed area for a ring. - */ - getArea: function() { - var area = 0.0; - if ( this.components && (this.components.length > 2)) { - var sum = 0.0; - for (var i=0, len=this.components.length; i} The spatial reference system - * for the geometry coordinates. If not provided, Geographic/WGS84 is - * assumed. - * - * Reference: - * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for - * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion - * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409 - * - * Returns: - * {float} The approximate signed geodesic area of the polygon in square - * meters. - */ - getGeodesicArea: function(projection) { - var ring = this; // so we can work with a clone if needed - if(projection) { - var gg = new OpenLayers.Projection("EPSG:4326"); - if(!gg.equals(projection)) { - ring = this.clone().transform(projection, gg); - } - } - var area = 0.0; - var len = ring.components && ring.components.length; - if(len > 2) { - var p1, p2; - for(var i=0; i} - * - * Returns: - * {Boolean | Number} The point is inside the linear ring. Returns 1 if - * the point is coincident with an edge. Returns boolean otherwise. - */ - containsPoint: function(point) { - var approx = OpenLayers.Number.limitSigDigs; - var digs = 14; - var px = approx(point.x, digs); - var py = approx(point.y, digs); - function getX(y, x1, y1, x2, y2) { - return (y - y2) * ((x2 - x1) / (y2 - y1)) + x2; - } - var numSeg = this.components.length - 1; - var start, end, x1, y1, x2, y2, cx, cy; - var crosses = 0; - for(var i=0; i= x1 && px <= x2) || // right or vert - x1 >= x2 && (px <= x1 && px >= x2)) { // left or vert - // point on edge - crosses = -1; - break; - } - } - // ignore other horizontal edges - continue; - } - cx = approx(getX(py, x1, y1, x2, y2), digs); - if(cx == px) { - // point on line - if(y1 < y2 && (py >= y1 && py <= y2) || // upward - y1 > y2 && (py <= y1 && py >= y2)) { // downward - // point on edge - crosses = -1; - break; - } - } - if(cx <= px) { - // no crossing to the right - continue; - } - if(x1 != x2 && (cx < Math.min(x1, x2) || cx > Math.max(x1, x2))) { - // no crossing - continue; - } - if(y1 < y2 && (py >= y1 && py < y2) || // upward - y1 > y2 && (py < y1 && py >= y2)) { // downward - ++crosses; - } - } - var contained = (crosses == -1) ? - // on edge - 1 : - // even (out) or odd (in) - !!(crosses & 1); - - return contained; - }, - - /** - * APIMethod: intersects - * Determine if the input geometry intersects this one. - * - * Parameters: - * geometry - {} Any type of geometry. - * - * Returns: - * {Boolean} The input geometry intersects this one. - */ - intersects: function(geometry) { - var intersect = false; - if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { - intersect = this.containsPoint(geometry); - } else if(geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") { - intersect = geometry.intersects(this); - } else if(geometry.CLASS_NAME == "OpenLayers.Geometry.LinearRing") { - intersect = OpenLayers.Geometry.LineString.prototype.intersects.apply( - this, [geometry] - ); - } else { - // check for component intersections - for(var i=0, len=geometry.components.length; i - * - - */ -OpenLayers.Geometry.Polygon = 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.LinearRing"], - - /** - * Constructor: OpenLayers.Geometry.Polygon - * Constructor for a Polygon geometry. - * The first ring (this.component[0])is the outer bounds of the polygon and - * all subsequent rings (this.component[1-n]) are internal holes. - * - * - * Parameters: - * components - {Array()} - */ - - /** - * APIMethod: getArea - * Calculated by subtracting the areas of the internal holes from the - * area of the outer hole. - * - * Returns: - * {float} The area of the geometry - */ - getArea: function() { - var area = 0.0; - if ( this.components && (this.components.length > 0)) { - area += Math.abs(this.components[0].getArea()); - for (var i=1, len=this.components.length; i} The spatial reference system - * for the geometry coordinates. If not provided, Geographic/WGS84 is - * assumed. - * - * Reference: - * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for - * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion - * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409 - * - * Returns: - * {float} The approximate geodesic area of the polygon in square meters. - */ - getGeodesicArea: function(projection) { - var area = 0.0; - if(this.components && (this.components.length > 0)) { - area += Math.abs(this.components[0].getGeodesicArea(projection)); - for(var i=1, len=this.components.length; i} - * - * Returns: - * {Boolean | Number} The point is inside the polygon. Returns 1 if the - * point is on an edge. Returns boolean otherwise. - */ - containsPoint: function(point) { - var numRings = this.components.length; - var contained = false; - if(numRings > 0) { - // check exterior ring - 1 means on edge, boolean otherwise - contained = this.components[0].containsPoint(point); - if(contained !== 1) { - if(contained && numRings > 1) { - // check interior rings - var hole; - for(var i=1; i} Any type of geometry. - * - * Returns: - * {Boolean} The input geometry intersects this one. - */ - intersects: function(geometry) { - var intersect = false; - var i, len; - if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { - intersect = this.containsPoint(geometry); - } else if(geometry.CLASS_NAME == "OpenLayers.Geometry.LineString" || - geometry.CLASS_NAME == "OpenLayers.Geometry.LinearRing") { - // check if rings/linestrings intersect - for(i=0, len=this.components.length; i} The target geometry. - * options - {Object} Optional properties for configuring the distance - * calculation. - * - * Valid options: - * details - {Boolean} Return details from the distance calculation. - * Default is false. - * edge - {Boolean} Calculate the distance from this geometry to the - * nearest edge of the target geometry. Default is true. If true, - * calling distanceTo from a geometry that is wholly contained within - * the target will result in a non-zero distance. If false, whenever - * geometries intersect, calling distanceTo will return 0. If false, - * details cannot be returned. - * - * Returns: - * {Number | Object} The distance between this geometry and the target. - * If details is true, the return will be an object with distance, - * x0, y0, x1, and y1 properties. The x0 and y0 properties represent - * the coordinates of the closest point on this geometry. The x1 and y1 - * properties represent the coordinates of the closest point on the - * target geometry. - */ - distanceTo: function(geometry, options) { - var edge = !(options && options.edge === false); - var result; - // this is the case where we might not be looking for distance to edge - if(!edge && this.intersects(geometry)) { - result = 0; - } else { - result = OpenLayers.Geometry.Collection.prototype.distanceTo.apply( - this, [geometry, options] - ); - } - return result; - }, - - CLASS_NAME: "OpenLayers.Geometry.Polygon" -}); - -/** - * APIMethod: createRegularPolygon - * Create a regular polygon around a radius. Useful for creating circles - * and the like. - * - * Parameters: - * origin - {} center of polygon. - * radius - {Float} distance to vertex, in map units. - * sides - {Integer} Number of sides. 20 approximates a circle. - * rotation - {Float} original angle of rotation, in degrees. - */ -OpenLayers.Geometry.Polygon.createRegularPolygon = function(origin, radius, sides, rotation) { - var angle = Math.PI * ((1/sides) - (1/2)); - if(rotation) { - angle += (rotation / 180) * Math.PI; - } - var rotatedAngle, x, y; - var points = []; - for(var i=0; i - * components. Create a new instance with the - * constructor. - * - * Inherits from: - * - - */ -OpenLayers.Geometry.MultiPolygon = 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.Polygon"], - - /** - * Constructor: OpenLayers.Geometry.MultiPolygon - * Create a new MultiPolygon geometry - * - * Parameters: - * components - {Array()} An array of polygons - * used to generate the MultiPolygon - * - */ - - CLASS_NAME: "OpenLayers.Geometry.MultiPolygon" -}); -/* ====================================================================== - OpenLayers/Format/GML.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Format/XML.js - * @requires OpenLayers/Feature/Vector.js - * @requires OpenLayers/Geometry/Point.js - * @requires OpenLayers/Geometry/MultiPoint.js - * @requires OpenLayers/Geometry/LineString.js - * @requires OpenLayers/Geometry/MultiLineString.js - * @requires OpenLayers/Geometry/Polygon.js - * @requires OpenLayers/Geometry/MultiPolygon.js - */ - -/** - * Class: OpenLayers.Format.GML - * Read/Write GML. Create a new instance with the - * constructor. Supports the GML simple features profile. - * - * Inherits from: - * - - */ -OpenLayers.Format.GML = OpenLayers.Class(OpenLayers.Format.XML, { - - /** - * APIProperty: featureNS - * {String} Namespace used for feature attributes. Default is - * "http://mapserver.gis.umn.edu/mapserver". - */ - featureNS: "http://mapserver.gis.umn.edu/mapserver", - - /** - * APIProperty: featurePrefix - * {String} Namespace alias (or prefix) for feature nodes. Default is - * "feature". - */ - featurePrefix: "feature", - - /** - * APIProperty: featureName - * {String} Element name for features. Default is "featureMember". - */ - featureName: "featureMember", - - /** - * APIProperty: layerName - * {String} Name of data layer. Default is "features". - */ - layerName: "features", - - /** - * APIProperty: geometryName - * {String} Name of geometry element. Defaults to "geometry". - */ - geometryName: "geometry", - - /** - * APIProperty: collectionName - * {String} Name of featureCollection element. - */ - collectionName: "FeatureCollection", - - /** - * APIProperty: gmlns - * {String} GML Namespace. - */ - gmlns: "http://www.opengis.net/gml", - - /** - * APIProperty: extractAttributes - * {Boolean} Extract attributes from GML. - */ - extractAttributes: true, - - /** - * 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, - - /** - * Constructor: OpenLayers.Format.GML - * Create a new parser for GML. - * - * Parameters: - * options - {Object} An optional object whose properties will be set on - * this instance. - */ - initialize: function(options) { - // compile regular expressions once instead of every time they are used - this.regExes = { - trimSpace: (/^\s*|\s*$/g), - removeSpace: (/\s*/g), - splitSpace: (/\s+/), - trimComma: (/\s*,\s*/g) - }; - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); - }, - - /** - * APIMethod: read - * Read data from a string, and return a list of features. - * - * Parameters: - * data - {String} or {DOMElement} data to read/parse. - * - * Returns: - * {Array()} An array of features. - */ - read: function(data) { - if(typeof data == "string") { - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); - } - var featureNodes = this.getElementsByTagNameNS(data.documentElement, - this.gmlns, - this.featureName); - var features = []; - for(var i=0; i 0) { - // only deal with first geometry of this type - parser = this.parseGeometry[type.toLowerCase()]; - if(parser) { - geometry = parser.apply(this, [nodeList[0]]); - if (this.internalProjection && this.externalProjection) { - geometry.transform(this.externalProjection, - this.internalProjection); - } - } else { - throw new TypeError("Unsupported geometry type: " + type); - } - // stop looking for different geometry types - break; - } - } - - var bounds; - var boxNodes = this.getElementsByTagNameNS(node, this.gmlns, "Box"); - for(i=0; i} A point geometry. - */ - point: function(node) { - /** - * Three coordinate variations to consider: - * 1) x y z - * 2) x, y, z - * 3) xy - */ - var nodeList, coordString; - var coords = []; - - // look for - var nodeList = this.getElementsByTagNameNS(node, this.gmlns, "pos"); - if(nodeList.length > 0) { - coordString = nodeList[0].firstChild.nodeValue; - coordString = coordString.replace(this.regExes.trimSpace, ""); - coords = coordString.split(this.regExes.splitSpace); - } - - // look for - if(coords.length == 0) { - nodeList = this.getElementsByTagNameNS(node, this.gmlns, - "coordinates"); - if(nodeList.length > 0) { - coordString = nodeList[0].firstChild.nodeValue; - coordString = coordString.replace(this.regExes.removeSpace, - ""); - coords = coordString.split(","); - } - } - - // look for - if(coords.length == 0) { - nodeList = this.getElementsByTagNameNS(node, this.gmlns, - "coord"); - if(nodeList.length > 0) { - var xList = this.getElementsByTagNameNS(nodeList[0], - this.gmlns, "X"); - var yList = this.getElementsByTagNameNS(nodeList[0], - this.gmlns, "Y"); - if(xList.length > 0 && yList.length > 0) { - coords = [xList[0].firstChild.nodeValue, - yList[0].firstChild.nodeValue]; - } - } - } - - // preserve third dimension - if(coords.length == 2) { - coords[2] = null; - } - - if (this.xy) { - return new OpenLayers.Geometry.Point(coords[0], coords[1], - coords[2]); - } - else{ - return new OpenLayers.Geometry.Point(coords[1], coords[0], - coords[2]); - } - }, - - /** - * Method: parseGeometry.multipoint - * Given a GML node representing a multipoint geometry, create an - * OpenLayers multipoint geometry. - * - * Parameters: - * node - {DOMElement} A GML node. - * - * Returns: - * {} A multipoint geometry. - */ - multipoint: function(node) { - var nodeList = this.getElementsByTagNameNS(node, this.gmlns, - "Point"); - var components = []; - if(nodeList.length > 0) { - var point; - for(var i=0; i} A linestring geometry. - */ - linestring: function(node, ring) { - /** - * Two coordinate variations to consider: - * 1) x0 y0 z0 x1 y1 z1 - * 2) x0, y0, z0 x1, y1, z1 - */ - var nodeList, coordString; - var coords = []; - var points = []; - - // look for - nodeList = this.getElementsByTagNameNS(node, this.gmlns, "posList"); - if(nodeList.length > 0) { - coordString = this.getChildValue(nodeList[0]); - coordString = coordString.replace(this.regExes.trimSpace, ""); - coords = coordString.split(this.regExes.splitSpace); - var dim = parseInt(nodeList[0].getAttribute("dimension")); - var j, x, y, z; - for(var i=0; i - if(coords.length == 0) { - nodeList = this.getElementsByTagNameNS(node, this.gmlns, - "coordinates"); - if(nodeList.length > 0) { - coordString = this.getChildValue(nodeList[0]); - coordString = coordString.replace(this.regExes.trimSpace, - ""); - coordString = coordString.replace(this.regExes.trimComma, - ","); - var pointList = coordString.split(this.regExes.splitSpace); - for(var i=0; i} A multilinestring geometry. - */ - multilinestring: function(node) { - var nodeList = this.getElementsByTagNameNS(node, this.gmlns, - "LineString"); - var components = []; - if(nodeList.length > 0) { - var line; - for(var i=0; i} A polygon geometry. - */ - polygon: function(node) { - var nodeList = this.getElementsByTagNameNS(node, this.gmlns, - "LinearRing"); - var components = []; - if(nodeList.length > 0) { - // this assumes exterior ring first, inner rings after - var ring; - for(var i=0; i} A multipolygon geometry. - */ - multipolygon: function(node) { - var nodeList = this.getElementsByTagNameNS(node, this.gmlns, - "Polygon"); - var components = []; - if(nodeList.length > 0) { - var polygon; - for(var i=0; i 0) { - var coords = []; - - if(lpoint.length > 0) { - coordString = lpoint[0].firstChild.nodeValue; - coordString = coordString.replace(this.regExes.trimSpace, ""); - coords = coordString.split(this.regExes.splitSpace); - } - - if(coords.length == 2) { - coords[2] = null; - } - if (this.xy) { - var lowerPoint = new OpenLayers.Geometry.Point(coords[0], coords[1],coords[2]); - } else { - var lowerPoint = new OpenLayers.Geometry.Point(coords[1], coords[0],coords[2]); - } - } - - var upoint = this.getElementsByTagNameNS(node, this.gmlns, "upperCorner"); - if (upoint.length > 0) { - var coords = []; - - if(upoint.length > 0) { - coordString = upoint[0].firstChild.nodeValue; - coordString = coordString.replace(this.regExes.trimSpace, ""); - coords = coordString.split(this.regExes.splitSpace); - } - - if(coords.length == 2) { - coords[2] = null; - } - if (this.xy) { - var upperPoint = new OpenLayers.Geometry.Point(coords[0], coords[1],coords[2]); - } else { - var upperPoint = new OpenLayers.Geometry.Point(coords[1], coords[0],coords[2]); - } - } - - if (lowerPoint && upperPoint) { - components.push(new OpenLayers.Geometry.Point(lowerPoint.x, lowerPoint.y)); - components.push(new OpenLayers.Geometry.Point(upperPoint.x, lowerPoint.y)); - components.push(new OpenLayers.Geometry.Point(upperPoint.x, upperPoint.y)); - components.push(new OpenLayers.Geometry.Point(lowerPoint.x, upperPoint.y)); - components.push(new OpenLayers.Geometry.Point(lowerPoint.x, lowerPoint.y)); - - var ring = new OpenLayers.Geometry.LinearRing(components); - envelope = new OpenLayers.Geometry.Polygon([ring]); - } - return envelope; - }, - - /** - * Method: parseGeometry.box - * Given a GML node representing a box geometry, create an - * OpenLayers.Bounds. - * - * Parameters: - * node - {DOMElement} A GML node. - * - * Returns: - * {} A bounds representing the box. - */ - box: function(node) { - var nodeList = this.getElementsByTagNameNS(node, this.gmlns, - "coordinates"); - var coordString; - var coords, beginPoint = null, endPoint = null; - if (nodeList.length > 0) { - coordString = nodeList[0].firstChild.nodeValue; - coords = coordString.split(" "); - if (coords.length == 2) { - beginPoint = coords[0].split(","); - endPoint = coords[1].split(","); - } - } - if (beginPoint !== null && endPoint !== null) { - return new OpenLayers.Bounds(parseFloat(beginPoint[0]), - parseFloat(beginPoint[1]), - parseFloat(endPoint[0]), - parseFloat(endPoint[1]) ); - } - } - - }, - - /** - * Method: parseAttributes - * - * Parameters: - * node - {DOMElement} - * - * Returns: - * {Object} An attributes object. - */ - parseAttributes: function(node) { - var attributes = {}; - // assume attributes are children of the first type 1 child - var childNode = node.firstChild; - var children, i, child, grandchildren, grandchild, name, value; - while(childNode) { - if(childNode.nodeType == 1) { - // attributes are type 1 children with one type 3 child - children = childNode.childNodes; - for(i=0; i becomes - // {fieldname: null} - attributes[child.nodeName.split(":").pop()] = null; - } - } - } - break; - } - childNode = childNode.nextSibling; - } - return attributes; - }, - - /** - * APIMethod: write - * Generate a GML document string given a list of features. - * - * Parameters: - * features - {Array()} List of features to - * serialize into a string. - * - * Returns: - * {String} A string representing the GML document. - */ - write: function(features) { - if(!(OpenLayers.Util.isArray(features))) { - features = [features]; - } - var gml = this.createElementNS("http://www.opengis.net/wfs", - "wfs:" + this.collectionName); - for(var i=0; i} The feature to be built as GML. - * - * Returns: - * {DOMElement} A node reprensting the feature in GML. - */ - createFeatureXML: function(feature) { - var geometry = feature.geometry; - var geometryNode = this.buildGeometryNode(geometry); - var geomContainer = this.createElementNS(this.featureNS, - this.featurePrefix + ":" + - this.geometryName); - geomContainer.appendChild(geometryNode); - var featureNode = this.createElementNS(this.gmlns, - "gml:" + this.featureName); - var featureContainer = this.createElementNS(this.featureNS, - this.featurePrefix + ":" + - this.layerName); - var fid = feature.fid || feature.id; - featureContainer.setAttribute("fid", fid); - featureContainer.appendChild(geomContainer); - for(var attr in feature.attributes) { - var attrText = this.createTextNode(feature.attributes[attr]); - var nodename = attr.substring(attr.lastIndexOf(":") + 1); - var attrContainer = this.createElementNS(this.featureNS, - this.featurePrefix + ":" + - nodename); - attrContainer.appendChild(attrText); - featureContainer.appendChild(attrContainer); - } - featureNode.appendChild(featureContainer); - return featureNode; - }, - - /** - * APIMethod: buildGeometryNode - */ - buildGeometryNode: function(geometry) { - if (this.externalProjection && this.internalProjection) { - geometry = geometry.clone(); - geometry.transform(this.internalProjection, - this.externalProjection); - } - var className = geometry.CLASS_NAME; - var type = className.substring(className.lastIndexOf(".") + 1); - var builder = this.buildGeometry[type.toLowerCase()]; - return builder.apply(this, [geometry]); - }, - - /** - * Property: buildGeometry - * Object containing methods to do the actual geometry node building - * based on geometry type. - */ - buildGeometry: { - // TBD retrieve the srs from layer - // srsName is non-standard, so not including it until it's right. - // gml.setAttribute("srsName", - // "http://www.opengis.net/gml/srs/epsg.xml#4326"); - - /** - * Method: buildGeometry.point - * Given an OpenLayers point geometry, create a GML point. - * - * Parameters: - * geometry - {} A point geometry. - * - * Returns: - * {DOMElement} A GML point node. - */ - point: function(geometry) { - var gml = this.createElementNS(this.gmlns, "gml:Point"); - gml.appendChild(this.buildCoordinatesNode(geometry)); - return gml; - }, - - /** - * Method: buildGeometry.multipoint - * Given an OpenLayers multipoint geometry, create a GML multipoint. - * - * Parameters: - * geometry - {} A multipoint geometry. - * - * Returns: - * {DOMElement} A GML multipoint node. - */ - multipoint: function(geometry) { - var gml = this.createElementNS(this.gmlns, "gml:MultiPoint"); - var points = geometry.components; - var pointMember, pointGeom; - for(var i=0; i} A linestring geometry. - * - * Returns: - * {DOMElement} A GML linestring node. - */ - linestring: function(geometry) { - var gml = this.createElementNS(this.gmlns, "gml:LineString"); - gml.appendChild(this.buildCoordinatesNode(geometry)); - return gml; - }, - - /** - * Method: buildGeometry.multilinestring - * Given an OpenLayers multilinestring geometry, create a GML - * multilinestring. - * - * Parameters: - * geometry - {} A multilinestring - * geometry. - * - * Returns: - * {DOMElement} A GML multilinestring node. - */ - multilinestring: function(geometry) { - var gml = this.createElementNS(this.gmlns, "gml:MultiLineString"); - var lines = geometry.components; - var lineMember, lineGeom; - for(var i=0; i} A linearring geometry. - * - * Returns: - * {DOMElement} A GML linearring node. - */ - linearring: function(geometry) { - var gml = this.createElementNS(this.gmlns, "gml:LinearRing"); - gml.appendChild(this.buildCoordinatesNode(geometry)); - return gml; - }, - - /** - * Method: buildGeometry.polygon - * Given an OpenLayers polygon geometry, create a GML polygon. - * - * Parameters: - * geometry - {} A polygon geometry. - * - * Returns: - * {DOMElement} A GML polygon node. - */ - polygon: function(geometry) { - var gml = this.createElementNS(this.gmlns, "gml:Polygon"); - var rings = geometry.components; - var ringMember, ringGeom, type; - for(var i=0; i} A multipolygon - * geometry. - * - * Returns: - * {DOMElement} A GML multipolygon node. - */ - multipolygon: function(geometry) { - var gml = this.createElementNS(this.gmlns, "gml:MultiPolygon"); - var polys = geometry.components; - var polyMember, polyGeom; - for(var i=0; i} A bounds object. - * - * Returns: - * {DOMElement} A GML box node. - */ - bounds: function(bounds) { - var gml = this.createElementNS(this.gmlns, "gml:Box"); - gml.appendChild(this.buildCoordinatesNode(bounds)); - return gml; - } - }, - - /** - * Method: buildCoordinates - * builds the coordinates XmlNode - * (code) - * ... - * (end) - * - * Parameters: - * geometry - {} - * - * Returns: - * {XmlNode} created xmlNode - */ - buildCoordinatesNode: function(geometry) { - var coordinatesNode = this.createElementNS(this.gmlns, - "gml:coordinates"); - coordinatesNode.setAttribute("decimal", "."); - coordinatesNode.setAttribute("cs", ","); - coordinatesNode.setAttribute("ts", " "); - - var parts = []; - - if(geometry instanceof OpenLayers.Bounds){ - parts.push(geometry.left + "," + geometry.bottom); - parts.push(geometry.right + "," + geometry.top); - } else { - var points = (geometry.components) ? geometry.components : [geometry]; - for(var i=0; i - */ -OpenLayers.Format.GML.Base = OpenLayers.Class(OpenLayers.Format.XML, { - - /** - * Property: namespaces - * {Object} Mapping of namespace aliases to namespace URIs. - */ - namespaces: { - gml: "http://www.opengis.net/gml", - xlink: "http://www.w3.org/1999/xlink", - xsi: "http://www.w3.org/2001/XMLSchema-instance", - wfs: "http://www.opengis.net/wfs" // this is a convenience for reading wfs:FeatureCollection - }, - - /** - * Property: defaultPrefix - */ - defaultPrefix: "gml", - - /** - * Property: schemaLocation - * {String} Schema location for a particular minor version. - */ - schemaLocation: null, - - /** - * APIProperty: featureType - * {Array(String) or String} The local (without prefix) feature typeName(s). - */ - featureType: null, - - /** - * APIProperty: featureNS - * {String} The feature namespace. Must be set in the options at - * construction. - */ - featureNS: null, - - /** - * APIProperty: geometry - * {String} Name of geometry element. Defaults to "geometry". If null, it - * will be set on when the first geometry is parsed. - */ - geometryName: "geometry", - - /** - * APIProperty: extractAttributes - * {Boolean} Extract attributes from GML. Default is true. - */ - extractAttributes: true, - - /** - * APIProperty: srsName - * {String} URI for spatial reference system. This is optional for - * single part geometries and mandatory for collections and multis. - * If set, the srsName attribute will be written for all geometries. - * Default is null. - */ - srsName: null, - - /** - * 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: geometryTypes - * {Object} Maps OpenLayers geometry class names to GML element names. - * Use before accessing this property. - */ - geometryTypes: null, - - /** - * Property: singleFeatureType - * {Boolean} True if there is only 1 featureType, and not an array - * of featuretypes. - */ - singleFeatureType: null, - - /** - * Property: autoConfig - * {Boolean} Indicates if the format was configured without a , - * but auto-configured and during read. - * Subclasses making use of auto-configuration should make - * the first call to the method (usually in the read method) - * with true as 3rd argument, so the auto-configured featureType can be - * reset and the format can be reused for subsequent reads with data from - * different featureTypes. Set to false after read if you want to keep the - * auto-configured values. - */ - - /** - * Property: regExes - * Compiled regular expressions for manipulating strings. - */ - regExes: { - trimSpace: (/^\s*|\s*$/g), - removeSpace: (/\s*/g), - splitSpace: (/\s+/), - trimComma: (/\s*,\s*/g), - featureMember: (/^(.*:)?featureMembers?$/) - }, - - /** - * Constructor: OpenLayers.Format.GML.Base - * Instances of this class are not created directly. Use the - * or constructor - * instead. - * - * Parameters: - * options - {Object} An optional object whose properties will be set on - * this instance. - * - * Valid options properties: - * featureType - {Array(String) or String} Local (without prefix) feature - * typeName(s) (required for write). - * featureNS - {String} Feature namespace (required for write). - * geometryName - {String} Geometry element name (required for write). - */ - initialize: function(options) { - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); - this.setGeometryTypes(); - if(options && options.featureNS) { - this.setNamespace("feature", options.featureNS); - } - this.singleFeatureType = !options || (typeof options.featureType === "string"); - }, - - /** - * Method: read - * - * Parameters: - * data - {DOMElement} A gml:featureMember element, a gml:featureMembers - * element, or an element containing either of the above at any level. - * - * Returns: - * {Array()} An array of features. - */ - 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 features = []; - this.readNode(data, {features: features}, true); - if(features.length == 0) { - // look for gml:featureMember elements - var elements = this.getElementsByTagNameNS( - data, this.namespaces.gml, "featureMember" - ); - if(elements.length) { - for(var i=0, len=elements.length; i 0) { - obj.bounds = container.components[0]; - } - }, - "Point": function(node, container) { - var obj = {points: []}; - this.readChildNodes(node, obj); - if(!container.components) { - container.components = []; - } - container.components.push(obj.points[0]); - }, - "coordinates": function(node, obj) { - var str = this.getChildValue(node).replace( - this.regExes.trimSpace, "" - ); - str = str.replace(this.regExes.trimComma, ","); - var pointList = str.split(this.regExes.splitSpace); - var coords; - var numPoints = pointList.length; - var points = new Array(numPoints); - for(var i=0; i) | 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(OpenLayers.Util.isArray(features)) { - name = "featureMembers"; - } else { - name = "featureMember"; - } - var root = this.writeNode("gml:" + 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": { - "featureMember": function(feature) { - var node = this.createElementNSPlus("gml:featureMember"); - this.writeNode("feature:_typeName", feature, node); - return node; - }, - "MultiPoint": function(geometry) { - var node = this.createElementNSPlus("gml:MultiPoint"); - var components = geometry.components || [geometry]; - for(var i=0, ii=components.length; i mapping. - */ - setGeometryTypes: function() { - this.geometryTypes = { - "OpenLayers.Geometry.Point": "Point", - "OpenLayers.Geometry.MultiPoint": "MultiPoint", - "OpenLayers.Geometry.LineString": "LineString", - "OpenLayers.Geometry.MultiLineString": "MultiLineString", - "OpenLayers.Geometry.Polygon": "Polygon", - "OpenLayers.Geometry.MultiPolygon": "MultiPolygon", - "OpenLayers.Geometry.Collection": "GeometryCollection" - }; - }, - - CLASS_NAME: "OpenLayers.Format.GML.Base" - -}); -/* ====================================================================== - OpenLayers/Format/GML/v3.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Format/GML/Base.js - */ - -/** - * Class: OpenLayers.Format.GML.v3 - * Parses GML version 3. - * - * Inherits from: - * - - */ -OpenLayers.Format.GML.v3 = OpenLayers.Class(OpenLayers.Format.GML.Base, { - - /** - * Property: schemaLocation - * {String} Schema location for a particular minor version. The writers - * conform with the Simple Features Profile for GML. - */ - schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/1.0.0/gmlsf.xsd", - - /** - * Property: curve - * {Boolean} Write gml:Curve instead of gml:LineString elements. This also - * affects the elements in multi-part geometries. Default is false. - * To write gml:Curve elements instead of gml:LineString, set curve - * to true in the options to the contstructor (cannot be changed after - * instantiation). - */ - curve: false, - - /** - * Property: multiCurve - * {Boolean} Write gml:MultiCurve instead of gml:MultiLineString. Since - * the latter is deprecated in GML 3, the default is true. To write - * gml:MultiLineString instead of gml:MultiCurve, set multiCurve to - * false in the options to the constructor (cannot be changed after - * instantiation). - */ - multiCurve: true, - - /** - * Property: surface - * {Boolean} Write gml:Surface instead of gml:Polygon elements. This also - * affects the elements in multi-part geometries. Default is false. - * To write gml:Surface elements instead of gml:Polygon, set surface - * to true in the options to the contstructor (cannot be changed after - * instantiation). - */ - surface: false, - - /** - * Property: multiSurface - * {Boolean} Write gml:multiSurface instead of gml:MultiPolygon. Since - * the latter is deprecated in GML 3, the default is true. To write - * gml:MultiPolygon instead of gml:multiSurface, set multiSurface to - * false in the options to the constructor (cannot be changed after - * instantiation). - */ - multiSurface: true, - - /** - * Constructor: OpenLayers.Format.GML.v3 - * Create a parser for GML v3. - * - * 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({ - "_inherit": function(node, obj, container) { - // SRSReferenceGroup attributes - var dim = parseInt(node.getAttribute("srsDimension"), 10) || - (container && container.srsDimension); - if (dim) { - obj.srsDimension = dim; - } - }, - "featureMembers": function(node, obj) { - this.readChildNodes(node, obj); - }, - "Curve": function(node, container) { - var obj = {points: []}; - this.readers.gml._inherit.apply(this, [node, obj, container]); - this.readChildNodes(node, obj); - if(!container.components) { - container.components = []; - } - container.components.push( - new OpenLayers.Geometry.LineString(obj.points) - ); - }, - "segments": function(node, obj) { - this.readChildNodes(node, obj); - }, - "LineStringSegment": function(node, container) { - var obj = {}; - this.readChildNodes(node, obj); - if(obj.points) { - Array.prototype.push.apply(container.points, obj.points); - } - }, - "pos": function(node, obj) { - var str = this.getChildValue(node).replace( - this.regExes.trimSpace, "" - ); - var coords = str.split(this.regExes.splitSpace); - var point; - if(this.xy) { - point = new OpenLayers.Geometry.Point( - coords[0], coords[1], coords[2] - ); - } else { - point = new OpenLayers.Geometry.Point( - coords[1], coords[0], coords[2] - ); - } - obj.points = [point]; - }, - "posList": function(node, obj) { - var str = this.getChildValue(node).replace( - this.regExes.trimSpace, "" - ); - var coords = str.split(this.regExes.splitSpace); - // The "dimension" attribute is from the GML 3.0.1 spec. - var dim = obj.srsDimension || - parseInt(node.getAttribute("srsDimension") || node.getAttribute("dimension"), 10) || 2; - var j, x, y, z; - var numPoints = coords.length / dim; - var points = new Array(numPoints); - for(var i=0, len=coords.length; i 0) { - container.components = [ - new OpenLayers.Geometry.MultiLineString(obj.components) - ]; - } - }, - "curveMember": function(node, obj) { - this.readChildNodes(node, obj); - }, - "MultiSurface": function(node, container) { - var obj = {components: []}; - this.readers.gml._inherit.apply(this, [node, obj, container]); - this.readChildNodes(node, obj); - if(obj.components.length > 0) { - container.components = [ - new OpenLayers.Geometry.MultiPolygon(obj.components) - ]; - } - }, - "surfaceMember": function(node, obj) { - this.readChildNodes(node, obj); - }, - "surfaceMembers": function(node, obj) { - this.readChildNodes(node, obj); - }, - "pointMembers": function(node, obj) { - this.readChildNodes(node, obj); - }, - "lineStringMembers": function(node, obj) { - this.readChildNodes(node, obj); - }, - "polygonMembers": function(node, obj) { - this.readChildNodes(node, obj); - }, - "geometryMembers": function(node, obj) { - this.readChildNodes(node, obj); - }, - "Envelope": function(node, container) { - var obj = {points: new Array(2)}; - 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) - ); - }, - "lowerCorner": function(node, container) { - var obj = {}; - this.readers.gml.pos.apply(this, [node, obj]); - container.points[0] = obj.points[0]; - }, - "upperCorner": function(node, container) { - var obj = {}; - this.readers.gml.pos.apply(this, [node, obj]); - container.points[1] = obj.points[0]; - } - }, 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} - * 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(OpenLayers.Util.isArray(features)) { - name = "featureMembers"; - } else { - name = "featureMember"; - } - var root = this.writeNode("gml:" + 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({ - "featureMembers": function(features) { - var node = this.createElementNSPlus("gml:featureMembers"); - for(var i=0, len=features.length; i mapping. - */ - setGeometryTypes: function() { - this.geometryTypes = { - "OpenLayers.Geometry.Point": "Point", - "OpenLayers.Geometry.MultiPoint": "MultiPoint", - "OpenLayers.Geometry.LineString": (this.curve === true) ? "Curve": "LineString", - "OpenLayers.Geometry.MultiLineString": (this.multiCurve === false) ? "MultiLineString" : "MultiCurve", - "OpenLayers.Geometry.Polygon": (this.surface === true) ? "Surface" : "Polygon", - "OpenLayers.Geometry.MultiPolygon": (this.multiSurface === false) ? "MultiPolygon" : "MultiSurface", - "OpenLayers.Geometry.Collection": "GeometryCollection" - }; - }, - - CLASS_NAME: "OpenLayers.Format.GML.v3" - -}); -/* ====================================================================== - OpenLayers/Format/Filter/v1_1_0.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Format/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:PropertyIsNotEqual elements. - * - writes matchCase attribute from comparison filters of type EQUAL_TO, - * NOT_EQUAL_TO and LIKE. - * - * Inherits from: - * - - * - - */ -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 - * 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 PropertyName for now - this.writeNode("PropertyName", filter, node); - // handle Literals or Functions for now - this.writeOgcExpression(filter.value, node); - return node; - }, - "PropertyIsNotEqualTo": function(filter) { - var node = this.createElementNSPlus("ogc:PropertyIsNotEqualTo", { - attributes: {matchCase: filter.matchCase} - }); - // no ogc:expression handling for PropertyName for now - this.writeNode("PropertyName", filter, node); - // handle Literals or Functions for now - this.writeOgcExpression(filter.value, node); - return node; - }, - "PropertyIsLike": function(filter) { - var node = this.createElementNSPlus("ogc:PropertyIsLike", { - attributes: { - matchCase: filter.matchCase, - 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"); - // PropertyName is optional in 1.1.0 - filter.property && 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; - }, - "SortBy": function(sortProperties) { - var node = this.createElementNSPlus("ogc:SortBy"); - for (var i=0,l=sortProperties.length;i} filter and converts it into XML. - * - * Parameters: - * filter - {} 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); - if(filter.value instanceof OpenLayers.Filter.Function) { - this.writeNode("Function", filter.value, node); - } else { - 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/OWSCommon.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Format/XML/VersionedOGC.js - */ - -/** - * Class: OpenLayers.Format.OWSCommon - * Read OWSCommon. Create a new instance with the - * constructor. - * - * Inherits from: - * - - */ -OpenLayers.Format.OWSCommon = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { - - /** - * APIProperty: defaultVersion - * {String} Version number to assume if none found. Default is "1.0.0". - */ - defaultVersion: "1.0.0", - - /** - * Constructor: OpenLayers.Format.OWSCommon - * Create a new parser for OWSCommon. - * - * Parameters: - * options - {Object} An optional object whose properties will be set on - * this instance. - */ - - /** - * Method: getVersion - * Returns the version to use. Subclasses can override this function - * if a different version detection is needed. - * - * Parameters: - * root - {DOMElement} - * options - {Object} Optional configuration object. - * - * Returns: - * {String} The version to use. - */ - getVersion: function(root, options) { - var version = this.version; - if(!version) { - // remember version does not correspond to the OWS version - // it corresponds to the WMS/WFS/WCS etc. request version - var uri = root.getAttribute("xmlns:ows"); - // the above will fail if the namespace prefix is different than - // ows and if the namespace is declared on a different element - if (uri && uri.substring(uri.lastIndexOf("/")+1) === "1.1") { - version ="1.1.0"; - } - if(!version) { - version = this.defaultVersion; - } - } - return version; - }, - - /** - * APIMethod: read - * Read an OWSCommon document and return an object. - * - * Parameters: - * data - {String | DOMElement} Data to read. - * options - {Object} Options for the reader. - * - * Returns: - * {Object} An object representing the structure of the document. - */ - - CLASS_NAME: "OpenLayers.Format.OWSCommon" -}); -/* ====================================================================== - OpenLayers/Format/OWSCommon/v1.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Format/OWSCommon.js - */ - -/** - * Class: OpenLayers.Format.OWSCommon.v1 - * Common readers and writers for OWSCommon v1.X formats - * - * Inherits from: - * - - */ -OpenLayers.Format.OWSCommon.v1 = OpenLayers.Class(OpenLayers.Format.XML, { - - /** - * Property: regExes - * Compiled regular expressions for manipulating strings. - */ - regExes: { - trimSpace: (/^\s*|\s*$/g), - removeSpace: (/\s*/g), - splitSpace: (/\s+/), - trimComma: (/\s*,\s*/g) - }, - - /** - * Method: read - * - * Parameters: - * data - {DOMElement} An OWSCommon document element. - * options - {Object} Options for the reader. - * - * Returns: - * {Object} An object representing the OWSCommon document. - */ - read: function(data, options) { - options = OpenLayers.Util.applyDefaults(options, this.options); - var ows = {}; - this.readChildNodes(data, ows); - return ows; - }, - - /** - * 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: { - "ows": { - "Exception": function(node, exceptionReport) { - var exception = { - code: node.getAttribute('exceptionCode'), - locator: node.getAttribute('locator'), - texts: [] - }; - exceptionReport.exceptions.push(exception); - this.readChildNodes(node, exception); - }, - "ExceptionText": function(node, exception) { - var text = this.getChildValue(node); - exception.texts.push(text); - }, - "ServiceIdentification": function(node, obj) { - obj.serviceIdentification = {}; - this.readChildNodes(node, obj.serviceIdentification); - }, - "Title": function(node, obj) { - obj.title = this.getChildValue(node); - }, - "Abstract": function(node, serviceIdentification) { - serviceIdentification["abstract"] = this.getChildValue(node); - }, - "Keywords": function(node, serviceIdentification) { - serviceIdentification.keywords = {}; - this.readChildNodes(node, serviceIdentification.keywords); - }, - "Keyword": function(node, keywords) { - keywords[this.getChildValue(node)] = true; - }, - "ServiceType": function(node, serviceIdentification) { - serviceIdentification.serviceType = { - codeSpace: node.getAttribute('codeSpace'), - value: this.getChildValue(node)}; - }, - "ServiceTypeVersion": function(node, serviceIdentification) { - serviceIdentification.serviceTypeVersion = this.getChildValue(node); - }, - "Fees": function(node, serviceIdentification) { - serviceIdentification.fees = this.getChildValue(node); - }, - "AccessConstraints": function(node, serviceIdentification) { - serviceIdentification.accessConstraints = - this.getChildValue(node); - }, - "ServiceProvider": function(node, obj) { - obj.serviceProvider = {}; - this.readChildNodes(node, obj.serviceProvider); - }, - "ProviderName": function(node, serviceProvider) { - serviceProvider.providerName = this.getChildValue(node); - }, - "ProviderSite": function(node, serviceProvider) { - serviceProvider.providerSite = this.getAttributeNS(node, - this.namespaces.xlink, "href"); - }, - "ServiceContact": function(node, serviceProvider) { - serviceProvider.serviceContact = {}; - this.readChildNodes(node, serviceProvider.serviceContact); - }, - "IndividualName": function(node, serviceContact) { - serviceContact.individualName = this.getChildValue(node); - }, - "PositionName": function(node, serviceContact) { - serviceContact.positionName = this.getChildValue(node); - }, - "ContactInfo": function(node, serviceContact) { - serviceContact.contactInfo = {}; - this.readChildNodes(node, serviceContact.contactInfo); - }, - "Phone": function(node, contactInfo) { - contactInfo.phone = {}; - this.readChildNodes(node, contactInfo.phone); - }, - "Voice": function(node, phone) { - phone.voice = this.getChildValue(node); - }, - "Address": function(node, contactInfo) { - contactInfo.address = {}; - this.readChildNodes(node, contactInfo.address); - }, - "DeliveryPoint": function(node, address) { - address.deliveryPoint = this.getChildValue(node); - }, - "City": function(node, address) { - address.city = this.getChildValue(node); - }, - "AdministrativeArea": function(node, address) { - address.administrativeArea = this.getChildValue(node); - }, - "PostalCode": function(node, address) { - address.postalCode = this.getChildValue(node); - }, - "Country": function(node, address) { - address.country = this.getChildValue(node); - }, - "ElectronicMailAddress": function(node, address) { - address.electronicMailAddress = this.getChildValue(node); - }, - "Role": function(node, serviceContact) { - serviceContact.role = this.getChildValue(node); - }, - "OperationsMetadata": function(node, obj) { - obj.operationsMetadata = {}; - this.readChildNodes(node, obj.operationsMetadata); - }, - "Operation": function(node, operationsMetadata) { - var name = node.getAttribute("name"); - operationsMetadata[name] = {}; - this.readChildNodes(node, operationsMetadata[name]); - }, - "DCP": function(node, operation) { - operation.dcp = {}; - this.readChildNodes(node, operation.dcp); - }, - "HTTP": function(node, dcp) { - dcp.http = {}; - this.readChildNodes(node, dcp.http); - }, - "Get": function(node, http) { - if (!http.get) { - http.get = []; - } - var obj = { - url: this.getAttributeNS(node, this.namespaces.xlink, "href") - }; - this.readChildNodes(node, obj); - http.get.push(obj); - }, - "Post": function(node, http) { - if (!http.post) { - http.post = []; - } - var obj = { - url: this.getAttributeNS(node, this.namespaces.xlink, "href") - }; - this.readChildNodes(node, obj); - http.post.push(obj); - }, - "Parameter": function(node, operation) { - if (!operation.parameters) { - operation.parameters = {}; - } - var name = node.getAttribute("name"); - operation.parameters[name] = {}; - this.readChildNodes(node, operation.parameters[name]); - }, - "Constraint": function(node, obj) { - if (!obj.constraints) { - obj.constraints = {}; - } - var name = node.getAttribute("name"); - obj.constraints[name] = {}; - this.readChildNodes(node, obj.constraints[name]); - }, - "Value": function(node, allowedValues) { - allowedValues[this.getChildValue(node)] = true; - }, - "OutputFormat": function(node, obj) { - obj.formats.push({value: this.getChildValue(node)}); - this.readChildNodes(node, obj); - }, - "WGS84BoundingBox": function(node, obj) { - var boundingBox = {}; - boundingBox.crs = node.getAttribute("crs"); - if (obj.BoundingBox) { - obj.BoundingBox.push(boundingBox); - } else { - obj.projection = boundingBox.crs; - boundingBox = obj; - } - this.readChildNodes(node, boundingBox); - }, - "BoundingBox": function(node, obj) { - // FIXME: We consider that BoundingBox is the same as WGS84BoundingBox - // LowerCorner = "min_x min_y" - // UpperCorner = "max_x max_y" - // It should normally depend on the projection - this.readers['ows']['WGS84BoundingBox'].apply(this, [node, obj]); - }, - "LowerCorner": function(node, obj) { - var str = this.getChildValue(node).replace( - this.regExes.trimSpace, ""); - str = str.replace(this.regExes.trimComma, ","); - var pointList = str.split(this.regExes.splitSpace); - obj.left = pointList[0]; - obj.bottom = pointList[1]; - }, - "UpperCorner": function(node, obj) { - var str = this.getChildValue(node).replace( - this.regExes.trimSpace, ""); - str = str.replace(this.regExes.trimComma, ","); - var pointList = str.split(this.regExes.splitSpace); - obj.right = pointList[0]; - obj.top = pointList[1]; - obj.bounds = new OpenLayers.Bounds(obj.left, obj.bottom, - obj.right, obj.top); - delete obj.left; - delete obj.bottom; - delete obj.right; - delete obj.top; - }, - "Language": function(node, obj) { - obj.language = this.getChildValue(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: { - "ows": { - "BoundingBox": function(options, nodeName) { - var node = this.createElementNSPlus(nodeName || "ows:BoundingBox", { - attributes: { - crs: options.projection - } - }); - this.writeNode("ows:LowerCorner", options, node); - this.writeNode("ows:UpperCorner", options, node); - return node; - }, - "LowerCorner": function(options) { - var node = this.createElementNSPlus("ows:LowerCorner", { - value: options.bounds.left + " " + options.bounds.bottom }); - return node; - }, - "UpperCorner": function(options) { - var node = this.createElementNSPlus("ows:UpperCorner", { - value: options.bounds.right + " " + options.bounds.top }); - return node; - }, - "Identifier": function(identifier) { - var node = this.createElementNSPlus("ows:Identifier", { - value: identifier }); - return node; - }, - "Title": function(title) { - var node = this.createElementNSPlus("ows:Title", { - value: title }); - return node; - }, - "Abstract": function(abstractValue) { - var node = this.createElementNSPlus("ows:Abstract", { - value: abstractValue }); - return node; - }, - "OutputFormat": function(format) { - var node = this.createElementNSPlus("ows:OutputFormat", { - value: format }); - return node; - } - } - }, - - CLASS_NAME: "OpenLayers.Format.OWSCommon.v1" - -}); -/* ====================================================================== - OpenLayers/Format/OWSCommon/v1_0_0.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Format/OWSCommon/v1.js - */ - -/** - * Class: OpenLayers.Format.OWSCommon.v1_0_0 - * Parser for OWS Common version 1.0.0. - * - * Inherits from: - * - - */ -OpenLayers.Format.OWSCommon.v1_0_0 = OpenLayers.Class(OpenLayers.Format.OWSCommon.v1, { - - /** - * Property: namespaces - * {Object} Mapping of namespace aliases to namespace URIs. - */ - namespaces: { - ows: "http://www.opengis.net/ows", - xlink: "http://www.w3.org/1999/xlink" - }, - - /** - * 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: { - "ows": OpenLayers.Util.applyDefaults({ - "ExceptionReport": function(node, obj) { - obj.success = false; - obj.exceptionReport = { - version: node.getAttribute('version'), - language: node.getAttribute('language'), - exceptions: [] - }; - this.readChildNodes(node, obj.exceptionReport); - } - }, OpenLayers.Format.OWSCommon.v1.prototype.readers.ows) - }, - - /** - * 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: { - "ows": OpenLayers.Format.OWSCommon.v1.prototype.writers.ows - }, - - CLASS_NAME: "OpenLayers.Format.OWSCommon.v1_0_0" - -}); -/* ====================================================================== - OpenLayers/Format/WFST/v1_1_0.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Format/WFST/v1.js - * @requires OpenLayers/Format/Filter/v1_1_0.js - * @requires OpenLayers/Format/OWSCommon/v1_0_0.js - */ - -/** - * Class: OpenLayers.Format.WFST.v1_1_0 - * A format for creating WFS v1.1.0 transactions. Create a new instance with the - * constructor. - * - * Inherits from: - * - - * - - */ -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 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]); - }, - - /** - * 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). - * first - {Boolean} Should be set to true for the first node read. This - * is usually the readNode call in the read method. Without this being - * set, auto-configured properties will stick on subsequent reads. - * - * Returns: - * {Object} The input object, modified (or a new one if none was provided). - */ - readNode: function(node, obj, first) { - // Not the superclass, only the mixin classes inherit from - // Format.GML.v3. We need this because we don't want to get readNode - // from the superclass's superclass, which is OpenLayers.Format.XML. - return OpenLayers.Format.GML.v3.prototype.readNode.apply(this, arguments); - }, - - /** - * 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"], - "ows": OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers["ows"] - }, - - /** - * 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 && this.setAttributes(node, { - resultType: options.resultType, - startIndex: options.startIndex, - count: options.count - }); - return node; - }, - "Query": function(options) { - options = OpenLayers.Util.extend({ - featureNS: this.featureNS, - featurePrefix: this.featurePrefix, - featureType: this.featureType, - srsName: this.srsName - }, options); - var prefix = options.featurePrefix; - var node = this.createElementNSPlus("wfs:Query", { - attributes: { - typeName: (prefix ? prefix + ":" : "") + - options.featureType, - srsName: options.srsName - } - }); - if(options.featureNS) { - node.setAttribute("xmlns:" + prefix, options.featureNS); - } - if(options.propertyNames) { - for(var i=0,len = options.propertyNames.length; i transform-origin - * or WebkitTransformOrigin -> -webkit-transform-origin - * - * Parameters: - * prefixedDom - {String} The property to convert - * - * Returns: - * {String} The CSS property - */ - function domToCss(prefixedDom) { - if (!prefixedDom) { return null; } - return prefixedDom. - replace(/([A-Z])/g, function(c) { return "-" + c.toLowerCase(); }). - replace(/^ms-/, "-ms-"); - } - - /** - * APIMethod: css - * Detect which property is used for a CSS property - * - * Parameters: - * property - {String} The standard (unprefixed) CSS property name - * - * Returns: - * {String} The standard CSS property, prefixed property or null if not - * supported - */ - function css(property) { - if (cssCache[property] === undefined) { - var domProperty = property. - replace(/(-[\s\S])/g, function(c) { return c.charAt(1).toUpperCase(); }); - var prefixedDom = style(domProperty); - cssCache[property] = domToCss(prefixedDom); - } - return cssCache[property]; - } - - /** - * APIMethod: js - * Detect which property is used for a JS property/method - * - * Parameters: - * obj - {Object} The object to test on - * property - {String} The standard (unprefixed) JS property name - * - * Returns: - * {String} The standard JS property, prefixed property or null if not - * supported - */ - function js(obj, property) { - if (jsCache[property] === undefined) { - var tmpProp, - i = 0, - l = VENDOR_PREFIXES.length, - prefix, - isStyleObj = (typeof obj.cssText !== "undefined"); - - jsCache[property] = null; - for(; i in series for some - * duration. - * - * Parameters: - * callback - {Function} The function to be called at the next animation frame. - * duration - {Number} Optional duration for the loop. If not provided, the - * animation loop will execute indefinitely. - * element - {DOMElement} Optional element that visually bounds the animation. - * - * Returns: - * {Number} Identifier for the animation loop. Used to stop animations with - * . - */ - function start(callback, duration, element) { - duration = duration > 0 ? duration : Number.POSITIVE_INFINITY; - var id = ++counter; - var start = +new Date; - loops[id] = function() { - if (loops[id] && +new Date - start <= duration) { - callback(); - if (loops[id]) { - requestFrame(loops[id], element); - } - } else { - delete loops[id]; - } - }; - requestFrame(loops[id], element); - return id; - } - - /** - * Function: stop - * Terminates an animation loop started with . - * - * Parameters: - * id - {Number} Identifier returned from . - */ - function stop(id) { - delete loops[id]; - } - - return { - isNative: isNative, - requestFrame: requestFrame, - start: start, - stop: stop - }; - -})(window); -/* ====================================================================== - OpenLayers/Tween.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/BaseTypes/Class.js - * @requires OpenLayers/Animation.js - */ - -/** - * Namespace: OpenLayers.Tween - */ -OpenLayers.Tween = OpenLayers.Class({ - - /** - * APIProperty: easing - * {(Function)} Easing equation used for the animation - * Defaultly set to OpenLayers.Easing.Expo.easeOut - */ - easing: null, - - /** - * APIProperty: begin - * {Object} Values to start the animation with - */ - begin: null, - - /** - * APIProperty: finish - * {Object} Values to finish the animation with - */ - finish: null, - - /** - * APIProperty: duration - * {int} duration of the tween (number of steps) - */ - duration: null, - - /** - * APIProperty: callbacks - * {Object} An object with start, eachStep and done properties whose values - * are functions to be call during the animation. They are passed the - * current computed value as argument. - */ - callbacks: null, - - /** - * Property: time - * {int} Step counter - */ - time: null, - - /** - * Property: animationId - * {int} Loop id returned by OpenLayers.Animation.start - */ - animationId: null, - - /** - * Property: playing - * {Boolean} Tells if the easing is currently playing - */ - playing: false, - - /** - * Constructor: OpenLayers.Tween - * Creates a Tween. - * - * Parameters: - * easing - {(Function)} easing function method to use - */ - initialize: function(easing) { - this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut; - }, - - /** - * APIMethod: start - * Plays the Tween, and calls the callback method on each step - * - * Parameters: - * begin - {Object} values to start the animation with - * finish - {Object} values to finish the animation with - * duration - {int} duration of the tween (number of steps) - * options - {Object} hash of options (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; - OpenLayers.Animation.stop(this.animationId); - this.animationId = null; - if (this.callbacks && this.callbacks.start) { - this.callbacks.start.call(this, this.begin); - } - this.animationId = OpenLayers.Animation.start( - OpenLayers.Function.bind(this.play, this) - ); - }, - - /** - * APIMethod: stop - * Stops the Tween, and calls the done callback - * Doesn't do anything if animation is already finished - */ - stop: function() { - if (!this.playing) { - return; - } - - if (this.callbacks && this.callbacks.done) { - this.callbacks.done.call(this, this.finish); - } - OpenLayers.Animation.stop(this.animationId); - this.animationId = null; - this.playing = false; - }, - - /** - * Method: play - * Calls the appropriate easing method - */ - play: function() { - var value = {}; - for (var i in this.begin) { - var b = this.begin[i]; - var f = this.finish[i]; - if (b == null || f == null || isNaN(b) || isNaN(f)) { - throw new TypeError('invalid value for Tween'); - } - - var c = f - b; - value[i] = this.easing.apply(this, [this.time, b, c, this.duration]); - } - this.time++; - - if (this.callbacks && this.callbacks.eachStep) { - this.callbacks.eachStep.call(this, value); - } - - if (this.time > this.duration) { - this.stop(); - } - }, - - /** - * Create empty functions for all easing methods. - */ - CLASS_NAME: "OpenLayers.Tween" -}); - -/** - * Namespace: OpenLayers.Easing - * - * Credits: - * Easing Equations by Robert Penner, - */ -OpenLayers.Easing = { - /** - * Create empty functions for all easing methods. - */ - CLASS_NAME: "OpenLayers.Easing" -}; - -/** - * Namespace: OpenLayers.Easing.Linear - */ -OpenLayers.Easing.Linear = { - - /** - * Function: easeIn - * - * Parameters: - * t - {Float} time - * b - {Float} beginning position - * c - {Float} total change - * d - {Float} duration of the transition - * - * Returns: - * {Float} - */ - easeIn: function(t, b, c, d) { - return c*t/d + b; - }, - - /** - * Function: easeOut - * - * Parameters: - * t - {Float} time - * b - {Float} beginning position - * c - {Float} total change - * d - {Float} duration of the transition - * - * Returns: - * {Float} - */ - easeOut: function(t, b, c, d) { - return c*t/d + b; - }, - - /** - * Function: easeInOut - * - * Parameters: - * t - {Float} time - * b - {Float} beginning position - * c - {Float} total change - * d - {Float} duration of the transition - * - * Returns: - * {Float} - */ - easeInOut: function(t, b, c, d) { - return c*t/d + b; - }, - - CLASS_NAME: "OpenLayers.Easing.Linear" -}; - -/** - * Namespace: OpenLayers.Easing.Expo - */ -OpenLayers.Easing.Expo = { - - /** - * Function: easeIn - * - * Parameters: - * t - {Float} time - * b - {Float} beginning position - * c - {Float} total change - * d - {Float} duration of the transition - * - * Returns: - * {Float} - */ - easeIn: function(t, b, c, d) { - return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; - }, - - /** - * Function: easeOut - * - * Parameters: - * t - {Float} time - * b - {Float} beginning position - * c - {Float} total change - * d - {Float} duration of the transition - * - * Returns: - * {Float} - */ - easeOut: function(t, b, c, d) { - return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; - }, - - /** - * Function: easeInOut - * - * Parameters: - * t - {Float} time - * b - {Float} beginning position - * c - {Float} total change - * d - {Float} duration of the transition - * - * Returns: - * {Float} - */ - easeInOut: function(t, b, c, d) { - if (t==0) return b; - if (t==d) return b+c; - if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; - return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; - }, - - CLASS_NAME: "OpenLayers.Easing.Expo" -}; - -/** - * Namespace: OpenLayers.Easing.Quad - */ -OpenLayers.Easing.Quad = { - - /** - * Function: easeIn - * - * Parameters: - * t - {Float} time - * b - {Float} beginning position - * c - {Float} total change - * d - {Float} duration of the transition - * - * Returns: - * {Float} - */ - easeIn: function(t, b, c, d) { - return c*(t/=d)*t + b; - }, - - /** - * Function: easeOut - * - * Parameters: - * t - {Float} time - * b - {Float} beginning position - * c - {Float} total change - * d - {Float} duration of the transition - * - * Returns: - * {Float} - */ - easeOut: function(t, b, c, d) { - return -c *(t/=d)*(t-2) + b; - }, - - /** - * Function: easeInOut - * - * Parameters: - * t - {Float} time - * b - {Float} beginning position - * c - {Float} total change - * d - {Float} duration of the transition - * - * Returns: - * {Float} - */ - easeInOut: function(t, b, c, d) { - if ((t/=d/2) < 1) return c/2*t*t + b; - return -c/2 * ((--t)*(t-2) - 1) + b; - }, - - CLASS_NAME: "OpenLayers.Easing.Quad" -}; -/* ====================================================================== - OpenLayers/Projection.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/BaseTypes/Class.js - * @requires OpenLayers/Util.js - */ - -/** - * Namespace: OpenLayers.Projection - * Methods for coordinate transforms between coordinate systems. By default, - * OpenLayers ships with the ability to transform coordinates between - * geographic (EPSG:4326) and web or spherical mercator (EPSG:900913 et al.) - * coordinate reference systems. See the method for details - * on usage. - * - * Additional transforms may be added by using the - * library. If the proj4js library is included, the method - * will work between any two coordinate reference systems with proj4js - * definitions. - * - * If the proj4js library is not included, or if you wish to allow transforms - * between arbitrary coordinate reference systems, use the - * method to register a custom transform method. - */ -OpenLayers.Projection = OpenLayers.Class({ - - /** - * Property: proj - * {Object} Proj4js.Proj instance. - */ - proj: null, - - /** - * Property: projCode - * {String} - */ - projCode: null, - - /** - * Property: titleRegEx - * {RegExp} regular expression to strip the title from a proj4js definition - */ - titleRegEx: /\+title=[^\+]*/, - - /** - * Constructor: OpenLayers.Projection - * This class offers several methods for interacting with a wrapped - * pro4js projection object. - * - * Parameters: - * projCode - {String} A string identifying the Well Known Identifier for - * the projection. - * options - {Object} An optional object to set additional properties - * on the projection. - * - * Returns: - * {} A projection object. - */ - initialize: function(projCode, options) { - OpenLayers.Util.extend(this, options); - this.projCode = projCode; - if (typeof Proj4js == "object") { - this.proj = new Proj4js.Proj(projCode); - } - }, - - /** - * APIMethod: getCode - * Get the string SRS code. - * - * Returns: - * {String} The SRS code. - */ - getCode: function() { - return this.proj ? this.proj.srsCode : this.projCode; - }, - - /** - * APIMethod: getUnits - * Get the units string for the projection -- returns null if - * proj4js is not available. - * - * Returns: - * {String} The units abbreviation. - */ - getUnits: function() { - return this.proj ? this.proj.units : null; - }, - - /** - * Method: toString - * Convert projection to string (getCode wrapper). - * - * Returns: - * {String} The projection code. - */ - toString: function() { - return this.getCode(); - }, - - /** - * Method: equals - * Test equality of two projection instances. Determines equality based - * soley on the projection code. - * - * Returns: - * {Boolean} The two projections are equivalent. - */ - equals: function(projection) { - var p = projection, equals = false; - if (p) { - if (!(p instanceof OpenLayers.Projection)) { - p = new OpenLayers.Projection(p); - } - if ((typeof Proj4js == "object") && this.proj.defData && p.proj.defData) { - equals = this.proj.defData.replace(this.titleRegEx, "") == - p.proj.defData.replace(this.titleRegEx, ""); - } else if (p.getCode) { - var source = this.getCode(), target = p.getCode(); - equals = source == target || - !!OpenLayers.Projection.transforms[source] && - OpenLayers.Projection.transforms[source][target] === - OpenLayers.Projection.nullTransform; - } - } - return equals; - }, - - /* Method: destroy - * Destroy projection object. - */ - destroy: function() { - delete this.proj; - delete this.projCode; - }, - - CLASS_NAME: "OpenLayers.Projection" -}); - -/** - * Property: transforms - * {Object} Transforms is an object, with from properties, each of which may - * have a to property. This allows you to define projections without - * requiring support for proj4js to be included. - * - * This object has keys which correspond to a 'source' projection object. The - * keys should be strings, corresponding to the projection.getCode() value. - * Each source projection object should have a set of destination projection - * keys included in the object. - * - * Each value in the destination object should be a transformation function, - * where the function is expected to be passed an object with a .x and a .y - * property. The function should return the object, with the .x and .y - * transformed according to the transformation function. - * - * Note - Properties on this object should not be set directly. To add a - * transform method to this object, use the method. For an - * example of usage, see the OpenLayers.Layer.SphericalMercator file. - */ -OpenLayers.Projection.transforms = {}; - -/** - * APIProperty: defaults - * {Object} Defaults for the SRS codes known to OpenLayers (currently - * EPSG:4326, CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, EPSG:900913, EPSG:3857, - * EPSG:102113 and EPSG:102100). Keys are the SRS code, values are units, - * maxExtent (the validity extent for the SRS) and yx (true if this SRS is - * known to have a reverse axis order). - */ -OpenLayers.Projection.defaults = { - "EPSG:4326": { - units: "degrees", - maxExtent: [-180, -90, 180, 90], - yx: true - }, - "CRS:84": { - units: "degrees", - maxExtent: [-180, -90, 180, 90] - }, - "EPSG:900913": { - units: "m", - maxExtent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34] - } -}; - -/** - * APIMethod: addTransform - * Set a custom transform method between two projections. Use this method in - * cases where the proj4js lib is not available or where custom projections - * need to be handled. - * - * Parameters: - * from - {String} The code for the source projection - * to - {String} the code for the destination projection - * method - {Function} A function that takes a point as an argument and - * transforms that point from the source to the destination projection - * in place. The original point should be modified. - */ -OpenLayers.Projection.addTransform = function(from, to, method) { - if (method === OpenLayers.Projection.nullTransform) { - var defaults = OpenLayers.Projection.defaults[from]; - if (defaults && !OpenLayers.Projection.defaults[to]) { - OpenLayers.Projection.defaults[to] = defaults; - } - } - if(!OpenLayers.Projection.transforms[from]) { - OpenLayers.Projection.transforms[from] = {}; - } - OpenLayers.Projection.transforms[from][to] = method; -}; - -/** - * APIMethod: transform - * Transform a point coordinate from one projection to another. Note that - * the input point is transformed in place. - * - * Parameters: - * point - { | Object} An object with x and y - * properties representing coordinates in those dimensions. - * source - {OpenLayers.Projection} Source map coordinate system - * dest - {OpenLayers.Projection} Destination map coordinate system - * - * Returns: - * point - {object} A transformed coordinate. The original point is modified. - */ -OpenLayers.Projection.transform = function(point, source, dest) { - if (source && dest) { - if (!(source instanceof OpenLayers.Projection)) { - source = new OpenLayers.Projection(source); - } - if (!(dest instanceof OpenLayers.Projection)) { - dest = new OpenLayers.Projection(dest); - } - if (source.proj && dest.proj) { - point = Proj4js.transform(source.proj, dest.proj, point); - } else { - var sourceCode = source.getCode(); - var destCode = dest.getCode(); - var transforms = OpenLayers.Projection.transforms; - if (transforms[sourceCode] && transforms[sourceCode][destCode]) { - transforms[sourceCode][destCode](point); - } - } - } - return point; -}; - -/** - * APIFunction: nullTransform - * A null transformation - useful for defining projection aliases when - * proj4js is not available: - * - * (code) - * OpenLayers.Projection.addTransform("EPSG:3857", "EPSG:900913", - * OpenLayers.Projection.nullTransform); - * OpenLayers.Projection.addTransform("EPSG:900913", "EPSG:3857", - * OpenLayers.Projection.nullTransform); - * (end) - */ -OpenLayers.Projection.nullTransform = function(point) { - return point; -}; - -/** - * Note: Transforms for web mercator <-> geographic - * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113 and EPSG:102100. - * OpenLayers originally started referring to EPSG:900913 as web mercator. - * The EPSG has declared EPSG:3857 to be web mercator. - * ArcGIS 10 recognizes the EPSG:3857, EPSG:102113, and EPSG:102100 as - * equivalent. See http://blogs.esri.com/Dev/blogs/arcgisserver/archive/2009/11/20/ArcGIS-Online-moving-to-Google-_2F00_-Bing-tiling-scheme_3A00_-What-does-this-mean-for-you_3F00_.aspx#12084. - * For geographic, OpenLayers recognizes EPSG:4326, CRS:84 and - * urn:ogc:def:crs:EPSG:6.6:4326. OpenLayers also knows about the reverse axis - * order for EPSG:4326. - */ -(function() { - - var pole = 20037508.34; - - function inverseMercator(xy) { - xy.x = 180 * xy.x / pole; - xy.y = 180 / Math.PI * (2 * Math.atan(Math.exp((xy.y / pole) * Math.PI)) - Math.PI / 2); - return xy; - } - - function forwardMercator(xy) { - xy.x = xy.x * pole / 180; - xy.y = Math.log(Math.tan((90 + xy.y) * Math.PI / 360)) / Math.PI * pole; - return xy; - } - - function map(base, codes) { - var add = OpenLayers.Projection.addTransform; - var same = OpenLayers.Projection.nullTransform; - var i, len, code, other, j; - for (i=0, len=codes.length; i=0; --i) { - map(mercator[i], geographic); - } - for (i=geographic.length-1; i>=0; --i) { - map(geographic[i], mercator); - } - -})(); -/* ====================================================================== - OpenLayers/Map.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/BaseTypes/Class.js - * @requires OpenLayers/Util.js - * @requires OpenLayers/Events.js - * @requires OpenLayers/Tween.js - * @requires OpenLayers/Projection.js - */ - -/** - * Class: OpenLayers.Map - * Instances of OpenLayers.Map are interactive maps embedded in a web page. - * Create a new map with the constructor. - * - * On their own maps do not provide much functionality. To extend a map - * it's necessary to add controls () and - * layers () to the map. - */ -OpenLayers.Map = OpenLayers.Class({ - - /** - * Constant: Z_INDEX_BASE - * {Object} Base z-indexes for different classes of thing - */ - Z_INDEX_BASE: { - BaseLayer: 100, - Overlay: 325, - Feature: 725, - Popup: 750, - Control: 1000 - }, - - /** - * APIProperty: events - * {} - * - * Register a listener for a particular event with the following syntax: - * (code) - * map.events.register(type, obj, listener); - * (end) - * - * Listeners will be called with a reference to an event object. The - * properties of this event depends on exactly what happened. - * - * All event objects have at least the following properties: - * object - {Object} A reference to map.events.object. - * element - {DOMElement} A reference to map.events.element. - * - * Browser events have the following additional properties: - * xy - {} The pixel location of the event (relative - * to the the map viewport). - * - * Supported map event types: - * preaddlayer - triggered before a layer has been added. The event - * object will include a *layer* property that references the layer - * to be added. When a listener returns "false" the adding will be - * aborted. - * addlayer - triggered after a layer has been added. The event object - * will include a *layer* property that references the added layer. - * preremovelayer - triggered before a layer has been removed. The event - * object will include a *layer* property that references the layer - * to be removed. When a listener returns "false" the removal will be - * aborted. - * removelayer - triggered after a layer has been removed. The event - * object will include a *layer* property that references the removed - * layer. - * changelayer - triggered after a layer name change, order change, - * opacity change, params change, visibility change (due to resolution - * thresholds) or attribution change (due to extent change). Listeners - * will receive an event object with *layer* and *property* properties. - * The *layer* property will be a reference to the changed layer. The - * *property* property will be a key to the changed property (name, - * order, opacity, params, visibility or attribution). - * movestart - triggered after the start of a drag, pan, or zoom - * move - triggered after each drag, pan, or zoom - * moveend - triggered after a drag, pan, or zoom completes - * zoomend - triggered after a zoom completes - * mouseover - triggered after mouseover the map - * mouseout - triggered after mouseout the map - * mousemove - triggered after mousemove the map - * changebaselayer - triggered after the base layer changes - * updatesize - triggered after the method was executed - */ - - /** - * Property: id - * {String} Unique identifier for the map - */ - id: null, - - /** - * Property: fractionalZoom - * {Boolean} For a base layer that supports it, allow the map resolution - * to be set to a value between one of the values in the resolutions - * array. Default is false. - * - * When fractionalZoom is set to true, it is possible to zoom to - * an arbitrary extent. This requires a base layer from a source - * that supports requests for arbitrary extents (i.e. not cached - * tiles on a regular lattice). This means that fractionalZoom - * will not work with commercial layers (Google, Yahoo, VE), layers - * using TileCache, or any other pre-cached data sources. - * - * If you are using fractionalZoom, then you should also use - * instead of layer.resolutions[zoom] as the - * former works for non-integer zoom levels. - */ - fractionalZoom: false, - - /** - * APIProperty: events - * {} An events object that handles all - * events on the map - */ - events: null, - - /** - * APIProperty: allOverlays - * {Boolean} Allow the map to function with "overlays" only. Defaults to - * false. If true, the lowest layer in the draw order will act as - * the base layer. In addition, if set to true, all layers will - * have isBaseLayer set to false when they are added to the map. - * - * Note: - * If you set map.allOverlays to true, then you *cannot* use - * map.setBaseLayer or layer.setIsBaseLayer. With allOverlays true, - * the lowest layer in the draw layer is the base layer. So, to change - * the base layer, use or to set the layer - * index to 0. - */ - allOverlays: false, - - /** - * APIProperty: div - * {DOMElement|String} The element that contains the map (or an id for - * that element). If the constructor is called - * with two arguments, this should be provided as the first argument. - * Alternatively, the map constructor can be called with the options - * object as the only argument. In this case (one argument), a - * div property may or may not be provided. If the div property - * is not provided, the map can be rendered to a container later - * using the method. - * - * Note: - * If you are calling after map construction, do not use - * auto. Instead, divide your by your - * maximum expected dimension. - */ - div: null, - - /** - * Property: dragging - * {Boolean} The map is currently being dragged. - */ - dragging: false, - - /** - * Property: size - * {} Size of the main div (this.div) - */ - size: null, - - /** - * Property: viewPortDiv - * {HTMLDivElement} The element that represents the map viewport - */ - viewPortDiv: null, - - /** - * Property: layerContainerOrigin - * {} The lonlat at which the later container was - * re-initialized (on-zoom) - */ - layerContainerOrigin: null, - - /** - * Property: layerContainerDiv - * {HTMLDivElement} The element that contains the layers. - */ - layerContainerDiv: null, - - /** - * APIProperty: layers - * {Array()} Ordered list of layers in the map - */ - layers: null, - - /** - * APIProperty: controls - * {Array()} List of controls associated with the map. - * - * If not provided in the map options at construction, the map will - * by default be given the following controls if present in the build: - * - or - * - or - * - - * - - */ - controls: null, - - /** - * Property: popups - * {Array()} List of popups associated with the map - */ - popups: null, - - /** - * APIProperty: baseLayer - * {} The currently selected base layer. This determines - * min/max zoom level, projection, etc. - */ - baseLayer: null, - - /** - * Property: center - * {} The current center of the map - */ - center: null, - - /** - * Property: resolution - * {Float} The resolution of the map. - */ - resolution: null, - - /** - * Property: zoom - * {Integer} The current zoom level of the map - */ - zoom: 0, - - /** - * Property: panRatio - * {Float} The ratio of the current extent within - * which panning will tween. - */ - panRatio: 1.5, - - /** - * APIProperty: options - * {Object} The options object passed to the class constructor. Read-only. - */ - options: null, - - // Options - - /** - * APIProperty: tileSize - * {} Set in the map options to override the default tile - * size for this map. - */ - tileSize: null, - - /** - * APIProperty: projection - * {String} Set in the map options to specify the default projection - * for layers added to this map. When using a projection other than EPSG:4326 - * (CRS:84, Geographic) or EPSG:3857 (EPSG:900913, Web Mercator), - * also set maxExtent, maxResolution or resolutions. Default is "EPSG:4326". - * Note that the projection of the map is usually determined - * by that of the current baseLayer (see and ). - */ - projection: "EPSG:4326", - - /** - * APIProperty: units - * {String} The map units. Possible values are 'degrees' (or 'dd'), 'm', - * 'ft', 'km', 'mi', 'inches'. Normally taken from the projection. - * Only required if both map and layers do not define a projection, - * or if they define a projection which does not define units - */ - units: null, - - /** - * APIProperty: resolutions - * {Array(Float)} A list of map resolutions (map units per pixel) in - * descending order. If this is not set in the layer constructor, it - * will be set based on other resolution related properties - * (maxExtent, maxResolution, maxScale, etc.). - */ - resolutions: null, - - /** - * APIProperty: maxResolution - * {Float} Required if you are not displaying the whole world on a tile - * with the size specified in . - */ - maxResolution: null, - - /** - * APIProperty: minResolution - * {Float} - */ - minResolution: null, - - /** - * APIProperty: maxScale - * {Float} - */ - maxScale: null, - - /** - * APIProperty: minScale - * {Float} - */ - minScale: null, - - /** - * APIProperty: maxExtent - * {|Array} If provided as an array, the array - * should consist of four values (left, bottom, right, top). - * The maximum extent for the map. Defaults to the - * whole world in decimal degrees (-180, -90, 180, 90). Specify a - * different extent in the map options if you are not using a geographic - * projection and displaying the whole world. To restrict user panning - * and zooming of the map, use instead. The value - * for will change calculations for tile URLs. - */ - maxExtent: null, - - /** - * APIProperty: minExtent - * {|Array} If provided as an array, the array - * should consist of four values (left, bottom, right, top). - * The minimum extent for the map. Defaults to null. - */ - minExtent: null, - - /** - * APIProperty: restrictedExtent - * {|Array} If provided as an array, the array - * should consist of four values (left, bottom, right, top). - * Limit map navigation to this extent where possible. - * If a non-null restrictedExtent is set, panning will be restricted - * to the given bounds. In addition, zooming to a resolution that - * displays more than the restricted extent will center the map - * on the restricted extent. If you wish to limit the zoom level - * or resolution, use maxResolution. - */ - restrictedExtent: null, - - /** - * APIProperty: numZoomLevels - * {Integer} Number of zoom levels for the map. Defaults to 16. Set a - * different value in the map options if needed. - */ - numZoomLevels: 16, - - /** - * APIProperty: theme - * {String} Relative path to a CSS file from which to load theme styles. - * Specify null in the map options (e.g. {theme: null}) if you - * want to get cascading style declarations - by putting links to - * stylesheets or style declarations directly in your page. - */ - theme: null, - - /** - * APIProperty: displayProjection - * {} Requires proj4js support for projections other - * than EPSG:4326 or EPSG:900913/EPSG:3857. Projection used by - * several controls to display data to user. If this property is set, - * it will be set on any control which has a null displayProjection - * property at the time the control is added to the map. - */ - displayProjection: null, - - /** - * APIProperty: fallThrough - * {Boolean} Should OpenLayers allow events on the map to fall through to - * other elements on the page, or should it swallow them? (#457) - * Default is to fall through. - */ - fallThrough: true, - - /** - * APIProperty: autoUpdateSize - * {Boolean} Should OpenLayers automatically update the size of the map - * when the resize event is fired. Default is true. - */ - autoUpdateSize: true, - - /** - * Property: panTween - * {} Animated panning tween object, see panTo() - */ - panTween: null, - - /** - * APIProperty: eventListeners - * {Object} If set as an option at construction, the eventListeners - * object will be registered with . Object - * structure must be a listeners object as shown in the example for - * the events.on method. - */ - eventListeners: null, - - /** - * APIProperty: panMethod - * {Function} The Easing function to be used for tweening. Default is - * OpenLayers.Easing.Expo.easeOut. Setting this to 'null' turns off - * animated panning. - */ - panMethod: OpenLayers.Easing.Expo.easeOut, - - /** - * Property: panDuration - * {Integer} The number of steps to be passed to the - * OpenLayers.Tween.start() method when the map is - * panned. - * Default is 50. - */ - panDuration: 50, - - /** - * Property: paddingForPopups - * {} Outside margin of the popup. Used to prevent - * the popup from getting too close to the map border. - */ - paddingForPopups : null, - - /** - * Property: layerContainerOriginPx - * {Object} Cached object representing the layer container origin (in pixels). - */ - layerContainerOriginPx: null, - - /** - * Property: minPx - * {Object} An object with a 'x' and 'y' values that is the lower - * left of maxExtent in viewport pixel space. - * Used to verify in moveByPx that the new location we're moving to - * is valid. It is also used in the getLonLatFromViewPortPx function - * of Layer. - */ - minPx: null, - - /** - * Property: maxPx - * {Object} An object with a 'x' and 'y' values that is the top - * right of maxExtent in viewport pixel space. - * Used to verify in moveByPx that the new location we're moving to - * is valid. - */ - maxPx: null, - - /** - * Constructor: OpenLayers.Map - * Constructor for a new OpenLayers.Map instance. There are two possible - * ways to call the map constructor. See the examples below. - * - * Parameters: - * div - {DOMElement|String} The element or id of an element in your page - * that will contain the map. May be omitted if the
option is - * provided or if you intend to call the method later. - * options - {Object} Optional object with properties to tag onto the map. - * - * Valid options (in addition to the listed API properties): - * center - {|Array} The default initial center of the map. - * If provided as array, the first value is the x coordinate, - * and the 2nd value is the y coordinate. - * Only specify if is provided. - * Note that if an ArgParser/Permalink control is present, - * and the querystring contains coordinates, center will be set - * by that, and this option will be ignored. - * zoom - {Number} The initial zoom level for the map. Only specify if - * is provided. - * Note that if an ArgParser/Permalink control is present, - * and the querystring contains a zoom level, zoom will be set - * by that, and this option will be ignored. - * extent - {|Array} The initial extent of the map. - * If provided as an array, the array should consist of - * four values (left, bottom, right, top). - * Only specify if
and are not provided. - * - * Examples: - * (code) - * // create a map with default options in an element with the id "map1" - * var map = new OpenLayers.Map("map1"); - * - * // create a map with non-default options in an element with id "map2" - * var options = { - * projection: "EPSG:3857", - * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000), - * center: new OpenLayers.LonLat(-12356463.476333, 5621521.4854095) - * }; - * var map = new OpenLayers.Map("map2", options); - * - * // map with non-default options - same as above but with a single argument, - * // a restricted extent, and using arrays for bounds and center - * var map = new OpenLayers.Map({ - * div: "map_id", - * projection: "EPSG:3857", - * maxExtent: [-18924313.432222, -15538711.094146, 18924313.432222, 15538711.094146], - * restrictedExtent: [-13358338.893333, -9608371.5085962, 13358338.893333, 9608371.5085962], - * center: [-12356463.476333, 5621521.4854095] - * }); - * - * // create a map without a reference to a container - call render later - * var map = new OpenLayers.Map({ - * projection: "EPSG:3857", - * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000) - * }); - * (end) - */ - initialize: function (div, options) { - - // If only one argument is provided, check if it is an object. - if(arguments.length === 1 && typeof div === "object") { - options = div; - div = options && options.div; - } - - // Simple-type defaults are set in class definition. - // Now set complex-type defaults - this.tileSize = new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH, - OpenLayers.Map.TILE_HEIGHT); - - this.paddingForPopups = new OpenLayers.Bounds(15, 15, 15, 15); - - this.theme = OpenLayers._getScriptLocation() + - 'theme/default/style.css'; - - // backup original options - this.options = OpenLayers.Util.extend({}, options); - - // now override default options - OpenLayers.Util.extend(this, options); - - var projCode = this.projection instanceof OpenLayers.Projection ? - this.projection.projCode : this.projection; - OpenLayers.Util.applyDefaults(this, OpenLayers.Projection.defaults[projCode]); - - // allow extents and center to be arrays - if (this.maxExtent && !(this.maxExtent instanceof OpenLayers.Bounds)) { - this.maxExtent = new OpenLayers.Bounds(this.maxExtent); - } - if (this.minExtent && !(this.minExtent instanceof OpenLayers.Bounds)) { - this.minExtent = new OpenLayers.Bounds(this.minExtent); - } - if (this.restrictedExtent && !(this.restrictedExtent instanceof OpenLayers.Bounds)) { - this.restrictedExtent = new OpenLayers.Bounds(this.restrictedExtent); - } - if (this.center && !(this.center instanceof OpenLayers.LonLat)) { - this.center = new OpenLayers.LonLat(this.center); - } - - // initialize layers array - this.layers = []; - - this.id = OpenLayers.Util.createUniqueID("OpenLayers.Map_"); - - this.div = OpenLayers.Util.getElement(div); - if(!this.div) { - this.div = document.createElement("div"); - this.div.style.height = "1px"; - this.div.style.width = "1px"; - } - - OpenLayers.Element.addClass(this.div, 'olMap'); - - // the viewPortDiv is the outermost div we modify - var id = this.id + "_OpenLayers_ViewPort"; - this.viewPortDiv = OpenLayers.Util.createDiv(id, null, null, null, - "relative", null, - "hidden"); - this.viewPortDiv.style.width = "100%"; - this.viewPortDiv.style.height = "100%"; - this.viewPortDiv.className = "olMapViewport"; - this.div.appendChild(this.viewPortDiv); - - this.events = new OpenLayers.Events( - this, this.viewPortDiv, null, this.fallThrough, - {includeXY: true} - ); - - // the layerContainerDiv is the one that holds all the layers - id = this.id + "_OpenLayers_Container"; - this.layerContainerDiv = OpenLayers.Util.createDiv(id); - this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1; - this.layerContainerOriginPx = {x: 0, y: 0}; - - this.viewPortDiv.appendChild(this.layerContainerDiv); - - this.updateSize(); - if(this.eventListeners instanceof Object) { - this.events.on(this.eventListeners); - } - - if (this.autoUpdateSize === true) { - // updateSize on catching the window's resize - // Note that this is ok, as updateSize() does nothing if the - // map's size has not actually changed. - this.updateSizeDestroy = OpenLayers.Function.bind(this.updateSize, - this); - OpenLayers.Event.observe(window, 'resize', - this.updateSizeDestroy); - } - - // only append link stylesheet if the theme property is set - if(this.theme) { - // check existing links for equivalent url - var addNode = true; - var nodes = document.getElementsByTagName('link'); - for(var i=0, len=nodes.length; i=0; --i) { - this.controls[i].destroy(); - } - this.controls = null; - } - if (this.layers != null) { - for (var i = this.layers.length - 1; i>=0; --i) { - //pass 'false' to destroy so that map wont try to set a new - // baselayer after each baselayer is removed - this.layers[i].destroy(false); - } - this.layers = null; - } - if (this.viewPortDiv) { - this.div.removeChild(this.viewPortDiv); - } - this.viewPortDiv = null; - - if(this.eventListeners) { - this.events.un(this.eventListeners); - this.eventListeners = null; - } - this.events.destroy(); - this.events = null; - - this.options = null; - }, - - /** - * APIMethod: setOptions - * Change the map options - * - * Parameters: - * options - {Object} Hashtable of options to tag to the map - */ - setOptions: function(options) { - var updatePxExtent = this.minPx && - options.restrictedExtent != this.restrictedExtent; - OpenLayers.Util.extend(this, options); - // force recalculation of minPx and maxPx - updatePxExtent && this.moveTo(this.getCachedCenter(), this.zoom, { - forceZoomChange: true - }); - }, - - /** - * APIMethod: getTileSize - * Get the tile size for the map - * - * Returns: - * {} - */ - getTileSize: function() { - return this.tileSize; - }, - - - /** - * APIMethod: getBy - * Get a list of objects given a property and a match item. - * - * Parameters: - * array - {String} A property on the map whose value is an array. - * property - {String} A property on each item of the given array. - * match - {String | Object} A string to match. Can also be a regular - * expression literal or object. In addition, it can be any object - * with a method named test. For reqular expressions or other, if - * match.test(map[array][i][property]) evaluates to true, the item will - * be included in the array returned. If no items are found, an empty - * array is returned. - * - * Returns: - * {Array} An array of items where the given property matches the given - * criteria. - */ - getBy: function(array, property, match) { - var test = (typeof match.test == "function"); - var found = OpenLayers.Array.filter(this[array], function(item) { - return item[property] == match || (test && match.test(item[property])); - }); - return found; - }, - - /** - * APIMethod: getLayersBy - * Get a list of layers with properties matching the given criteria. - * - * Parameters: - * property - {String} A layer property to be matched. - * match - {String | Object} A string to match. Can also be a regular - * expression literal or object. In addition, it can be any object - * with a method named test. For reqular expressions or other, if - * match.test(layer[property]) evaluates to true, the layer will be - * included in the array returned. If no layers are found, an empty - * array is returned. - * - * Returns: - * {Array()} A list of layers matching the given criteria. - * An empty array is returned if no matches are found. - */ - getLayersBy: function(property, match) { - return this.getBy("layers", property, match); - }, - - /** - * APIMethod: getLayersByName - * Get a list of layers with names matching the given name. - * - * Parameters: - * match - {String | Object} A layer name. The name can also be a regular - * expression literal or object. In addition, it can be any object - * with a method named test. For reqular expressions or other, if - * name.test(layer.name) evaluates to true, the layer will be included - * in the list of layers returned. If no layers are found, an empty - * array is returned. - * - * Returns: - * {Array()} A list of layers matching the given name. - * An empty array is returned if no matches are found. - */ - getLayersByName: function(match) { - return this.getLayersBy("name", match); - }, - - /** - * APIMethod: getLayersByClass - * Get a list of layers of a given class (CLASS_NAME). - * - * Parameters: - * match - {String | Object} A layer class name. The match can also be a - * regular expression literal or object. In addition, it can be any - * object with a method named test. For reqular expressions or other, - * if type.test(layer.CLASS_NAME) evaluates to true, the layer will - * be included in the list of layers returned. If no layers are - * found, an empty array is returned. - * - * Returns: - * {Array()} A list of layers matching the given class. - * An empty array is returned if no matches are found. - */ - getLayersByClass: function(match) { - return this.getLayersBy("CLASS_NAME", match); - }, - - /** - * APIMethod: getControlsBy - * Get a list of controls with properties matching the given criteria. - * - * Parameters: - * property - {String} A control property to be matched. - * match - {String | Object} A string to match. Can also be a regular - * expression literal or object. In addition, it can be any object - * with a method named test. For reqular expressions or other, if - * match.test(layer[property]) evaluates to true, the layer will be - * included in the array returned. If no layers are found, an empty - * array is returned. - * - * Returns: - * {Array()} A list of controls matching the given - * criteria. An empty array is returned if no matches are found. - */ - getControlsBy: function(property, match) { - return this.getBy("controls", property, match); - }, - - /** - * APIMethod: getControlsByClass - * Get a list of controls of a given class (CLASS_NAME). - * - * Parameters: - * match - {String | Object} A control class name. The match can also be a - * regular expression literal or object. In addition, it can be any - * object with a method named test. For reqular expressions or other, - * if type.test(control.CLASS_NAME) evaluates to true, the control will - * be included in the list of controls returned. If no controls are - * found, an empty array is returned. - * - * Returns: - * {Array()} A list of controls matching the given class. - * An empty array is returned if no matches are found. - */ - getControlsByClass: function(match) { - return this.getControlsBy("CLASS_NAME", match); - }, - - /********************************************************/ - /* */ - /* Layer Functions */ - /* */ - /* The following functions deal with adding and */ - /* removing Layers to and from the Map */ - /* */ - /********************************************************/ - - /** - * APIMethod: getLayer - * Get a layer based on its id - * - * Parameters: - * id - {String} A layer id - * - * Returns: - * {} The Layer with the corresponding id from the map's - * layer collection, or null if not found. - */ - getLayer: function(id) { - var foundLayer = null; - for (var i=0, len=this.layers.length; i} - * zIdx - {int} - */ - setLayerZIndex: function (layer, zIdx) { - layer.setZIndex( - this.Z_INDEX_BASE[layer.isBaseLayer ? 'BaseLayer' : 'Overlay'] - + zIdx * 5 ); - }, - - /** - * Method: resetLayersZIndex - * Reset each layer's z-index based on layer's array index - */ - resetLayersZIndex: function() { - for (var i=0, len=this.layers.length; i} - * - * Returns: - * {Boolean} True if the layer has been added to the map. - */ - addLayer: function (layer) { - for(var i = 0, len = this.layers.length; i < len; i++) { - if (this.layers[i] == layer) { - return false; - } - } - if (this.events.triggerEvent("preaddlayer", {layer: layer}) === false) { - return false; - } - if(this.allOverlays) { - layer.isBaseLayer = false; - } - - layer.div.className = "olLayerDiv"; - layer.div.style.overflow = ""; - this.setLayerZIndex(layer, this.layers.length); - - if (layer.isFixed) { - this.viewPortDiv.appendChild(layer.div); - } else { - this.layerContainerDiv.appendChild(layer.div); - } - this.layers.push(layer); - layer.setMap(this); - - if (layer.isBaseLayer || (this.allOverlays && !this.baseLayer)) { - if (this.baseLayer == null) { - // set the first baselaye we add as the baselayer - this.setBaseLayer(layer); - } else { - layer.setVisibility(false); - } - } else { - layer.redraw(); - } - - this.events.triggerEvent("addlayer", {layer: layer}); - layer.events.triggerEvent("added", {map: this, layer: layer}); - layer.afterAdd(); - - return true; - }, - - /** - * APIMethod: addLayers - * - * Parameters: - * layers - {Array()} - */ - addLayers: function (layers) { - for (var i=0, len=layers.length; i} - * setNewBaseLayer - {Boolean} Default is true - */ - removeLayer: function(layer, setNewBaseLayer) { - if (this.events.triggerEvent("preremovelayer", {layer: layer}) === false) { - return; - } - if (setNewBaseLayer == null) { - setNewBaseLayer = true; - } - - if (layer.isFixed) { - this.viewPortDiv.removeChild(layer.div); - } else { - this.layerContainerDiv.removeChild(layer.div); - } - OpenLayers.Util.removeItem(this.layers, layer); - layer.removeMap(this); - layer.map = null; - - // if we removed the base layer, need to set a new one - if(this.baseLayer == layer) { - this.baseLayer = null; - if(setNewBaseLayer) { - for(var i=0, len=this.layers.length; i} - * - * Returns: - * {Integer} The current (zero-based) index of the given layer in the map's - * layer stack. Returns -1 if the layer isn't on the map. - */ - getLayerIndex: function (layer) { - return OpenLayers.Util.indexOf(this.layers, layer); - }, - - /** - * APIMethod: setLayerIndex - * Move the given layer to the specified (zero-based) index in the layer - * list, changing its z-index in the map display. Use - * map.getLayerIndex() to find out the current index of a layer. Note - * that this cannot (or at least should not) be effectively used to - * raise base layers above overlays. - * - * Parameters: - * layer - {} - * idx - {int} - */ - setLayerIndex: function (layer, idx) { - var base = this.getLayerIndex(layer); - if (idx < 0) { - idx = 0; - } else if (idx > this.layers.length) { - idx = this.layers.length; - } - if (base != idx) { - this.layers.splice(base, 1); - this.layers.splice(idx, 0, layer); - for (var i=0, len=this.layers.length; i} - * delta - {int} - */ - raiseLayer: function (layer, delta) { - var idx = this.getLayerIndex(layer) + delta; - this.setLayerIndex(layer, idx); - }, - - /** - * APIMethod: setBaseLayer - * Allows user to specify one of the currently-loaded layers as the Map's - * new base layer. - * - * Parameters: - * newBaseLayer - {} - */ - setBaseLayer: function(newBaseLayer) { - - if (newBaseLayer != this.baseLayer) { - - // ensure newBaseLayer is already loaded - if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) { - - // preserve center and scale when changing base layers - var center = this.getCachedCenter(); - var newResolution = OpenLayers.Util.getResolutionFromScale( - this.getScale(), newBaseLayer.units - ); - - // make the old base layer invisible - if (this.baseLayer != null && !this.allOverlays) { - this.baseLayer.setVisibility(false); - } - - // set new baselayer - this.baseLayer = newBaseLayer; - - if(!this.allOverlays || this.baseLayer.visibility) { - this.baseLayer.setVisibility(true); - // Layer may previously have been visible but not in range. - // In this case we need to redraw it to make it visible. - if (this.baseLayer.inRange === false) { - this.baseLayer.redraw(); - } - } - - // recenter the map - if (center != null) { - // new zoom level derived from old scale - var newZoom = this.getZoomForResolution( - newResolution || this.resolution, true - ); - // zoom and force zoom change - this.setCenter(center, newZoom, false, true); - } - - this.events.triggerEvent("changebaselayer", { - layer: this.baseLayer - }); - } - } - }, - - - /********************************************************/ - /* */ - /* Control Functions */ - /* */ - /* The following functions deal with adding and */ - /* removing Controls to and from the Map */ - /* */ - /********************************************************/ - - /** - * APIMethod: addControl - * Add the passed over control to the map. Optionally - * position the control at the given pixel. - * - * Parameters: - * control - {} - * px - {} - */ - addControl: function (control, px) { - this.controls.push(control); - this.addControlToMap(control, px); - }, - - /** - * APIMethod: addControls - * Add all of the passed over controls to the map. - * You can pass over an optional second array - * with pixel-objects to position the controls. - * The indices of the two arrays should match and - * you can add null as pixel for those controls - * you want to be autopositioned. - * - * Parameters: - * controls - {Array()} - * pixels - {Array()} - */ - addControls: function (controls, pixels) { - var pxs = (arguments.length === 1) ? [] : pixels; - for (var i=0, len=controls.length; i} - * px - {} - */ - addControlToMap: function (control, px) { - // If a control doesn't have a div at this point, it belongs in the - // viewport. - control.outsideViewport = (control.div != null); - - // If the map has a displayProjection, and the control doesn't, set - // the display projection. - if (this.displayProjection && !control.displayProjection) { - control.displayProjection = this.displayProjection; - } - - control.setMap(this); - var div = control.draw(px); - if (div) { - if(!control.outsideViewport) { - div.style.zIndex = this.Z_INDEX_BASE['Control'] + - this.controls.length; - this.viewPortDiv.appendChild( div ); - } - } - if(control.autoActivate) { - control.activate(); - } - }, - - /** - * APIMethod: getControl - * - * Parameters: - * id - {String} ID of the control to return. - * - * Returns: - * {} The control from the map's list of controls - * which has a matching 'id'. If none found, - * returns null. - */ - getControl: function (id) { - var returnControl = null; - for(var i=0, len=this.controls.length; i} The control to remove. - */ - removeControl: function (control) { - //make sure control is non-null and actually part of our map - if ( (control) && (control == this.getControl(control.id)) ) { - if (control.div && (control.div.parentNode == this.viewPortDiv)) { - this.viewPortDiv.removeChild(control.div); - } - OpenLayers.Util.removeItem(this.controls, control); - } - }, - - /********************************************************/ - /* */ - /* Popup Functions */ - /* */ - /* The following functions deal with adding and */ - /* removing Popups to and from the Map */ - /* */ - /********************************************************/ - - /** - * APIMethod: addPopup - * - * Parameters: - * popup - {} - * exclusive - {Boolean} If true, closes all other popups first - */ - addPopup: function(popup, exclusive) { - - if (exclusive) { - //remove all other popups from screen - for (var i = this.popups.length - 1; i >= 0; --i) { - this.removePopup(this.popups[i]); - } - } - - popup.map = this; - this.popups.push(popup); - var popupDiv = popup.draw(); - if (popupDiv) { - popupDiv.style.zIndex = this.Z_INDEX_BASE['Popup'] + - this.popups.length; - this.layerContainerDiv.appendChild(popupDiv); - } - }, - - /** - * APIMethod: removePopup - * - * Parameters: - * popup - {} - */ - removePopup: function(popup) { - OpenLayers.Util.removeItem(this.popups, popup); - if (popup.div) { - try { this.layerContainerDiv.removeChild(popup.div); } - catch (e) { } // Popups sometimes apparently get disconnected - // from the layerContainerDiv, and cause complaints. - } - popup.map = null; - }, - - /********************************************************/ - /* */ - /* Container Div Functions */ - /* */ - /* The following functions deal with the access to */ - /* and maintenance of the size of the container div */ - /* */ - /********************************************************/ - - /** - * APIMethod: getSize - * - * Returns: - * {} An object that represents the - * size, in pixels, of the div into which OpenLayers - * has been loaded. - * Note - A clone() of this locally cached variable is - * returned, so as not to allow users to modify it. - */ - getSize: function () { - var size = null; - if (this.size != null) { - size = this.size.clone(); - } - return size; - }, - - /** - * APIMethod: updateSize - * This function should be called by any external code which dynamically - * changes the size of the map div (because mozilla wont let us catch - * the "onresize" for an element) - */ - updateSize: function() { - // the div might have moved on the page, also - var newSize = this.getCurrentSize(); - if (newSize && !isNaN(newSize.h) && !isNaN(newSize.w)) { - this.events.clearMouseCache(); - var oldSize = this.getSize(); - if (oldSize == null) { - this.size = oldSize = newSize; - } - if (!newSize.equals(oldSize)) { - - // store the new size - this.size = newSize; - - //notify layers of mapresize - for(var i=0, len=this.layers.length; i} A new object with the dimensions - * of the map div - */ - getCurrentSize: function() { - - var size = new OpenLayers.Size(this.div.clientWidth, - this.div.clientHeight); - - if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) { - size.w = this.div.offsetWidth; - size.h = this.div.offsetHeight; - } - if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) { - size.w = parseInt(this.div.style.width); - size.h = parseInt(this.div.style.height); - } - return size; - }, - - /** - * Method: calculateBounds - * - * Parameters: - * center - {} Default is this.getCenter() - * resolution - {float} Default is this.getResolution() - * - * Returns: - * {} A bounds based on resolution, center, and - * current mapsize. - */ - calculateBounds: function(center, resolution) { - - var extent = null; - - if (center == null) { - center = this.getCachedCenter(); - } - if (resolution == null) { - resolution = this.getResolution(); - } - - if ((center != null) && (resolution != null)) { - var halfWDeg = (this.size.w * resolution) / 2; - var halfHDeg = (this.size.h * resolution) / 2; - - extent = new OpenLayers.Bounds(center.lon - halfWDeg, - center.lat - halfHDeg, - center.lon + halfWDeg, - center.lat + halfHDeg); - } - - return extent; - }, - - - /********************************************************/ - /* */ - /* Zoom, Center, Pan Functions */ - /* */ - /* The following functions handle the validation, */ - /* getting and setting of the Zoom Level and Center */ - /* as well as the panning of the Map */ - /* */ - /********************************************************/ - /** - * APIMethod: getCenter - * - * Returns: - * {} - */ - getCenter: function () { - var center = null; - var cachedCenter = this.getCachedCenter(); - if (cachedCenter) { - center = cachedCenter.clone(); - } - return center; - }, - - /** - * Method: getCachedCenter - * - * Returns: - * {} - */ - getCachedCenter: function() { - if (!this.center && this.size) { - this.center = this.getLonLatFromViewPortPx({ - x: this.size.w / 2, - y: this.size.h / 2 - }); - } - return this.center; - }, - - /** - * APIMethod: getZoom - * - * Returns: - * {Integer} - */ - getZoom: function () { - return this.zoom; - }, - - /** - * APIMethod: pan - * Allows user to pan by a value of screen pixels - * - * Parameters: - * dx - {Integer} - * dy - {Integer} - * options - {Object} Options to configure panning: - * - *animate* {Boolean} Use panTo instead of setCenter. Default is true. - * - *dragging* {Boolean} Call setCenter with dragging true. Default is - * false. - */ - pan: function(dx, dy, options) { - options = OpenLayers.Util.applyDefaults(options, { - animate: true, - dragging: false - }); - if (options.dragging) { - if (dx != 0 || dy != 0) { - this.moveByPx(dx, dy); - } - } else { - // getCenter - var centerPx = this.getViewPortPxFromLonLat(this.getCachedCenter()); - - // adjust - var newCenterPx = centerPx.add(dx, dy); - - if (this.dragging || !newCenterPx.equals(centerPx)) { - var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx); - if (options.animate) { - this.panTo(newCenterLonLat); - } else { - this.moveTo(newCenterLonLat); - if(this.dragging) { - this.dragging = false; - this.events.triggerEvent("moveend"); - } - } - } - } - - }, - - /** - * APIMethod: panTo - * Allows user to pan to a new lonlat - * If the new lonlat is in the current extent the map will slide smoothly - * - * Parameters: - * lonlat - {} - */ - panTo: function(lonlat) { - if (this.panMethod && this.getExtent().scale(this.panRatio).containsLonLat(lonlat)) { - if (!this.panTween) { - this.panTween = new OpenLayers.Tween(this.panMethod); - } - var center = this.getCachedCenter(); - - // center will not change, don't do nothing - if (lonlat.equals(center)) { - return; - } - - var from = this.getPixelFromLonLat(center); - var to = this.getPixelFromLonLat(lonlat); - var vector = { x: to.x - from.x, y: to.y - from.y }; - var last = { x: 0, y: 0 }; - - this.panTween.start( { x: 0, y: 0 }, vector, this.panDuration, { - callbacks: { - eachStep: OpenLayers.Function.bind(function(px) { - var x = px.x - last.x, - y = px.y - last.y; - this.moveByPx(x, y); - last.x = Math.round(px.x); - last.y = Math.round(px.y); - }, this), - done: OpenLayers.Function.bind(function(px) { - this.moveTo(lonlat); - this.dragging = false; - this.events.triggerEvent("moveend"); - }, this) - } - }); - } else { - this.setCenter(lonlat); - } - }, - - /** - * APIMethod: setCenter - * Set the map center (and optionally, the zoom level). - * - * Parameters: - * lonlat - {|Array} The new center location. - * If provided as array, the first value is the x coordinate, - * and the 2nd value is the y coordinate. - * zoom - {Integer} Optional zoom level. - * dragging - {Boolean} Specifies whether or not to trigger - * movestart/end events - * forceZoomChange - {Boolean} Specifies whether or not to trigger zoom - * change events (needed on baseLayer change) - * - * TBD: reconsider forceZoomChange in 3.0 - */ - setCenter: function(lonlat, zoom, dragging, forceZoomChange) { - this.panTween && this.panTween.stop(); - this.moveTo(lonlat, zoom, { - 'dragging': dragging, - 'forceZoomChange': forceZoomChange - }); - }, - - /** - * Method: moveByPx - * Drag the map by pixels. - * - * Parameters: - * dx - {Number} - * dy - {Number} - */ - moveByPx: function(dx, dy) { - var hw = this.size.w / 2; - var hh = this.size.h / 2; - var x = hw + dx; - var y = hh + dy; - var wrapDateLine = this.baseLayer.wrapDateLine; - var xRestriction = 0; - var yRestriction = 0; - if (this.restrictedExtent) { - xRestriction = hw; - yRestriction = hh; - // wrapping the date line makes no sense for restricted extents - wrapDateLine = false; - } - dx = wrapDateLine || - x <= this.maxPx.x - xRestriction && - x >= this.minPx.x + xRestriction ? Math.round(dx) : 0; - dy = y <= this.maxPx.y - yRestriction && - y >= this.minPx.y + yRestriction ? Math.round(dy) : 0; - if (dx || dy) { - if (!this.dragging) { - this.dragging = true; - this.events.triggerEvent("movestart"); - } - this.center = null; - if (dx) { - this.layerContainerDiv.style.left = - (this.layerContainerOriginPx.x -= dx) + "px"; - this.minPx.x -= dx; - this.maxPx.x -= dx; - } - if (dy) { - this.layerContainerDiv.style.top = - (this.layerContainerOriginPx.y -= dy) + "px"; - this.minPx.y -= dy; - this.maxPx.y -= dy; - } - var layer, i, len; - for (i=0, len=this.layers.length; i's maxExtent. - */ - adjustZoom: function(zoom) { - if (this.baseLayer && this.baseLayer.wrapDateLine) { - var resolution, resolutions = this.baseLayer.resolutions, - maxResolution = this.getMaxExtent().getWidth() / this.size.w; - if (this.getResolutionForZoom(zoom) > maxResolution) { - if (this.fractionalZoom) { - zoom = this.getZoomForResolution(maxResolution); - } else { - for (var i=zoom|0, ii=resolutions.length; i set to true, this will be the - * first zoom level that shows no more than one world width in the current - * map viewport. Components that rely on this value (e.g. zoom sliders) - * should also listen to the map's "updatesize" event and call this method - * in the "updatesize" listener. - * - * Returns: - * {Number} Minimum zoom level that shows a map not wider than its - * 's maxExtent. This is an Integer value, unless the map is - * configured with set to true. - */ - getMinZoom: function() { - return this.adjustZoom(0); - }, - - /** - * Method: moveTo - * - * Parameters: - * lonlat - {} - * zoom - {Integer} - * options - {Object} - */ - moveTo: function(lonlat, zoom, options) { - if (lonlat != null && !(lonlat instanceof OpenLayers.LonLat)) { - lonlat = new OpenLayers.LonLat(lonlat); - } - if (!options) { - options = {}; - } - if (zoom != null) { - zoom = parseFloat(zoom); - if (!this.fractionalZoom) { - zoom = Math.round(zoom); - } - } - var requestedZoom = zoom; - zoom = this.adjustZoom(zoom); - if (zoom !== requestedZoom) { - // zoom was adjusted, so keep old lonlat to avoid panning - lonlat = this.getCenter(); - } - // dragging is false by default - var dragging = options.dragging || this.dragging; - // forceZoomChange is false by default - var forceZoomChange = options.forceZoomChange; - - if (!this.getCachedCenter() && !this.isValidLonLat(lonlat)) { - lonlat = this.maxExtent.getCenterLonLat(); - this.center = lonlat.clone(); - } - - if(this.restrictedExtent != null) { - // In 3.0, decide if we want to change interpretation of maxExtent. - if(lonlat == null) { - lonlat = this.center; - } - if(zoom == null) { - zoom = this.getZoom(); - } - var resolution = this.getResolutionForZoom(zoom); - var extent = this.calculateBounds(lonlat, resolution); - if(!this.restrictedExtent.containsBounds(extent)) { - var maxCenter = this.restrictedExtent.getCenterLonLat(); - if(extent.getWidth() > this.restrictedExtent.getWidth()) { - lonlat = new OpenLayers.LonLat(maxCenter.lon, lonlat.lat); - } else if(extent.left < this.restrictedExtent.left) { - lonlat = lonlat.add(this.restrictedExtent.left - - extent.left, 0); - } else if(extent.right > this.restrictedExtent.right) { - lonlat = lonlat.add(this.restrictedExtent.right - - extent.right, 0); - } - if(extent.getHeight() > this.restrictedExtent.getHeight()) { - lonlat = new OpenLayers.LonLat(lonlat.lon, maxCenter.lat); - } else if(extent.bottom < this.restrictedExtent.bottom) { - lonlat = lonlat.add(0, this.restrictedExtent.bottom - - extent.bottom); - } - else if(extent.top > this.restrictedExtent.top) { - lonlat = lonlat.add(0, this.restrictedExtent.top - - extent.top); - } - } - } - - var zoomChanged = forceZoomChange || ( - (this.isValidZoomLevel(zoom)) && - (zoom != this.getZoom()) ); - - var centerChanged = (this.isValidLonLat(lonlat)) && - (!lonlat.equals(this.center)); - - // if neither center nor zoom will change, no need to do anything - if (zoomChanged || centerChanged || dragging) { - dragging || this.events.triggerEvent("movestart"); - - if (centerChanged) { - if (!zoomChanged && this.center) { - // if zoom hasnt changed, just slide layerContainer - // (must be done before setting this.center to new value) - this.centerLayerContainer(lonlat); - } - this.center = lonlat.clone(); - } - - var res = zoomChanged ? - this.getResolutionForZoom(zoom) : this.getResolution(); - // (re)set the layerContainerDiv's location - if (zoomChanged || this.layerContainerOrigin == null) { - this.layerContainerOrigin = this.getCachedCenter(); - var style = this.layerContainerDiv.style; - style.left = "0px"; - style.top = "0px"; - this.layerContainerOriginPx.x = 0; - this.layerContainerOriginPx.y = 0; - var maxExtent = this.getMaxExtent({restricted: true}); - var maxExtentCenter = maxExtent.getCenterLonLat(); - var lonDelta = this.center.lon - maxExtentCenter.lon; - var latDelta = maxExtentCenter.lat - this.center.lat; - var extentWidth = Math.round(maxExtent.getWidth() / res); - var extentHeight = Math.round(maxExtent.getHeight() / res); - this.minPx = { - x: (this.size.w - extentWidth) / 2 - lonDelta / res, - y: (this.size.h - extentHeight) / 2 - latDelta / res - }; - this.maxPx = { - x: this.minPx.x + Math.round(maxExtent.getWidth() / res), - y: this.minPx.y + Math.round(maxExtent.getHeight() / res) - }; - } - - if (zoomChanged) { - this.zoom = zoom; - this.resolution = res; - } - - var bounds = this.getExtent(); - - //send the move call to the baselayer and all the overlays - - if(this.baseLayer.visibility) { - this.baseLayer.moveTo(bounds, zoomChanged, options.dragging); - options.dragging || this.baseLayer.events.triggerEvent( - "moveend", {zoomChanged: zoomChanged} - ); - } - - bounds = this.baseLayer.getExtent(); - - for (var i=this.layers.length-1; i>=0; --i) { - var layer = this.layers[i]; - if (layer !== this.baseLayer && !layer.isBaseLayer) { - var inRange = layer.calculateInRange(); - if (layer.inRange != inRange) { - // the inRange property has changed. If the layer is - // no longer in range, we turn it off right away. If - // the layer is no longer out of range, the moveTo - // call below will turn on the layer. - layer.inRange = inRange; - if (!inRange) { - layer.display(false); - } - this.events.triggerEvent("changelayer", { - layer: layer, property: "visibility" - }); - } - if (inRange && layer.visibility) { - layer.moveTo(bounds, zoomChanged, options.dragging); - options.dragging || layer.events.triggerEvent( - "moveend", {zoomChanged: zoomChanged} - ); - } - } - } - - this.events.triggerEvent("move"); - dragging || this.events.triggerEvent("moveend"); - - if (zoomChanged) { - //redraw popups - for (var i=0, len=this.popups.length; i} - */ - centerLayerContainer: function (lonlat) { - var originPx = this.getViewPortPxFromLonLat(this.layerContainerOrigin); - var newPx = this.getViewPortPxFromLonLat(lonlat); - - if ((originPx != null) && (newPx != null)) { - var oldLeft = this.layerContainerOriginPx.x; - var oldTop = this.layerContainerOriginPx.y; - var newLeft = Math.round(originPx.x - newPx.x); - var newTop = Math.round(originPx.y - newPx.y); - this.layerContainerDiv.style.left = - (this.layerContainerOriginPx.x = newLeft) + "px"; - this.layerContainerDiv.style.top = - (this.layerContainerOriginPx.y = newTop) + "px"; - var dx = oldLeft - newLeft; - var dy = oldTop - newTop; - this.minPx.x -= dx; - this.maxPx.x -= dx; - this.minPx.y -= dy; - this.maxPx.y -= dy; - } - }, - - /** - * Method: isValidZoomLevel - * - * Parameters: - * zoomLevel - {Integer} - * - * Returns: - * {Boolean} Whether or not the zoom level passed in is non-null and - * within the min/max range of zoom levels. - */ - isValidZoomLevel: function(zoomLevel) { - return ( (zoomLevel != null) && - (zoomLevel >= 0) && - (zoomLevel < this.getNumZoomLevels()) ); - }, - - /** - * Method: isValidLonLat - * - * Parameters: - * lonlat - {} - * - * Returns: - * {Boolean} Whether or not the lonlat passed in is non-null and within - * the maxExtent bounds - */ - isValidLonLat: function(lonlat) { - var valid = false; - if (lonlat != null) { - var maxExtent = this.getMaxExtent(); - var worldBounds = this.baseLayer.wrapDateLine && maxExtent; - valid = maxExtent.containsLonLat(lonlat, {worldBounds: worldBounds}); - } - return valid; - }, - - /********************************************************/ - /* */ - /* Layer Options */ - /* */ - /* Accessor functions to Layer Options parameters */ - /* */ - /********************************************************/ - - /** - * APIMethod: getProjection - * This method returns a string representing the projection. In - * the case of projection support, this will be the srsCode which - * is loaded -- otherwise it will simply be the string value that - * was passed to the projection at startup. - * - * FIXME: In 3.0, we will remove getProjectionObject, and instead - * return a Projection object from this function. - * - * Returns: - * {String} The Projection string from the base layer or null. - */ - getProjection: function() { - var projection = this.getProjectionObject(); - return projection ? projection.getCode() : null; - }, - - /** - * APIMethod: getProjectionObject - * Returns the projection obect from the baselayer. - * - * Returns: - * {} The Projection of the base layer. - */ - getProjectionObject: function() { - var projection = null; - if (this.baseLayer != null) { - projection = this.baseLayer.projection; - } - return projection; - }, - - /** - * APIMethod: getMaxResolution - * - * Returns: - * {String} The Map's Maximum Resolution - */ - getMaxResolution: function() { - var maxResolution = null; - if (this.baseLayer != null) { - maxResolution = this.baseLayer.maxResolution; - } - return maxResolution; - }, - - /** - * APIMethod: getMaxExtent - * - * Parameters: - * options - {Object} - * - * Allowed Options: - * restricted - {Boolean} If true, returns restricted extent (if it is - * available.) - * - * Returns: - * {} The maxExtent property as set on the current - * baselayer, unless the 'restricted' option is set, in which case - * the 'restrictedExtent' option from the map is returned (if it - * is set). - */ - getMaxExtent: function (options) { - var maxExtent = null; - if(options && options.restricted && this.restrictedExtent){ - maxExtent = this.restrictedExtent; - } else if (this.baseLayer != null) { - maxExtent = this.baseLayer.maxExtent; - } - return maxExtent; - }, - - /** - * APIMethod: getNumZoomLevels - * - * Returns: - * {Integer} The total number of zoom levels that can be displayed by the - * current baseLayer. - */ - getNumZoomLevels: function() { - var numZoomLevels = null; - if (this.baseLayer != null) { - numZoomLevels = this.baseLayer.numZoomLevels; - } - return numZoomLevels; - }, - - /********************************************************/ - /* */ - /* Baselayer Functions */ - /* */ - /* The following functions, all publicly exposed */ - /* in the API?, are all merely wrappers to the */ - /* the same calls on whatever layer is set as */ - /* the current base layer */ - /* */ - /********************************************************/ - - /** - * APIMethod: getExtent - * - * Returns: - * {} A Bounds object which represents the lon/lat - * bounds of the current viewPort. - * If no baselayer is set, returns null. - */ - getExtent: function () { - var extent = null; - if (this.baseLayer != null) { - extent = this.baseLayer.getExtent(); - } - return extent; - }, - - /** - * APIMethod: getResolution - * - * Returns: - * {Float} The current resolution of the map. - * If no baselayer is set, returns null. - */ - getResolution: function () { - var resolution = null; - if (this.baseLayer != null) { - resolution = this.baseLayer.getResolution(); - } else if(this.allOverlays === true && this.layers.length > 0) { - // while adding the 1st layer to the map in allOverlays mode, - // this.baseLayer is not set yet when we need the resolution - // for calculateInRange. - resolution = this.layers[0].getResolution(); - } - return resolution; - }, - - /** - * APIMethod: getUnits - * - * Returns: - * {Float} The current units of the map. - * If no baselayer is set, returns null. - */ - getUnits: function () { - var units = null; - if (this.baseLayer != null) { - units = this.baseLayer.units; - } - return units; - }, - - /** - * APIMethod: getScale - * - * Returns: - * {Float} The current scale denominator of the map. - * If no baselayer is set, returns null. - */ - getScale: function () { - var scale = null; - if (this.baseLayer != null) { - var res = this.getResolution(); - var units = this.baseLayer.units; - scale = OpenLayers.Util.getScaleFromResolution(res, units); - } - return scale; - }, - - - /** - * APIMethod: getZoomForExtent - * - * Parameters: - * bounds - {} - * closest - {Boolean} Find the zoom level that most closely fits the - * specified bounds. Note that this may result in a zoom that does - * not exactly contain the entire extent. - * Default is false. - * - * Returns: - * {Integer} A suitable zoom level for the specified bounds. - * If no baselayer is set, returns null. - */ - getZoomForExtent: function (bounds, closest) { - var zoom = null; - if (this.baseLayer != null) { - zoom = this.baseLayer.getZoomForExtent(bounds, closest); - } - return zoom; - }, - - /** - * APIMethod: getResolutionForZoom - * - * Parameters: - * zoom - {Float} - * - * Returns: - * {Float} A suitable resolution for the specified zoom. If no baselayer - * is set, returns null. - */ - getResolutionForZoom: function(zoom) { - var resolution = null; - if(this.baseLayer) { - resolution = this.baseLayer.getResolutionForZoom(zoom); - } - return resolution; - }, - - /** - * APIMethod: getZoomForResolution - * - * Parameters: - * resolution - {Float} - * closest - {Boolean} Find the zoom level that corresponds to the absolute - * closest resolution, which may result in a zoom whose corresponding - * resolution is actually smaller than we would have desired (if this - * is being called from a getZoomForExtent() call, then this means that - * the returned zoom index might not actually contain the entire - * extent specified... but it'll be close). - * Default is false. - * - * Returns: - * {Integer} A suitable zoom level for the specified resolution. - * If no baselayer is set, returns null. - */ - getZoomForResolution: function(resolution, closest) { - var zoom = null; - if (this.baseLayer != null) { - zoom = this.baseLayer.getZoomForResolution(resolution, closest); - } - return zoom; - }, - - /********************************************************/ - /* */ - /* Zooming Functions */ - /* */ - /* The following functions, all publicly exposed */ - /* in the API, are all merely wrappers to the */ - /* the setCenter() function */ - /* */ - /********************************************************/ - - /** - * APIMethod: zoomTo - * Zoom to a specific zoom level - * - * Parameters: - * zoom - {Integer} - */ - zoomTo: function(zoom) { - if (this.isValidZoomLevel(zoom)) { - this.setCenter(null, zoom); - } - }, - - /** - * APIMethod: zoomIn - * - */ - zoomIn: function() { - this.zoomTo(this.getZoom() + 1); - }, - - /** - * APIMethod: zoomOut - * - */ - zoomOut: function() { - this.zoomTo(this.getZoom() - 1); - }, - - /** - * APIMethod: zoomToExtent - * Zoom to the passed in bounds, recenter - * - * Parameters: - * bounds - {|Array} If provided as an array, the array - * should consist of four values (left, bottom, right, top). - * closest - {Boolean} Find the zoom level that most closely fits the - * specified bounds. Note that this may result in a zoom that does - * not exactly contain the entire extent. - * Default is false. - * - */ - zoomToExtent: function(bounds, closest) { - if (!(bounds instanceof OpenLayers.Bounds)) { - bounds = new OpenLayers.Bounds(bounds); - } - var center = bounds.getCenterLonLat(); - if (this.baseLayer.wrapDateLine) { - var maxExtent = this.getMaxExtent(); - - //fix straddling bounds (in the case of a bbox that straddles the - // dateline, it's left and right boundaries will appear backwards. - // we fix this by allowing a right value that is greater than the - // max value at the dateline -- this allows us to pass a valid - // bounds to calculate zoom) - // - bounds = bounds.clone(); - while (bounds.right < bounds.left) { - bounds.right += maxExtent.getWidth(); - } - //if the bounds was straddling (see above), then the center point - // we got from it was wrong. So we take our new bounds and ask it - // for the center. - // - center = bounds.getCenterLonLat().wrapDateLine(maxExtent); - } - this.setCenter(center, this.getZoomForExtent(bounds, closest)); - }, - - /** - * APIMethod: zoomToMaxExtent - * Zoom to the full extent and recenter. - * - * Parameters: - * options - {Object} - * - * Allowed Options: - * restricted - {Boolean} True to zoom to restricted extent if it is - * set. Defaults to true. - */ - zoomToMaxExtent: function(options) { - //restricted is true by default - var restricted = (options) ? options.restricted : true; - - var maxExtent = this.getMaxExtent({ - 'restricted': restricted - }); - this.zoomToExtent(maxExtent); - }, - - /** - * APIMethod: zoomToScale - * Zoom to a specified scale - * - * Parameters: - * scale - {float} - * closest - {Boolean} Find the zoom level that most closely fits the - * specified scale. Note that this may result in a zoom that does - * not exactly contain the entire extent. - * Default is false. - * - */ - zoomToScale: function(scale, closest) { - var res = OpenLayers.Util.getResolutionFromScale(scale, - this.baseLayer.units); - - var halfWDeg = (this.size.w * res) / 2; - var halfHDeg = (this.size.h * res) / 2; - var center = this.getCachedCenter(); - - var extent = new OpenLayers.Bounds(center.lon - halfWDeg, - center.lat - halfHDeg, - center.lon + halfWDeg, - center.lat + halfHDeg); - this.zoomToExtent(extent, closest); - }, - - /********************************************************/ - /* */ - /* Translation Functions */ - /* */ - /* The following functions translate between */ - /* LonLat, LayerPx, and ViewPortPx */ - /* */ - /********************************************************/ - - // - // TRANSLATION: LonLat <-> ViewPortPx - // - - /** - * Method: getLonLatFromViewPortPx - * - * Parameters: - * viewPortPx - {|Object} An OpenLayers.Pixel or - * an object with a 'x' - * and 'y' properties. - * - * Returns: - * {} An OpenLayers.LonLat which is the passed-in view - * port , translated into lon/lat - * by the current base layer. - */ - getLonLatFromViewPortPx: function (viewPortPx) { - var lonlat = null; - if (this.baseLayer != null) { - lonlat = this.baseLayer.getLonLatFromViewPortPx(viewPortPx); - } - return lonlat; - }, - - /** - * APIMethod: getViewPortPxFromLonLat - * - * Parameters: - * lonlat - {} - * - * Returns: - * {} An OpenLayers.Pixel which is the passed-in - * , translated into view port - * pixels by the current base layer. - */ - getViewPortPxFromLonLat: function (lonlat) { - var px = null; - if (this.baseLayer != null) { - px = this.baseLayer.getViewPortPxFromLonLat(lonlat); - } - return px; - }, - - - // - // CONVENIENCE TRANSLATION FUNCTIONS FOR API - // - - /** - * APIMethod: getLonLatFromPixel - * - * Parameters: - * px - {|Object} An OpenLayers.Pixel or an object with - * a 'x' and 'y' properties. - * - * Returns: - * {} An OpenLayers.LonLat corresponding to the given - * OpenLayers.Pixel, translated into lon/lat by the - * current base layer - */ - getLonLatFromPixel: function (px) { - return this.getLonLatFromViewPortPx(px); - }, - - /** - * APIMethod: getPixelFromLonLat - * Returns a pixel location given a map location. The map location is - * translated to an integer pixel location (in viewport pixel - * coordinates) by the current base layer. - * - * Parameters: - * lonlat - {} A map location. - * - * Returns: - * {} An OpenLayers.Pixel corresponding to the - * translated into view port pixels by the current - * base layer. - */ - getPixelFromLonLat: function (lonlat) { - var px = this.getViewPortPxFromLonLat(lonlat); - px.x = Math.round(px.x); - px.y = Math.round(px.y); - return px; - }, - - /** - * Method: getGeodesicPixelSize - * - * Parameters: - * px - {} The pixel to get the geodesic length for. If - * not provided, the center pixel of the map viewport will be used. - * - * Returns: - * {} The geodesic size of the pixel in kilometers. - */ - getGeodesicPixelSize: function(px) { - var lonlat = px ? this.getLonLatFromPixel(px) : ( - this.getCachedCenter() || new OpenLayers.LonLat(0, 0)); - var res = this.getResolution(); - var left = lonlat.add(-res / 2, 0); - var right = lonlat.add(res / 2, 0); - var bottom = lonlat.add(0, -res / 2); - var top = lonlat.add(0, res / 2); - var dest = new OpenLayers.Projection("EPSG:4326"); - var source = this.getProjectionObject() || dest; - if(!source.equals(dest)) { - left.transform(source, dest); - right.transform(source, dest); - bottom.transform(source, dest); - top.transform(source, dest); - } - - return new OpenLayers.Size( - OpenLayers.Util.distVincenty(left, right), - OpenLayers.Util.distVincenty(bottom, top) - ); - }, - - - - // - // TRANSLATION: ViewPortPx <-> LayerPx - // - - /** - * APIMethod: getViewPortPxFromLayerPx - * - * Parameters: - * layerPx - {} - * - * Returns: - * {} Layer Pixel translated into ViewPort Pixel - * coordinates - */ - getViewPortPxFromLayerPx:function(layerPx) { - var viewPortPx = null; - if (layerPx != null) { - var dX = this.layerContainerOriginPx.x; - var dY = this.layerContainerOriginPx.y; - viewPortPx = layerPx.add(dX, dY); - } - return viewPortPx; - }, - - /** - * APIMethod: getLayerPxFromViewPortPx - * - * Parameters: - * viewPortPx - {} - * - * Returns: - * {} ViewPort Pixel translated into Layer Pixel - * coordinates - */ - getLayerPxFromViewPortPx:function(viewPortPx) { - var layerPx = null; - if (viewPortPx != null) { - var dX = -this.layerContainerOriginPx.x; - var dY = -this.layerContainerOriginPx.y; - layerPx = viewPortPx.add(dX, dY); - if (isNaN(layerPx.x) || isNaN(layerPx.y)) { - layerPx = null; - } - } - return layerPx; - }, - - // - // TRANSLATION: LonLat <-> LayerPx - // - - /** - * Method: getLonLatFromLayerPx - * - * Parameters: - * px - {} - * - * Returns: - * {} - */ - getLonLatFromLayerPx: function (px) { - //adjust for displacement of layerContainerDiv - px = this.getViewPortPxFromLayerPx(px); - return this.getLonLatFromViewPortPx(px); - }, - - /** - * APIMethod: getLayerPxFromLonLat - * - * Parameters: - * lonlat - {} lonlat - * - * Returns: - * {} An OpenLayers.Pixel which is the passed-in - * , translated into layer pixels - * by the current base layer - */ - getLayerPxFromLonLat: function (lonlat) { - //adjust for displacement of layerContainerDiv - var px = this.getPixelFromLonLat(lonlat); - return this.getLayerPxFromViewPortPx(px); - }, - - CLASS_NAME: "OpenLayers.Map" -}); - -/** - * Constant: TILE_WIDTH - * {Integer} 256 Default tile width (unless otherwise specified) - */ -OpenLayers.Map.TILE_WIDTH = 256; -/** - * Constant: TILE_HEIGHT - * {Integer} 256 Default tile height (unless otherwise specified) - */ -OpenLayers.Map.TILE_HEIGHT = 256; -/* ====================================================================== - OpenLayers/Layer.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/BaseTypes/Class.js - * @requires OpenLayers/Map.js - * @requires OpenLayers/Projection.js - */ - -/** - * Class: OpenLayers.Layer - */ -OpenLayers.Layer = OpenLayers.Class({ - - /** - * APIProperty: id - * {String} - */ - id: null, - - /** - * APIProperty: name - * {String} - */ - name: null, - - /** - * APIProperty: div - * {DOMElement} - */ - div: null, - - /** - * APIProperty: opacity - * {Float} The layer's opacity. Float number between 0.0 and 1.0. Default - * is 1. - */ - opacity: 1, - - /** - * APIProperty: alwaysInRange - * {Boolean} If a layer's display should not be scale-based, this should - * be set to true. This will cause the layer, as an overlay, to always - * be 'active', by always returning true from the calculateInRange() - * function. - * - * If not explicitly specified for a layer, its value will be - * determined on startup in initResolutions() based on whether or not - * any scale-specific properties have been set as options on the - * layer. If no scale-specific options have been set on the layer, we - * assume that it should always be in range. - * - * See #987 for more info. - */ - alwaysInRange: null, - - /** - * Constant: RESOLUTION_PROPERTIES - * {Array} The properties that are used for calculating resolutions - * information. - */ - RESOLUTION_PROPERTIES: [ - 'scales', 'resolutions', - 'maxScale', 'minScale', - 'maxResolution', 'minResolution', - 'numZoomLevels', 'maxZoomLevel' - ], - - /** - * APIProperty: events - * {} - * - * Register a listener for a particular event with the following syntax: - * (code) - * layer.events.register(type, obj, listener); - * (end) - * - * Listeners will be called with a reference to an event object. The - * properties of this event depends on exactly what happened. - * - * All event objects have at least the following properties: - * object - {Object} A reference to layer.events.object. - * element - {DOMElement} A reference to layer.events.element. - * - * Supported map event types: - * loadstart - Triggered when layer loading starts. - * loadend - Triggered when layer loading ends. When using Fixed or BBOX - * strategies, the event object includes a *response* property holding - * an OpenLayers.Protocol.Response object. - * visibilitychanged - Triggered when layer visibility is changed. - * move - Triggered when layer moves (triggered with every mousemove - * during a drag). - * moveend - Triggered when layer is done moving, object passed as - * argument has a zoomChanged boolean property which tells that the - * zoom has changed. - * added - Triggered after the layer is added to a map. Listeners will - * receive an object with a *map* property referencing the map and a - * *layer* property referencing the layer. - * removed - Triggered after the layer is removed from the map. Listeners - * will receive an object with a *map* property referencing the map and - * a *layer* property referencing the layer. - */ - events: null, - - /** - * APIProperty: map - * {} This variable is set when the layer is added to - * the map, via the accessor function setMap(). - */ - map: null, - - /** - * APIProperty: isBaseLayer - * {Boolean} Whether or not the layer is a base layer. This should be set - * individually by all subclasses. Default is false - */ - isBaseLayer: false, - - /** - * Property: alpha - * {Boolean} The layer's images have an alpha channel. Default is false. - */ - alpha: false, - - /** - * APIProperty: displayInLayerSwitcher - * {Boolean} Display the layer's name in the layer switcher. Default is - * true. - */ - displayInLayerSwitcher: true, - - /** - * APIProperty: visibility - * {Boolean} The layer should be displayed in the map. Default is true. - */ - visibility: true, - - /** - * APIProperty: attribution - * {String} Attribution string, displayed when an - * has been added to the map. - */ - attribution: null, - - /** - * Property: inRange - * {Boolean} The current map resolution is within the layer's min/max - * range. This is set in whenever the zoom - * changes. - */ - inRange: false, - - /** - * Propery: imageSize - * {} For layers with a gutter, the image is larger than - * the tile by twice the gutter in each dimension. - */ - imageSize: null, - - // OPTIONS - - /** - * Property: options - * {Object} An optional object whose properties will be set on the layer. - * Any of the layer properties can be set as a property of the options - * object and sent to the constructor when the layer is created. - */ - options: null, - - /** - * APIProperty: eventListeners - * {Object} If set as an option at construction, the eventListeners - * object will be registered with . Object - * structure must be a listeners object as shown in the example for - * the events.on method. - */ - eventListeners: null, - - /** - * APIProperty: gutter - * {Integer} Determines the width (in pixels) of the gutter around image - * tiles to ignore. By setting this property to a non-zero value, - * images will be requested that are wider and taller than the tile - * size by a value of 2 x gutter. This allows artifacts of rendering - * at tile edges to be ignored. Set a gutter value that is equal to - * half the size of the widest symbol that needs to be displayed. - * Defaults to zero. Non-tiled layers always have zero gutter. - */ - gutter: 0, - - /** - * APIProperty: projection - * {} or {} Specifies the projection of the layer. - * Can be set in the layer options. If not specified in the layer options, - * it is set to the default projection specified in the map, - * when the layer is added to the map. - * Projection along with default maxExtent and resolutions - * are set automatically with commercial baselayers in EPSG:3857, - * such as Google, Bing and OpenStreetMap, and do not need to be specified. - * Otherwise, if specifying projection, also set maxExtent, - * maxResolution or resolutions as appropriate. - * When using vector layers with strategies, layer projection should be set - * to the projection of the source data if that is different from the map default. - * - * Can be either a string or an object; - * if a string is passed, will be converted to an object when - * the layer is added to the map. - * - */ - projection: null, - - /** - * APIProperty: units - * {String} The layer map units. Defaults to null. Possible values - * are 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'. - * Normally taken from the projection. - * Only required if both map and layers do not define a projection, - * or if they define a projection which does not define units. - */ - units: null, - - /** - * APIProperty: scales - * {Array} An array of map scales in descending order. The values in the - * array correspond to the map scale denominator. Note that these - * values only make sense if the display (monitor) resolution of the - * client is correctly guessed by whomever is configuring the - * application. In addition, the units property must also be set. - * Use instead wherever possible. - */ - scales: null, - - /** - * APIProperty: resolutions - * {Array} A list of map resolutions (map units per pixel) in descending - * order. If this is not set in the layer constructor, it will be set - * based on other resolution related properties (maxExtent, - * maxResolution, maxScale, etc.). - */ - resolutions: null, - - /** - * APIProperty: maxExtent - * {|Array} If provided as an array, the array - * should consist of four values (left, bottom, right, top). - * The maximum extent for the layer. Defaults to null. - * - * The center of these bounds will not stray outside - * of the viewport extent during panning. In addition, if - * is set to false, data will not be - * requested that falls completely outside of these bounds. - */ - maxExtent: null, - - /** - * APIProperty: minExtent - * {|Array} If provided as an array, the array - * should consist of four values (left, bottom, right, top). - * The minimum extent for the layer. Defaults to null. - */ - minExtent: null, - - /** - * APIProperty: maxResolution - * {Float} Default max is 360 deg / 256 px, which corresponds to - * zoom level 0 on gmaps. Specify a different value in the layer - * options if you are not using the default - * and displaying the whole world. - */ - maxResolution: null, - - /** - * APIProperty: minResolution - * {Float} - */ - minResolution: null, - - /** - * APIProperty: numZoomLevels - * {Integer} - */ - numZoomLevels: null, - - /** - * APIProperty: minScale - * {Float} - */ - minScale: null, - - /** - * APIProperty: maxScale - * {Float} - */ - maxScale: null, - - /** - * APIProperty: displayOutsideMaxExtent - * {Boolean} Request map tiles that are completely outside of the max - * extent for this layer. Defaults to false. - */ - displayOutsideMaxExtent: false, - - /** - * APIProperty: wrapDateLine - * {Boolean} Wraps the world at the international dateline, so the map can - * be panned infinitely in longitudinal direction. Only use this on the - * base layer, and only if the layer's maxExtent equals the world bounds. - * #487 for more info. - */ - wrapDateLine: false, - - /** - * Property: metadata - * {Object} This object can be used to store additional information on a - * layer object. - */ - metadata: null, - - /** - * Constructor: OpenLayers.Layer - * - * Parameters: - * name - {String} The layer name - * options - {Object} Hashtable of extra options to tag onto the layer - */ - initialize: function(name, options) { - - this.metadata = {}; - - options = OpenLayers.Util.extend({}, options); - // make sure we respect alwaysInRange if set on the prototype - if (this.alwaysInRange != null) { - options.alwaysInRange = this.alwaysInRange; - } - this.addOptions(options); - - this.name = name; - - if (this.id == null) { - - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); - - this.div = OpenLayers.Util.createDiv(this.id); - this.div.style.width = "100%"; - this.div.style.height = "100%"; - this.div.dir = "ltr"; - - this.events = new OpenLayers.Events(this, this.div); - if(this.eventListeners instanceof Object) { - this.events.on(this.eventListeners); - } - - } - }, - - /** - * Method: destroy - * Destroy is a destructor: this is to alleviate cyclic references which - * the Javascript garbage cleaner can not take care of on its own. - * - * Parameters: - * setNewBaseLayer - {Boolean} Set a new base layer when this layer has - * been destroyed. Default is true. - */ - destroy: function(setNewBaseLayer) { - if (setNewBaseLayer == null) { - setNewBaseLayer = true; - } - if (this.map != null) { - this.map.removeLayer(this, setNewBaseLayer); - } - this.projection = null; - this.map = null; - this.name = null; - this.div = null; - this.options = null; - - if (this.events) { - if(this.eventListeners) { - this.events.un(this.eventListeners); - } - this.events.destroy(); - } - this.eventListeners = null; - this.events = null; - }, - - /** - * Method: clone - * - * Parameters: - * obj - {} The layer to be cloned - * - * Returns: - * {} An exact clone of this - */ - clone: function (obj) { - - if (obj == null) { - obj = new OpenLayers.Layer(this.name, this.getOptions()); - } - - // catch any randomly tagged-on properties - OpenLayers.Util.applyDefaults(obj, this); - - // a cloned layer should never have its map property set - // because it has not been added to a map yet. - obj.map = null; - - return obj; - }, - - /** - * Method: getOptions - * Extracts an object from the layer with the properties that were set as - * options, but updates them with the values currently set on the - * instance. - * - * Returns: - * {Object} the of the layer, representing the current state. - */ - getOptions: function() { - var options = {}; - for(var o in this.options) { - options[o] = this[o]; - } - return options; - }, - - /** - * APIMethod: setName - * Sets the new layer name for this layer. Can trigger a changelayer event - * on the map. - * - * Parameters: - * newName - {String} The new name. - */ - setName: function(newName) { - if (newName != this.name) { - this.name = newName; - if (this.map != null) { - this.map.events.triggerEvent("changelayer", { - layer: this, - property: "name" - }); - } - } - }, - - /** - * APIMethod: addOptions - * - * Parameters: - * newOptions - {Object} - * reinitialize - {Boolean} If set to true, and if resolution options of the - * current baseLayer were changed, the map will be recentered to make - * sure that it is displayed with a valid resolution, and a - * changebaselayer event will be triggered. - */ - addOptions: function (newOptions, reinitialize) { - - if (this.options == null) { - this.options = {}; - } - - if (newOptions) { - // make sure this.projection references a projection object - if(typeof newOptions.projection == "string") { - newOptions.projection = new OpenLayers.Projection(newOptions.projection); - } - if (newOptions.projection) { - // get maxResolution, units and maxExtent from projection defaults if - // they are not defined already - OpenLayers.Util.applyDefaults(newOptions, - OpenLayers.Projection.defaults[newOptions.projection.getCode()]); - } - // allow array for extents - if (newOptions.maxExtent && !(newOptions.maxExtent instanceof OpenLayers.Bounds)) { - newOptions.maxExtent = new OpenLayers.Bounds(newOptions.maxExtent); - } - if (newOptions.minExtent && !(newOptions.minExtent instanceof OpenLayers.Bounds)) { - newOptions.minExtent = new OpenLayers.Bounds(newOptions.minExtent); - } - } - - // update our copy for clone - OpenLayers.Util.extend(this.options, newOptions); - - // add new options to this - OpenLayers.Util.extend(this, newOptions); - - // get the units from the projection, if we have a projection - // and it it has units - if(this.projection && this.projection.getUnits()) { - this.units = this.projection.getUnits(); - } - - // re-initialize resolutions if necessary, i.e. if any of the - // properties of the "properties" array defined below is set - // in the new options - if(this.map) { - // store current resolution so we can try to restore it later - var resolution = this.map.getResolution(); - var properties = this.RESOLUTION_PROPERTIES.concat( - ["projection", "units", "minExtent", "maxExtent"] - ); - for(var o in newOptions) { - if(newOptions.hasOwnProperty(o) && - OpenLayers.Util.indexOf(properties, o) >= 0) { - - this.initResolutions(); - if (reinitialize && this.map.baseLayer === this) { - // update map position, and restore previous resolution - this.map.setCenter(this.map.getCenter(), - this.map.getZoomForResolution(resolution), - false, true - ); - // trigger a changebaselayer event to make sure that - // all controls (especially - // OpenLayers.Control.PanZoomBar) get notified of the - // new options - this.map.events.triggerEvent("changebaselayer", { - layer: this - }); - } - break; - } - } - } - }, - - /** - * APIMethod: onMapResize - * This function can be implemented by subclasses - */ - onMapResize: function() { - //this function can be implemented by subclasses - }, - - /** - * APIMethod: redraw - * Redraws the layer. Returns true if the layer was redrawn, false if not. - * - * Returns: - * {Boolean} The layer was redrawn. - */ - redraw: function() { - var redrawn = false; - if (this.map) { - - // min/max Range may have changed - this.inRange = this.calculateInRange(); - - // map's center might not yet be set - var extent = this.getExtent(); - - if (extent && this.inRange && this.visibility) { - var zoomChanged = true; - this.moveTo(extent, zoomChanged, false); - this.events.triggerEvent("moveend", - {"zoomChanged": zoomChanged}); - redrawn = true; - } - } - return redrawn; - }, - - /** - * Method: moveTo - * - * Parameters: - * bounds - {} - * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to - * do some init work in that case. - * dragging - {Boolean} - */ - moveTo:function(bounds, zoomChanged, dragging) { - var display = this.visibility; - if (!this.isBaseLayer) { - display = display && this.inRange; - } - this.display(display); - }, - - /** - * Method: moveByPx - * Move the layer based on pixel vector. To be implemented by subclasses. - * - * Parameters: - * dx - {Number} The x coord of the displacement vector. - * dy - {Number} The y coord of the displacement vector. - */ - moveByPx: function(dx, dy) { - }, - - /** - * Method: setMap - * Set the map property for the layer. This is done through an accessor - * so that subclasses can override this and take special action once - * they have their map variable set. - * - * Here we take care to bring over any of the necessary default - * properties from the map. - * - * Parameters: - * map - {} - */ - setMap: function(map) { - if (this.map == null) { - - this.map = map; - - // grab some essential layer data from the map if it hasn't already - // been set - this.maxExtent = this.maxExtent || this.map.maxExtent; - this.minExtent = this.minExtent || this.map.minExtent; - - this.projection = this.projection || this.map.projection; - if (typeof this.projection == "string") { - this.projection = new OpenLayers.Projection(this.projection); - } - - // Check the projection to see if we can get units -- if not, refer - // to properties. - this.units = this.projection.getUnits() || - this.units || this.map.units; - - this.initResolutions(); - - if (!this.isBaseLayer) { - this.inRange = this.calculateInRange(); - var show = ((this.visibility) && (this.inRange)); - this.div.style.display = show ? "" : "none"; - } - - // deal with gutters - this.setTileSize(); - } - }, - - /** - * Method: afterAdd - * Called at the end of the map.addLayer sequence. At this point, the map - * will have a base layer. To be overridden by subclasses. - */ - afterAdd: function() { - }, - - /** - * APIMethod: removeMap - * Just as setMap() allows each layer the possibility to take a - * personalized action on being added to the map, removeMap() allows - * each layer to take a personalized action on being removed from it. - * For now, this will be mostly unused, except for the EventPane layer, - * which needs this hook so that it can remove the special invisible - * pane. - * - * Parameters: - * map - {} - */ - removeMap: function(map) { - //to be overridden by subclasses - }, - - /** - * APIMethod: getImageSize - * - * Parameters: - * bounds - {} optional tile bounds, can be used - * by subclasses that have to deal with different tile sizes at the - * layer extent edges (e.g. Zoomify) - * - * Returns: - * {} The size that the image should be, taking into - * account gutters. - */ - getImageSize: function(bounds) { - return (this.imageSize || this.tileSize); - }, - - /** - * APIMethod: setTileSize - * Set the tile size based on the map size. This also sets layer.imageSize - * or use by Tile.Image. - * - * Parameters: - * size - {} - */ - setTileSize: function(size) { - var tileSize = (size) ? size : - ((this.tileSize) ? this.tileSize : - this.map.getTileSize()); - this.tileSize = tileSize; - if(this.gutter) { - // layers with gutters need non-null tile sizes - //if(tileSize == null) { - // OpenLayers.console.error("Error in layer.setMap() for " + - // this.name + ": layers with " + - // "gutters need non-null tile sizes"); - //} - this.imageSize = new OpenLayers.Size(tileSize.w + (2*this.gutter), - tileSize.h + (2*this.gutter)); - } - }, - - /** - * APIMethod: getVisibility - * - * Returns: - * {Boolean} The layer should be displayed (if in range). - */ - getVisibility: function() { - return this.visibility; - }, - - /** - * APIMethod: setVisibility - * Set the visibility flag for the layer and hide/show & redraw - * accordingly. Fire event unless otherwise specified - * - * Note that visibility is no longer simply whether or not the layer's - * style.display is set to "block". Now we store a 'visibility' state - * property on the layer class, this allows us to remember whether or - * not we *desire* for a layer to be visible. In the case where the - * map's resolution is out of the layer's range, this desire may be - * subverted. - * - * Parameters: - * visibility - {Boolean} Whether or not to display the layer (if in range) - */ - setVisibility: function(visibility) { - if (visibility != this.visibility) { - this.visibility = visibility; - this.display(visibility); - this.redraw(); - if (this.map != null) { - this.map.events.triggerEvent("changelayer", { - layer: this, - property: "visibility" - }); - } - this.events.triggerEvent("visibilitychanged"); - } - }, - - /** - * APIMethod: display - * Hide or show the Layer. This is designed to be used internally, and - * is not generally the way to enable or disable the layer. For that, - * use the setVisibility function instead.. - * - * Parameters: - * display - {Boolean} - */ - display: function(display) { - if (display != (this.div.style.display != "none")) { - this.div.style.display = (display && this.calculateInRange()) ? "block" : "none"; - } - }, - - /** - * APIMethod: calculateInRange - * - * Returns: - * {Boolean} The layer is displayable at the current map's current - * resolution. Note that if 'alwaysInRange' is true for the layer, - * this function will always return true. - */ - calculateInRange: function() { - var inRange = false; - - if (this.alwaysInRange) { - inRange = true; - } else { - if (this.map) { - var resolution = this.map.getResolution(); - inRange = ( (resolution >= this.minResolution) && - (resolution <= this.maxResolution) ); - } - } - return inRange; - }, - - /** - * APIMethod: setIsBaseLayer - * - * Parameters: - * isBaseLayer - {Boolean} - */ - setIsBaseLayer: function(isBaseLayer) { - if (isBaseLayer != this.isBaseLayer) { - this.isBaseLayer = isBaseLayer; - if (this.map != null) { - this.map.events.triggerEvent("changebaselayer", { - layer: this - }); - } - } - }, - - /********************************************************/ - /* */ - /* Baselayer Functions */ - /* */ - /********************************************************/ - - /** - * Method: initResolutions - * This method's responsibility is to set up the 'resolutions' array - * for the layer -- this array is what the layer will use to interface - * between the zoom levels of the map and the resolution display - * of the layer. - * - * The user has several options that determine how the array is set up. - * - * For a detailed explanation, see the following wiki from the - * openlayers.org homepage: - * http://trac.openlayers.org/wiki/SettingZoomLevels - */ - initResolutions: function() { - - // ok we want resolutions, here's our strategy: - // - // 1. if resolutions are defined in the layer config, use them - // 2. else, if scales are defined in the layer config then derive - // resolutions from these scales - // 3. else, attempt to calculate resolutions from maxResolution, - // minResolution, numZoomLevels, maxZoomLevel set in the - // layer config - // 4. if we still don't have resolutions, and if resolutions - // are defined in the same, use them - // 5. else, if scales are defined in the map then derive - // resolutions from these scales - // 6. else, attempt to calculate resolutions from maxResolution, - // minResolution, numZoomLevels, maxZoomLevel set in the - // map - // 7. hope for the best! - - var i, len, p; - var props = {}, alwaysInRange = true; - - // get resolution data from layer config - // (we also set alwaysInRange in the layer as appropriate) - for(i=0, len=this.RESOLUTION_PROPERTIES.length; i} A Bounds object which represents the lon/lat - * bounds of the current viewPort. - */ - getExtent: function() { - // just use stock map calculateBounds function -- passing no arguments - // means it will user map's current center & resolution - // - return this.map.calculateBounds(); - }, - - /** - * APIMethod: getZoomForExtent - * - * Parameters: - * extent - {} - * closest - {Boolean} Find the zoom level that most closely fits the - * specified bounds. Note that this may result in a zoom that does - * not exactly contain the entire extent. - * Default is false. - * - * Returns: - * {Integer} The index of the zoomLevel (entry in the resolutions array) - * for the passed-in extent. We do this by calculating the ideal - * resolution for the given extent (based on the map size) and then - * calling getZoomForResolution(), passing along the 'closest' - * parameter. - */ - getZoomForExtent: function(extent, closest) { - var viewSize = this.map.getSize(); - var idealResolution = Math.max( extent.getWidth() / viewSize.w, - extent.getHeight() / viewSize.h ); - - return this.getZoomForResolution(idealResolution, closest); - }, - - /** - * Method: getDataExtent - * Calculates the max extent which includes all of the data for the layer. - * This function is to be implemented by subclasses. - * - * Returns: - * {} - */ - getDataExtent: function () { - //to be implemented by subclasses - }, - - /** - * APIMethod: getResolutionForZoom - * - * Parameters: - * zoom - {Float} - * - * Returns: - * {Float} A suitable resolution for the specified zoom. - */ - getResolutionForZoom: function(zoom) { - zoom = Math.max(0, Math.min(zoom, this.resolutions.length - 1)); - var resolution; - if(this.map.fractionalZoom) { - var low = Math.floor(zoom); - var high = Math.ceil(zoom); - resolution = this.resolutions[low] - - ((zoom-low) * (this.resolutions[low]-this.resolutions[high])); - } else { - resolution = this.resolutions[Math.round(zoom)]; - } - return resolution; - }, - - /** - * APIMethod: getZoomForResolution - * - * Parameters: - * resolution - {Float} - * closest - {Boolean} Find the zoom level that corresponds to the absolute - * closest resolution, which may result in a zoom whose corresponding - * resolution is actually smaller than we would have desired (if this - * is being called from a getZoomForExtent() call, then this means that - * the returned zoom index might not actually contain the entire - * extent specified... but it'll be close). - * Default is false. - * - * Returns: - * {Integer} The index of the zoomLevel (entry in the resolutions array) - * that corresponds to the best fit resolution given the passed in - * value and the 'closest' specification. - */ - getZoomForResolution: function(resolution, closest) { - var zoom, i, len; - if(this.map.fractionalZoom) { - var lowZoom = 0; - var highZoom = this.resolutions.length - 1; - var highRes = this.resolutions[lowZoom]; - var lowRes = this.resolutions[highZoom]; - var res; - for(i=0, len=this.resolutions.length; i= resolution) { - highRes = res; - lowZoom = i; - } - if(res <= resolution) { - lowRes = res; - highZoom = i; - break; - } - } - var dRes = highRes - lowRes; - if(dRes > 0) { - zoom = lowZoom + ((highRes - resolution) / dRes); - } else { - zoom = lowZoom; - } - } else { - var diff; - var minDiff = Number.POSITIVE_INFINITY; - for(i=0, len=this.resolutions.length; i minDiff) { - break; - } - minDiff = diff; - } else { - if (this.resolutions[i] < resolution) { - break; - } - } - } - zoom = Math.max(0, i-1); - } - return zoom; - }, - - /** - * APIMethod: getLonLatFromViewPortPx - * - * Parameters: - * viewPortPx - {|Object} An OpenLayers.Pixel or - * an object with a 'x' - * and 'y' properties. - * - * Returns: - * {} An OpenLayers.LonLat which is the passed-in - * view port , translated into lon/lat by the layer. - */ - getLonLatFromViewPortPx: function (viewPortPx) { - var lonlat = null; - var map = this.map; - if (viewPortPx != null && map.minPx) { - var res = map.getResolution(); - var maxExtent = map.getMaxExtent({restricted: true}); - var lon = (viewPortPx.x - map.minPx.x) * res + maxExtent.left; - var lat = (map.minPx.y - viewPortPx.y) * res + maxExtent.top; - lonlat = new OpenLayers.LonLat(lon, lat); - - if (this.wrapDateLine) { - lonlat = lonlat.wrapDateLine(this.maxExtent); - } - } - return lonlat; - }, - - /** - * APIMethod: getViewPortPxFromLonLat - * Returns a pixel location given a map location. This method will return - * fractional pixel values. - * - * Parameters: - * lonlat - {|Object} An OpenLayers.LonLat or - * an object with a 'lon' - * and 'lat' properties. - * - * Returns: - * {} An which is the passed-in - * lonlat translated into view port pixels. - */ - getViewPortPxFromLonLat: function (lonlat, resolution) { - var px = null; - if (lonlat != null) { - resolution = resolution || this.map.getResolution(); - var extent = this.map.calculateBounds(null, resolution); - px = new OpenLayers.Pixel( - (1/resolution * (lonlat.lon - extent.left)), - (1/resolution * (extent.top - lonlat.lat)) - ); - } - return px; - }, - - /** - * APIMethod: setOpacity - * Sets the opacity for the entire layer (all images) - * - * Parameters: - * opacity - {Float} - */ - setOpacity: function(opacity) { - if (opacity != this.opacity) { - this.opacity = opacity; - var childNodes = this.div.childNodes; - for(var i = 0, len = childNodes.length; i < len; ++i) { - var element = childNodes[i].firstChild || childNodes[i]; - var lastChild = childNodes[i].lastChild; - //TODO de-uglify this - if (lastChild && lastChild.nodeName.toLowerCase() === "iframe") { - element = lastChild.parentNode; - } - OpenLayers.Util.modifyDOMElement(element, null, null, null, - null, null, null, opacity); - } - if (this.map != null) { - this.map.events.triggerEvent("changelayer", { - layer: this, - property: "opacity" - }); - } - } - }, - - /** - * Method: getZIndex - * - * Returns: - * {Integer} the z-index of this layer - */ - getZIndex: function () { - return this.div.style.zIndex; - }, - - /** - * Method: setZIndex - * - * Parameters: - * zIndex - {Integer} - */ - setZIndex: function (zIndex) { - this.div.style.zIndex = zIndex; - }, - - /** - * Method: adjustBounds - * This function will take a bounds, and if wrapDateLine option is set - * on the layer, it will return a bounds which is wrapped around the - * world. We do not wrap for bounds which *cross* the - * maxExtent.left/right, only bounds which are entirely to the left - * or entirely to the right. - * - * Parameters: - * bounds - {} - */ - adjustBounds: function (bounds) { - - if (this.gutter) { - // Adjust the extent of a bounds in map units by the - // layer's gutter in pixels. - var mapGutter = this.gutter * this.map.getResolution(); - bounds = new OpenLayers.Bounds(bounds.left - mapGutter, - bounds.bottom - mapGutter, - bounds.right + mapGutter, - bounds.top + mapGutter); - } - - if (this.wrapDateLine) { - // wrap around the date line, within the limits of rounding error - var wrappingOptions = { - 'rightTolerance':this.getResolution(), - 'leftTolerance':this.getResolution() - }; - bounds = bounds.wrapDateLine(this.maxExtent, wrappingOptions); - - } - return bounds; - }, - - CLASS_NAME: "OpenLayers.Layer" -}); -/* ====================================================================== - OpenLayers/Layer/HTTPRequest.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/Layer.js - */ - -/** - * Class: OpenLayers.Layer.HTTPRequest - * - * Inherits from: - * - - */ -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://docs.openlayers.org/library/spherical_mercator.html - * for information on the replacement for this functionality. - * {Boolean} Whether layer should reproject itself based on base layer - * locations. This allows reprojection onto commercial layers. - * Default is false: Most layers can't reproject, but layers - * which can create non-square geographic pixels can, like WMS. - * - */ - 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) { - OpenLayers.Layer.prototype.initialize.apply(this, [name, options]); - this.url = url; - if (!this.params) { - 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: - * {} An exact clone of this - * - */ - 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 constructor, or a subclass. - * - * TBD 3.0 - remove reference to url in above paragraph - * - */ -OpenLayers.Tile = OpenLayers.Class({ - - /** - * APIProperty: events - * {} An events object that handles all - * events on the tile. - * - * Register a listener for a particular event with the following syntax: - * (code) - * tile.events.register(type, obj, listener); - * (end) - * - * Supported event types: - * beforedraw - Triggered before the tile is drawn. Used to defer - * drawing to an animation queue. To defer drawing, listeners need - * to return false, which will abort drawing. The queue handler needs - * to call (true) to actually draw the tile. - * loadstart - Triggered when tile loading starts. - * loadend - Triggered when tile loading ends. - * loaderror - Triggered before the loadend event (i.e. when the tile is - * still hidden) if the tile could not be loaded. - * reload - Triggered when an already loading tile is reloaded. - * unload - Triggered before a tile is unloaded. - */ - events: null, - - /** - * APIProperty: eventListeners - * {Object} If set as an option at construction, the eventListeners - * object will be registered with . Object - * structure must be a listeners object as shown in the example for - * the events.on method. - * - * This options can be set in the ``tileOptions`` option from - * . For example, to be notified of the - * ``loadend`` event of each tiles: - * (code) - * new OpenLayers.Layer.OSM('osm', 'http://tile.openstreetmap.org/${z}/${x}/${y}.png', { - * tileOptions: { - * eventListeners: { - * 'loadend': function(evt) { - * // do something on loadend - * } - * } - * } - * }); - * (end) - */ - eventListeners: null, - - /** - * Property: id - * {String} null - */ - id: null, - - /** - * Property: layer - * {} layer the tile is attached to - */ - layer: null, - - /** - * Property: url - * {String} url of the request. - * - * TBD 3.0 - * Deprecated. The base tile class does not need an url. This should be - * handled in subclasses. Does not belong here. - */ - url: null, - - /** - * APIProperty: bounds - * {} null - */ - bounds: null, - - /** - * Property: size - * {} null - */ - size: null, - - /** - * Property: position - * {} Top Left pixel of the tile - */ - position: null, - - /** - * Property: isLoading - * {Boolean} Is the tile loading? - */ - isLoading: false, - - /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor. - * there is no need for the base tile class to have a url. - */ - - /** - * Constructor: OpenLayers.Tile - * Constructor for a new instance. - * - * Parameters: - * layer - {} layer that the tile will go in. - * position - {} - * bounds - {} - * url - {} - * size - {} - * options - {Object} - */ - initialize: function(layer, position, bounds, url, size, options) { - this.layer = layer; - this.position = position.clone(); - this.setBounds(bounds); - this.url = url; - if (size) { - this.size = size.clone(); - } - - //give the tile a unique id based on its BBOX. - this.id = OpenLayers.Util.createUniqueID("Tile_"); - - OpenLayers.Util.extend(this, options); - - this.events = new OpenLayers.Events(this); - if (this.eventListeners instanceof Object) { - this.events.on(this.eventListeners); - } - }, - - /** - * Method: unload - * Call immediately before destroying if you are listening to tile - * events, so that counters are properly handled if tile is still - * loading at destroy-time. Will only fire an event if the tile is - * still loading. - */ - unload: function() { - if (this.isLoading) { - this.isLoading = false; - this.events.triggerEvent("unload"); - } - }, - - /** - * APIMethod: destroy - * Nullify references to prevent circular references and memory leaks. - */ - destroy:function() { - this.layer = null; - this.bounds = null; - this.size = null; - this.position = null; - - if (this.eventListeners) { - this.events.un(this.eventListeners); - } - this.events.destroy(); - this.eventListeners = null; - this.events = null; - }, - - /** - * Method: draw - * Clear whatever is currently in the tile, then return whether or not - * it should actually be re-drawn. This is an example implementation - * that can be overridden by subclasses. The minimum thing to do here - * is to call and return the result from . - * - * Parameters: - * immediately - {Boolean} When e.g. drawing was aborted by returning false - * from a *beforedraw* listener, the queue manager needs to pass true, - * so the tile will not be cleared and immediately be drawn. Otherwise, - * the tile will be cleared and a *beforedraw* event will be fired. - * - * Returns: - * {Boolean} Whether or not the tile should actually be drawn. - */ - draw: function(immediately) { - if (!immediately) { - //clear tile's contents and mark as not drawn - this.clear(); - } - var draw = this.shouldDraw(); - if (draw && !immediately) { - draw = this.events.triggerEvent("beforedraw") !== false; - } - return draw; - }, - - /** - * Method: shouldDraw - * Return whether or not the tile should actually be (re-)drawn. The only - * case where we *wouldn't* want to draw the tile is if the tile is outside - * its layer's maxExtent - * - * Returns: - * {Boolean} Whether or not the tile should actually be drawn. - */ - shouldDraw: function() { - var withinMaxExtent = false, - maxExtent = this.layer.maxExtent; - if (maxExtent) { - var map = this.layer.map; - var worldBounds = map.baseLayer.wrapDateLine && map.getMaxExtent(); - if (this.bounds.intersectsBounds(maxExtent, {inclusive: false, worldBounds: worldBounds})) { - withinMaxExtent = true; - } - } - - return withinMaxExtent || this.layer.displayOutsideMaxExtent; - }, - - /** - * Method: setBounds - * Sets the bounds on this instance - * - * Parameters: - * bounds {} - */ - setBounds: function(bounds) { - bounds = bounds.clone(); - if (this.layer.map.baseLayer.wrapDateLine) { - var worldExtent = this.layer.map.getMaxExtent(), - tolerance = this.layer.map.getResolution(); - bounds = bounds.wrapDateLine(worldExtent, { - leftTolerance: tolerance, - rightTolerance: tolerance - }); - } - this.bounds = bounds; - }, - - /** - * Method: moveTo - * Reposition the tile. - * - * Parameters: - * bounds - {} - * position - {} - * redraw - {Boolean} Call draw method on tile after moving. - * Default is true - */ - moveTo: function (bounds, position, redraw) { - if (redraw == null) { - redraw = true; - } - - this.setBounds(bounds); - this.position = position.clone(); - if (redraw) { - this.draw(); - } - }, - - /** - * Method: clear - * Clear the tile of any bounds/position-related data so that it can - * be reused in a new location. - */ - clear: function(draw) { - // to be extended by subclasses - }, - - CLASS_NAME: "OpenLayers.Tile" -}); -/* ====================================================================== - OpenLayers/Tile/Image.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/Tile.js - * @requires OpenLayers/Animation.js - */ - -/** - * Class: OpenLayers.Tile.Image - * Instances of OpenLayers.Tile.Image are used to manage the image tiles - * used by various layers. Create a new image tile with the - * constructor. - * - * Inherits from: - * - - */ -OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { - - /** - * APIProperty: url - * {String} The URL of the image being requested. No default. Filled in by - * layer.getURL() function. May be modified by loadstart listeners. - */ - url: null, - - /** - * Property: imgDiv - * {HTMLImageElement} The image for this tile. - */ - imgDiv: null, - - /** - * Property: frame - * {DOMElement} The image element is appended to the frame. Any gutter on - * the image will be hidden behind the frame. If no gutter is set, - * this will be null. - */ - frame: null, - - /** - * Property: imageReloadAttempts - * {Integer} Attempts to load the image. - */ - imageReloadAttempts: null, - - /** - * Property: layerAlphaHack - * {Boolean} True if the png alpha hack needs to be applied on the layer's div. - */ - layerAlphaHack: null, - - /** - * Property: asyncRequestId - * {Integer} ID of an request to see if request is still valid. This is a - * number which increments by 1 for each asynchronous request. - */ - asyncRequestId: null, - - /** - * Property: blankImageUrl - * {String} Using a data scheme url is not supported by all browsers, but - * we don't care because we either set it as css backgroundImage, or the - * image's display style is set to "none" when we use it. - */ - blankImageUrl: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7", - - /** - * APIProperty: maxGetUrlLength - * {Number} If set, requests that would result in GET urls with more - * characters than the number provided will be made using form-encoded - * HTTP POST. It is good practice to avoid urls that are longer than 2048 - * characters. - * - * Caution: - * Older versions of Gecko based browsers (e.g. Firefox < 3.5) and most - * Opera versions do not fully support this option. On all browsers, - * transition effects are not supported if POST requests are used. - */ - maxGetUrlLength: null, - - /** - * Property: canvasContext - * {CanvasRenderingContext2D} A canvas context associated with - * the tile image. - */ - canvasContext: null, - - /** - * APIProperty: crossOriginKeyword - * The value of the crossorigin keyword to use when loading images. This is - * only relevant when using for tiles from remote - * origins and should be set to either 'anonymous' or 'use-credentials' - * for servers that send Access-Control-Allow-Origin headers with their - * tiles. - */ - crossOriginKeyword: null, - - /** TBD 3.0 - reorder the parameters to the init function to remove - * URL. the getUrl() function on the layer gets called on - * each draw(), so no need to specify it here. - */ - - /** - * Constructor: OpenLayers.Tile.Image - * Constructor for a new instance. - * - * Parameters: - * layer - {} layer that the tile will go in. - * position - {} - * bounds - {} - * url - {} Deprecated. Remove me in 3.0. - * size - {} - * options - {Object} - */ - initialize: function(layer, position, bounds, url, size, options) { - OpenLayers.Tile.prototype.initialize.apply(this, arguments); - - this.url = url; //deprecated remove me - - this.layerAlphaHack = this.layer.alpha && OpenLayers.Util.alphaHack(); - - if (this.maxGetUrlLength != null || this.layer.gutter || this.layerAlphaHack) { - // only create frame if it's needed - this.frame = document.createElement("div"); - this.frame.style.position = "absolute"; - this.frame.style.overflow = "hidden"; - } - if (this.maxGetUrlLength != null) { - OpenLayers.Util.extend(this, OpenLayers.Tile.Image.IFrame); - } - }, - - /** - * APIMethod: destroy - * nullify references to prevent circular references and memory leaks - */ - destroy: function() { - if (this.imgDiv) { - this.clear(); - this.imgDiv = null; - this.frame = null; - } - // don't handle async requests any more - this.asyncRequestId = null; - OpenLayers.Tile.prototype.destroy.apply(this, arguments); - }, - - /** - * Method: draw - * Check that a tile should be drawn, and draw it. - * - * Returns: - * {Boolean} Was a tile drawn? - */ - draw: function() { - var drawn = OpenLayers.Tile.prototype.draw.apply(this, arguments); - if (drawn) { - // The layer's reproject option is deprecated. - if (this.layer != this.layer.map.baseLayer && this.layer.reproject) { - // getBoundsFromBaseLayer is defined in deprecated.js. - this.bounds = this.getBoundsFromBaseLayer(this.position); - } - if (this.isLoading) { - //if we're already loading, send 'reload' instead of 'loadstart'. - this._loadEvent = "reload"; - } else { - this.isLoading = true; - this._loadEvent = "loadstart"; - } - this.positionTile(); - this.renderTile(); - } else { - this.unload(); - } - return drawn; - }, - - /** - * Method: renderTile - * Internal function to actually initialize the image tile, - * position it correctly, and set its url. - */ - renderTile: function() { - this.layer.div.appendChild(this.getTile()); - if (this.layer.async) { - // Asynchronous image requests call the asynchronous getURL method - // on the layer to fetch an image that covers 'this.bounds'. - var id = this.asyncRequestId = (this.asyncRequestId || 0) + 1; - this.layer.getURLasync(this.bounds, function(url) { - if (id == this.asyncRequestId) { - this.url = url; - this.initImage(); - } - }, this); - } else { - // synchronous image requests get the url immediately. - this.url = this.layer.getURL(this.bounds); - this.initImage(); - } - }, - - /** - * Method: positionTile - * Using the properties currenty set on the layer, position the tile correctly. - * This method is used both by the async and non-async versions of the Tile.Image - * code. - */ - positionTile: function() { - var style = this.getTile().style, - size = this.frame ? this.size : - this.layer.getImageSize(this.bounds), - ratio = 1; - if (this.layer instanceof OpenLayers.Layer.Grid) { - ratio = this.layer.getServerResolution() / this.layer.map.getResolution(); - } - style.left = (this.position.x | 0) + "px"; - style.top = (this.position.y | 0) + "px"; - style.width = Math.round(ratio * size.w) + "px"; - style.height = Math.round(ratio * size.h) + "px"; - }, - - /** - * Method: clear - * Remove the tile from the DOM, clear it of any image related data so that - * it can be reused in a new location. - */ - clear: function() { - OpenLayers.Tile.prototype.clear.apply(this, arguments); - var img = this.imgDiv; - if (img) { - OpenLayers.Event.stopObservingElement(img); - var tile = this.getTile(); - if (tile.parentNode === this.layer.div) { - this.layer.div.removeChild(tile); - } - this.setImgSrc(); - if (this.layerAlphaHack === true) { - img.style.filter = ""; - } - OpenLayers.Element.removeClass(img, "olImageLoadError"); - } - this.canvasContext = null; - }, - - /** - * Method: getImage - * Returns or creates and returns the tile image. - */ - getImage: function() { - if (!this.imgDiv) { - this.imgDiv = document.createElement("img"); - - this.imgDiv.className = "olTileImage"; - // avoid image gallery menu in IE6 - this.imgDiv.galleryImg = "no"; - - var style = this.imgDiv.style; - if (this.frame) { - var left = 0, top = 0; - if (this.layer.gutter) { - left = this.layer.gutter / this.layer.tileSize.w * 100; - top = this.layer.gutter / this.layer.tileSize.h * 100; - } - style.left = -left + "%"; - style.top = -top + "%"; - style.width = (2 * left + 100) + "%"; - style.height = (2 * top + 100) + "%"; - } - style.visibility = "hidden"; - style.opacity = 0; - if (this.layer.opacity < 1) { - style.filter = 'alpha(opacity=' + - (this.layer.opacity * 100) + - ')'; - } - style.position = "absolute"; - if (this.layerAlphaHack) { - // move the image out of sight - style.paddingTop = style.height; - style.height = "0"; - style.width = "100%"; - } - if (this.frame) { - this.frame.appendChild(this.imgDiv); - } - } - - return this.imgDiv; - }, - - /** - * Method: initImage - * Creates the content for the frame on the tile. - */ - initImage: function() { - this.events.triggerEvent(this._loadEvent); - var img = this.getImage(); - if (this.url && img.getAttribute("src") == this.url) { - this.onImageLoad(); - } else { - // We need to start with a blank image, to make sure that no - // loading image placeholder and no old image is displayed when we - // set the display style to "" in onImageLoad, which is called - // after the image is loaded, but before it is rendered. So we set - // a blank image with a data scheme URI, and register for the load - // event (for browsers that support data scheme) and the error - // event (for browsers that don't). In the event handler, we set - // the final src. - var load = OpenLayers.Function.bind(function() { - OpenLayers.Event.stopObservingElement(img); - OpenLayers.Event.observe(img, "load", - OpenLayers.Function.bind(this.onImageLoad, this) - ); - OpenLayers.Event.observe(img, "error", - OpenLayers.Function.bind(this.onImageError, this) - ); - this.imageReloadAttempts = 0; - this.setImgSrc(this.url); - }, this); - if (img.getAttribute("src") == this.blankImageUrl) { - load(); - } else { - OpenLayers.Event.observe(img, "load", load); - OpenLayers.Event.observe(img, "error", load); - if (this.crossOriginKeyword) { - img.removeAttribute("crossorigin"); - } - img.src = this.blankImageUrl; - } - } - }, - - /** - * Method: setImgSrc - * Sets the source for the tile image - * - * Parameters: - * url - {String} or undefined to hide the image - */ - setImgSrc: function(url) { - var img = this.imgDiv; - if (url) { - img.style.visibility = 'hidden'; - img.style.opacity = 0; - // don't set crossOrigin if the url is a data URL - if (this.crossOriginKeyword) { - if (url.substr(0, 5) !== 'data:') { - img.setAttribute("crossorigin", this.crossOriginKeyword); - } else { - img.removeAttribute("crossorigin"); - } - } - img.src = url; - } else { - // Remove reference to the image, and leave it to the browser's - // caching and garbage collection. - this.imgDiv = null; - if (img.parentNode) { - img.parentNode.removeChild(img); - } - } - }, - - /** - * Method: getTile - * Get the tile's markup. - * - * Returns: - * {DOMElement} The tile's markup - */ - getTile: function() { - return this.frame ? this.frame : this.getImage(); - }, - - /** - * Method: createBackBuffer - * Create a backbuffer for this tile. A backbuffer isn't exactly a clone - * of the tile's markup, because we want to avoid the reloading of the - * image. So we clone the frame, and steal the image from the tile. - * - * Returns: - * {DOMElement} The markup, or undefined if the tile has no image - * or if it's currently loading. - */ - createBackBuffer: function() { - if (!this.imgDiv || this.isLoading) { - return; - } - var backBuffer; - if (this.frame) { - backBuffer = this.frame.cloneNode(false); - backBuffer.appendChild(this.imgDiv); - } else { - backBuffer = this.imgDiv; - } - this.imgDiv = null; - return backBuffer; - }, - - /** - * Method: onImageLoad - * Handler for the image onload event - */ - onImageLoad: function() { - var img = this.imgDiv; - OpenLayers.Event.stopObservingElement(img); - - img.style.visibility = 'inherit'; - img.style.opacity = this.layer.opacity; - - this.isLoading = false; - this.canvasContext = null; - this.events.triggerEvent("loadend"); - - if (this.layerAlphaHack === true) { - img.style.filter = - "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + - img.src + "', sizingMethod='scale')"; - } - }, - - /** - * Method: onImageError - * Handler for the image onerror event - */ - onImageError: function() { - var img = this.imgDiv; - if (img.src != null) { - this.imageReloadAttempts++; - if (this.imageReloadAttempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) { - this.setImgSrc(this.layer.getURL(this.bounds)); - } else { - OpenLayers.Element.addClass(img, "olImageLoadError"); - this.events.triggerEvent("loaderror"); - this.onImageLoad(); - } - } - }, - - /** - * APIMethod: getCanvasContext - * Returns a canvas context associated with the tile image (with - * the image drawn on it). - * Returns undefined if the browser does not support canvas, if - * the tile has no image or if it's currently loading. - * - * The function returns a canvas context instance but the - * underlying canvas is still available in the 'canvas' property: - * (code) - * var context = tile.getCanvasContext(); - * if (context) { - * var data = context.canvas.toDataURL('image/jpeg'); - * } - * (end) - * - * Returns: - * {Boolean} - */ - getCanvasContext: function() { - if (OpenLayers.CANVAS_SUPPORTED && this.imgDiv && !this.isLoading) { - if (!this.canvasContext) { - var canvas = document.createElement("canvas"); - canvas.width = this.size.w; - canvas.height = this.size.h; - this.canvasContext = canvas.getContext("2d"); - this.canvasContext.drawImage(this.imgDiv, 0, 0); - } - return this.canvasContext; - } - }, - - CLASS_NAME: "OpenLayers.Tile.Image" - -}); -/* ====================================================================== - OpenLayers/Layer/Grid.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/Layer/HTTPRequest.js - * @requires OpenLayers/Tile/Image.js - */ - -/** - * Class: OpenLayers.Layer.Grid - * Base class for layers that use a lattice of tiles. Create a new grid - * layer with the constructor. - * - * Inherits from: - * - - */ -OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { - - /** - * APIProperty: tileSize - * {} - */ - tileSize: null, - - /** - * Property: tileOriginCorner - * {String} If the property is not provided, the tile origin - * will be derived from the layer's . The corner of the - * used is determined by this property. Acceptable values - * are "tl" (top left), "tr" (top right), "bl" (bottom left), and "br" - * (bottom right). Default is "bl". - */ - tileOriginCorner: "bl", - - /** - * APIProperty: tileOrigin - * {} Optional origin for aligning the grid of tiles. - * If provided, requests for tiles at all resolutions will be aligned - * with this location (no tiles shall overlap this location). If - * not provided, the grid of tiles will be aligned with the layer's - * . Default is ``null``. - */ - tileOrigin: null, - - /** APIProperty: tileOptions - * {Object} optional configuration options for instances - * created by this Layer, if supported by the tile class. - */ - tileOptions: null, - - /** - * APIProperty: tileClass - * {} The tile class to use for this layer. - * Defaults is OpenLayers.Tile.Image. - */ - tileClass: OpenLayers.Tile.Image, - - /** - * Property: grid - * {Array(Array())} 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. - * For very slow loading layers, a larger value may increase - * performance somewhat when dragging, but will increase bandwidth - * use significantly. - */ - buffer: 0, - - /** - * APIProperty: transitionEffect - * {String} The transition effect to use when the map is zoomed. - * Two posible values: - * - * null - No transition effect (the default). - * "resize" - Existing tiles are resized on zoom to provide a visual - * effect of the zoom having taken place immediately. As the - * new tiles become available, they are drawn over top of the - * resized tiles. - * - * Using "resize" on non-opaque layers can cause undesired visual - * effects. This is therefore discouraged. - */ - transitionEffect: null, - - /** - * APIProperty: numLoadingTiles - * {Integer} How many tiles are still loading? - */ - numLoadingTiles: 0, - - /** - * APIProperty: tileLoadingDelay - * {Integer} Number of milliseconds before we shift and load - * tiles when panning. Ignored if is - * true. Default is 85. - */ - tileLoadingDelay: 85, - - /** - * Property: serverResolutions - * {Array(Number}} This property is documented in subclasses as - * an API property. - */ - serverResolutions: null, - - /** - * Property: moveTimerId - * {Number} The id of the timer. - */ - moveTimerId: null, - - /** - * Property: deferMoveGriddedTiles - * {Function} A function that defers execution of by - * . If is true, this - * is null and unused. - */ - deferMoveGriddedTiles: null, - - /** - * Property: tileQueueId - * {Number} The id of the animation. - */ - tileQueueId: null, - - /** - * Property: tileQueue - * {Array()} Tiles queued for drawing. - */ - tileQueue: null, - - /** - * Property: loading - * {Boolean} Indicates if tiles are being loaded. - */ - loading: false, - - /** - * Property: backBuffer - * {DOMElement} The back buffer. - */ - backBuffer: null, - - /** - * Property: gridResolution - * {Number} The resolution of the current grid. Used for backbuffer and - * client zoom. This property is updated every time the grid is - * initialized. - */ - gridResolution: null, - - /** - * Property: backBufferResolution - * {Number} The resolution of the current back buffer. This property is - * updated each time a back buffer is created. - */ - backBufferResolution: null, - - /** - * Property: backBufferLonLat - * {Object} The top-left corner of the current back buffer. Includes lon - * and lat properties. This object is updated each time a back buffer - * is created. - */ - backBufferLonLat: null, - - /** - * Property: backBufferTimerId - * {Number} The id of the back buffer timer. This timer is used to - * delay the removal of the back buffer, thereby preventing - * flash effects caused by tile animation. - */ - backBufferTimerId: null, - - /** - * APIProperty: removeBackBufferDelay - * {Number} Delay for removing the backbuffer when all tiles have finished - * loading. Can be set to 0 when no css opacity transitions for the - * olTileImage class are used. Default is 0 for layers, - * 2500 for tiled layers. See for more information on - * tile animation. - */ - removeBackBufferDelay: null, - - /** - * APIProperty: className - * {String} Name of the class added to the layer div. If not set in the - * options passed to the constructor then className defaults to - * "olLayerGridSingleTile" for single tile layers (see ), - * and "olLayerGrid" for non single tile layers. - * - * Note: - * - * The displaying of tiles is not animated by default for single tile - * layers - OpenLayers' default theme (style.css) includes this: - * (code) - * .olLayerGrid .olTileImage { - * -webkit-transition: opacity 0.2s linear; - * -moz-transition: opacity 0.2s linear; - * -o-transition: opacity 0.2s linear; - * transition: opacity 0.2s linear; - * } - * (end) - * To animate tile displaying for any grid layer the following - * CSS rule can be used: - * (code) - * .olTileImage { - * -webkit-transition: opacity 0.2s linear; - * -moz-transition: opacity 0.2s linear; - * -o-transition: opacity 0.2s linear; - * transition: opacity 0.2s linear; - * } - * (end) - * In that case, to avoid flash effects, - * should not be zero. - */ - className: null, - - /** - * Register a listener for a particular event with the following syntax: - * (code) - * layer.events.register(type, obj, listener); - * (end) - * - * Listeners will be called with a reference to an event object. The - * properties of this event depends on exactly what happened. - * - * All event objects have at least the following properties: - * object - {Object} A reference to layer.events.object. - * element - {DOMElement} A reference to layer.events.element. - * - * Supported event types: - * tileloadstart - Triggered when a tile starts loading. Listeners receive - * an object as first argument, which has a tile property that - * references the tile that starts loading. - * tileloaded - Triggered when each new tile is - * loaded, as a means of progress update to listeners. - * listeners can access 'numLoadingTiles' if they wish to keep - * track of the loading progress. Listeners are called with an object - * with a tile property as first argument, making the loded tile - * available to the listener. - * tileerror - Triggered before the tileloaded event (i.e. when the tile is - * still hidden) if a tile failed to load. Listeners receive an object - * as first argument, which has a tile property that references the - * tile that could not be loaded. - */ - - /** - * 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); - this.grid = []; - this.tileQueue = []; - - if (this.removeBackBufferDelay === null) { - this.removeBackBufferDelay = this.singleTile ? 0 : 2500; - } - - if (this.className === null) { - this.className = this.singleTile ? 'olLayerGridSingleTile' : - 'olLayerGrid'; - } - - if (!OpenLayers.Animation.isNative) { - this.deferMoveGriddedTiles = OpenLayers.Function.bind(function() { - this.moveGriddedTiles(true); - this.moveTimerId = null; - }, this); - } - }, - - /** - * Method: setMap - * - * Parameters: - * map - {} The map. - */ - setMap: function(map) { - OpenLayers.Layer.HTTPRequest.prototype.setMap.call(this, map); - OpenLayers.Element.addClass(this.div, this.className); - }, - - /** - * Method: removeMap - * Called when the layer is removed from the map. - * - * Parameters: - * map - {} The map. - */ - removeMap: function(map) { - if (this.moveTimerId !== null) { - window.clearTimeout(this.moveTimerId); - this.moveTimerId = null; - } - this.clearTileQueue(); - if(this.backBufferTimerId !== null) { - window.clearTimeout(this.backBufferTimerId); - this.backBufferTimerId = null; - } - }, - - /** - * APIMethod: destroy - * Deconstruct the layer and clear the grid. - */ - destroy: function() { - this.removeBackBuffer(); - 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() { - this.clearTileQueue(); - if (this.grid) { - for(var iRow=0, len=this.grid.length; iRow} 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 = []; - obj.gridResolution = null; - // same for backbuffer and tile queue - obj.backBuffer = null; - obj.backBufferTimerId = null; - obj.tileQueue = []; - obj.tileQueueId = null; - obj.loading = false; - obj.moveTimerId = null; - - 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 - {} - * 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(); - - // the new map resolution - var resolution = this.map.getResolution(); - - // the server-supported resolution for the new map resolution - var serverResolution = this.getServerResolution(resolution); - - 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))) { - - // In single tile mode with no transition effect, we insert - // a non-scaled backbuffer when the layer is moved. But if - // a zoom occurs right after a move, i.e. before the new - // image is received, we need to remove the backbuffer, or - // an ill-positioned image will be visible during the zoom - // transition. - - if(zoomChanged && this.transitionEffect !== 'resize') { - this.removeBackBuffer(); - } - - if(!zoomChanged || this.transitionEffect === 'resize') { - this.applyBackBuffer(resolution); - } - - this.initSingleTile(bounds); - } - } else { - - // if the bounds have changed such that they are not even - // *partially* contained by our tiles (e.g. when user has - // programmatically panned to the other side of the earth on - // zoom level 18), then moveGriddedTiles could potentially have - // to run through thousands of cycles, so we want to reTile - // instead (thus, partial true). - forceReTile = forceReTile || - !tilesBounds.intersectsBounds(bounds, { - worldBounds: this.map.baseLayer.wrapDateLine && - this.map.getMaxExtent() - }); - - if(forceReTile) { - if(zoomChanged && this.transitionEffect === 'resize') { - this.applyBackBuffer(resolution); - } - this.initGriddedTiles(bounds); - } else { - this.moveGriddedTiles(); - } - } - } - }, - - /** - * Method: getTileData - * Given a map location, retrieve a tile and the pixel offset within that - * tile corresponding to the location. If there is not an existing - * tile in the grid that covers the given location, null will be - * returned. - * - * Parameters: - * loc - {} map location - * - * Returns: - * {Object} Object with the following properties: tile ({}), - * i ({Number} x-pixel offset from top left), and j ({Integer} y-pixel - * offset from top left). - */ - getTileData: function(loc) { - var data = null, - x = loc.lon, - y = loc.lat, - numRows = this.grid.length; - - if (this.map && numRows) { - var res = this.map.getResolution(), - tileWidth = this.tileSize.w, - tileHeight = this.tileSize.h, - bounds = this.grid[0][0].bounds, - left = bounds.left, - top = bounds.top; - - if (x < left) { - // deal with multiple worlds - if (this.map.baseLayer.wrapDateLine) { - var worldWidth = this.map.getMaxExtent().getWidth(); - var worldsAway = Math.ceil((left - x) / worldWidth); - x += worldWidth * worldsAway; - } - } - // tile distance to location (fractional number of tiles); - var dtx = (x - left) / (res * tileWidth); - var dty = (top - y) / (res * tileHeight); - // index of tile in grid - var col = Math.floor(dtx); - var row = Math.floor(dty); - if (row >= 0 && row < numRows) { - var tile = this.grid[row][col]; - if (tile) { - data = { - tile: tile, - // pixel index within tile - i: Math.floor((dtx - col) * tileWidth), - j: Math.floor((dty - row) * tileHeight) - }; - } - } - } - return data; - }, - - /** - * Method: queueTileDraw - * Adds a tile to the animation queue that will draw it. - * - * Parameters: - * evt - {Object} Listener argument of the tile's beforedraw event - */ - queueTileDraw: function(evt) { - var tile = evt.object; - if (!~OpenLayers.Util.indexOf(this.tileQueue, tile)) { - // queue only if not in queue already - this.tileQueue.push(tile); - } - if (!this.tileQueueId) { - this.tileQueueId = OpenLayers.Animation.start( - OpenLayers.Function.bind(this.drawTileFromQueue, this), - null, this.div - ); - } - return false; - }, - - /** - * Method: drawTileFromQueue - * Draws the first tile from the tileQueue, and unqueues that tile - */ - drawTileFromQueue: function() { - if (this.tileQueue.length === 0) { - this.clearTileQueue(); - } else { - this.tileQueue.shift().draw(true); - } - }, - - /** - * Method: clearTileQueue - * Clears the animation queue - */ - clearTileQueue: function() { - OpenLayers.Animation.stop(this.tileQueueId); - this.tileQueueId = null; - this.tileQueue = []; - }, - - /** - * Method: destroyTile - * - * Parameters: - * tile - {} - */ - destroyTile: function(tile) { - this.removeTileMonitoringHooks(tile); - tile.destroy(); - }, - - /** - * Method: getServerResolution - * Return the closest server-supported resolution. - * - * Parameters: - * resolution - {Number} The base resolution. If undefined the - * map resolution is used. - * - * Returns: - * {Number} The closest server resolution value. - */ - getServerResolution: function(resolution) { - var distance = Number.POSITIVE_INFINITY; - resolution = resolution || this.map.getResolution(); - if(this.serverResolutions && - OpenLayers.Util.indexOf(this.serverResolutions, resolution) === -1) { - var i, newDistance, newResolution, serverResolution; - for(i=this.serverResolutions.length-1; i>= 0; i--) { - newResolution = this.serverResolutions[i]; - newDistance = Math.abs(newResolution - resolution); - if (newDistance > distance) { - break; - } - distance = newDistance; - serverResolution = newResolution; - } - resolution = serverResolution; - } - return resolution; - }, - - /** - * Method: getServerZoom - * Return the zoom value corresponding to the best matching server - * resolution, taking into account and . - * - * Returns: - * {Number} The closest server supported zoom. This is not the map zoom - * level, but an index of the server's resolutions array. - */ - getServerZoom: function() { - var resolution = this.getServerResolution(); - return this.serverResolutions ? - OpenLayers.Util.indexOf(this.serverResolutions, resolution) : - this.map.getZoomForResolution(resolution) + (this.zoomOffset || 0); - }, - - /** - * Method: applyBackBuffer - * Create, insert, scale and position a back buffer for the layer. - * - * Parameters: - * resolution - {Number} The resolution to transition to. - */ - applyBackBuffer: function(resolution) { - if(this.backBufferTimerId !== null) { - this.removeBackBuffer(); - } - var backBuffer = this.backBuffer; - if(!backBuffer) { - backBuffer = this.createBackBuffer(); - if(!backBuffer) { - return; - } - this.div.insertBefore(backBuffer, this.div.firstChild); - this.backBuffer = backBuffer; - - // set some information in the instance for subsequent - // calls to applyBackBuffer where the same back buffer - // is reused - var topLeftTileBounds = this.grid[0][0].bounds; - this.backBufferLonLat = { - lon: topLeftTileBounds.left, - lat: topLeftTileBounds.top - }; - this.backBufferResolution = this.gridResolution; - } - - var ratio = this.backBufferResolution / resolution; - - // scale the tiles inside the back buffer - var tiles = backBuffer.childNodes, tile; - for (var i=tiles.length-1; i>=0; --i) { - tile = tiles[i]; - tile.style.top = ((ratio * tile._i * tile._h) | 0) + 'px'; - tile.style.left = ((ratio * tile._j * tile._w) | 0) + 'px'; - tile.style.width = Math.round(ratio * tile._w) + 'px'; - tile.style.height = Math.round(ratio * tile._h) + 'px'; - } - - // and position it (based on the grid's top-left corner) - var position = this.getViewPortPxFromLonLat( - this.backBufferLonLat, resolution); - var leftOffset = this.map.layerContainerOriginPx.x; - var topOffset = this.map.layerContainerOriginPx.y; - backBuffer.style.left = Math.round(position.x - leftOffset) + 'px'; - backBuffer.style.top = Math.round(position.y - topOffset) + 'px'; - }, - - /** - * Method: createBackBuffer - * Create a back buffer. - * - * Returns: - * {DOMElement} The DOM element for the back buffer, undefined if the - * grid isn't initialized yet. - */ - createBackBuffer: function() { - var backBuffer; - if(this.grid.length > 0) { - backBuffer = document.createElement('div'); - backBuffer.id = this.div.id + '_bb'; - backBuffer.className = 'olBackBuffer'; - backBuffer.style.position = 'absolute'; - for(var i=0, lenI=this.grid.length; i} - */ - 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]); - }, - - /** - * APIMethod: getTilesBounds - * Return the bounds of the tile grid. - * - * Returns: - * {} A Bounds object representing the bounds of all the - * currently loaded tiles (including those partially or not at all seen - * onscreen). - */ - getTilesBounds: function() { - var bounds = null; - - var length = this.grid.length; - if (length) { - var bottomLeftTileBounds = this.grid[length - 1][0].bounds, - width = this.grid[0].length * bottomLeftTileBounds.getWidth(), - height = this.grid.length * bottomLeftTileBounds.getHeight(); - - bounds = new OpenLayers.Bounds(bottomLeftTileBounds.left, - bottomLeftTileBounds.bottom, - bottomLeftTileBounds.left + width, - bottomLeftTileBounds.bottom + height); - } - return bounds; - }, - - /** - * Method: initSingleTile - * - * Parameters: - * bounds - {} - */ - initSingleTile: function(bounds) { - this.clearTileQueue(); - - //determine new tile bounds - var center = bounds.getCenterLonLat(); - var tileWidth = bounds.getWidth() * this.ratio; - var tileHeight = bounds.getHeight() * this.ratio; - - var tileBounds = - new OpenLayers.Bounds(center.lon - (tileWidth/2), - center.lat - (tileHeight/2), - center.lon + (tileWidth/2), - center.lat + (tileHeight/2)); - - var px = this.map.getLayerPxFromLonLat({ - lon: tileBounds.left, - lat: tileBounds.top - }); - - if (!this.grid.length) { - this.grid[0] = []; - } - - var tile = this.grid[0][0]; - if (!tile) { - tile = this.addTile(tileBounds, px); - - this.addTileMonitoringHooks(tile); - tile.draw(); - this.grid[0][0] = tile; - } else { - tile.moveTo(tileBounds, px); - } - - //remove all but our single tile - this.removeExcessTiles(1,1); - - // store the resolution of the grid - this.gridResolution = this.getServerResolution(); - }, - - /** - * Method: calculateGridLayout - * Generate parameters for the grid layout. - * - * Parameters: - * bounds - {|Object} OpenLayers.Bounds or an - * object with a 'left' and 'top' properties. - * origin - {|Object} OpenLayers.LonLat or an - * object with a 'lon' and 'lat' properties. - * resolution - {Number} - * - * Returns: - * {Object} 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 ratio = resolution / this.map.getResolution(), - tileSize = { - w: Math.round(this.tileSize.w * ratio), - h: Math.round(this.tileSize.h * ratio) - }; - - var offsetlon = bounds.left - origin.lon; - var tilecol = Math.floor(offsetlon/tilelon) - this.buffer; - var tilecolremain = offsetlon/tilelon - tilecol; - var tileoffsetx = -tilecolremain * 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 * 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 - * property is supplied, that will be returned. Otherwise, the origin - * will be derived from the layer's property. In this case, - * the tile origin will be the corner of the given by the - * property. - * - * Returns: - * {} The tile origin. - */ - getTileOrigin: function() { - var origin = this.tileOrigin; - if (!origin) { - var extent = this.getMaxExtent(); - var edges = ({ - "tl": ["left", "top"], - "tr": ["right", "top"], - "bl": ["left", "bottom"], - "br": ["right", "bottom"] - })[this.tileOriginCorner]; - origin = new OpenLayers.LonLat(extent[edges[0]], extent[edges[1]]); - } - return origin; - }, - - /** - * Method: initGriddedTiles - * - * Parameters: - * bounds - {} - */ - initGriddedTiles:function(bounds) { - this.clearTileQueue(); - - // work out mininum number of rows and columns; this is the number of - // tiles required to cover the viewport plus at least one for panning - - var viewSize = this.map.getSize(); - - var origin = this.getTileOrigin(); - var resolution = this.map.getResolution(), - serverResolution = this.getServerResolution(), - ratio = resolution / serverResolution, - tileSize = { - w: this.tileSize.w / ratio, - h: this.tileSize.h / ratio - }; - - var minRows = Math.ceil(viewSize.h/tileSize.h) + - 2 * this.buffer + 1; - var minCols = Math.ceil(viewSize.w/tileSize.w) + - 2 * this.buffer + 1; - - var tileLayout = this.calculateGridLayout(bounds, origin, serverResolution); - 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; - - var startX = tileoffsetx; - var startLon = tileoffsetlon; - - var rowidx = 0; - - var layerContainerDivLeft = this.map.layerContainerOriginPx.x; - var layerContainerDivTop = this.map.layerContainerOriginPx.y; - - var tileData = [], center = this.map.getCenter(); - 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); - } - var tileCenter = tileBounds.getCenterLonLat(); - tileData.push({ - tile: tile, - distance: Math.pow(tileCenter.lon - center.lon, 2) + - Math.pow(tileCenter.lat - center.lat, 2) - }); - - tileoffsetlon += tilelon; - tileoffsetx += Math.round(tileSize.w); - } while ((tileoffsetlon <= bounds.right + tilelon * this.buffer) - || colidx < minCols); - - tileoffsetlat -= tilelat; - tileoffsety += Math.round(tileSize.h); - } while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer) - || rowidx < minRows); - - //shave off exceess rows and colums - this.removeExcessTiles(rowidx, colidx); - - var resolution = this.getServerResolution(), - immediately = resolution === this.gridResolution; - // store the resolution of the grid - this.gridResolution = resolution; - - //now actually draw the tiles - tileData.sort(function(a, b) { - return a.distance - b.distance; - }); - for (var i=0, ii=tileData.length; i} - */ - getMaxExtent: function() { - return this.maxExtent; - }, - - /** - * APIMethod: addTile - * Create a tile, initialize it, and add it to the layer div. - * - * Parameters - * bounds - {} - * position - {} - * - * Returns: - * {} The added OpenLayers.Tile - */ - addTile: function(bounds, position) { - var tile = new this.tileClass( - this, position, bounds, null, this.tileSize, this.tileOptions - ); - tile.events.register("beforedraw", this, this.queueTileDraw); - return tile; - }, - - /** - * Method: addTileMonitoringHooks - * This function takes a tile as input and adds the appropriate hooks to - * the tile so that the layer can keep track of the loading tiles. - * - * Parameters: - * tile - {} - */ - addTileMonitoringHooks: function(tile) { - - tile.onLoadStart = function() { - //if that was first tile then trigger a 'loadstart' on the layer - if (this.loading === false) { - this.loading = true; - this.events.triggerEvent("loadstart"); - } - this.events.triggerEvent("tileloadstart", {tile: tile}); - this.numLoadingTiles++; - }; - - tile.onLoadEnd = function() { - this.numLoadingTiles--; - this.events.triggerEvent("tileloaded", {tile: tile}); - //if that was the last tile, then trigger a 'loadend' on the layer - if (this.tileQueue.length === 0 && this.numLoadingTiles === 0) { - this.loading = false; - this.events.triggerEvent("loadend"); - if(this.backBuffer) { - // the removal of the back buffer is delayed to prevent flash - // effects due to the animation of tile displaying - this.backBufferTimerId = window.setTimeout( - OpenLayers.Function.bind(this.removeBackBuffer, this), - this.removeBackBufferDelay - ); - } - } - }; - - tile.onLoadError = function() { - this.events.triggerEvent("tileerror", {tile: tile}); - }; - - tile.events.on({ - "loadstart": tile.onLoadStart, - "loadend": tile.onLoadEnd, - "unload": tile.onLoadEnd, - "loaderror": tile.onLoadError, - scope: this - }); - }, - - /** - * Method: removeTileMonitoringHooks - * This function takes a tile as input and removes the tile hooks - * that were added in addTileMonitoringHooks() - * - * Parameters: - * tile - {} - */ - removeTileMonitoringHooks: function(tile) { - tile.unload(); - tile.events.un({ - "loadstart": tile.onLoadStart, - "loadend": tile.onLoadEnd, - "unload": tile.onLoadEnd, - "loaderror": tile.onLoadError, - scope: this - }); - }, - - /** - * Method: moveGriddedTiles - * - * Parameter: - * deferred - {Boolean} true if this is a deferred call that should not - * be delayed. - */ - moveGriddedTiles: function(deferred) { - if (!deferred && !OpenLayers.Animation.isNative) { - if (this.moveTimerId != null) { - window.clearTimeout(this.moveTimerId); - } - this.moveTimerId = window.setTimeout( - this.deferMoveGriddedTiles, this.tileLoadingDelay - ); - return; - } - var buffer = this.buffer + 1; - while(true) { - var tlTile = this.grid[0][0]; - var tlViewPort = { - x: tlTile.position.x + - this.map.layerContainerOriginPx.x, - y: tlTile.position.y + - this.map.layerContainerOriginPx.y - }; - var ratio = this.getServerResolution() / this.map.getResolution(); - var tileSize = { - w: Math.round(this.tileSize.w * ratio), - h: Math.round(this.tileSize.h * ratio) - }; - if (tlViewPort.x > -tileSize.w * (buffer - 1)) { - this.shiftColumn(true, tileSize); - } else if (tlViewPort.x < -tileSize.w * buffer) { - this.shiftColumn(false, tileSize); - } else if (tlViewPort.y > -tileSize.h * (buffer - 1)) { - this.shiftRow(true, tileSize); - } else if (tlViewPort.y < -tileSize.h * buffer) { - this.shiftRow(false, tileSize); - } else { - break; - } - } - }, - - /** - * Method: shiftRow - * Shifty grid work - * - * Parameters: - * prepend - {Boolean} if true, prepend to beginning. - * if false, then append to end - * tileSize - {Object} rendered tile size; object with w and h properties - */ - shiftRow:function(prepend, tileSize) { - var modelRowIndex = (prepend) ? 0 : (this.grid.length - 1); - var grid = this.grid; - var modelRow = grid[modelRowIndex]; - - var sign = prepend ? -1 : 1; - var deltaLat = this.getServerResolution() * -sign * this.tileSize.h; - - var row = (prepend) ? grid.pop() : grid.shift(); - - for (var i=0, len=modelRow.length; i rows) { - var row = this.grid.pop(); - for (i=0, l=row.length; i columns) { - var row = this.grid[i]; - var tile = row.pop(); - this.destroyTile(tile); - } - } - }, - - /** - * Method: onMapResize - * For singleTile layers, this will set a new tile size according to the - * dimensions of the map pane. - */ - onMapResize: function() { - if (this.singleTile) { - this.clearGrid(); - this.setTileSize(); - } - }, - - /** - * APIMethod: getTileBounds - * Returns The tile bounds for a layer given a pixel location. - * - * Parameters: - * viewPortPx - {} The location in the viewport. - * - * Returns: - * {} Bounds of the tile at the given pixel location. - */ - getTileBounds: function(viewPortPx) { - var maxExtent = this.maxExtent; - var resolution = this.getResolution(); - var tileMapWidth = resolution * this.tileSize.w; - var tileMapHeight = resolution * this.tileSize.h; - var mapPoint = this.getLonLatFromViewPortPx(viewPortPx); - var tileLeft = maxExtent.left + (tileMapWidth * - Math.floor((mapPoint.lon - - maxExtent.left) / - tileMapWidth)); - var tileBottom = maxExtent.bottom + (tileMapHeight * - Math.floor((mapPoint.lat - - maxExtent.bottom) / - tileMapHeight)); - return new OpenLayers.Bounds(tileLeft, tileBottom, - tileLeft + tileMapWidth, - tileBottom + tileMapHeight); - }, - - CLASS_NAME: "OpenLayers.Layer.Grid" -}); -/* ====================================================================== - OpenLayers/Layer/XYZ.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Layer/Grid.js - */ - -/** - * 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.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 is an alternative to - * setting 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 differ from the server. This - * property serves two purposes. (a) can include - * resolutions that the server supports and that you don't want to - * provide with this layer; you can also look at , which is - * an alternative to for that specific purpose. - * (b) The map can work with resolutions that aren't supported by - * the server, i.e. that aren't in . When the - * map is displayed in such a resolution data for the closest - * server-supported resolution is loaded and the layer div is - * stretched as necessary. - */ - 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({ - projection: "EPSG:900913", - numZoomLevels: 19 - }, options); - } - OpenLayers.Layer.Grid.prototype.initialize.apply(this, [ - name || this.name, url || this.url, {}, options - ]); - }, - - /** - * APIMethod: clone - * Create a clone of this layer - * - * Parameters: - * obj - {Object} Is this ever used? - * - * Returns: - * {} An exact clone of this OpenLayers.Layer.XYZ - */ - 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 - {} - * - * 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 (OpenLayers.Util.isArray(url)) { - 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 - {} - * - * Returns: - * {Object} - an object with x, y and z properties. - */ - getXYZ: function(bounds) { - var res = this.getServerResolution(); - var x = Math.round((bounds.left - this.maxExtent.left) / - (res * this.tileSize.w)); - var y = Math.round((this.maxExtent.top - bounds.top) / - (res * this.tileSize.h)); - var z = this.getServerZoom(); - - if (this.wrapDateLine) { - var limit = Math.pow(2, z); - x = ((x % limit) + limit) % limit; - } - - return {'x': x, 'y': y, 'z': z}; - }, - - /* APIMethod: setMap - * When the layer is added to a map, then we can fetch our origin - * (if we don't have one.) - * - * Parameters: - * 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" -}); -/* ====================================================================== - OpenLayers/Layer/OSM.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Layer/XYZ.js - */ - -/** - * Class: OpenLayers.Layer.OSM - * This layer allows accessing OpenStreetMap tiles. By default the OpenStreetMap - * hosted tile.openstreetmap.org Mapnik tileset is used. If you wish to use - * a different layer instead, you need to provide a different - * URL to the constructor. Here's an example for using OpenCycleMap: - * - * (code) - * new OpenLayers.Layer.OSM("OpenCycleMap", - * ["http://a.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png", - * "http://b.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png", - * "http://c.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png"]); - * (end) - * - * Inherits from: - * - - */ -OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { - - /** - * APIProperty: name - * {String} The layer name. Defaults to "OpenStreetMap" if the first - * argument to the constructor is null or undefined. - */ - name: "OpenStreetMap", - - /** - * APIProperty: url - * {String} The tileset URL scheme. Defaults to - * : http://[a|b|c].tile.openstreetmap.org/${z}/${x}/${y}.png - * (the official OSM tileset) if the second argument to the constructor - * is null or undefined. To use another tileset you can have something - * like this: - * (code) - * new OpenLayers.Layer.OSM("OpenCycleMap", - * ["http://a.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png", - * "http://b.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png", - * "http://c.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png"]); - * (end) - */ - url: [ - 'http://a.tile.openstreetmap.org/${z}/${x}/${y}.png', - 'http://b.tile.openstreetmap.org/${z}/${x}/${y}.png', - 'http://c.tile.openstreetmap.org/${z}/${x}/${y}.png' - ], - - /** - * Property: attribution - * {String} The layer attribution. - */ - attribution: "Data CC-By-SA by OpenStreetMap", - - /** - * Property: sphericalMercator - * {Boolean} - */ - sphericalMercator: true, - - /** - * Property: wrapDateLine - * {Boolean} - */ - wrapDateLine: true, - - /** APIProperty: tileOptions - * {Object} optional configuration options for instances - * created by this Layer. Default is - * - * (code) - * {crossOriginKeyword: 'anonymous'} - * (end) - * - * When using OSM tilesets other than the default ones, it may be - * necessary to set this to - * - * (code) - * {crossOriginKeyword: null} - * (end) - * - * if the server does not send Access-Control-Allow-Origin headers. - */ - tileOptions: null, - - /** - * Constructor: OpenLayers.Layer.OSM - * - * Parameters: - * name - {String} The layer name. - * url - {String} The tileset URL scheme. - * options - {Object} Configuration options for the layer. Any inherited - * layer option can be set in this object (e.g. - * ). - */ - initialize: function(name, url, options) { - OpenLayers.Layer.XYZ.prototype.initialize.apply(this, arguments); - this.tileOptions = OpenLayers.Util.extend({ - crossOriginKeyword: 'anonymous' - }, this.options && this.options.tileOptions); - }, - - /** - * Method: clone - */ - 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.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/BaseTypes/Class.js - */ - -/** - * Class: OpenLayers.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 - * {} - */ - extent: null, - - /** - * Property: locked - * {Boolean} If the renderer is currently in a state where many things - * are changing, the 'locked' property is set to true. This means - * that renderers can expect at least one more drawFeature event to be - * called with the 'locked' property set to 'true': In some renderers, - * this might make sense to use as a 'only update local information' - * flag. - */ - locked: false, - - /** - * Property: size - * {} - */ - size: null, - - /** - * Property: resolution - * {Float} cache of current map resolution - */ - resolution: null, - - /** - * Property: map - * {} Reference to the map -- this is set in Vector's setMap() - */ - map: null, - - /** - * Property: featureDx - * {Number} Feature offset in x direction. Will be calculated for and - * applied to the current feature while rendering (see - * ). - */ - featureDx: 0, - - /** - * Constructor: OpenLayers.Renderer - * - * Parameters: - * containerID - {} - * options - {Object} options for this renderer. See sublcasses for - * supported options. - */ - initialize: function(containerID, options) { - this.container = OpenLayers.Util.getElement(containerID); - OpenLayers.Util.extend(this, options); - }, - - /** - * APIMethod: destroy - */ - destroy: function() { - this.container = null; - this.extent = null; - this.size = null; - this.resolution = null; - this.map = null; - }, - - /** - * APIMethod: supported - * This should be overridden by specific subclasses - * - * Returns: - * {Boolean} Whether or not the browser supports the renderer class - */ - supported: function() { - return false; - }, - - /** - * Method: setExtent - * Set the visible part of the layer. - * - * Resolution has probably changed, so we nullify the resolution - * cache (this.resolution) -- this way it will be re-computed when - * next it is needed. - * We nullify the resolution cache (this.resolution) if resolutionChanged - * is set to true - this way it will be re-computed on the next - * getResolution() request. - * - * Parameters: - * extent - {} - * resolutionChanged - {Boolean} - * - * Returns: - * {Boolean} true to notify the layer that the new extent does not exceed - * the coordinate range, and the features will not need to be redrawn. - * False otherwise. - */ - setExtent: function(extent, resolutionChanged) { - this.extent = extent.clone(); - if (this.map.baseLayer && this.map.baseLayer.wrapDateLine) { - var ratio = extent.getWidth() / this.map.getExtent().getWidth(), - extent = extent.scale(1 / ratio); - this.extent = extent.wrapDateLine(this.map.getMaxExtent()).scale(ratio); - } - if (resolutionChanged) { - this.resolution = null; - } - return true; - }, - - /** - * Method: setSize - * Sets the size of the drawing surface. - * - * Resolution has probably changed, so we nullify the resolution - * cache (this.resolution) -- this way it will be re-computed when - * next it is needed. - * - * Parameters: - * size - {} - */ - setSize: function(size) { - this.size = size.clone(); - this.resolution = null; - }, - - /** - * Method: getResolution - * Uses cached copy of resolution if available to minimize computing - * - * Returns: - * {Float} The current map's resolution - */ - getResolution: function() { - this.resolution = this.resolution || this.map.getResolution(); - return this.resolution; - }, - - /** - * Method: drawFeature - * Draw the feature. The optional style argument can be used - * to override the feature's own style. This method should only - * be called from layer.drawFeature(). - * - * Parameters: - * feature - {} - * style - {} - * - * Returns: - * {Boolean} true if the feature has been drawn completely, false if not, - * undefined if the feature had no geometry - */ - drawFeature: function(feature, style) { - if(style == null) { - style = feature.style; - } - if (feature.geometry) { - var bounds = feature.geometry.getBounds(); - if(bounds) { - var worldBounds; - if (this.map.baseLayer && this.map.baseLayer.wrapDateLine) { - worldBounds = this.map.getMaxExtent(); - } - if (!bounds.intersectsBounds(this.extent, {worldBounds: worldBounds})) { - style = {display: "none"}; - } else { - this.calculateFeatureDx(bounds, worldBounds); - } - var rendered = this.drawGeometry(feature.geometry, style, feature.id); - if(style.display != "none" && style.label && rendered !== false) { - - var location = feature.geometry.getCentroid(); - if(style.labelXOffset || style.labelYOffset) { - var xOffset = isNaN(style.labelXOffset) ? 0 : style.labelXOffset; - var yOffset = isNaN(style.labelYOffset) ? 0 : style.labelYOffset; - var res = this.getResolution(); - location.move(xOffset*res, yOffset*res); - } - this.drawText(feature.id, style, location); - } else { - this.removeText(feature.id); - } - return rendered; - } - } - }, - - /** - * Method: calculateFeatureDx - * {Number} Calculates the feature offset in x direction. Looking at the - * center of the feature bounds and the renderer extent, we calculate how - * many world widths the two are away from each other. This distance is - * used to shift the feature as close as possible to the center of the - * current enderer extent, which ensures that the feature is visible in the - * current viewport. - * - * Parameters: - * bounds - {} Bounds of the feature - * worldBounds - {} Bounds of the world - */ - calculateFeatureDx: function(bounds, worldBounds) { - this.featureDx = 0; - if (worldBounds) { - var worldWidth = worldBounds.getWidth(), - rendererCenterX = (this.extent.left + this.extent.right) / 2, - featureCenterX = (bounds.left + bounds.right) / 2, - worldsAway = Math.round((featureCenterX - rendererCenterX) / worldWidth); - this.featureDx = worldsAway * worldWidth; - } - }, - - /** - * Method: drawGeometry - * - * Draw a geometry. This should only be called from the renderer itself. - * Use layer.drawFeature() from outside the renderer. - * virtual function - * - * Parameters: - * geometry - {} - * style - {Object} - * featureId - {} - */ - drawGeometry: function(geometry, style, featureId) {}, - - /** - * Method: drawText - * Function for drawing text labels. - * This method is only called by the renderer itself. - * - * Parameters: - * featureId - {String} - * style - - * location - {} - */ - drawText: function(featureId, style, location) {}, - - /** - * Method: removeText - * Function for removing text labels. - * This method is only called by the renderer itself. - * - * Parameters: - * featureId - {String} - */ - removeText: function(featureId) {}, - - /** - * Method: clear - * Clear all vectors from the renderer. - * virtual function. - */ - clear: function() {}, - - /** - * Method: getFeatureIdFromEvent - * Returns a feature id from an event on the renderer. - * How this happens is specific to the renderer. This should be - * called from layer.getFeatureFromEvent(). - * Virtual function. - * - * Parameters: - * evt - {} - * - * Returns: - * {String} A feature id or undefined. - */ - getFeatureIdFromEvent: function(evt) {}, - - /** - * Method: eraseFeatures - * This is called by the layer to erase features - * - * Parameters: - * features - {Array()} - */ - eraseFeatures: function(features) { - if(!(OpenLayers.Util.isArray(features))) { - features = [features]; - } - for(var i=0, len=features.length; i} - * featureId - {String} - */ - eraseGeometry: function(geometry, featureId) {}, - - /** - * Method: moveRoot - * moves this renderer's root to a (different) renderer. - * To be implemented by subclasses that require a common renderer root for - * feature selection. - * - * Parameters: - * renderer - {} target renderer for the moved root - */ - moveRoot: function(renderer) {}, - - /** - * Method: getRenderLayerId - * Gets the layer that this renderer's output appears on. If moveRoot was - * used, this will be different from the id of the layer containing the - * features rendered by this renderer. - * - * Returns: - * {String} the id of the output layer. - */ - 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, - labelAlign: 'cm' -}; - - - -/** - * Constant: OpenLayers.Renderer.symbol - * Coordinate arrays for well known (named) symbols. - */ -OpenLayers.Renderer.symbol = { - "star": [350,75, 379,161, 469,161, 397,215, 423,301, 350,250, 277,301, - 303,215, 231,161, 321,161, 350,75], - "cross": [4,0, 6,0, 6,4, 10,4, 10,6, 6,6, 6,10, 4,10, 4,6, 0,6, 0,4, 4,4, - 4,0], - "x": [0,0, 25,0, 50,35, 75,0, 100,0, 65,50, 100,100, 75,100, 50,65, 25,100, 0,100, 35,50, 0,0], - "square": [0,0, 0,1, 1,1, 1,0, 0,0], - "triangle": [0,10, 10,10, 5,0, 0,10] -}; -/* ====================================================================== - OpenLayers/Renderer/Canvas.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Renderer.js - */ - -/** - * Class: OpenLayers.Renderer.Canvas - * A renderer based on the 2D 'canvas' drawing element. - * - * Inherits: - * - - */ -OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { - - /** - * APIProperty: hitDetection - * {Boolean} Allow for hit detection of features. Default is true. - */ - hitDetection: true, - - /** - * Property: hitOverflow - * {Number} The method for converting feature identifiers to color values - * supports 16777215 sequential values. Two features cannot be - * predictably detected if their identifiers differ by more than this - * value. The hitOverflow allows for bigger numbers (but the - * difference in values is still limited). - */ - hitOverflow: 0, - - /** - * 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, - - /** - * Property: pendingRedraw - * {Boolean} The renderer needs a redraw call to render features added while - * the renderer was locked. - */ - pendingRedraw: false, - - /** - * Property: cachedSymbolBounds - * {Object} Internal cache of calculated symbol extents. - */ - cachedSymbolBounds: {}, - - /** - * Constructor: OpenLayers.Renderer.Canvas - * - * Parameters: - * containerID - {} - * options - {Object} Optional properties to be set on the renderer. - */ - initialize: function(containerID, options) { - 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 = {}; - if (this.hitDetection) { - this.hitCanvas = document.createElement("canvas"); - this.hitContext = this.hitCanvas.getContext("2d"); - } - }, - - /** - * Method: setExtent - * Set the visible part of the layer. - * - * Parameters: - * extent - {} - * resolutionChanged - {Boolean} - * - * Returns: - * {Boolean} true to notify the layer that the new extent does not exceed - * the coordinate range, and the features will not need to be redrawn. - * False otherwise. - */ - setExtent: function() { - OpenLayers.Renderer.prototype.setExtent.apply(this, arguments); - // always redraw features - return false; - }, - - /** - * 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 - {} - * 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() { - return OpenLayers.CANVAS_SUPPORTED; - }, - - /** - * Method: setSize - * Sets the size of the drawing surface. - * - * Once the size is updated, redraw the canvas. - * - * Parameters: - * size - {} - */ - setSize: function(size) { - this.size = size.clone(); - var root = this.root; - root.style.width = size.w + "px"; - root.style.height = size.h + "px"; - root.width = size.w; - root.height = size.h; - this.resolution = null; - if (this.hitDetection) { - var hitCanvas = this.hitCanvas; - hitCanvas.style.width = size.w + "px"; - hitCanvas.style.height = size.h + "px"; - hitCanvas.width = size.w; - hitCanvas.height = size.h; - } - }, - - /** - * Method: drawFeature - * Draw the feature. Stores the feature in the features list, - * then redraws the layer. - * - * Parameters: - * feature - {} - * style - {} - * - * Returns: - * {Boolean} The feature has been drawn completely. If the feature has no - * geometry, undefined will be returned. If the feature is not rendered - * for other reasons, false will be returned. - */ - drawFeature: function(feature, style) { - var rendered; - if (feature.geometry) { - style = this.applyDefaultSymbolizer(style || feature.style); - // don't render if display none or feature outside extent - var bounds = feature.geometry.getBounds(); - - var worldBounds; - if (this.map.baseLayer && this.map.baseLayer.wrapDateLine) { - worldBounds = this.map.getMaxExtent(); - } - - var intersects = bounds && bounds.intersectsBounds(this.extent, {worldBounds: worldBounds}); - - rendered = (style.display !== "none") && !!bounds && intersects; - if (rendered) { - // keep track of what we have rendered for redraw - this.features[feature.id] = [feature, style]; - } - else { - // remove from features tracked for redraw - delete(this.features[feature.id]); - } - this.pendingRedraw = true; - } - if (this.pendingRedraw && !this.locked) { - this.redraw(); - this.pendingRedraw = false; - } - return rendered; - }, - - /** - * Method: drawGeometry - * Used when looping (in redraw) over the features; draws - * the canvas. - * - * Parameters: - * geometry - {} - * style - {Object} - */ - drawGeometry: function(geometry, style, featureId) { - 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, featureId); - } - return; - } - switch (geometry.CLASS_NAME) { - case "OpenLayers.Geometry.Point": - this.drawPoint(geometry, style, featureId); - break; - case "OpenLayers.Geometry.LineString": - this.drawLineString(geometry, style, featureId); - break; - case "OpenLayers.Geometry.LinearRing": - this.drawLinearRing(geometry, style, featureId); - break; - case "OpenLayers.Geometry.Polygon": - this.drawPolygon(geometry, style, featureId); - break; - default: - break; - } - }, - - /** - * Method: drawExternalGraphic - * Called to draw External graphics. - * - * Parameters: - * geometry - {} - * style - {Object} - * featureId - {String} - */ - drawExternalGraphic: function(geometry, style, featureId) { - var img = new Image(); - - var title = style.title || style.graphicTitle; - if (title) { - img.title = title; - } - - 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; - - var onLoad = function() { - if(!this.features[featureId]) { - return; - } - var pt = this.getLocalXY(geometry); - var p0 = pt[0]; - var p1 = pt[1]; - if(!isNaN(p0) && !isNaN(p1)) { - var x = (p0 + xOffset) | 0; - var y = (p1 + yOffset) | 0; - var canvas = this.canvas; - canvas.globalAlpha = opacity; - var factor = OpenLayers.Renderer.Canvas.drawImageScaleFactor || - (OpenLayers.Renderer.Canvas.drawImageScaleFactor = - /android 2.1/.test(navigator.userAgent.toLowerCase()) ? - // 320 is the screen width of the G1 phone, for - // which drawImage works out of the box. - 320 / window.screen.width : 1 - ); - canvas.drawImage( - img, x*factor, y*factor, width*factor, height*factor - ); - if (this.hitDetection) { - this.setHitContextStyle("fill", featureId); - this.hitContext.fillRect(x, y, width, height); - } - } - }; - - img.onload = OpenLayers.Function.bind(onLoad, this); - img.src = style.externalGraphic; - }, - - /** - * Method: drawNamedSymbol - * Called to draw Well Known Graphic Symbol Name. - * This method is only called by the renderer itself. - * - * Parameters: - * geometry - {} - * style - {Object} - * featureId - {String} - */ - drawNamedSymbol: function(geometry, style, featureId) { - var x, y, cx, cy, i, symbolBounds, scaling, angle; - var unscaledStrokeWidth; - var deg2rad = Math.PI / 180.0; - - var symbol = OpenLayers.Renderer.symbol[style.graphicName]; - - if (!symbol) { - throw new Error(style.graphicName + ' is not a valid symbol name'); - } - - if (!symbol.length || symbol.length < 2) return; - - var pt = this.getLocalXY(geometry); - var p0 = pt[0]; - var p1 = pt[1]; - - if (isNaN(p0) || isNaN(p1)) return; - - // Use rounded line caps - this.canvas.lineCap = "round"; - this.canvas.lineJoin = "round"; - - if (this.hitDetection) { - this.hitContext.lineCap = "round"; - this.hitContext.lineJoin = "round"; - } - - // Scale and rotate symbols, using precalculated bounds whenever possible. - if (style.graphicName in this.cachedSymbolBounds) { - symbolBounds = this.cachedSymbolBounds[style.graphicName]; - } else { - symbolBounds = new OpenLayers.Bounds(); - for(i = 0; i < symbol.length; i+=2) { - symbolBounds.extend(new OpenLayers.LonLat(symbol[i], symbol[i+1])); - } - this.cachedSymbolBounds[style.graphicName] = symbolBounds; - } - - // Push symbol scaling, translation and rotation onto the transformation stack in reverse order. - // Don't forget to apply all canvas transformations to the hitContext canvas as well(!) - this.canvas.save(); - if (this.hitDetection) { this.hitContext.save(); } - - // Step 3: place symbol at the desired location - this.canvas.translate(p0,p1); - if (this.hitDetection) { this.hitContext.translate(p0,p1); } - - // Step 2a. rotate the symbol if necessary - angle = deg2rad * style.rotation; // will be NaN when style.rotation is undefined. - if (!isNaN(angle)) { - this.canvas.rotate(angle); - if (this.hitDetection) { this.hitContext.rotate(angle); } - } - - // // Step 2: scale symbol such that pointRadius equals half the maximum symbol dimension. - scaling = 2.0 * style.pointRadius / Math.max(symbolBounds.getWidth(), symbolBounds.getHeight()); - this.canvas.scale(scaling,scaling); - if (this.hitDetection) { this.hitContext.scale(scaling,scaling); } - - // Step 1: center the symbol at the origin - cx = symbolBounds.getCenterLonLat().lon; - cy = symbolBounds.getCenterLonLat().lat; - this.canvas.translate(-cx,-cy); - if (this.hitDetection) { this.hitContext.translate(-cx,-cy); } - - // Don't forget to scale stroke widths, because they are affected by canvas scale transformations as well(!) - // Alternative: scale symbol coordinates manually, so stroke width scaling is not needed anymore. - unscaledStrokeWidth = style.strokeWidth; - style.strokeWidth = unscaledStrokeWidth / scaling; - - if (style.fill !== false) { - this.setCanvasStyle("fill", style); - this.canvas.beginPath(); - for (i=0; i= 16777216) { - this.hitOverflow = id - 16777215; - id = id % 16777216 + 1; - } - var hex = "000000" + id.toString(16); - var len = hex.length; - hex = "#" + hex.substring(len-6, len); - return hex; - }, - - /** - * Method: setHitContextStyle - * Prepare the hit canvas for drawing by setting various global settings. - * - * Parameters: - * type - {String} one of 'stroke', 'fill', or 'reset' - * featureId - {String} The feature id. - * symbolizer - {} The symbolizer. - */ - setHitContextStyle: function(type, featureId, symbolizer, strokeScaling) { - var hex = this.featureIdToHex(featureId); - if (type == "fill") { - this.hitContext.globalAlpha = 1.0; - this.hitContext.fillStyle = hex; - } else if (type == "stroke") { - this.hitContext.globalAlpha = 1.0; - this.hitContext.strokeStyle = hex; - // bump up stroke width to deal with antialiasing. If strokeScaling is defined, we're rendering a symbol - // on a transformed canvas, so the antialias width bump has to scale as well. - if (typeof strokeScaling === "undefined") { - this.hitContext.lineWidth = symbolizer.strokeWidth + 2; - } else { - if (!isNaN(strokeScaling)) { this.hitContext.lineWidth = symbolizer.strokeWidth + 2.0 / strokeScaling; } - } - } else { - this.hitContext.globalAlpha = 0; - this.hitContext.lineWidth = 1; - } - }, - - /** - * Method: drawPoint - * This method is only called by the renderer itself. - * - * Parameters: - * geometry - {} - * style - {Object} - * featureId - {String} - */ - drawPoint: function(geometry, style, featureId) { - if(style.graphic !== false) { - if(style.externalGraphic) { - this.drawExternalGraphic(geometry, style, featureId); - } else if (style.graphicName && (style.graphicName != "circle")) { - this.drawNamedSymbol(geometry, style, featureId); - } else { - var pt = this.getLocalXY(geometry); - var p0 = pt[0]; - var p1 = pt[1]; - if(!isNaN(p0) && !isNaN(p1)) { - var twoPi = Math.PI*2; - var radius = style.pointRadius; - if(style.fill !== false) { - this.setCanvasStyle("fill", style); - this.canvas.beginPath(); - this.canvas.arc(p0, p1, radius, 0, twoPi, true); - this.canvas.fill(); - if (this.hitDetection) { - this.setHitContextStyle("fill", featureId, style); - this.hitContext.beginPath(); - this.hitContext.arc(p0, p1, radius, 0, twoPi, true); - this.hitContext.fill(); - } - } - - if(style.stroke !== false) { - this.setCanvasStyle("stroke", style); - this.canvas.beginPath(); - this.canvas.arc(p0, p1, radius, 0, twoPi, true); - this.canvas.stroke(); - if (this.hitDetection) { - this.setHitContextStyle("stroke", featureId, style); - this.hitContext.beginPath(); - this.hitContext.arc(p0, p1, radius, 0, twoPi, true); - this.hitContext.stroke(); - } - this.setCanvasStyle("reset"); - } - } - } - } - }, - - /** - * Method: drawLineString - * This method is only called by the renderer itself. - * - * Parameters: - * geometry - {} - * style - {Object} - * featureId - {String} - */ - drawLineString: function(geometry, style, featureId) { - style = OpenLayers.Util.applyDefaults({fill: false}, style); - this.drawLinearRing(geometry, style, featureId); - }, - - /** - * Method: drawLinearRing - * This method is only called by the renderer itself. - * - * Parameters: - * geometry - {} - * style - {Object} - * featureId - {String} - */ - drawLinearRing: function(geometry, style, featureId) { - if (style.fill !== false) { - this.setCanvasStyle("fill", style); - this.renderPath(this.canvas, geometry, style, featureId, "fill"); - if (this.hitDetection) { - this.setHitContextStyle("fill", featureId, style); - this.renderPath(this.hitContext, geometry, style, featureId, "fill"); - } - } - if (style.stroke !== false) { - this.setCanvasStyle("stroke", style); - this.renderPath(this.canvas, geometry, style, featureId, "stroke"); - if (this.hitDetection) { - this.setHitContextStyle("stroke", featureId, style); - this.renderPath(this.hitContext, geometry, style, featureId, "stroke"); - } - } - this.setCanvasStyle("reset"); - }, - - /** - * Method: renderPath - * Render a path with stroke and optional fill. - */ - renderPath: function(context, geometry, style, featureId, type) { - var components = geometry.components; - var len = components.length; - context.beginPath(); - var start = this.getLocalXY(components[0]); - var x = start[0]; - var y = start[1]; - if (!isNaN(x) && !isNaN(y)) { - context.moveTo(start[0], start[1]); - for (var i=1; i} - * style - {Object} - * featureId - {String} - */ - drawPolygon: function(geometry, style, featureId) { - var components = geometry.components; - var len = components.length; - this.drawLinearRing(components[0], style, featureId); - // erase inner rings - for (var i=1; i} - * style - {Object} - */ - drawText: function(location, style) { - var pt = this.getLocalXY(location); - - this.setCanvasStyle("reset"); - this.canvas.fillStyle = style.fontColor; - this.canvas.globalAlpha = style.fontOpacity || 1.0; - var fontStyle = [style.fontStyle ? style.fontStyle : "normal", - "normal", // "font-variant" not supported - style.fontWeight ? style.fontWeight : "normal", - style.fontSize ? style.fontSize : "1em", - style.fontFamily ? style.fontFamily : "sans-serif"].join(" "); - var labelRows = style.label.split('\n'); - var numRows = labelRows.length; - if (this.canvas.fillText) { - // HTML5 - this.canvas.font = fontStyle; - this.canvas.textAlign = - OpenLayers.Renderer.Canvas.LABEL_ALIGN[style.labelAlign[0]] || - "center"; - this.canvas.textBaseline = - OpenLayers.Renderer.Canvas.LABEL_ALIGN[style.labelAlign[1]] || - "middle"; - var vfactor = - OpenLayers.Renderer.Canvas.LABEL_FACTOR[style.labelAlign[1]]; - if (vfactor == null) { - vfactor = -.5; - } - var lineHeight = - this.canvas.measureText('Mg').height || - this.canvas.measureText('xx').width; - pt[1] += lineHeight*vfactor*(numRows-1); - for (var i = 0; i < numRows; i++) { - if (style.labelOutlineWidth) { - this.canvas.save(); - this.canvas.strokeStyle = style.labelOutlineColor; - this.canvas.lineWidth = style.labelOutlineWidth; - this.canvas.strokeText(labelRows[i], pt[0], pt[1] + (lineHeight*i) + 1); - this.canvas.restore(); - } - this.canvas.fillText(labelRows[i], pt[0], pt[1] + (lineHeight*i)); - } - } else if (this.canvas.mozDrawText) { - // Mozilla pre-Gecko1.9.1 (} - */ - getLocalXY: function(point) { - var resolution = this.getResolution(); - var extent = this.extent; - var x = ((point.x - this.featureDx) / 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() { - var height = this.root.height; - var width = this.root.width; - this.canvas.clearRect(0, 0, width, height); - this.features = {}; - if (this.hitDetection) { - this.hitContext.clearRect(0, 0, width, height); - } - }, - - /** - * Method: getFeatureIdFromEvent - * Returns a feature id from an event on the renderer. - * - * Parameters: - * evt - {} - * - * Returns: - * {)} - */ - eraseFeatures: function(features) { - if(!(OpenLayers.Util.isArray(features))) { - features = [features]; - } - for(var i=0; i}. The control that initialized this handler. The - * control is assumed to have a valid map property - that map is used - * in the handler's own setMap method. - */ - control: null, - - /** - * Property: map - * {} - */ - map: null, - - /** - * APIProperty: keyMask - * {Integer} Use bitwise operators and one or more of the OpenLayers.Handler - * constants to construct a keyMask. The keyMask is used by - * . If the keyMask matches the combination of keys - * down on an event, checkModifiers returns true. - * - * Example: - * (code) - * // handler only responds if the Shift key is down - * handler.keyMask = OpenLayers.Handler.MOD_SHIFT; - * - * // handler only responds if Ctrl-Shift is down - * handler.keyMask = OpenLayers.Handler.MOD_SHIFT | - * OpenLayers.Handler.MOD_CTRL; - * (end) - */ - keyMask: null, - - /** - * Property: active - * {Boolean} - */ - active: false, - - /** - * Property: evt - * {Event} This property references the last event handled by the handler. - * Note that this property is not part of the stable API. Use of the - * evt property should be restricted to controls in the library - * or other applications that are willing to update with changes to - * the OpenLayers code. - */ - evt: null, - - /** - * Constructor: OpenLayers.Handler - * Construct a handler. - * - * Parameters: - * control - {} The control that initialized this - * handler. The control is assumed to have a valid map property; that - * map is used in the handler's own setMap method. If a map property - * is present in the options argument it will be used instead. - * callbacks - {Object} An object whose properties correspond to abstracted - * events or sequences of browser events. The values for these - * properties are functions defined by the control that get called by - * the handler. - * options - {Object} An optional object whose properties will be set on - * the handler. - */ - initialize: function(control, callbacks, options) { - OpenLayers.Util.extend(this, options); - this.control = control; - this.callbacks = callbacks; - - var map = this.map || control.map; - if (map) { - this.setMap(map); - } - - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); - }, - - /** - * Method: setMap - */ - setMap: function (map) { - this.map = map; - }, - - /** - * Method: checkModifiers - * Check the keyMask on the handler. If no is set, this always - * returns true. If a is set and it matches the combination - * of keys down on an event, this returns true. - * - * Returns: - * {Boolean} The keyMask matches the keys down on an event. - */ - checkModifiers: function (evt) { - if(this.keyMask == null) { - return true; - } - /* calculate the keyboard modifier mask for this event */ - var keyModifiers = - (evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) | - (evt.ctrlKey ? OpenLayers.Handler.MOD_CTRL : 0) | - (evt.altKey ? OpenLayers.Handler.MOD_ALT : 0) | - (evt.metaKey ? OpenLayers.Handler.MOD_META : 0); - - /* if it differs from the handler object's key mask, - bail out of the event handler */ - return (keyModifiers == this.keyMask); - }, - - /** - * APIMethod: activate - * Turn on the handler. Returns false if the handler was already active. - * - * Returns: - * {Boolean} The handler was activated. - */ - activate: function() { - if(this.active) { - return false; - } - // register for event handlers defined on this class. - var events = OpenLayers.Events.prototype.BROWSER_EVENTS; - for (var i=0, len=events.length; i, returns false if any key is down. - */ -OpenLayers.Handler.MOD_NONE = 0; - -/** - * Constant: OpenLayers.Handler.MOD_SHIFT - * If set as the , returns false if Shift is down. - */ -OpenLayers.Handler.MOD_SHIFT = 1; - -/** - * Constant: OpenLayers.Handler.MOD_CTRL - * If set as the , returns false if Ctrl is down. - */ -OpenLayers.Handler.MOD_CTRL = 2; - -/** - * Constant: OpenLayers.Handler.MOD_ALT - * If set as the , returns false if Alt is down. - */ -OpenLayers.Handler.MOD_ALT = 4; - -/** - * Constant: OpenLayers.Handler.MOD_META - * If set as the , returns false if Cmd is down. - */ -OpenLayers.Handler.MOD_META = 8; - - -/* ====================================================================== - OpenLayers/Handler/MouseWheel.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Handler.js - */ - -/** - * Class: OpenLayers.Handler.MouseWheel - * Handler for wheel up/down events. - * - * Inherits from: - * - - */ -OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, { - /** - * Property: wheelListener - * {function} - */ - wheelListener: null, - - /** - * Property: interval - * {Integer} In order to increase server performance, an interval (in - * milliseconds) can be set to reduce the number of up/down events - * called. If set, a new up/down event will not be set until the - * interval has passed. - * Defaults to 0, meaning no interval. - */ - 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 - {} - * 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 (CSS overflow property) - // * one of our layer divs or a div marked as scrollable - // ('olScrollable' CSS class) - // * the map div - // - var overScrollableDiv = false; - var allowScroll = false; - var overMapDiv = false; - - var elem = OpenLayers.Event.element(e); - while((elem != null) && !overMapDiv && !overScrollableDiv) { - - if (!overScrollableDiv) { - try { - var overflow; - if (elem.currentStyle) { - overflow = elem.currentStyle["overflow"]; - } else { - var style = - document.defaultView.getComputedStyle(elem, null); - overflow = style.getPropertyValue("overflow"); - } - overScrollableDiv = ( overflow && - (overflow == "auto") || (overflow == "scroll") ); - } catch(err) { - //sometimes when scrolling in a popup, this causes - // obscure browser error - } - } - - if (!allowScroll) { - allowScroll = OpenLayers.Element.hasClass(elem, 'olScrollable'); - if (!allowScroll) { - for (var i = 0, len = this.map.layers.length; i < len; i++) { - // Are we in the layer div? Note that we have two cases - // here: one is to catch EventPane layers, which have a - // pane above the layer (layer.pane) - var layer = this.map.layers[i]; - if (elem == layer.div || elem == layer.pane) { - allowScroll = true; - break; - } - } - } - } - overMapDiv = (elem == this.map.div); - - elem = elem.parentNode; - } - - // Logic below is the following: - // - // If we are over a scrollable div or not over the map div: - // * do nothing (let the browser handle scrolling) - // - // otherwise - // - // If we are over the layer div or a 'olScrollable' div: - // * zoom/in out - // then - // * kill event (so as not to also scroll the page after zooming) - // - // otherwise - // - // Kill the event (dont scroll the page if we wheel over the - // layerswitcher or the pan/zoom control) - // - if (!overScrollableDiv && overMapDiv) { - if (allowScroll) { - var delta = 0; - if (!e) { - e = window.event; - } - - if (e.wheelDelta) { - delta = e.wheelDelta; - if (delta % 160 === 0) { - // opera have steps of 160 instead of 120 - delta = delta * 0.75; - } - delta = delta / 120; - } else if (e.detail) { - // detail in Firefox on OS X is 1/3 of Windows - // so force delta 1 / -1 - delta = - (e.detail / Math.abs(e.detail)); - } - this.delta = 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) { - e.xy = this.map.events.getMousePosition(e); - if (delta < 0) { - this.callback("down", [e, this.cumulative ? delta : -1]); - } else { - this.callback("up", [e, this.cumulative ? delta : 1]); - } - } - }, - - /** - * Method: activate - */ - activate: function (evt) { - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { - //register mousewheel events specifically on the window and document - var wheelListener = this.wheelListener; - OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener); - OpenLayers.Event.observe(window, "mousewheel", wheelListener); - OpenLayers.Event.observe(document, "mousewheel", wheelListener); - return true; - } else { - return false; - } - }, - - /** - * Method: deactivate - */ - deactivate: function (evt) { - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { - // unregister mousewheel events specifically on the window and document - var wheelListener = this.wheelListener; - OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener); - OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener); - OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener); - return true; - } else { - return false; - } - }, - - CLASS_NAME: "OpenLayers.Handler.MouseWheel" -}); -/* ====================================================================== - OpenLayers/Renderer/Elements.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/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} 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.clear(); - }, - - /** - * 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 - {} - * 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 - {} - * 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 - {} - * 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.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: xOffset - * {Number} Offset to apply to the renderer viewport translation in x - * direction. If the renderer extent's center is on the right of the - * dateline (i.e. exceeds the world bounds), we shift the viewport to the - * left by one world width. This avoids that features disappear from the - * map viewport. Because our dateline handling logic in other places - * ensures that extents crossing the dateline always have a center - * exceeding the world bounds on the left, we need this offset to make sure - * that the same is true for the renderer extent in pixel space as well. - */ - xOffset: 0, - - /** - * Property: rightOfDateLine - * {Boolean} Keeps track of the location of the map extent relative to the - * date line. The method compares this value (which is the one - * from the previous call) with the current position of the map - * extent relative to the date line and updates the xOffset when the extent - * has moved from one side of the date line to the other. - */ - - /** - * Property: Indexer - * {} 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: LABEL_ID_SUFFIX - * {String} - */ - LABEL_ID_SUFFIX: "_label", - - /** - * Constant: LABEL_OUTLINE_SUFFIX - * {String} - */ - LABEL_OUTLINE_SUFFIX: "_outline", - - /** - * 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: setExtent - * Set the visible part of the layer. - * - * Parameters: - * extent - {} - * resolutionChanged - {Boolean} - * - * Returns: - * {Boolean} true to notify the layer that the new extent does not exceed - * the coordinate range, and the features will not need to be redrawn. - * False otherwise. - */ - setExtent: function(extent, resolutionChanged) { - var coordSysUnchanged = OpenLayers.Renderer.prototype.setExtent.apply(this, arguments); - var resolution = this.getResolution(); - if (this.map.baseLayer && this.map.baseLayer.wrapDateLine) { - var rightOfDateLine, - ratio = extent.getWidth() / this.map.getExtent().getWidth(), - extent = extent.scale(1 / ratio), - world = this.map.getMaxExtent(); - if (world.right > extent.left && world.right < extent.right) { - rightOfDateLine = true; - } else if (world.left > extent.left && world.left < extent.right) { - rightOfDateLine = false; - } - if (rightOfDateLine !== this.rightOfDateLine || resolutionChanged) { - coordSysUnchanged = false; - this.xOffset = rightOfDateLine === true ? - world.getWidth() / resolution : 0; - } - this.rightOfDateLine = rightOfDateLine; - } - return coordSysUnchanged; - }, - - /** - * 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 - {} - * 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 - {} - * 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} - * 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 - {} - * 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 - {} - * 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.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 - {} - * - * 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 - {} - * - * 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 - {} - * - * 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 - {} - * - * 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 - {} - * - * 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 - {} - * - * Returns: - * {DOMElement} or false if the renderer could not draw the circle - */ - drawCircle: 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); - } - var outline = document.getElementById(featureId + this.LABEL_OUTLINE_SUFFIX); - if (outline) { - this.textRoot.removeChild(outline); - } - }, - - /** - * Method: getFeatureIdFromEvent - * - * Parameters: - * evt - {Object} An object - * - * Returns: - * {String} A feature id or undefined. - */ - getFeatureIdFromEvent: function(evt) { - var target = evt.target; - var useElement = target && target.correspondingUseElement; - var node = useElement ? useElement : (target || evt.srcElement); - return node._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 - {} - * 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} 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" -}); - -/* ====================================================================== - OpenLayers/Control.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/BaseTypes/Class.js - */ - -/** - * Class: OpenLayers.Control - * Controls affect the display or behavior of the map. They allow everything - * from panning and zooming to displaying a scale indicator. Controls by - * default are added to the map they are contained within however it is - * possible to add a control to an external div by passing the div in the - * options parameter. - * - * Example: - * The following example shows how to add many of the common controls - * to a map. - * - * > var map = new OpenLayers.Map('map', { controls: [] }); - * > - * > map.addControl(new OpenLayers.Control.PanZoomBar()); - * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false})); - * > map.addControl(new OpenLayers.Control.Permalink()); - * > map.addControl(new OpenLayers.Control.Permalink('permalink')); - * > map.addControl(new OpenLayers.Control.MousePosition()); - * > map.addControl(new OpenLayers.Control.OverviewMap()); - * > map.addControl(new OpenLayers.Control.KeyboardDefaults()); - * - * The next code fragment is a quick example of how to intercept - * shift-mouse click to display the extent of the bounding box - * dragged out by the user. Usually controls are not created - * in exactly this manner. See the source for a more complete - * example: - * - * > var control = new OpenLayers.Control(); - * > OpenLayers.Util.extend(control, { - * > draw: function () { - * > // this Handler.Box will intercept the shift-mousedown - * > // before Control.MouseDefault gets to see it - * > this.box = new OpenLayers.Handler.Box( control, - * > {"done": this.notice}, - * > {keyMask: OpenLayers.Handler.MOD_SHIFT}); - * > this.box.activate(); - * > }, - * > - * > notice: function (bounds) { - * > OpenLayers.Console.userError(bounds); - * > } - * > }); - * > map.addControl(control); - * - */ -OpenLayers.Control = OpenLayers.Class({ - - /** - * Property: id - * {String} - */ - id: null, - - /** - * Property: map - * {} this gets set in the addControl() function in - * OpenLayers.Map - */ - map: null, - - /** - * APIProperty: div - * {DOMElement} The element that contains the control, if not present the - * control is placed inside the map. - */ - div: null, - - /** - * APIProperty: type - * {Number} Controls can have a 'type'. The type determines the type of - * interactions which are possible with them when they are placed in an - * . - */ - type: null, - - /** - * Property: allowSelection - * {Boolean} By default, controls do not allow selection, because - * it may interfere with map dragging. If this is true, OpenLayers - * will not prevent selection of the control. - * Default is false. - */ - allowSelection: false, - - /** - * Property: displayClass - * {string} This property is used for CSS related to the drawing of the - * Control. - */ - displayClass: "", - - /** - * APIProperty: title - * {string} This property is used for showing a tooltip over the - * Control. - */ - title: "", - - /** - * APIProperty: autoActivate - * {Boolean} Activate the control when it is added to a map. Default is - * false. - */ - autoActivate: false, - - /** - * APIProperty: active - * {Boolean} The control is active (read-only). Use and - * to change control state. - */ - active: null, - - /** - * Property: handlerOptions - * {Object} Used to set non-default properties on the control's handler - */ - handlerOptions: null, - - /** - * Property: handler - * {} null - */ - handler: null, - - /** - * APIProperty: eventListeners - * {Object} If set as an option at construction, the eventListeners - * object will be registered with . Object - * structure must be a listeners object as shown in the example for - * the events.on method. - */ - eventListeners: null, - - /** - * APIProperty: events - * {} Events instance for listeners and triggering - * control specific events. - * - * Register a listener for a particular event with the following syntax: - * (code) - * control.events.register(type, obj, listener); - * (end) - * - * Listeners will be called with a reference to an event object. The - * properties of this event depends on exactly what happened. - * - * All event objects have at least the following properties: - * object - {Object} A reference to control.events.object (a reference - * to the control). - * element - {DOMElement} A reference to control.events.element (which - * will be null unless documented otherwise). - * - * Supported map event types: - * activate - Triggered when activated. - * deactivate - Triggered when deactivated. - */ - events: null, - - /** - * Constructor: OpenLayers.Control - * Create an OpenLayers Control. The options passed as a parameter - * directly extend the control. For example passing the following: - * - * > var control = new OpenLayers.Control({div: myDiv}); - * - * Overrides the default div attribute value of null. - * - * Parameters: - * options - {Object} - */ - initialize: function (options) { - // We do this before the extend so that instances can override - // className in options. - this.displayClass = - this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, ""); - - OpenLayers.Util.extend(this, options); - - this.events = new OpenLayers.Events(this); - if(this.eventListeners instanceof Object) { - this.events.on(this.eventListeners); - } - if (this.id == null) { - this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_"); - } - }, - - /** - * Method: destroy - * The destroy method is used to perform any clean up before the control - * is dereferenced. Typically this is where event listeners are removed - * to prevent memory leaks. - */ - destroy: function () { - if(this.events) { - if(this.eventListeners) { - this.events.un(this.eventListeners); - } - this.events.destroy(); - this.events = null; - } - this.eventListeners = null; - - // eliminate circular references - if (this.handler) { - this.handler.destroy(); - this.handler = null; - } - if(this.handlers) { - for(var key in this.handlers) { - if(this.handlers.hasOwnProperty(key) && - typeof this.handlers[key].destroy == "function") { - this.handlers[key].destroy(); - } - } - this.handlers = null; - } - if (this.map) { - this.map.removeControl(this); - this.map = null; - } - this.div = null; - }, - - /** - * Method: setMap - * Set the map property for the control. This is done through an accessor - * so that subclasses can override this and take special action once - * they have their map variable set. - * - * Parameters: - * map - {} - */ - setMap: function(map) { - this.map = map; - if (this.handler) { - this.handler.setMap(map); - } - }, - - /** - * Method: draw - * The draw method is called when the control is ready to be displayed - * on the page. If a div has not been created one is created. Controls - * with a visual component will almost always want to override this method - * to customize the look of control. - * - * Parameters: - * px - {} The top-left pixel position of the control - * or null. - * - * Returns: - * {DOMElement} A reference to the DIV DOMElement containing the control - */ - draw: function (px) { - if (this.div == null) { - this.div = OpenLayers.Util.createDiv(this.id); - this.div.className = this.displayClass; - if (!this.allowSelection) { - this.div.className += " olControlNoSelect"; - this.div.setAttribute("unselectable", "on", 0); - this.div.onselectstart = OpenLayers.Function.False; - } - if (this.title != "") { - this.div.title = this.title; - } - } - if (px != null) { - this.position = px.clone(); - } - this.moveTo(this.position); - return this.div; - }, - - /** - * Method: moveTo - * Sets the left and top style attributes to the passed in pixel - * coordinates. - * - * Parameters: - * px - {} - */ - moveTo: function (px) { - if ((px != null) && (this.div != null)) { - this.div.style.left = px.x + "px"; - this.div.style.top = px.y + "px"; - } - }, - - /** - * APIMethod: activate - * Explicitly activates a control and it's associated - * handler if one has been set. Controls can be - * deactivated by calling the deactivate() method. - * - * Returns: - * {Boolean} True if the control was successfully activated or - * false if the control was already active. - */ - activate: function () { - if (this.active) { - return false; - } - if (this.handler) { - this.handler.activate(); - } - this.active = true; - if(this.map) { - OpenLayers.Element.addClass( - this.map.viewPortDiv, - this.displayClass.replace(/ /g, "") + "Active" - ); - } - this.events.triggerEvent("activate"); - return true; - }, - - /** - * APIMethod: deactivate - * Deactivates a control and it's associated handler if any. The exact - * effect of this depends on the control itself. - * - * Returns: - * {Boolean} True if the control was effectively deactivated or false - * if the control was already inactive. - */ - deactivate: function () { - if (this.active) { - if (this.handler) { - this.handler.deactivate(); - } - this.active = false; - if(this.map) { - OpenLayers.Element.removeClass( - this.map.viewPortDiv, - this.displayClass.replace(/ /g, "") + "Active" - ); - } - this.events.triggerEvent("deactivate"); - return true; - } - return false; - }, - - CLASS_NAME: "OpenLayers.Control" -}); - -/** - * Constant: OpenLayers.Control.TYPE_BUTTON - */ -OpenLayers.Control.TYPE_BUTTON = 1; - -/** - * Constant: OpenLayers.Control.TYPE_TOGGLE - */ -OpenLayers.Control.TYPE_TOGGLE = 2; - -/** - * Constant: OpenLayers.Control.TYPE_TOOL - */ -OpenLayers.Control.TYPE_TOOL = 3; -/* ====================================================================== - OpenLayers/Control/Zoom.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Control.js - * @requires OpenLayers/Events/buttonclick.js - */ - -/** - * Class: OpenLayers.Control.Zoom - * The Zoom control is a pair of +/- links for zooming in and out. - * - * Inherits from: - * - - */ -OpenLayers.Control.Zoom = OpenLayers.Class(OpenLayers.Control, { - - /** - * APIProperty: zoomInText - * {String} - * Text for zoom-in link. Default is "+". - */ - zoomInText: "+", - - /** - * APIProperty: zoomInId - * {String} - * Instead of having the control create a zoom in link, you can provide - * the identifier for an anchor element already added to the document. - * By default, an element with id "olZoomInLink" will be searched for - * and used if it exists. - */ - zoomInId: "olZoomInLink", - - /** - * APIProperty: zoomOutText - * {String} - * Text for zoom-out link. Default is "\u2212". - */ - zoomOutText: "\u2212", - - /** - * APIProperty: zoomOutId - * {String} - * Instead of having the control create a zoom out link, you can provide - * the identifier for an anchor element already added to the document. - * By default, an element with id "olZoomOutLink" will be searched for - * and used if it exists. - */ - zoomOutId: "olZoomOutLink", - - /** - * Method: draw - * - * Returns: - * {DOMElement} A reference to the DOMElement containing the zoom links. - */ - draw: function() { - var div = OpenLayers.Control.prototype.draw.apply(this), - links = this.getOrCreateLinks(div), - zoomIn = links.zoomIn, - zoomOut = links.zoomOut, - eventsInstance = this.map.events; - - if (zoomOut.parentNode !== div) { - eventsInstance = this.events; - eventsInstance.attachToElement(zoomOut.parentNode); - } - eventsInstance.register("buttonclick", this, this.onZoomClick); - - this.zoomInLink = zoomIn; - this.zoomOutLink = zoomOut; - return div; - }, - - /** - * Method: getOrCreateLinks - * - * Parameters: - * el - {DOMElement} - * - * Return: - * {Object} Object with zoomIn and zoomOut properties referencing links. - */ - getOrCreateLinks: function(el) { - var zoomIn = document.getElementById(this.zoomInId), - zoomOut = document.getElementById(this.zoomOutId); - if (!zoomIn) { - zoomIn = document.createElement("a"); - zoomIn.href = "#zoomIn"; - zoomIn.appendChild(document.createTextNode(this.zoomInText)); - zoomIn.className = "olControlZoomIn"; - el.appendChild(zoomIn); - } - OpenLayers.Element.addClass(zoomIn, "olButton"); - if (!zoomOut) { - zoomOut = document.createElement("a"); - zoomOut.href = "#zoomOut"; - zoomOut.appendChild(document.createTextNode(this.zoomOutText)); - zoomOut.className = "olControlZoomOut"; - el.appendChild(zoomOut); - } - OpenLayers.Element.addClass(zoomOut, "olButton"); - return { - zoomIn: zoomIn, zoomOut: zoomOut - }; - }, - - /** - * Method: onZoomClick - * Called when zoomin/out link is clicked. - */ - onZoomClick: function(evt) { - var button = evt.buttonElement; - if (button === this.zoomInLink) { - this.map.zoomIn(); - } else if (button === this.zoomOutLink) { - this.map.zoomOut(); - } - }, - - /** - * Method: destroy - * Clean up. - */ - destroy: function() { - if (this.map) { - this.map.events.unregister("buttonclick", this, this.onZoomClick); - } - delete this.zoomInLink; - delete this.zoomOutLink; - OpenLayers.Control.prototype.destroy.apply(this); - }, - - CLASS_NAME: "OpenLayers.Control.Zoom" -}); -/* ====================================================================== - OpenLayers/Protocol.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/BaseTypes/Class.js - */ - -/** - * Class: OpenLayers.Protocol - * Abstract vector layer protocol class. Not to be instantiated directly. Use - * one of the protocol subclasses instead. - */ -OpenLayers.Protocol = OpenLayers.Class({ - - /** - * Property: format - * {} The format used by this protocol. - */ - format: null, - - /** - * Property: options - * {Object} Any options sent to the constructor. - */ - options: null, - - /** - * Property: autoDestroy - * {Boolean} The creator of the protocol can set autoDestroy to false - * to fully control when the protocol is destroyed. Defaults to - * true. - */ - autoDestroy: true, - - /** - * Property: defaultFilter - * {} Optional default filter to read requests - */ - defaultFilter: null, - - /** - * Constructor: OpenLayers.Protocol - * Abstract class for vector protocols. Create instances of a subclass. - * - * Parameters: - * options - {Object} Optional object whose properties will be set on the - * instance. - */ - initialize: function(options) { - options = options || {}; - OpenLayers.Util.extend(this, options); - this.options = options; - }, - - /** - * Method: mergeWithDefaultFilter - * Merge filter passed to the read method with the default one - * - * Parameters: - * filter - {} - */ - mergeWithDefaultFilter: function(filter) { - var merged; - if (filter && this.defaultFilter) { - merged = new OpenLayers.Filter.Logical({ - type: OpenLayers.Filter.Logical.AND, - filters: [this.defaultFilter, filter] - }); - } else { - merged = filter || this.defaultFilter || undefined; - } - return merged; - }, - - /** - * APIMethod: destroy - * Clean up the protocol. - */ - destroy: function() { - this.options = null; - this.format = null; - }, - - /** - * APIMethod: read - * Construct a request for reading new features. - * - * Parameters: - * options - {Object} Optional object for configuring the request. - * - * Returns: - * {} An - * object, the same object will be passed to the callback function passed - * if one exists in the options object. - */ - read: function(options) { - options = options || {}; - options.filter = this.mergeWithDefaultFilter(options.filter); - }, - - - /** - * APIMethod: create - * Construct a request for writing newly created features. - * - * Parameters: - * features - {Array({})} or - * {} - * options - {Object} Optional object for configuring the request. - * - * Returns: - * {} An - * object, the same object will be passed to the callback function passed - * if one exists in the options object. - */ - create: function() { - }, - - /** - * APIMethod: update - * Construct a request updating modified features. - * - * Parameters: - * features - {Array({})} or - * {} - * options - {Object} Optional object for configuring the request. - * - * Returns: - * {} An - * object, the same object will be passed to the callback function passed - * if one exists in the options object. - */ - update: function() { - }, - - /** - * APIMethod: delete - * Construct a request deleting a removed feature. - * - * Parameters: - * feature - {} - * options - {Object} Optional object for configuring the request. - * - * Returns: - * {} An - * object, the same object will be passed to the callback function passed - * if one exists in the options object. - */ - "delete": function() { - }, - - /** - * APIMethod: commit - * Go over the features and for each take action - * based on the feature state. Possible actions are create, - * update and delete. - * - * Parameters: - * features - {Array({})} - * options - {Object} Object whose possible keys are "create", "update", - * "delete", "callback" and "scope", the values referenced by the - * first three are objects as passed to the "create", "update", and - * "delete" methods, the value referenced by the "callback" key is - * a function which is called when the commit operation is complete - * using the scope referenced by the "scope" key. - * - * Returns: - * {Array({})} An array of - * objects. - */ - commit: function() { - }, - - /** - * Method: abort - * Abort an ongoing request. - * - * Parameters: - * response - {} - */ - abort: function(response) { - }, - - /** - * Method: createCallback - * Returns a function that applies the given public method with resp and - * options arguments. - * - * Parameters: - * method - {Function} The method to be applied by the callback. - * response - {} The protocol response object. - * options - {Object} Options sent to the protocol method - */ - createCallback: function(method, response, options) { - return OpenLayers.Function.bind(function() { - method.apply(this, [response, options]); - }, this); - }, - - CLASS_NAME: "OpenLayers.Protocol" -}); - -/** - * Class: OpenLayers.Protocol.Response - * Protocols return Response objects to their users. - */ -OpenLayers.Protocol.Response = OpenLayers.Class({ - /** - * Property: code - * {Number} - OpenLayers.Protocol.Response.SUCCESS or - * OpenLayers.Protocol.Response.FAILURE - */ - code: null, - - /** - * Property: requestType - * {String} The type of request this response corresponds to. Either - * "create", "read", "update" or "delete". - */ - requestType: null, - - /** - * Property: last - * {Boolean} - true if this is the last response expected in a commit, - * false otherwise, defaults to true. - */ - last: true, - - /** - * Property: features - * {Array({})} or {} - * The features returned in the response by the server. Depending on the - * protocol's read payload, either features or data will be populated. - */ - features: null, - - /** - * Property: data - * {Object} - * The data returned in the response by the server. Depending on the - * protocol's read payload, either features or data will be populated. - */ - data: null, - - /** - * Property: reqFeatures - * {Array({})} or {} - * The features provided by the user and placed in the request by the - * protocol. - */ - reqFeatures: null, - - /** - * Property: priv - */ - priv: null, - - /** - * Property: error - * {Object} The error object in case a service exception was encountered. - */ - error: null, - - /** - * Constructor: OpenLayers.Protocol.Response - * - * Parameters: - * options - {Object} Optional object whose properties will be set on the - * instance. - */ - initialize: function(options) { - OpenLayers.Util.extend(this, options); - }, - - /** - * Method: success - * - * Returns: - * {Boolean} - true on success, false otherwise - */ - success: function() { - return this.code > 0; - }, - - CLASS_NAME: "OpenLayers.Protocol.Response" -}); - -OpenLayers.Protocol.Response.SUCCESS = 1; -OpenLayers.Protocol.Response.FAILURE = 0; -/* ====================================================================== - OpenLayers/Protocol/WFS.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Protocol.js - */ - -/** - * Class: OpenLayers.Protocol.WFS - * Used to create a versioned WFS protocol. Default version is 1.0.0. - * - * Returns: - * {} A WFS protocol of the given version. - * - * Example: - * (code) - * var protocol = new OpenLayers.Protocol.WFS({ - * version: "1.1.0", - * url: "http://demo.opengeo.org/geoserver/wfs", - * featureType: "tasmania_roads", - * featureNS: "http://www.openplans.org/topp", - * geometryName: "the_geom" - * }); - * (end) - * - * See the protocols for specific WFS versions for more detail. - */ -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: 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 , , - * and for WFS 1.1.0. Note that - * srsName matching with the WMS layer will not work with WFS 1.0.0. - * - * Parameters: - * layer - {} 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. - * - * Returns: - * {} - */ -OpenLayers.Protocol.WFS.fromWMSLayer = function(layer, options) { - var typeName, featurePrefix; - var param = layer.params["LAYERS"]; - var parts = (OpenLayers.Util.isArray(param) ? 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/Strategy.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/BaseTypes/Class.js - */ - -/** - * Class: OpenLayers.Strategy - * Abstract vector layer strategy class. Not to be instantiated directly. Use - * one of the strategy subclasses instead. - */ -OpenLayers.Strategy = OpenLayers.Class({ - - /** - * Property: layer - * {} The layer this strategy belongs to. - */ - layer: null, - - /** - * Property: options - * {Object} Any options sent to the constructor. - */ - options: null, - - /** - * Property: active - * {Boolean} The control is active. - */ - active: null, - - /** - * Property: autoActivate - * {Boolean} The creator of the strategy can set autoActivate to false - * to fully control when the protocol is activated and deactivated. - * Defaults to true. - */ - autoActivate: true, - - /** - * Property: autoDestroy - * {Boolean} The creator of the strategy can set autoDestroy to false - * to fully control when the strategy is destroyed. Defaults to - * true. - */ - autoDestroy: true, - - /** - * Constructor: OpenLayers.Strategy - * Abstract class for vector strategies. Create instances of a subclass. - * - * Parameters: - * options - {Object} Optional object whose properties will be set on the - * instance. - */ - initialize: function(options) { - OpenLayers.Util.extend(this, options); - this.options = options; - // set the active property here, so that user cannot override it - this.active = false; - }, - - /** - * APIMethod: destroy - * Clean up the strategy. - */ - destroy: function() { - this.deactivate(); - this.layer = null; - this.options = null; - }, - - /** - * Method: setLayer - * Called to set the property. - * - * Parameters: - * layer - {} - */ - setLayer: function(layer) { - this.layer = layer; - }, - - /** - * Method: activate - * Activate the strategy. Register any listeners, do appropriate setup. - * - * Returns: - * {Boolean} True if the strategy was successfully activated or false if - * the strategy was already active. - */ - activate: function() { - if (!this.active) { - this.active = true; - return true; - } - return false; - }, - - /** - * Method: deactivate - * Deactivate the strategy. Unregister any listeners, do appropriate - * tear-down. - * - * Returns: - * {Boolean} True if the strategy was successfully deactivated or false if - * the strategy was already inactive. - */ - deactivate: function() { - if (this.active) { - this.active = false; - return true; - } - return false; - }, - - CLASS_NAME: "OpenLayers.Strategy" -}); -/* ====================================================================== - OpenLayers/Strategy/BBOX.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Strategy.js - * @requires OpenLayers/Filter/Spatial.js - */ - -/** - * Class: OpenLayers.Strategy.BBOX - * A simple strategy that reads new features when the viewport invalidates - * some bounds. - * - * Inherits from: - * - - */ -OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, { - - /** - * Property: 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 - * {} 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. - */ - - /** - * 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, - "refresh": this.update, - "visibilitychanged": this.update, - scope: this - }); - this.update(); - } - 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, - "refresh": this.update, - "visibilitychanged": this.update, - scope: this - }); - } - return deactivated; - }, - - /** - * Method: update - * Callback function called on "moveend" or "refresh" layer events. - * - * Parameters: - * options - {Object} Optional object whose properties will determine - * the behaviour of this Strategy - * - * Valid options include: - * force - {Boolean} if true, new data must be unconditionally read. - * noAbort - {Boolean} if true, do not abort previous requests. - */ - update: function(options) { - var mapBounds = this.getMapBounds(); - if (mapBounds !== null && ((options && options.force) || - (this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds)))) { - this.calculateBounds(mapBounds); - this.resolution = this.layer.map.getResolution(); - this.triggerRead(options); - } - }, - - /** - * Method: getMapBounds - * Get the map bounds expressed in the same projection as this layer. - * - * Returns: - * {} Map bounds in the projection of the layer. - */ - getMapBounds: function() { - if (this.layer.map === null) { - return null; - } - var bounds = this.layer.map.getExtent(); - if(bounds && !this.layer.projection.equals( - this.layer.map.getProjectionObject())) { - bounds = bounds.clone().transform( - this.layer.map.getProjectionObject(), this.layer.projection - ); - } - return bounds; - }, - - /** - * Method: invalidBounds - * Determine whether the previously requested set of features is invalid. - * This occurs when the new map bounds do not contain the previously - * requested bounds. In addition, if is set, it will be - * considered. - * - * Parameters: - * mapBounds - {} the current map extent, will be - * retrieved from the map object if not provided - * - * Returns: - * {Boolean} - */ - 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 - {} 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 - * - * Parameters: - * options - {Object} Additional options for the protocol's read method - * (optional) - * - * Returns: - * {} The protocol response object - * returned by the layer protocol. - */ - triggerRead: function(options) { - if (this.response && !(options && options.noAbort === true)) { - this.layer.protocol.abort(this.response); - this.layer.events.triggerEvent("loadend"); - } - this.layer.events.triggerEvent("loadstart"); - this.response = this.layer.protocol.read( - OpenLayers.Util.applyDefaults({ - filter: this.createFilter(), - callback: this.merge, - scope: this - }, options)); - }, - - /** - * Method: createFilter - * Creates a spatial BBOX filter. If the layer that this strategy belongs - * to has a filter property, this filter will be combined with the BBOX - * filter. - * - * Returns - * {} The filter object. - */ - createFilter: function() { - var filter = new OpenLayers.Filter.Spatial({ - type: OpenLayers.Filter.Spatial.BBOX, - value: this.bounds, - projection: this.layer.projection - }); - if (this.layer.filter) { - filter = new OpenLayers.Filter.Logical({ - type: OpenLayers.Filter.Logical.AND, - filters: [this.layer.filter, filter] - }); - } - return filter; - }, - - /** - * Method: merge - * Given a list of features, determine which ones to add to the layer. - * If the layer projection differs from the map projection, features - * will be transformed from the layer projection to the map projection. - * - * Parameters: - * resp - {} The response object passed - * by the protocol. - */ - merge: function(resp) { - this.layer.destroyFeatures(); - 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 - */ -OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, { - - /** - * Property: EVENTMAP - * {Object} A object mapping the browser events to objects with callback - * keys for in and out. - */ - EVENTMAP: { - 'click': {'in': 'click', 'out': 'clickout'}, - 'mousemove': {'in': 'over', 'out': 'out'}, - 'dblclick': {'in': 'dblclick', 'out': null}, - 'mousedown': {'in': null, 'out': null}, - 'mouseup': {'in': null, 'out': null}, - 'touchstart': {'in': 'click', 'out': 'clickout'} - }, - - /** - * Property: feature - * {} The last feature that was hovered. - */ - feature: null, - - /** - * Property: lastFeature - * {} The last feature that was handled. - */ - lastFeature: null, - - /** - * Property: down - * {} The location of the last mousedown. - */ - down: null, - - /** - * Property: up - * {} The location of the last mouseup. - */ - up: null, - - /** - * Property: touch - * {Boolean} When a touchstart event is fired, touch will be true and all - * mouse related listeners will do nothing. - */ - touch: false, - - /** - * Property: clickTolerance - * {Number} The number of pixels the mouse can move between mousedown - * and mouseup for the event to still be considered a click. - * Dragging the map should not trigger the click and clickout callbacks - * unless the map is moved by less than this tolerance. Defaults to 4. - */ - clickTolerance: 4, - - /** - * Property: geometryTypes - * To restrict dragging to a limited set of geometry types, send a list - * of strings corresponding to the geometry class names. - * - * @type Array(String) - */ - geometryTypes: null, - - /** - * Property: stopClick - * {Boolean} If stopClick is set to true, handled clicks do not - * propagate to other click listeners. Otherwise, handled clicks - * do propagate. Unhandled clicks always propagate, whatever the - * value of stopClick. Defaults to true. - */ - stopClick: true, - - /** - * Property: stopDown - * {Boolean} If stopDown is set to true, handled mousedowns do not - * propagate to other mousedown listeners. Otherwise, handled - * mousedowns do propagate. Unhandled mousedowns always propagate, - * whatever the value of stopDown. Defaults to true. - */ - stopDown: true, - - /** - * Property: stopUp - * {Boolean} If stopUp is set to true, handled mouseups do not - * propagate to other mouseup listeners. Otherwise, handled mouseups - * do propagate. Unhandled mouseups always propagate, whatever the - * value of stopUp. Defaults to false. - */ - stopUp: false, - - /** - * Constructor: OpenLayers.Handler.Feature - * - * Parameters: - * control - {} - * layer - {} - * callbacks - {Object} An object with a 'over' property whos value is - * a function to be called when the mouse is over a feature. The - * callback should expect to recieve a single argument, the feature. - * options - {Object} - */ - initialize: function(control, layer, callbacks, options) { - OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]); - this.layer = layer; - }, - - /** - * Method: touchstart - * Handle touchstart events - * - * Parameters: - * evt - {Event} - * - * Returns: - * {Boolean} Let the event propagate. - */ - touchstart: function(evt) { - if(!this.touch) { - this.touch = true; - this.map.events.un({ - mousedown: this.mousedown, - mouseup: this.mouseup, - mousemove: this.mousemove, - click: this.click, - dblclick: this.dblclick, - scope: this - }); - } - return OpenLayers.Event.isMultiTouch(evt) ? - true : this.mousedown(evt); - }, - - /** - * Method: touchmove - * Handle touchmove events. We just prevent the browser default behavior, - * for Android Webkit not to select text when moving the finger after - * selecting a feature. - * - * Parameters: - * evt - {Event} - */ - touchmove: function(evt) { - OpenLayers.Event.stop(evt); - }, - - /** - * Method: mousedown - * Handle mouse down. Stop propagation if a feature is targeted by this - * event (stops map dragging during feature selection). - * - * Parameters: - * evt - {Event} - */ - mousedown: function(evt) { - // Feature selection is only done with a left click. Other handlers may stop the - // propagation of left-click mousedown events but not right-click mousedown events. - // This mismatch causes problems when comparing the location of the down and up - // events in the click function so it is important ignore right-clicks. - if (OpenLayers.Event.isLeftClick(evt) || OpenLayers.Event.isSingleTouch(evt)) { - this.down = evt.xy; - } - return this.handle(evt) ? !this.stopDown : true; - }, - - /** - * Method: mouseup - * Handle mouse up. Stop propagation if a feature is targeted by this - * event. - * - * Parameters: - * evt - {Event} - */ - mouseup: function(evt) { - this.up = evt.xy; - return this.handle(evt) ? !this.stopUp : true; - }, - - /** - * Method: click - * Handle click. Call the "click" callback if click on a feature, - * or the "clickout" callback if click outside any feature. - * - * Parameters: - * evt - {Event} - * - * Returns: - * {Boolean} - */ - click: function(evt) { - return this.handle(evt) ? !this.stopClick : true; - }, - - /** - * Method: mousemove - * Handle mouse moves. Call the "over" callback if moving in to a feature, - * or the "out" callback if moving out of a feature. - * - * Parameters: - * evt - {Event} - * - * Returns: - * {Boolean} - */ - mousemove: function(evt) { - if (!this.callbacks['over'] && !this.callbacks['out']) { - return true; - } - this.handle(evt); - return true; - }, - - /** - * Method: dblclick - * Handle dblclick. Call the "dblclick" callback if dblclick on a feature. - * - * Parameters: - * evt - {Event} - * - * Returns: - * {Boolean} - */ - dblclick: function(evt) { - return !this.handle(evt); - }, - - /** - * Method: geometryTypeMatches - * Return true if the geometry type of the passed feature matches - * one of the geometry types in the geometryTypes array. - * - * Parameters: - * feature - {} - * - * Returns: - * {Boolean} - */ - geometryTypeMatches: function(feature) { - return this.geometryTypes == null || - OpenLayers.Util.indexOf(this.geometryTypes, - feature.geometry.CLASS_NAME) > -1; - }, - - /** - * Method: handle - * - * Parameters: - * evt - {Event} - * - * Returns: - * {Boolean} The event occurred over a relevant feature. - */ - handle: function(evt) { - if(this.feature && !this.feature.layer) { - // feature has been destroyed - this.feature = null; - } - var type = evt.type; - var handled = false; - var previouslyIn = !!(this.feature); // previously in a feature - var click = (type == "click" || type == "dblclick" || type == "touchstart"); - this.feature = this.layer.getFeatureFromEvent(evt); - if(this.feature && !this.feature.layer) { - // feature has been destroyed - this.feature = null; - } - if(this.lastFeature && !this.lastFeature.layer) { - // last feature has been destroyed - this.lastFeature = null; - } - if(this.feature) { - if(type === "touchstart") { - // stop the event to prevent Android Webkit from - // "flashing" the map div - OpenLayers.Event.stop(evt); - } - var inNew = (this.feature != this.lastFeature); - if(this.geometryTypeMatches(this.feature)) { - // in to a feature - if(previouslyIn && inNew) { - // out of last feature and in to another - if(this.lastFeature) { - this.triggerCallback(type, 'out', [this.lastFeature]); - } - this.triggerCallback(type, 'in', [this.feature]); - } else if(!previouslyIn || click) { - // in feature for the first time - this.triggerCallback(type, 'in', [this.feature]); - } - this.lastFeature = this.feature; - handled = true; - } else { - // not in to a feature - if(this.lastFeature && (previouslyIn && inNew || click)) { - // out of last feature for the first time - this.triggerCallback(type, 'out', [this.lastFeature]); - } - // next time the mouse goes in a feature whose geometry type - // doesn't match we don't want to call the 'out' callback - // again, so let's set this.feature to null so that - // previouslyIn will evaluate to false the next time - // we enter handle. Yes, a bit hackish... - this.feature = null; - } - } else { - if(this.lastFeature && (previouslyIn || click)) { - this.triggerCallback(type, 'out', [this.lastFeature]); - } - } - return handled; - }, - - /** - * Method: triggerCallback - * Call the callback keyed in the event map with the supplied arguments. - * For click and clickout, the is checked first. - * - * Parameters: - * type - {String} - */ - triggerCallback: function(type, mode, args) { - var key = this.EVENTMAP[type][mode]; - if(key) { - if(type == 'click' && this.up && this.down) { - // for click/clickout, only trigger callback if tolerance is met - var dpx = Math.sqrt( - Math.pow(this.up.x - this.down.x, 2) + - Math.pow(this.up.y - this.down.y, 2) - ); - if(dpx <= this.clickTolerance) { - this.callback(key, args); - } - } 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.touch = false; - this.map.events.un({ - "removelayer": this.handleMapEvents, - "changelayer": this.handleMapEvents, - scope: this - }); - deactivated = true; - } - return deactivated; - }, - - /** - * Method: handleMapEvents - * - * Parameters: - * evt - {Object} - */ - handleMapEvents: function(evt) { - if (evt.type == "removelayer" || evt.property == "order") { - this.moveLayerToTop(); - } - }, - - /** - * Method: moveLayerToTop - * Moves the layer for this handler to the top, so mouse events can reach - * it. - */ - moveLayerToTop: function() { - var index = Math.max(this.map.Z_INDEX_BASE['Feature'] - 1, - this.layer.getZIndex()) + 1; - this.layer.setZIndex(index); - - }, - - /** - * Method: moveLayerBack - * Moves the layer back to the position determined by the map's layers - * array. - */ - moveLayerBack: function() { - var index = this.layer.getZIndex() - 1; - if (index >= this.map.Z_INDEX_BASE['Feature']) { - this.layer.setZIndex(index); - } else { - this.map.setLayerZIndex(this.layer, - this.map.getLayerIndex(this.layer)); - } - }, - - CLASS_NAME: "OpenLayers.Handler.Feature" -}); -/* ====================================================================== - OpenLayers/StyleMap.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/BaseTypes/Class.js - * @requires OpenLayers/Style.js - * @requires OpenLayers/Feature/Vector.js - */ - -/** - * Class: OpenLayers.StyleMap - */ -OpenLayers.StyleMap = OpenLayers.Class({ - - /** - * Property: styles - * {Object} Hash of {}, keyed by names of well known - * rendering intents (e.g. "default", "temporary", "select", "delete"). - */ - styles: null, - - /** - * Property: extendDefault - * {Boolean} if true, every render intent will extend the symbolizers - * specified for the "default" intent at rendering time. Otherwise, every - * rendering intent will be treated as a completely independent style. - */ - extendDefault: true, - - /** - * Constructor: OpenLayers.StyleMap - * - * Parameters: - * style - {Object} Optional. Either a style hash, or a style object, or - * a hash of style objects (style hashes) keyed by rendering - * intent. If just one style hash or style object is passed, - * this will be used for all known render intents (default, - * select, temporary) - * options - {Object} optional hash of additional options for this - * instance - */ - initialize: function (style, options) { - this.styles = { - "default": new OpenLayers.Style( - OpenLayers.Feature.Vector.style["default"]), - "select": new OpenLayers.Style( - OpenLayers.Feature.Vector.style["select"]), - "temporary": new OpenLayers.Style( - OpenLayers.Feature.Vector.style["temporary"]), - "delete": new OpenLayers.Style( - OpenLayers.Feature.Vector.style["delete"]) - }; - - // take whatever the user passed as style parameter and convert it - // into parts of stylemap. - if(style instanceof OpenLayers.Style) { - // user passed a style object - this.styles["default"] = style; - this.styles["select"] = style; - this.styles["temporary"] = style; - this.styles["delete"] = style; - } else if(typeof style == "object") { - for(var key in style) { - if(style[key] instanceof OpenLayers.Style) { - // user passed a hash of style objects - this.styles[key] = style[key]; - } else if(typeof style[key] == "object") { - // user passsed a hash of style hashes - this.styles[key] = new OpenLayers.Style(style[key]); - } else { - // user passed a style hash (i.e. symbolizer) - this.styles["default"] = new OpenLayers.Style(style); - this.styles["select"] = new OpenLayers.Style(style); - this.styles["temporary"] = new OpenLayers.Style(style); - this.styles["delete"] = new OpenLayers.Style(style); - break; - } - } - } - OpenLayers.Util.extend(this, options); - }, - - /** - * Method: destroy - */ - destroy: function() { - for(var key in this.styles) { - this.styles[key].destroy(); - } - this.styles = null; - }, - - /** - * Method: createSymbolizer - * Creates the symbolizer for a feature for a render intent. - * - * Parameters: - * feature - {} The feature to evaluate the rules - * of the intended style against. - * intent - {String} The intent determines the symbolizer that will be - * used to draw the feature. Well known intents are "default" - * (for just drawing the features), "select" (for selected - * features) and "temporary" (for drawing features). - * - * Returns: - * {Object} symbolizer hash - */ - createSymbolizer: function(feature, intent) { - if(!feature) { - feature = new OpenLayers.Feature.Vector(); - } - if(!this.styles[intent]) { - intent = "default"; - } - feature.renderIntent = intent; - var defaultSymbolizer = {}; - if(this.extendDefault && intent != "default") { - defaultSymbolizer = this.styles["default"].createSymbolizer(feature); - } - return OpenLayers.Util.extend(defaultSymbolizer, - this.styles[intent].createSymbolizer(feature)); - }, - - /** - * Method: addUniqueValueRules - * Convenience method to create comparison rules for unique values of a - * property. The rules will be added to the style object for a specified - * rendering intent. This method is a shortcut for creating something like - * the "unique value legends" familiar from well known desktop GIS systems - * - * Parameters: - * renderIntent - {String} rendering intent to add the rules to - * property - {String} values of feature attributes to create the - * rules for - * symbolizers - {Object} Hash of symbolizers, keyed by the desired - * property values - * context - {Object} An optional object with properties that - * symbolizers' property values should be evaluated - * against. If no context is specified, feature.attributes - * will be used - */ - addUniqueValueRules: function(renderIntent, property, symbolizers, context) { - var rules = []; - for (var value in symbolizers) { - rules.push(new OpenLayers.Rule({ - symbolizer: symbolizers[value], - context: context, - filter: new OpenLayers.Filter.Comparison({ - type: OpenLayers.Filter.Comparison.EQUAL_TO, - property: property, - value: value - }) - })); - } - this.styles[renderIntent].addRules(rules); - }, - - CLASS_NAME: "OpenLayers.StyleMap" -}); -/* ====================================================================== - OpenLayers/Layer/Vector.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Layer.js - * @requires OpenLayers/Renderer.js - * @requires OpenLayers/StyleMap.js - * @requires OpenLayers/Feature/Vector.js - * @requires OpenLayers/Console.js - * @requires OpenLayers/Lang.js - */ - -/** - * Class: OpenLayers.Layer.Vector - * Instances of OpenLayers.Layer.Vector are used to render vector data from - * a variety of sources. Create a new vector layer with the - * constructor. - * - * Inherits from: - * - - */ -OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, { - - /** - * APIProperty: events - * {} - * - * Register a listener for a particular event with the following syntax: - * (code) - * layer.events.register(type, obj, listener); - * (end) - * - * Listeners will be called with a reference to an event object. The - * properties of this event depends on exactly what happened. - * - * All event objects have at least the following properties: - * object - {Object} A reference to layer.events.object. - * element - {DOMElement} A reference to layer.events.element. - * - * Supported map event types (in addition to those from ): - * beforefeatureadded - Triggered before a feature is added. Listeners - * will receive an object with a *feature* property referencing the - * feature to be added. To stop the feature from being added, a - * listener should return false. - * beforefeaturesadded - Triggered before an array of features is added. - * Listeners will receive an object with a *features* property - * referencing the feature to be added. To stop the features from - * being added, a listener should return false. - * featureadded - Triggered after a feature is added. The event - * object passed to listeners will have a *feature* property with a - * reference to the added feature. - * featuresadded - Triggered after features are added. The event - * object passed to listeners will have a *features* property with a - * reference to an array of added features. - * beforefeatureremoved - Triggered before a feature is removed. Listeners - * will receive an object with a *feature* property referencing the - * feature to be removed. - * beforefeaturesremoved - Triggered before multiple features are removed. - * Listeners will receive an object with a *features* property - * referencing the features to be removed. - * featureremoved - Triggerd after a feature is removed. The event - * object passed to listeners will have a *feature* property with a - * reference to the removed feature. - * featuresremoved - Triggered after features are removed. The event - * object passed to listeners will have a *features* property with a - * reference to an array of removed features. - * beforefeatureselected - Triggered before a feature is selected. Listeners - * will receive an object with a *feature* property referencing the - * feature to be selected. To stop the feature from being selectd, a - * listener should return false. - * featureselected - Triggered after a feature is selected. Listeners - * will receive an object with a *feature* property referencing the - * selected feature. - * featureunselected - Triggered after a feature is unselected. - * Listeners will receive an object with a *feature* property - * referencing the unselected feature. - * beforefeaturemodified - Triggered when a feature is selected to - * be modified. Listeners will receive an object with a *feature* - * property referencing the selected feature. - * featuremodified - Triggered when a feature has been modified. - * Listeners will receive an object with a *feature* property referencing - * the modified feature. - * afterfeaturemodified - Triggered when a feature is finished being modified. - * Listeners will receive an object with a *feature* property referencing - * the modified feature. - * vertexmodified - Triggered when a vertex within any feature geometry - * has been modified. Listeners will receive an object with a - * *feature* property referencing the modified feature, a *vertex* - * property referencing the vertex modified (always a point geometry), - * and a *pixel* property referencing the pixel location of the - * modification. - * vertexremoved - Triggered when a vertex within any feature geometry - * has been deleted. Listeners will receive an object with a - * *feature* property referencing the modified feature, a *vertex* - * property referencing the vertex modified (always a point geometry), - * and a *pixel* property referencing the pixel location of the - * removal. - * sketchstarted - Triggered when a feature sketch bound for this layer - * is started. Listeners will receive an object with a *feature* - * property referencing the new sketch feature and a *vertex* property - * referencing the creation point. - * sketchmodified - Triggered when a feature sketch bound for this layer - * is modified. Listeners will receive an object with a *vertex* - * property referencing the modified vertex and a *feature* property - * referencing the sketch feature. - * sketchcomplete - Triggered when a feature sketch bound for this layer - * is complete. Listeners will receive an object with a *feature* - * property referencing the sketch feature. By returning false, a - * listener can stop the sketch feature from being added to the layer. - * refresh - Triggered when something wants a strategy to ask the protocol - * for a new set of features. - */ - - /** - * APIProperty: isBaseLayer - * {Boolean} The layer is a base layer. Default is false. Set this property - * in the layer options. - */ - isBaseLayer: false, - - /** - * APIProperty: isFixed - * {Boolean} Whether the layer remains in one place while dragging the - * map. - */ - isFixed: false, - - /** - * APIProperty: features - * {Array()} - */ - features: null, - - /** - * Property: filter - * {} The filter set in this layer, - * a strategy launching read requests can combined - * this filter with its own filter. - */ - filter: null, - - /** - * Property: selectedFeatures - * {Array()} - */ - selectedFeatures: null, - - /** - * Property: unrenderedFeatures - * {Object} hash of features, keyed by feature.id, that the renderer - * failed to draw - */ - unrenderedFeatures: null, - - /** - * APIProperty: reportError - * {Boolean} report friendly error message when loading of renderer - * fails. - */ - reportError: true, - - /** - * APIProperty: style - * {Object} Default style for the layer - */ - style: null, - - /** - * Property: styleMap - * {} - */ - styleMap: null, - - /** - * Property: strategies - * {Array(})} Optional list of strategies for the layer. - */ - strategies: null, - - /** - * Property: protocol - * {} Optional protocol for the layer. - */ - protocol: null, - - /** - * Property: renderers - * {Array(String)} List of supported Renderer classes. Add to this list to - * add support for additional renderers. This list is ordered: - * the first renderer which returns true for the 'supported()' - * method will be used, if not defined in the 'renderer' option. - */ - renderers: ['SVG', 'VML', 'Canvas'], - - /** - * Property: renderer - * {} - */ - renderer: null, - - /** - * APIProperty: rendererOptions - * {Object} Options for the renderer. See {} for - * supported options. - */ - rendererOptions: null, - - /** - * APIProperty: geometryType - * {String} geometryType allows you to limit the types of geometries this - * layer supports. This should be set to something like - * "OpenLayers.Geometry.Point" to limit types. - */ - geometryType: null, - - /** - * Property: drawn - * {Boolean} Whether the Vector Layer features have been drawn yet. - */ - drawn: false, - - /** - * APIProperty: ratio - * {Float} This specifies the ratio of the size of the visiblity of the Vector Layer features to the size of the map. - */ - ratio: 1, - - /** - * 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: - * {} A new vector layer - */ - initialize: function(name, options) { - 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} 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} - */ - setMap: function(map) { - OpenLayers.Layer.prototype.setMap.apply(this, arguments); - - if (!this.renderer) { - this.map.removeLayer(this); - } else { - this.renderer.map = this.map; - - var newSize = this.map.getSize(); - newSize.w = newSize.w * this.ratio; - newSize.h = newSize.h * this.ratio; - this.renderer.setSize(newSize); - } - }, - - /** - * 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} - */ - removeMap: function(map) { - this.drawn = false; - if(this.strategies) { - var strategy, i, len; - for(i=0, len=this.strategies.length; i} - * 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'; - - var viewSize = this.map.getSize(), - viewWidth = viewSize.w, - viewHeight = viewSize.h, - offsetLeft = (viewWidth / 2 * this.ratio) - viewWidth / 2, - offsetTop = (viewHeight / 2 * this.ratio) - viewHeight / 2; - offsetLeft += this.map.layerContainerOriginPx.x; - offsetLeft = -Math.round(offsetLeft); - offsetTop += this.map.layerContainerOriginPx.y; - offsetTop = -Math.round(offsetTop); - - this.div.style.left = offsetLeft + 'px'; - this.div.style.top = offsetTop + 'px'; - - var extent = this.map.getExtent().scale(this.ratio); - 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)} - * options - {Object} - */ - addFeatures: function(features, options) { - if (!(OpenLayers.Util.isArray(features))) { - 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)} 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 (!(OpenLayers.Util.isArray(features))) { - 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()} 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 - {} - * 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); - } - } - - var drawn = this.renderer.drawFeature(feature, style); - //TODO remove the check for null when we get rid of Renderer.SVG - if (drawn === false || drawn === null) { - this.unrenderedFeatures[feature.id] = feature; - } else { - delete this.unrenderedFeatures[feature.id]; - } - }, - - /** - * Method: eraseFeatures - * Erase features from the layer. - * - * Parameters: - * features - {Array()} - */ - 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: - * {} A feature if one was under the event. - */ - getFeatureFromEvent: function(evt) { - if (!this.renderer) { - throw new Error('getFeatureFromEvent called on layer with no ' + - 'renderer. This usually means you destroyed a ' + - 'layer, but not some handler which is associated ' + - 'with it.'); - } - var feature = null; - var featureId = this.renderer.getFeatureIdFromEvent(evt); - if (featureId) { - if (typeof featureId === "string") { - feature = this.getFeatureById(featureId); - } else { - feature = featureId; - } - } - return feature; - }, - - /** - * APIMethod: getFeatureBy - * Given a property value, return the feature if it exists in the features array - * - * Parameters: - * property - {String} - * value - {String} - * - * Returns: - * {} 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} 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: - * {} 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({}) 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. - * - * Parameters: - * feature - {} - */ - 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 - {} - */ - preFeatureInsert: function(feature) { - }, - - /** - * APIMethod: getDataExtent - * Calculates the max extent which includes all of the features. - * - * Returns: - * {} or null if the layer has no features with - * geometries. - */ - getDataExtent: function () { - var maxExtent = null; - var features = this.features; - if(features && (features.length > 0)) { - var geometry = null; - for(var i=0, len=features.length; i - */ -OpenLayers.Layer.Vector.RootContainer = OpenLayers.Class(OpenLayers.Layer.Vector, { - - /** - * Property: displayInLayerSwitcher - * Set to false for this layer type - */ - displayInLayerSwitcher: false, - - /** - * APIProperty: layers - * Layers that are attached to this container. Required config option. - */ - layers: null, - - /** - * Constructor: OpenLayers.Layer.Vector.RootContainer - * Create a new root container for multiple vector layer. This constructor - * is not supposed to be used from user space, it is only to be used by - * controls that need feature selection across multiple vector layers. - * - * Parameters: - * name - {String} A name for the layer - * options - {Object} Optional object with non-default properties to set on - * the layer. - * - * Required options properties: - * layers - {Array()} The layers managed by this - * container - * - * Returns: - * {} A new vector layer root - * container - */ - - /** - * Method: display - */ - display: function() {}, - - /** - * Method: getFeatureFromEvent - * walk through the layers to find the feature returned by the event - * - * Parameters: - * evt - {Object} event object with a feature property - * - * Returns: - * {} - */ - getFeatureFromEvent: function(evt) { - var layers = this.layers; - var feature; - for(var i=0; i} - */ - setMap: function(map) { - OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments); - this.collectRoots(); - map.events.register("changelayer", this, this.handleChangeLayer); - }, - - /** - * Method: removeMap - * - * Parameters: - * map - {} - */ - removeMap: function(map) { - map.events.unregister("changelayer", this, this.handleChangeLayer); - this.resetRoots(); - OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments); - }, - - /** - * Method: collectRoots - * Collects the root nodes of all layers this control is configured with - * and moveswien the nodes to this control's layer - */ - collectRoots: function() { - var layer; - // walk through all map layers, because we want to keep the order - for(var i=0; i - */ -OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, { - - /** - * APIProperty: events - * {} Events instance for listeners and triggering - * control specific events. - * - * Register a listener for a particular event with the following syntax: - * (code) - * control.events.register(type, obj, listener); - * (end) - * - * Supported event types (in addition to those from ): - * beforefeaturehighlighted - Triggered before a feature is highlighted - * featurehighlighted - Triggered when a feature is highlighted - * featureunhighlighted - Triggered when a feature is unhighlighted - * boxselectionstart - Triggered before box selection starts - * boxselectionend - Triggered after box selection ends - */ - - /** - * Property: multipleKey - * {String} An event modifier ('altKey' or 'shiftKey') that temporarily sets - * the property to true. Default is null. - */ - multipleKey: null, - - /** - * Property: toggleKey - * {String} An event modifier ('altKey' or 'shiftKey') that temporarily sets - * the property to true. Default is null. - */ - toggleKey: null, - - /** - * APIProperty: multiple - * {Boolean} Allow selection of multiple geometries. Default is false. - */ - multiple: false, - - /** - * APIProperty: clickout - * {Boolean} Unselect features when clicking outside any feature. - * Default is true. - */ - clickout: true, - - /** - * APIProperty: toggle - * {Boolean} Unselect a selected feature on click. Default is false. Only - * has meaning if hover is false. - */ - toggle: false, - - /** - * APIProperty: hover - * {Boolean} Select on mouse over and deselect on mouse out. If true, this - * ignores clicks and only listens to mouse moves. - */ - hover: false, - - /** - * APIProperty: highlightOnly - * {Boolean} If true do not actually select features (that is place them in - * the layer's selected features array), just highlight them. This property - * has no effect if hover is false. Defaults to false. - */ - highlightOnly: false, - - /** - * APIProperty: box - * {Boolean} Allow feature selection by drawing a box. - */ - box: false, - - /** - * Property: onBeforeSelect - * {Function} Optional function to be called before a feature is selected. - * The function should expect to be called with a feature. - */ - onBeforeSelect: function() {}, - - /** - * APIProperty: onSelect - * {Function} Optional function to be called when a feature is selected. - * The function should expect to be called with a feature. - */ - onSelect: function() {}, - - /** - * APIProperty: onUnselect - * {Function} Optional function to be called when a feature is unselected. - * The function should expect to be called with a feature. - */ - onUnselect: function() {}, - - /** - * Property: scope - * {Object} The scope to use with the onBeforeSelect, onSelect, onUnselect - * callbacks. If null the scope will be this control. - */ - scope: null, - - /** - * APIProperty: geometryTypes - * {Array(String)} To restrict selecting to a limited set of geometry types, - * send a list of strings corresponding to the geometry class names. - */ - geometryTypes: null, - - /** - * Property: layer - * {} The vector layer with a common renderer - * root for all layers this control is configured with (if an array of - * layers was passed to the constructor), or the vector layer the control - * was configured with (if a single layer was passed to the constructor). - */ - layer: null, - - /** - * Property: layers - * {Array()} The layers this control will work on, - * or null if the control was configured with a single layer - */ - layers: null, - - /** - * APIProperty: callbacks - * {Object} The functions that are sent to the handlers.feature for callback - */ - callbacks: null, - - /** - * APIProperty: selectStyle - * {Object} Hash of styles - */ - selectStyle: null, - - /** - * Property: renderIntent - * {String} key used to retrieve the select style from the layer's - * style map. - */ - renderIntent: "select", - - /** - * Property: handlers - * {Object} Object with references to multiple - * instances. - */ - handlers: null, - - /** - * Constructor: OpenLayers.Control.SelectFeature - * Create a new control for selecting features. - * - * Parameters: - * layers - {}, or an array of vector layers. The - * layer(s) this control will select features from. - * options - {Object} - */ - initialize: function(layers, options) { - OpenLayers.Control.prototype.initialize.apply(this, [options]); - - if(this.scope === null) { - this.scope = this; - } - this.initLayer(layers); - var callbacks = { - click: this.clickFeature, - clickout: this.clickoutFeature - }; - if (this.hover) { - callbacks.over = this.overFeature; - callbacks.out = this.outFeature; - } - - this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks); - this.handlers = { - feature: new OpenLayers.Handler.Feature( - this, this.layer, this.callbacks, - {geometryTypes: this.geometryTypes} - ) - }; - - if (this.box) { - this.handlers.box = new OpenLayers.Handler.Box( - this, {done: this.selectBox}, - {boxDivClassName: "olHandlerBoxSelectFeature"} - ); - } - }, - - /** - * Method: initLayer - * Assign the layer property. If layers is an array, we need to use - * a RootContainer. - * - * Parameters: - * layers - {}, or an array of vector layers. - */ - initLayer: function(layers) { - if(OpenLayers.Util.isArray(layers)) { - this.layers = layers; - this.layer = new OpenLayers.Layer.Vector.RootContainer( - this.id + "_container", { - layers: layers - } - ); - } else { - this.layer = layers; - } - }, - - /** - * Method: destroy - */ - destroy: function() { - if(this.active && this.layers) { - this.map.removeLayer(this.layer); - } - OpenLayers.Control.prototype.destroy.apply(this, arguments); - if(this.layers) { - this.layer.destroy(); - } - }, - - /** - * Method: activate - * Activates the control. - * - * Returns: - * {Boolean} The control was effectively activated. - */ - activate: function () { - if (!this.active) { - if(this.layers) { - this.map.addLayer(this.layer); - } - this.handlers.feature.activate(); - if(this.box && this.handlers.box) { - this.handlers.box.activate(); - } - } - return OpenLayers.Control.prototype.activate.apply( - this, arguments - ); - }, - - /** - * Method: deactivate - * Deactivates the control. - * - * Returns: - * {Boolean} The control was effectively deactivated. - */ - deactivate: function () { - if (this.active) { - this.handlers.feature.deactivate(); - if(this.handlers.box) { - this.handlers.box.deactivate(); - } - if(this.layers) { - this.map.removeLayer(this.layer); - } - } - return OpenLayers.Control.prototype.deactivate.apply( - this, arguments - ); - }, - - /** - * Method: unselectAll - * Unselect all selected features. To unselect all except for a single - * feature, set the options.except property to the feature. - * - * Parameters: - * options - {Object} Optional configuration object. - */ - unselectAll: function(options) { - // we'll want an option to supress notification here - var layers = this.layers || [this.layer], - layer, feature, l, numExcept; - for(l=0; l numExcept) { - feature = layer.selectedFeatures[numExcept]; - if(!options || options.except != feature) { - this.unselect(feature); - } else { - ++numExcept; - } - } - } - }, - - /** - * Method: clickFeature - * Called on click in a feature - * Only responds if this.hover is false. - * - * Parameters: - * feature - {} - */ - clickFeature: function(feature) { - if(!this.hover) { - var selected = (OpenLayers.Util.indexOf( - feature.layer.selectedFeatures, feature) > -1); - if(selected) { - if(this.toggleSelect()) { - this.unselect(feature); - } else if(!this.multipleSelect()) { - this.unselectAll({except: feature}); - } - } else { - if(!this.multipleSelect()) { - this.unselectAll({except: feature}); - } - this.select(feature); - } - } - }, - - /** - * Method: multipleSelect - * Allow for multiple selected features based on property and - * event modifier. - * - * Returns: - * {Boolean} Allow for multiple selected features. - */ - multipleSelect: function() { - return this.multiple || (this.handlers.feature.evt && - this.handlers.feature.evt[this.multipleKey]); - }, - - /** - * Method: toggleSelect - * Event should toggle the selected state of a feature based on - * property and event modifier. - * - * Returns: - * {Boolean} Toggle the selected state of a feature. - */ - toggleSelect: function() { - return this.toggle || (this.handlers.feature.evt && - this.handlers.feature.evt[this.toggleKey]); - }, - - /** - * Method: clickoutFeature - * Called on click outside a previously clicked (selected) feature. - * Only responds if this.hover is false. - * - * Parameters: - * feature - {} - */ - clickoutFeature: function(feature) { - if(!this.hover && this.clickout) { - this.unselectAll(); - } - }, - - /** - * Method: overFeature - * Called on over a feature. - * Only responds if this.hover is true. - * - * Parameters: - * feature - {} - */ - overFeature: function(feature) { - var layer = feature.layer; - if(this.hover) { - if(this.highlightOnly) { - this.highlight(feature); - } else if(OpenLayers.Util.indexOf( - layer.selectedFeatures, feature) == -1) { - this.select(feature); - } - } - }, - - /** - * Method: outFeature - * Called on out of a selected feature. - * Only responds if this.hover is true. - * - * Parameters: - * feature - {} - */ - outFeature: function(feature) { - if(this.hover) { - if(this.highlightOnly) { - // we do nothing if we're not the last highlighter of the - // feature - if(feature._lastHighlighter == this.id) { - // if another select control had highlighted the feature before - // we did it ourself then we use that control to highlight the - // feature as it was before we highlighted it, else we just - // unhighlight it - if(feature._prevHighlighter && - feature._prevHighlighter != this.id) { - delete feature._lastHighlighter; - var control = this.map.getControl( - feature._prevHighlighter); - if(control) { - control.highlight(feature); - } - } else { - this.unhighlight(feature); - } - } - } else { - this.unselect(feature); - } - } - }, - - /** - * Method: highlight - * Redraw feature with the select style. - * - * Parameters: - * feature - {} - */ - highlight: function(feature) { - var layer = feature.layer; - var cont = this.events.triggerEvent("beforefeaturehighlighted", { - feature : feature - }); - if(cont !== false) { - feature._prevHighlighter = feature._lastHighlighter; - feature._lastHighlighter = this.id; - var style = this.selectStyle || this.renderIntent; - layer.drawFeature(feature, style); - this.events.triggerEvent("featurehighlighted", {feature : feature}); - } - }, - - /** - * Method: unhighlight - * Redraw feature with the "default" style - * - * Parameters: - * feature - {} - */ - unhighlight: function(feature) { - var layer = feature.layer; - // three cases: - // 1. there's no other highlighter, in that case _prev is undefined, - // and we just need to undef _last - // 2. another control highlighted the feature after we did it, in - // that case _last references this other control, and we just - // need to undef _prev - // 3. another control highlighted the feature before we did it, in - // that case _prev references this other control, and we need to - // set _last to _prev and undef _prev - if(feature._prevHighlighter == undefined) { - delete feature._lastHighlighter; - } else if(feature._prevHighlighter == this.id) { - delete feature._prevHighlighter; - } else { - feature._lastHighlighter = feature._prevHighlighter; - delete feature._prevHighlighter; - } - layer.drawFeature(feature, feature.style || feature.layer.style || - "default"); - this.events.triggerEvent("featureunhighlighted", {feature : feature}); - }, - - /** - * Method: select - * Add feature to the layer's selectedFeature array, render the feature as - * selected, and call the onSelect function. - * - * Parameters: - * feature - {} - */ - select: function(feature) { - var cont = this.onBeforeSelect.call(this.scope, feature); - var layer = feature.layer; - if(cont !== false) { - cont = layer.events.triggerEvent("beforefeatureselected", { - feature: feature - }); - if(cont !== false) { - layer.selectedFeatures.push(feature); - this.highlight(feature); - // if the feature handler isn't involved in the feature - // selection (because the box handler is used or the - // feature is selected programatically) we fake the - // feature handler to allow unselecting on click - if(!this.handlers.feature.lastFeature) { - this.handlers.feature.lastFeature = layer.selectedFeatures[0]; - } - layer.events.triggerEvent("featureselected", {feature: feature}); - this.onSelect.call(this.scope, feature); - } - } - }, - - /** - * Method: unselect - * Remove feature from the layer's selectedFeature array, render the feature as - * normal, and call the onUnselect function. - * - * Parameters: - * feature - {} - */ - unselect: function(feature) { - var layer = feature.layer; - // Store feature style for restoration later - this.unhighlight(feature); - OpenLayers.Util.removeItem(layer.selectedFeatures, feature); - layer.events.triggerEvent("featureunselected", {feature: feature}); - this.onUnselect.call(this.scope, feature); - }, - - /** - * Method: selectBox - * Callback from the handlers.box set up when selection is true - * on. - * - * Parameters: - * position - { || } - */ - selectBox: function(position) { - if (position instanceof OpenLayers.Bounds) { - var minXY = this.map.getLonLatFromPixel({ - x: position.left, - y: position.bottom - }); - var maxXY = this.map.getLonLatFromPixel({ - x: position.right, - y: position.top - }); - var bounds = new OpenLayers.Bounds( - minXY.lon, minXY.lat, maxXY.lon, maxXY.lat - ); - - // if multiple is false, first deselect currently selected features - if (!this.multipleSelect()) { - this.unselectAll(); - } - - // because we're using a box, we consider we want multiple selection - var prevMultiple = this.multiple; - this.multiple = true; - var layers = this.layers || [this.layer]; - this.events.triggerEvent("boxselectionstart", {layers: layers}); - var layer; - for(var l=0; l -1) { - if (bounds.toGeometry().intersects(feature.geometry)) { - if (OpenLayers.Util.indexOf(layer.selectedFeatures, feature) == -1) { - this.select(feature); - } - } - } - } - } - this.multiple = prevMultiple; - this.events.triggerEvent("boxselectionend", {layers: layers}); - } - }, - - /** - * Method: setMap - * Set the map property for the control. - * - * Parameters: - * map - {} - */ - setMap: function(map) { - this.handlers.feature.setMap(map); - if (this.box) { - this.handlers.box.setMap(map); - } - OpenLayers.Control.prototype.setMap.apply(this, arguments); - }, - - /** - * APIMethod: setLayer - * Attach a new layer to the control, overriding any existing layers. - * - * Parameters: - * layers - Array of {} or a single - * {} - */ - setLayer: function(layers) { - var isActive = this.active; - this.unselectAll(); - this.deactivate(); - if(this.layers) { - this.layer.destroy(); - this.layers = null; - } - this.initLayer(layers); - this.handlers.feature.layer = this.layer; - if (isActive) { - this.activate(); - } - }, - - CLASS_NAME: "OpenLayers.Control.SelectFeature" -}); -/* ====================================================================== - OpenLayers/Handler/Point.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/Handler.js - * @requires OpenLayers/Geometry/Point.js - */ - -/** - * Class: OpenLayers.Handler.Point - * Handler to draw a point on the map. Point is displayed on activation, - * 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 - * constructor. - * - * Inherits from: - * - - */ -OpenLayers.Handler.Point = OpenLayers.Class(OpenLayers.Handler, { - - /** - * Property: point - * {} The currently drawn point - */ - point: null, - - /** - * Property: layer - * {} 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, - - /** - * APIProperty: citeCompliant - * {Boolean} If set to true, coordinates of features drawn in a map extent - * crossing the date line won't exceed the world bounds. Default is false. - */ - citeCompliant: false, - - /** - * Property: mouseDown - * {Boolean} The mouse is down - */ - mouseDown: false, - - /** - * Property: stoppedDown - * {Boolean} Indicate whether the last mousedown stopped the event - * propagation. - */ - stoppedDown: null, - - /** - * Property: lastDown - * {} Location of the last mouse down - */ - lastDown: null, - - /** - * Property: lastUp - * {} - */ - 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, - - /** - * APIProperty: stopDown - * {Boolean} Stop event propagation on mousedown. Must be false to - * allow "pan while drawing". Defaults to false. - */ - stopDown: false, - - /** - * APIPropery: stopUp - * {Boolean} Stop event propagation on mouse. Must be false to - * allow "pan while dragging". Defaults to fase. - */ - stopUp: false, - - /** - * Property: layerOptions - * {Object} Any optional properties to be set on the sketch layer. - */ - layerOptions: null, - - /** - * APIProperty: pixelTolerance - * {Number} Maximum number of pixels between down and up (mousedown - * and mouseup, or touchstart and touchend) for the handler to - * add a new point. If set to an integer value, if the - * displacement between down and up is great to this value - * no point will be added. Default value is 5. - */ - pixelTolerance: 5, - - /** - * Property: touch - * {Boolean} Indcates the support of touch events. - */ - touch: false, - - /** - * Property: lastTouchPx - * {} The last pixel used to know the distance between - * two touches (for double touch). - */ - lastTouchPx: null, - - /** - * Constructor: OpenLayers.Handler.Point - * Create a new point handler. - * - * Parameters: - * control - {} The control that owns this handler - * callbacks - {Object} An object with a properties whose values are - * functions. Various callbacks described below. - * options - {Object} An optional object with properties to be set on the - * handler - * - * Named callbacks: - * create - Called when a sketch is first created. Callback called with - * the creation point geometry and sketch feature. - * modify - Called with each move of a vertex with the vertex (point) - * geometry and the sketch feature. - * 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, - wrapDateLine: this.citeCompliant - }, 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 - {} A pixel location on the map. - */ - createFeature: function(pixel) { - var lonlat = this.layer.getLonLatFromViewPortPx(pixel); - var geometry = new OpenLayers.Geometry.Point( - lonlat.lon, lonlat.lat - ); - this.point = new OpenLayers.Feature.Vector(geometry); - this.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; - } - 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.destroyFeature(true); - this.layer.destroy(false); - } - this.layer = null; - this.touch = false; - return true; - }, - - /** - * Method: destroyFeature - * Destroy the temporary geometries - * - * Parameters: - * force - {Boolean} Destroy even if persist is true. - */ - destroyFeature: function(force) { - if(this.layer && (force || !this.persist)) { - this.layer.destroyFeatures(); - } - this.point = null; - }, - - /** - * Method: destroyPersistedFeature - * Destroy the persisted feature. - */ - destroyPersistedFeature: function() { - var layer = this.layer; - if(layer && layer.features.length > 1) { - this.layer.features[0].destroy(); - } - }, - - /** - * 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.mouseDown = false; - this.lastDown = null; - this.lastUp = null; - this.lastTouchPx = null; - this.callback(key, [this.geometryClone()]); - this.destroyFeature(cancel); - }, - - /** - * 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 - {} A pixel location on the map. - */ - modifyFeature: function(pixel) { - if(!this.point) { - this.createFeature(pixel); - } - var lonlat = this.layer.getLonLatFromViewPortPx(pixel); - this.point.geometry.x = lonlat.lon; - this.point.geometry.y = lonlat.lat; - this.callback("modify", [this.point.geometry, this.point, false]); - 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 is true, this will return - * a multi-part geometry. - * - * Returns: - * {} - */ - 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: - * {} - */ - geometryClone: function() { - var geom = this.getGeometry(); - return geom && geom.clone(); - }, - - /** - * Method: mousedown - * Handle mousedown. - * - * Parameters: - * evt - {Event} The browser event - * - * Returns: - * {Boolean} Allow event propagation - */ - mousedown: function(evt) { - return this.down(evt); - }, - - /** - * Method: touchstart - * Handle touchstart. - * - * Parameters: - * evt - {Event} The browser event - * - * Returns: - * {Boolean} Allow event propagation - */ - touchstart: function(evt) { - if (!this.touch) { - this.touch = true; - // unregister mouse listeners - this.map.events.un({ - mousedown: this.mousedown, - mouseup: this.mouseup, - mousemove: this.mousemove, - click: this.click, - dblclick: this.dblclick, - scope: this - }); - } - this.lastTouchPx = evt.xy; - return this.down(evt); - }, - - /** - * Method: mousemove - * Handle mousemove. - * - * Parameters: - * evt - {Event} The browser event - * - * Returns: - * {Boolean} Allow event propagation - */ - mousemove: function(evt) { - return this.move(evt); - }, - - /** - * Method: touchmove - * Handle touchmove. - * - * Parameters: - * evt - {Event} The browser event - * - * Returns: - * {Boolean} Allow event propagation - */ - touchmove: function(evt) { - this.lastTouchPx = evt.xy; - return this.move(evt); - }, - - /** - * Method: mouseup - * Handle mouseup. - * - * Parameters: - * evt - {Event} The browser event - * - * Returns: - * {Boolean} Allow event propagation - */ - mouseup: function(evt) { - return this.up(evt); - }, - - /** - * Method: touchend - * Handle touchend. - * - * Parameters: - * evt - {Event} The browser event - * - * Returns: - * {Boolean} Allow event propagation - */ - touchend: function(evt) { - evt.xy = this.lastTouchPx; - return this.up(evt); - }, - - /** - * Method: down - * Handle mousedown and touchstart. 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 - */ - down: function(evt) { - this.mouseDown = true; - this.lastDown = evt.xy; - if(!this.touch) { // no point displayed until up on touch devices - this.modifyFeature(evt.xy); - } - this.stoppedDown = this.stopDown; - return !this.stopDown; - }, - - /** - * Method: move - * Handle mousemove and touchmove. 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 - */ - move: function (evt) { - if(!this.touch // no point displayed until up on touch devices - && (!this.mouseDown || this.stoppedDown)) { - this.modifyFeature(evt.xy); - } - return true; - }, - - /** - * Method: up - * Handle mouseup and touchend. 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 - */ - up: function (evt) { - this.mouseDown = false; - this.stoppedDown = this.stopDown; - - // check keyboard modifiers - if(!this.checkModifiers(evt)) { - return true; - } - // ignore double-clicks - if (this.lastUp && this.lastUp.equals(evt.xy)) { - return true; - } - if (this.lastDown && this.passesTolerance(this.lastDown, evt.xy, - this.pixelTolerance)) { - if (this.touch) { - this.modifyFeature(evt.xy); - } - if(this.persist) { - this.destroyPersistedFeature(); - } - this.lastUp = evt.xy; - this.finalize(); - return !this.stopUp; - } else { - return true; - } - }, - - /** - * Method: mouseout - * Handle mouse out. For better user experience reset mouseDown - * and stoppedDown when the mouse leaves the map viewport. - * - * Parameters: - * evt - {Event} The browser event - */ - mouseout: function(evt) { - if(OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) { - this.stoppedDown = this.stopDown; - this.mouseDown = false; - } - }, - - /** - * Method: passesTolerance - * Determine whether the event is within the optional pixel tolerance. - * - * Returns: - * {Boolean} The event is within the pixel tolerance (if specified). - */ - passesTolerance: function(pixel1, pixel2, tolerance) { - var passes = true; - - if (tolerance != null && pixel1 && pixel2) { - var dist = pixel1.distanceTo(pixel2); - if (dist > tolerance) { - passes = false; - } - } - return passes; - }, - - CLASS_NAME: "OpenLayers.Handler.Point" -}); -/* ====================================================================== - OpenLayers/Handler/Path.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/Handler/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.Path = OpenLayers.Class(OpenLayers.Handler.Point, { - - /** - * Property: line - * {} - */ - line: null, - - /** - * APIProperty: maxVertices - * {Number} The maximum number of vertices which can be drawn by this - * handler. When the number of vertices reaches maxVertices, the - * geometry is automatically finalized. Default is null. - */ - maxVertices: null, - - /** - * Property: doubleTouchTolerance - * {Number} Maximum number of pixels between two touches for - * the gesture to be considered a "finalize feature" action. - * Default is 20. - */ - doubleTouchTolerance: 20, - - /** - * 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', - - /** - * Property: timerId - * {Integer} The timer used to test the double touch. - */ - timerId: null, - - /** - * Property: redoStack - * {Array} Stack containing points removed with . - */ - redoStack: null, - - /** - * Constructor: OpenLayers.Handler.Path - * Create a new path hander - * - * Parameters: - * control - {} The control that owns this handler - * callbacks - {Object} An object with a properties whose values are - * functions. Various callbacks described below. - * options - {Object} An optional object with properties to be set on the - * handler - * - * Named callbacks: - * create - Called when a sketch is first created. Callback called with - * the creation point geometry and sketch feature. - * modify - Called with each move of a vertex with the vertex (point) - * geometry and the sketch feature. - * point - Called as each point is added. Receives the new point geometry. - * done - Called when the point drawing is finished. The callback will - * recieve a single argument, the linestring geometry. - * cancel - Called when the handler is deactivated while drawing. The - * cancel callback will receive a geometry. - */ - - /** - * Method: createFeature - * Add temporary geometries - * - * Parameters: - * pixel - {} The initial pixel location for the new - * feature. - */ - createFeature: function(pixel) { - var lonlat = this.layer.getLonLatFromViewPortPx(pixel); - var geometry = new OpenLayers.Geometry.Point( - lonlat.lon, lonlat.lat - ); - this.point = new OpenLayers.Feature.Vector(geometry); - this.line = new OpenLayers.Feature.Vector( - new OpenLayers.Geometry.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 - * - * Parameters: - * force - {Boolean} Destroy even if persist is true. - */ - destroyFeature: function(force) { - OpenLayers.Handler.Point.prototype.destroyFeature.call( - this, force); - this.line = null; - }, - - /** - * Method: destroyPersistedFeature - * Destroy the persisted feature. - */ - destroyPersistedFeature: function() { - var layer = this.layer; - if(layer && layer.features.length > 2) { - this.layer.features[0].destroy(); - } - }, - - /** - * 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 - {} The pixel location for the new point. - */ - addPoint: function(pixel) { - this.layer.removeFeatures([this.point]); - var lonlat = this.layer.getLonLatFromViewPortPx(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.layer.addFeatures([this.point]); - this.callback("point", [this.point.geometry, this.getGeometry()]); - this.callback("modify", [this.point.geometry, this.getSketch()]); - this.drawFeature(); - delete this.redoStack; - }, - - /** - * Method: insertXY - * Insert a point in the current sketch given x & y coordinates. The new - * point is inserted immediately before the most recently drawn point. - * - * Parameters: - * x - {Number} The x-coordinate of the point. - * y - {Number} The y-coordinate of the point. - */ - insertXY: function(x, y) { - this.line.geometry.addComponent( - new OpenLayers.Geometry.Point(x, y), - this.getCurrentPointIndex() - ); - this.drawFeature(); - delete this.redoStack; - }, - - /** - * Method: insertDeltaXY - * Insert a point given offsets from the previously inserted point. - * - * Parameters: - * dx - {Number} The x-coordinate offset of the point. - * dy - {Number} The y-coordinate offset of the point. - */ - insertDeltaXY: function(dx, dy) { - var previousIndex = this.getCurrentPointIndex() - 1; - var p0 = this.line.geometry.components[previousIndex]; - if (p0 && !isNaN(p0.x) && !isNaN(p0.y)) { - this.insertXY(p0.x + dx, p0.y + dy); - } - }, - - /** - * Method: insertDirectionLength - * Insert a point in the current sketch given a direction and a length. - * - * Parameters: - * direction - {Number} Degrees clockwise from the positive x-axis. - * length - {Number} Distance from the previously drawn point. - */ - insertDirectionLength: function(direction, length) { - direction *= Math.PI / 180; - var dx = length * Math.cos(direction); - var dy = length * Math.sin(direction); - this.insertDeltaXY(dx, dy); - }, - - /** - * Method: insertDeflectionLength - * Insert a point in the current sketch given a deflection and a length. - * The deflection should be degrees clockwise from the previously - * digitized segment. - * - * Parameters: - * deflection - {Number} Degrees clockwise from the previous segment. - * length - {Number} Distance from the previously drawn point. - */ - insertDeflectionLength: function(deflection, length) { - var previousIndex = this.getCurrentPointIndex() - 1; - if (previousIndex > 0) { - var p1 = this.line.geometry.components[previousIndex]; - var p0 = this.line.geometry.components[previousIndex-1]; - var theta = Math.atan2(p1.y - p0.y, p1.x - p0.x); - this.insertDirectionLength( - (theta * 180 / Math.PI) + deflection, length - ); - } - }, - - /** - * Method: getCurrentPointIndex - * - * Returns: - * {Number} The index of the most recently drawn point. - */ - getCurrentPointIndex: function() { - return this.line.geometry.components.length - 1; - }, - - - /** - * Method: undo - * Remove the most recently added point in the sketch geometry. - * - * Returns: - * {Boolean} A point was removed. - */ - undo: function() { - var geometry = this.line.geometry; - var components = geometry.components; - var index = this.getCurrentPointIndex() - 1; - var target = components[index]; - var undone = geometry.removeComponent(target); - if (undone) { - if (!this.redoStack) { - this.redoStack = []; - } - this.redoStack.push(target); - this.drawFeature(); - } - return undone; - }, - - /** - * Method: redo - * Reinsert the most recently removed point resulting from an call. - * The undo stack is deleted whenever a point is added by other means. - * - * Returns: - * {Boolean} A point was added. - */ - redo: function() { - var target = this.redoStack && this.redoStack.pop(); - if (target) { - this.line.geometry.addComponent(target, this.getCurrentPointIndex()); - this.drawFeature(); - } - return !!target; - }, - - /** - * 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 - {} The updated pixel location for the latest - * point. - * drawing - {Boolean} Indicate if we're currently drawing. - */ - modifyFeature: function(pixel, drawing) { - if(!this.line) { - this.createFeature(pixel); - } - var lonlat = this.layer.getLonLatFromViewPortPx(pixel); - this.point.geometry.x = lonlat.lon; - this.point.geometry.y = lonlat.lat; - this.callback("modify", [this.point.geometry, this.getSketch(), drawing]); - 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: - * {} - */ - getSketch: function() { - return this.line; - }, - - /** - * Method: getGeometry - * Return the sketch geometry. If is true, this will return - * a multi-part geometry. - * - * Returns: - * {} - */ - getGeometry: function() { - var geometry = this.line && this.line.geometry; - if(geometry && this.multi) { - geometry = new OpenLayers.Geometry.MultiLineString([geometry]); - } - return geometry; - }, - - /** - * method: touchstart - * handle touchstart. - * - * parameters: - * evt - {event} the browser event - * - * returns: - * {boolean} allow event propagation - */ - touchstart: function(evt) { - if (this.timerId && - this.passesTolerance(this.lastTouchPx, evt.xy, - this.doubleTouchTolerance)) { - // double-tap, finalize the geometry - this.finishGeometry(); - window.clearTimeout(this.timerId); - this.timerId = null; - return false; - } else { - if (this.timerId) { - window.clearTimeout(this.timerId); - this.timerId = null; - } - this.timerId = window.setTimeout( - OpenLayers.Function.bind(function() { - this.timerId = null; - }, this), 300); - return OpenLayers.Handler.Point.prototype.touchstart.call(this, evt); - } - }, - - /** - * Method: down - * Handle mousedown and touchstart. 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 - */ - down: function(evt) { - var stopDown = this.stopDown; - if(this.freehandMode(evt)) { - stopDown = true; - if (this.touch) { - this.modifyFeature(evt.xy, !!this.lastUp); - OpenLayers.Event.stop(evt); - } - } - if (!this.touch && (!this.lastDown || - !this.passesTolerance(this.lastDown, evt.xy, - this.pixelTolerance))) { - this.modifyFeature(evt.xy, !!this.lastUp); - } - this.mouseDown = true; - this.lastDown = evt.xy; - this.stoppedDown = stopDown; - return !stopDown; - }, - - /** - * Method: move - * Handle mousemove and touchmove. 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 - */ - move: function (evt) { - if(this.stoppedDown && this.freehandMode(evt)) { - if(this.persist) { - this.destroyPersistedFeature(); - } - if(this.maxVertices && this.line && - this.line.geometry.components.length === this.maxVertices) { - this.removePoint(); - this.finalize(); - } else { - this.addPoint(evt.xy); - } - return false; - } - if (!this.touch && (!this.mouseDown || this.stoppedDown)) { - this.modifyFeature(evt.xy, !!this.lastUp); - } - return true; - }, - - /** - * Method: up - * Handle mouseup and touchend. 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 - */ - up: function (evt) { - if (this.mouseDown && (!this.lastUp || !this.lastUp.equals(evt.xy))) { - if(this.stoppedDown && this.freehandMode(evt)) { - if (this.persist) { - this.destroyPersistedFeature(); - } - this.removePoint(); - this.finalize(); - } else { - if (this.passesTolerance(this.lastDown, evt.xy, - this.pixelTolerance)) { - if (this.touch) { - this.modifyFeature(evt.xy); - } - if(this.lastUp == null && this.persist) { - this.destroyPersistedFeature(); - } - this.addPoint(evt.xy); - this.lastUp = evt.xy; - if(this.line.geometry.components.length === this.maxVertices + 1) { - this.finishGeometry(); - } - } - } - } - this.stoppedDown = this.stopDown; - this.mouseDown = false; - return !this.stopUp; - }, - - /** - * 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/Control/Attribution.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Control.js - */ - -/** - * Class: OpenLayers.Control.Attribution - * The attribution control adds attribution from layers to the map display. - * It uses 'attribution' property of each layer. - * - * Inherits from: - * - - */ -OpenLayers.Control.Attribution = - OpenLayers.Class(OpenLayers.Control, { - - /** - * APIProperty: seperator - * {String} String used to seperate layers. - */ - separator: ", ", - - /** - * APIProperty: template - * {String} Template for the attribution. This has to include the substring - * "${layers}", which will be replaced by the layer specific - * attributions, separated by . The default is "${layers}". - */ - template: "${layers}", - - /** - * Constructor: OpenLayers.Control.Attribution - * - * Parameters: - * options - {Object} Options for control. - */ - - /** - * Method: destroy - * Destroy control. - */ - destroy: function() { - this.map.events.un({ - "removelayer": this.updateAttribution, - "addlayer": this.updateAttribution, - "changelayer": this.updateAttribution, - "changebaselayer": this.updateAttribution, - scope: this - }); - - OpenLayers.Control.prototype.destroy.apply(this, arguments); - }, - - /** - * Method: draw - * Initialize control. - * - * Returns: - * {DOMElement} A reference to the DIV DOMElement containing the control - */ - draw: function() { - OpenLayers.Control.prototype.draw.apply(this, arguments); - - this.map.events.on({ - 'changebaselayer': this.updateAttribution, - 'changelayer': this.updateAttribution, - 'addlayer': this.updateAttribution, - 'removelayer': this.updateAttribution, - scope: this - }); - this.updateAttribution(); - - return this.div; - }, - - /** - * Method: updateAttribution - * Update attribution string. - */ - updateAttribution: function() { - var attributions = []; - if (this.map && this.map.layers) { - for(var i=0, len=this.map.layers.length; i} The new position. - */ - update: function(xy) { - this.points.unshift({xy: xy, tick: new Date().getTime()}); - if (this.points.length > this.nbPoints) { - this.points.pop(); - } - }, - - /** - * Method: end - * Ends the dragging, start the kinetic. - * - * Parameters: - * xy - {} The last position. - * - * Returns: - * {Object} An object with two properties: "speed", and "theta". The - * "speed" and "theta" values are to be passed to the move - * function when starting the animation. - */ - end: function(xy) { - var last, now = new Date().getTime(); - for (var i = 0, l = this.points.length, point; i < l; i++) { - point = this.points[i]; - if (now - point.tick > this.delay) { - break; - } - last = point; - } - if (!last) { - return; - } - var time = new Date().getTime() - last.tick; - var dist = Math.sqrt(Math.pow(xy.x - last.xy.x, 2) + - Math.pow(xy.y - last.xy.y, 2)); - var speed = dist / time; - if (speed == 0 || speed < this.threshold) { - return; - } - var theta = Math.asin((xy.y - last.xy.y) / dist); - if (last.xy.x <= xy.x) { - theta = Math.PI - theta; - } - return {speed: speed, theta: theta}; - }, - - /** - * Method: move - * Launch the kinetic move pan. - * - * Parameters: - * info - {Object} An object with two properties, "speed", and "theta". - * These values are those returned from the "end" call. - * callback - {Function} Function called on every step of the animation, - * receives x, y (values to pan), end (is the last point). - */ - move: function(info, callback) { - var v0 = info.speed; - var fx = Math.cos(info.theta); - var fy = -Math.sin(info.theta); - - var initialTime = new Date().getTime(); - - var lastX = 0; - var lastY = 0; - - var timerCallback = function() { - if (this.timerId == null) { - return; - } - - var t = new Date().getTime() - initialTime; - - var p = (-this.deceleration * Math.pow(t, 2)) / 2.0 + v0 * t; - var x = p * fx; - var y = p * fy; - - var args = {}; - args.end = false; - var v = -this.deceleration * t + v0; - - if (v <= 0) { - OpenLayers.Animation.stop(this.timerId); - this.timerId = null; - args.end = true; - } - - args.x = x - lastX; - args.y = y - lastY; - lastX = x; - lastY = y; - callback(args.x, args.y, args.end); - }; - - this.timerId = OpenLayers.Animation.start( - OpenLayers.Function.bind(timerCallback, this) - ); - }, - - CLASS_NAME: "OpenLayers.Kinetic" -}); -/* ====================================================================== - OpenLayers/Handler/Drag.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Handler.js - */ - -/** - * Class: OpenLayers.Handler.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 constructor. - * - * Inherits from: - * - - */ -OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, { - - /** - * Property: started - * {Boolean} When a mousedown or touchstart 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: touch - * {Boolean} When a touchstart event is fired, touch will be true and all - * mouse related listeners will do nothing. - */ - touch: false, - - /** - * Property: last - * {} The last pixel location of the drag. - */ - last: null, - - /** - * Property: start - * {} The first pixel location of the drag. - */ - start: null, - - /** - * Property: lastMoveEvt - * {Object} The last mousemove event that occurred. Used to - * position the map correctly when our "delay drag" - * timeout expired. - */ - lastMoveEvt: 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 - {} 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}}); - }; - } - }, - - - /** - * Method: dragstart - * This private method is factorized from mousedown and touchstart methods - * - * Parameters: - * evt - {Event} The event - * - * Returns: - * {Boolean} Let the event propagate. - */ - dragstart: function (evt) { - var propagate = true; - this.dragging = false; - if (this.checkModifiers(evt) && - (OpenLayers.Event.isLeftClick(evt) || - OpenLayers.Event.isSingleTouch(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]); - - // prevent document dragging - OpenLayers.Event.preventDefault(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: dragmove - * This private method is factorized from mousemove and touchmove methods - * - * Parameters: - * evt - {Event} The event - * - * Returns: - * {Boolean} Let the event propagate. - */ - dragmove: function (evt) { - this.lastMoveEvt = 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 = evt.xy; - } - return true; - }, - - /** - * Method: dragend - * This private method is factorized from mouseup and touchend methods - * - * Parameters: - * evt - {Event} The event - * - * Returns: - * {Boolean} Let the event propagate. - */ - dragend: 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; - }, - - /** - * 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) { - return this.dragstart(evt); - }, - - /** - * Method: touchstart - * Handle touchstart events - * - * Parameters: - * evt - {Event} - * - * Returns: - * {Boolean} Let the event propagate. - */ - touchstart: function(evt) { - if (!this.touch) { - this.touch = true; - // unregister mouse listeners - this.map.events.un({ - mousedown: this.mousedown, - mouseup: this.mouseup, - mousemove: this.mousemove, - click: this.click, - scope: this - }); - } - return this.dragstart(evt); - }, - - /** - * Method: mousemove - * Handle mousemove events - * - * Parameters: - * evt - {Event} - * - * Returns: - * {Boolean} Let the event propagate. - */ - mousemove: function(evt) { - return this.dragmove(evt); - }, - - /** - * Method: touchmove - * Handle touchmove events - * - * Parameters: - * evt - {Event} - * - * Returns: - * {Boolean} Let the event propagate. - */ - touchmove: function(evt) { - return this.dragmove(evt); - }, - - /** - * Method: removeTimeout - * Private. Called by mousemove() to remove the drag timeout. - */ - removeTimeout: function() { - this.timeoutId = null; - // if timeout expires while we're still dragging (mouseup - // hasn't occurred) then call mousemove to move to the - // correct position - if(this.dragging) { - this.mousemove(this.lastMoveEvt); - } - }, - - /** - * Method: mouseup - * Handle mouseup events - * - * Parameters: - * evt - {Event} - * - * Returns: - * {Boolean} Let the event propagate. - */ - mouseup: function(evt) { - return this.dragend(evt); - }, - - /** - * Method: touchend - * Handle touchend events - * - * Parameters: - * evt - {Event} - * - * Returns: - * {Boolean} Let the event propagate. - */ - touchend: function(evt) { - // override evt.xy with last position since touchend does not have - // any touch position - evt.xy = this.last; - return this.dragend(evt); - }, - - /** - * 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.touch = false; - 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-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Handler.js - * @requires OpenLayers/Handler/Drag.js - */ - -/** - * Class: OpenLayers.Handler.Box - * Handler for dragging a rectangle across the map. Box is displayed - * on mouse down, moves on mouse move, and is finished on mouse up. - * - * Inherits from: - * - - */ -OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, { - - /** - * Property: dragHandler - * {} - */ - dragHandler: null, - - /** - * APIProperty: boxDivClassName - * {String} The CSS class to use for drawing the box. Default is - * olHandlerBoxZoomBox - */ - boxDivClassName: 'olHandlerBoxZoomBox', - - /** - * Property: boxOffsets - * {Object} Caches box offsets from css. This is used by the getBoxOffsets - * method. - */ - boxOffsets: null, - - /** - * Constructor: OpenLayers.Handler.Box - * - * Parameters: - * control - {} - * callbacks - {Object} An object with a properties whose values are - * functions. Various callbacks described below. - * options - {Object} - * - * Named callbacks: - * start - Called when the box drag operation starts. - * done - Called when the box drag operation is finished. - * The callback should expect to receive a single argument, the box - * bounds or a pixel. If the box dragging didn't span more than a 5 - * pixel distance, a pixel will be returned instead of a bounds object. - */ - initialize: function(control, callbacks, options) { - OpenLayers.Handler.prototype.initialize.apply(this, arguments); - this.dragHandler = new OpenLayers.Handler.Drag( - this, - { - down: this.startBox, - move: this.moveBox, - out: this.removeBox, - up: this.endBox - }, - {keyMask: this.keyMask} - ); - }, - - /** - * Method: destroy - */ - destroy: function() { - OpenLayers.Handler.prototype.destroy.apply(this, arguments); - if (this.dragHandler) { - this.dragHandler.destroy(); - this.dragHandler = null; - } - }, - - /** - * Method: setMap - */ - setMap: function (map) { - OpenLayers.Handler.prototype.setMap.apply(this, arguments); - if (this.dragHandler) { - this.dragHandler.setMap(map); - } - }, - - /** - * Method: startBox - * - * Parameters: - * xy - {} - */ - startBox: function (xy) { - this.callback("start", []); - this.zoomBox = OpenLayers.Util.createDiv('zoomBox', { - x: -9999, y: -9999 - }); - this.zoomBox.className = this.boxDivClassName; - this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1; - - this.map.viewPortDiv.appendChild(this.zoomBox); - - OpenLayers.Element.addClass( - this.map.viewPortDiv, "olDrawBox" - ); - }, - - /** - * Method: moveBox - */ - moveBox: function (xy) { - var startX = this.dragHandler.start.x; - var startY = this.dragHandler.start.y; - var deltaX = Math.abs(startX - xy.x); - var deltaY = Math.abs(startY - xy.y); - - var offset = this.getBoxOffsets(); - this.zoomBox.style.width = (deltaX + offset.width + 1) + "px"; - this.zoomBox.style.height = (deltaY + offset.height + 1) + "px"; - this.zoomBox.style.left = (xy.x < startX ? - startX - deltaX - offset.left : startX - offset.left) + "px"; - this.zoomBox.style.top = (xy.y < startY ? - startY - deltaY - offset.top : startY - offset.top) + "px"; - }, - - /** - * Method: endBox - */ - endBox: function(end) { - var result; - if (Math.abs(this.dragHandler.start.x - end.x) > 5 || - Math.abs(this.dragHandler.start.y - end.y) > 5) { - var start = this.dragHandler.start; - var top = Math.min(start.y, end.y); - var bottom = Math.max(start.y, end.y); - var left = Math.min(start.x, end.x); - var right = Math.max(start.x, end.x); - result = new OpenLayers.Bounds(left, bottom, right, top); - } else { - result = this.dragHandler.start.clone(); // i.e. OL.Pixel - } - this.removeBox(); - - this.callback("done", [result]); - }, - - /** - * Method: removeBox - * Remove the zoombox from the screen and nullify our reference to it. - */ - removeBox: function() { - this.map.viewPortDiv.removeChild(this.zoomBox); - this.zoomBox = null; - this.boxOffsets = null; - OpenLayers.Element.removeClass( - this.map.viewPortDiv, "olDrawBox" - ); - - }, - - /** - * Method: activate - */ - activate: function () { - if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) { - this.dragHandler.activate(); - return true; - } else { - return false; - } - }, - - /** - * Method: deactivate - */ - deactivate: function () { - if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) { - if (this.dragHandler.deactivate()) { - if (this.zoomBox) { - this.removeBox(); - } - } - return true; - } else { - return false; - } - }, - - /** - * Method: getBoxOffsets - * Determines border offsets for a box, according to the box model. - * - * Returns: - * {Object} an object with the following offsets: - * - left - * - right - * - top - * - bottom - * - width - * - height - */ - getBoxOffsets: function() { - if (!this.boxOffsets) { - // Determine the box model. If the testDiv's clientWidth is 3, then - // the borders are outside and we are dealing with the w3c box - // model. Otherwise, the browser uses the traditional box model and - // the borders are inside the box bounds, leaving us with a - // clientWidth of 1. - var testDiv = document.createElement("div"); - //testDiv.style.visibility = "hidden"; - testDiv.style.position = "absolute"; - testDiv.style.border = "1px solid black"; - testDiv.style.width = "3px"; - document.body.appendChild(testDiv); - var w3cBoxModel = testDiv.clientWidth == 3; - document.body.removeChild(testDiv); - - var left = parseInt(OpenLayers.Element.getStyle(this.zoomBox, - "border-left-width")); - var right = parseInt(OpenLayers.Element.getStyle( - this.zoomBox, "border-right-width")); - var top = parseInt(OpenLayers.Element.getStyle(this.zoomBox, - "border-top-width")); - var bottom = parseInt(OpenLayers.Element.getStyle( - this.zoomBox, "border-bottom-width")); - this.boxOffsets = { - left: left, - right: right, - top: top, - bottom: bottom, - width: w3cBoxModel === false ? left + right : 0, - height: w3cBoxModel === false ? top + bottom : 0 - }; - } - return this.boxOffsets; - }, - - CLASS_NAME: "OpenLayers.Handler.Box" -}); -/* ====================================================================== - OpenLayers/Control/ZoomBox.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Control.js - * @requires OpenLayers/Handler/Box.js - */ - -/** - * Class: OpenLayers.Control.ZoomBox - * The ZoomBox control enables zooming directly to a given extent, by drawing - * a box on the map. The box is drawn by holding down shift, whilst dragging - * the mouse. - * - * Inherits from: - * - - */ -OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, { - /** - * Property: type - * {OpenLayers.Control.TYPE} - */ - type: OpenLayers.Control.TYPE_TOOL, - - /** - * Property: out - * {Boolean} Should the control be used for zooming out? - */ - out: false, - - /** - * APIProperty: keyMask - * {Integer} Zoom only occurs if the keyMask matches the combination of - * keys down. Use bitwise operators and one or more of the - * constants to construct a keyMask. Leave null if - * not used mask. Default is null. - */ - keyMask: null, - - /** - * APIProperty: alwaysZoom - * {Boolean} Always zoom in/out when box drawn, even if the zoom level does - * not change. - */ - alwaysZoom: false, - - /** - * APIProperty: zoomOnClick - * {Boolean} Should we zoom when no box was dragged, i.e. the user only - * clicked? Default is true. - */ - zoomOnClick: true, - - /** - * Method: draw - */ - draw: function() { - this.handler = new OpenLayers.Handler.Box( this, - {done: this.zoomBox}, {keyMask: this.keyMask} ); - }, - - /** - * Method: zoomBox - * - * Parameters: - * position - {} or {} - */ - zoomBox: function (position) { - if (position instanceof OpenLayers.Bounds) { - var bounds; - if (!this.out) { - var minXY = this.map.getLonLatFromPixel({ - x: position.left, - y: position.bottom - }); - var maxXY = this.map.getLonLatFromPixel({ - x: position.right, - y: position.top - }); - bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat, - maxXY.lon, maxXY.lat); - } else { - var pixWidth = 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 if (this.zoomOnClick) { // 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-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Control.js - * @requires OpenLayers/Handler/Drag.js - */ - -/** - * Class: OpenLayers.Control.DragPan - * The DragPan control pans the map with a drag of the mouse. - * - * Inherits from: - * - - */ -OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, { - - /** - * Property: type - * {OpenLayers.Control.TYPES} - */ - type: OpenLayers.Control.TYPE_TOOL, - - /** - * Property: panned - * {Boolean} The map moved. - */ - panned: false, - - /** - * Property: interval - * {Integer} The number of milliseconds that should ellapse before - * panning the map again. Defaults to 1 millisecond. In most cases - * you won't want to change this value. For slow machines/devices - * larger values can be tried out. - */ - interval: 1, - - /** - * APIProperty: documentDrag - * {Boolean} If set to true, mouse dragging will continue even if the - * mouse cursor leaves the map viewport. Default is false. - */ - documentDrag: false, - - /** - * Property: kinetic - * {} The OpenLayers.Kinetic object. - */ - kinetic: null, - - /** - * APIProperty: enableKinetic - * {Boolean} Set this option to enable "kinetic dragging". Can be - * set to true or to an object. If set to an object this - * object will be passed to the {} - * constructor. Defaults to false. - * If you set this property, you should ensure that - * OpenLayers/Kinetic.js is included in your build config - */ - enableKinetic: false, - - /** - * APIProperty: kineticInterval - * {Integer} Interval in milliseconds between 2 steps in the "kinetic - * scrolling". Applies only if enableKinetic is set. Defaults - * to 10 milliseconds. - */ - kineticInterval: 10, - - - /** - * Method: draw - * Creates a Drag handler, using and - * as callbacks. - */ - draw: function() { - if(this.enableKinetic) { - var config = {interval: this.kineticInterval}; - if(typeof this.enableKinetic === "object") { - config = OpenLayers.Util.extend(config, this.enableKinetic); - } - this.kinetic = new OpenLayers.Kinetic(config); - } - this.handler = new OpenLayers.Handler.Drag(this, { - "move": this.panMap, - "done": this.panMapDone, - "down": this.panMapStart - }, { - interval: this.interval, - documentDrag: this.documentDrag - } - ); - }, - - /** - * Method: panMapStart - */ - panMapStart: function() { - if(this.kinetic) { - this.kinetic.begin(); - } - }, - - /** - * Method: panMap - * - * Parameters: - * xy - {} Pixel of the mouse position - */ - panMap: function(xy) { - if(this.kinetic) { - this.kinetic.update(xy); - } - this.panned = true; - this.map.pan( - this.handler.last.x - xy.x, - this.handler.last.y - xy.y, - {dragging: true, animate: false} - ); - }, - - /** - * Method: panMapDone - * Finish the panning operation. Only call setCenter (through ) - * if the map has actually been moved. - * - * Parameters: - * xy - {} Pixel of the mouse position - */ - panMapDone: function(xy) { - if(this.panned) { - var res = null; - if (this.kinetic) { - res = this.kinetic.end(xy); - } - this.map.pan( - this.handler.last.x - xy.x, - this.handler.last.y - xy.y, - {dragging: !!res, animate: false} - ); - if (res) { - var self = this; - this.kinetic.move(res, function(x, y, end) { - self.map.pan(x, y, {dragging: !end, animate: false}); - }); - } - this.panned = false; - } - }, - - CLASS_NAME: "OpenLayers.Control.DragPan" -}); -/* ====================================================================== - OpenLayers/Handler/Click.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Handler.js - */ - -/** - * Class: OpenLayers.Handler.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 , controls can also ignore clicks - * that include a drag. Create a new instance with the - * constructor. - * - * Inherits from: - * - - */ -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: dblclickTolerance - * {Number} Maximum distance in pixels between clicks for a sequence of - * events to be considered a double click. Default is 13. If the - * distance between two clicks is greater than this value, a double- - * click will not be fired. - */ - dblclickTolerance: 13, - - /** - * APIProperty: stopSingle - * {Boolean} Stop other listeners from being notified of clicks. Default - * is false. If true, any listeners registered before this one for - * click or rightclick events will not be notified. - */ - 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 . - */ - timerId: null, - - /** - * Property: touch - * {Boolean} When a touchstart event is fired, touch will be true and all - * mouse related listeners will do nothing. - */ - touch: false, - - /** - * Property: down - * {Object} Object that store relevant information about the last - * mousedown or touchstart. Its 'xy' OpenLayers.Pixel property gives - * the average location of the mouse/touch event. Its 'touches' - * property records clientX/clientY of each touches. - */ - down: null, - - /** - * Property: last - * {Object} Object that store relevant information about the last - * mousemove or touchmove. Its 'xy' OpenLayers.Pixel property gives - * the average location of the mouse/touch event. Its 'touches' - * property records clientX/clientY of each touches. - */ - last: null, - - /** - * Property: first - * {Object} When waiting for double clicks, this object will store - * information about the first click in a two click sequence. - */ - first: null, - - /** - * Property: rightclickTimerId - * {Number} The id of the right mouse timeout waiting to clear the - * . - */ - rightclickTimerId: null, - - /** - * Constructor: OpenLayers.Handler.Click - * Create a new click handler. - * - * Parameters: - * 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. - */ - - /** - * Method: touchstart - * Handle touchstart. - * - * Returns: - * {Boolean} Continue propagating this event. - */ - touchstart: function(evt) { - if (!this.touch) { - this.unregisterMouseListeners(); - this.touch = true; - } - this.down = this.getEventInfo(evt); - this.last = this.getEventInfo(evt); - return true; - }, - - /** - * Method: touchmove - * Store position of last move, because touchend event can have - * an empty "touches" property. - * - * Returns: - * {Boolean} Continue propagating this event. - */ - touchmove: function(evt) { - this.last = this.getEventInfo(evt); - return true; - }, - - /** - * Method: touchend - * Correctly set event xy property, and add lastTouches to have - * touches property from last touchstart or touchmove - * - * Returns: - * {Boolean} Continue propagating this event. - */ - touchend: function(evt) { - // touchstart may not have been allowed to propagate - if (this.down) { - evt.xy = this.last.xy; - evt.lastTouches = this.last.touches; - this.handleSingle(evt); - this.down = null; - } - return true; - }, - - /** - * Method: unregisterMouseListeners - * In a touch environment, we don't want to handle mouse events. - */ - unregisterMouseListeners: function() { - this.map.events.un({ - mousedown: this.mousedown, - mouseup: this.mouseup, - click: this.click, - dblclick: this.dblclick, - scope: this - }); - }, - - /** - * Method: mousedown - * Handle mousedown. - * - * Returns: - * {Boolean} Continue propagating this event. - */ - mousedown: function(evt) { - this.down = this.getEventInfo(evt); - this.last = this.getEventInfo(evt); - return true; - }, - - /** - * 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 to null. And optionally triggers the - * rightclick callback if evt is set. - */ - delayedRightCall: function(evt) { - this.rightclickTimerId = null; - if (evt) { - this.callback('rightclick', [evt]); - } - }, - - /** - * Method: click - * Handle click events from the browser. This is registered as a listener - * for click events and should not be called from other events in this - * handler. - * - * Returns: - * {Boolean} Continue propagating this event. - */ - click: function(evt) { - if (!this.last) { - this.last = this.getEventInfo(evt); - } - this.handleSingle(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. This method is registered - * as a listener for the dblclick browser event. It should *not* be - * called by other methods in this handler. - * - * Returns: - * {Boolean} Continue propagating this event. - */ - dblclick: function(evt) { - this.handleDouble(evt); - return !this.stopDouble; - }, - - /** - * Method: handleDouble - * Handle double-click sequence. - */ - handleDouble: function(evt) { - if (this.passesDblclickTolerance(evt)) { - if (this["double"]) { - this.callback("dblclick", [evt]); - } - // to prevent a dblclick from firing the click callback in IE - this.clearTimer(); - } - }, - - /** - * Method: handleSingle - * Handle single click sequence. - */ - handleSingle: function(evt) { - if (this.passesTolerance(evt)) { - if (this.timerId != null) { - // already received a click - if (this.last.touches && this.last.touches.length === 1) { - // touch device, no dblclick event - this may be a double - if (this["double"]) { - // on Android don't let the browser zoom on the page - OpenLayers.Event.stop(evt); - } - this.handleDouble(evt); - } - // if we're not in a touch environment we clear the click timer - // if we've got a second touch, we'll get two touchend events - if (!this.last.touches || this.last.touches.length !== 2) { - this.clearTimer(); - } - } else { - // remember the first click info so we can compare to the second - this.first = this.getEventInfo(evt); - // 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.queuePotentialClick(clickEvent); - } - } - }, - - /** - * Method: queuePotentialClick - * This method is separated out largely to make testing easier (so we - * don't have to override window.setTimeout) - */ - queuePotentialClick: function(evt) { - this.timerId = window.setTimeout( - OpenLayers.Function.bind(this.delayedCall, this, evt), - this.delay - ); - }, - - /** - * 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 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 && this.down.xy) { - passes = this.pixelTolerance >= this.down.xy.distanceTo(evt.xy); - // for touch environments, we also enforce that all touches - // start and end within the given tolerance to be considered a click - if (passes && this.touch && - this.down.touches.length === this.last.touches.length) { - // the touchend event doesn't come with touches, so we check - // down and last - for (var i=0, ii=this.down.touches.length; i this.pixelTolerance) { - passes = false; - break; - } - } - } - } - return passes; - }, - - /** - * Method: getTouchDistance - * - * Returns: - * {Boolean} The pixel displacement between two touches. - */ - getTouchDistance: function(from, to) { - return Math.sqrt( - Math.pow(from.clientX - to.clientX, 2) + - Math.pow(from.clientY - to.clientY, 2) - ); - }, - - /** - * Method: passesDblclickTolerance - * Determine whether the event is within the optional double-cick pixel - * tolerance. - * - * Returns: - * {Boolean} The click is within the double-click pixel tolerance. - */ - passesDblclickTolerance: function(evt) { - var passes = true; - if (this.down && this.first) { - passes = this.down.xy.distanceTo(this.first.xy) <= this.dblclickTolerance; - } - return passes; - }, - - /** - * Method: clearTimer - * Clear the timer and set 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 to null. And optionally triggers the click callback if - * evt is set. - */ - delayedCall: function(evt) { - this.timerId = null; - if (evt) { - this.callback("click", [evt]); - } - }, - - /** - * Method: getEventInfo - * This method allows us to store event information without storing the - * actual event. In touch devices (at least), the same event is - * modified between touchstart, touchmove, and touchend. - * - * Returns: - * {Object} An object with event related info. - */ - getEventInfo: function(evt) { - var touches; - if (evt.touches) { - var len = evt.touches.length; - touches = new Array(len); - var touch; - for (var i=0; i control. - * - * Note that this control is added to the map by default (if no controls - * array is sent in the options object to the - * constructor). - * - * Inherits: - * - - */ -OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, { - - /** - * Property: dragPan - * {} - */ - dragPan: null, - - /** - * APIProperty: dragPanOptions - * {Object} Options passed to the DragPan control. - */ - dragPanOptions: null, - - /** - * Property: pinchZoom - * {} - */ - pinchZoom: null, - - /** - * APIProperty: pinchZoomOptions - * {Object} Options passed to the PinchZoom control. - */ - pinchZoomOptions: null, - - /** - * APIProperty: documentDrag - * {Boolean} Allow panning of the map by dragging outside map viewport. - * Default is false. - */ - documentDrag: false, - - /** - * Property: 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 - * is set to true) - */ - mouseWheelOptions: null, - - /** - * APIProperty: handleRightClicks - * {Boolean} Whether or not to handle right clicks. Default is false. - */ - handleRightClicks: false, - - /** - * APIProperty: zoomBoxKeyMask - * {Integer} key code of the key, which has to be - * pressed, while drawing the zoom box with the mouse on the screen. - * You should probably set handleRightClicks to true if you use this - * with MOD_CTRL, to disable the context menu for machines which use - * CTRL-Click as a right click. - * Default: - */ - 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; - - if (this.pinchZoom) { - this.pinchZoom.destroy(); - } - this.pinchZoom = 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(); - } - if (this.pinchZoom) { - this.pinchZoom.activate(); - } - return OpenLayers.Control.prototype.activate.apply(this,arguments); - }, - - /** - * Method: deactivate - */ - deactivate: function() { - if (this.pinchZoom) { - this.pinchZoom.deactivate(); - } - 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 = { - 'click': this.defaultClick, - 'dblclick': this.defaultDblClick, - 'dblrightclick': this.defaultDblRightClick - }; - var clickOptions = { - 'double': true, - 'stopDouble': true - }; - this.handlers.click = new OpenLayers.Handler.Click( - this, clickCallbacks, clickOptions - ); - 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 ); - if (OpenLayers.Control.PinchZoom) { - this.pinchZoom = new OpenLayers.Control.PinchZoom( - OpenLayers.Util.extend( - {map: this.map}, this.pinchZoomOptions)); - } - }, - - /** - * Method: defaultClick - * - * Parameters: - * evt - {Event} - */ - defaultClick: function (evt) { - if (evt.lastTouches && evt.lastTouches.length == 2) { - this.map.zoomOut(); - } - }, - - /** - * 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) { - if (!this.map.fractionalZoom) { - deltaZ = Math.round(deltaZ); - } - var currentZoom = this.map.getZoom(); - var newZoom = this.map.getZoom() + 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/WMS.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/Layer/Grid.js - */ - -/** - * 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 - * constructor. - * - * Inherits from: - * - - */ -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: "", - format: "image/jpeg" - }, - - /** - * 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, and - * only if yx is not set in for the - * used projection. - */ - yx: {}, - - /** - * Constructor: OpenLayers.Layer.WMS - * Create a new WMS layer object - * - * Examples: - * - * The code below creates a simple WMS layer using the image/jpeg format. - * (code) - * var wms = new OpenLayers.Layer.WMS("NASA Global Mosaic", - * "http://wms.jpl.nasa.gov/wms.cgi", - * {layers: "modis,global_mosaic"}); - * (end) - * Note the 3rd argument (params). Properties added to this object will be - * added to the WMS GetMap requests used for this layer's tiles. The only - * mandatory parameter is "layers". Other common WMS params include - * "transparent", "styles" and "format". Note that the "srs" param will - * always be ignored. Instead, it will be derived from the baseLayer's or - * map's projection. - * - * The code below creates a transparent WMS layer with additional options. - * (code) - * var wms = new OpenLayers.Layer.WMS("NASA Global Mosaic", - * "http://wms.jpl.nasa.gov/wms.cgi", - * { - * layers: "modis,global_mosaic", - * transparent: true - * }, { - * opacity: 0.5, - * singleTile: true - * }); - * (end) - * Note that by default, a WMS layer is configured as baseLayer. Setting - * the "transparent" param to true will apply some magic (see ). - * The default image format changes from image/jpeg to image/png, and the - * layer is not configured as baseLayer. - * - * 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 - {Object} Hashtable of extra options to tag onto the layer. - * These options include all properties listed above, plus the ones - * inherited from superclasses. - */ - 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 the browser's capabilities - if (this.params.FORMAT == "image/jpeg") { - this.params.FORMAT = OpenLayers.Util.alphaHack() ? "image/gif" - : "image/png"; - } - } - - }, - - /** - * Method: clone - * Create a clone of this layer - * - * Returns: - * {} 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() { - var projCode = this.projection.getCode(); - return parseFloat(this.params.VERSION) >= 1.3 && - !!(this.yx[projCode] || OpenLayers.Projection.defaults[projCode].yx); - }, - - /** - * Method: getURL - * Return a GetMap query string for this layer - * - * Parameters: - * 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; - }, - - /** - * 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 && 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; - } - - if (typeof this.params.TRANSPARENT == "boolean") { - newParams.TRANSPARENT = this.params.TRANSPARENT ? "TRUE" : "FALSE"; - } - - return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply( - this, arguments); - }, - - CLASS_NAME: "OpenLayers.Layer.WMS" -}); -/* ====================================================================== - OpenLayers/Renderer/SVG.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Renderer/Elements.js - */ - -/** - * Class: OpenLayers.Renderer.SVG - * - * Inherits: - * - - */ -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: 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 - {} - * 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) { - var coordSysUnchanged = OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, arguments); - - var resolution = this.getResolution(), - left = -extent.left / resolution, - 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(this.xOffset, 0); - return true; - } else { - var inRange = this.translate(left - this.left + this.xOffset, top - this.top); - if (!inRange) { - // recenter the coordinate system - this.setExtent(extent, true); - } - return coordSysUnchanged && 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 - {} 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 - {} - * 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": - 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 title = style.title || style.graphicTitle; - if (title) { - node.setAttributeNS(null, "title", title); - //Standards-conformant SVG - // Prevent duplicate nodes. See issue https://github.com/openlayers/openlayers/issues/92 - var titleNode = node.getElementsByTagName("title"); - if (titleNode.length > 0) { - titleNode[0].firstChild.textContent = title; - } else { - var label = this.nodeFactory(null, "title"); - label.textContent = title; - node.appendChild(label); - } - } - - 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.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); - node.onclick = OpenLayers.Event.preventDefault; - } 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 src = this.importSymbol(style.graphicName); - pos = this.getPosition(node); - widthFactor = this.symbolMetrics[src.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 - 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[src.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() { - var svg = this.nodeFactory(this.container.id + "_svgRoot", "svg"); - svg.style.display = "block"; - return svg; - }, - - /** - * Method: createRoot - * - * Parameters: - * 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 - {} - * - * 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 - {} - * 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 - this.featureDx) / 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 - {} - * - * 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 - {} - * - * 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 - {} - * - * 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} - * - * Returns: - * {DOMElement} or false if the renderer could not draw the rectangle - */ - drawRectangle: function(node, geometry) { - var resolution = this.getResolution(); - var x = ((geometry.x - this.featureDx) / 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: drawText - * This method is only called by the renderer itself. - * - * Parameters: - * featureId - {String} - * style - - * location - {} - */ - drawText: function(featureId, style, location) { - var drawOutline = (!!style.labelOutlineWidth); - // First draw text in halo color and size and overlay the - // normal text afterwards - if (drawOutline) { - var outlineStyle = OpenLayers.Util.extend({}, style); - outlineStyle.fontColor = outlineStyle.labelOutlineColor; - outlineStyle.fontStrokeColor = outlineStyle.labelOutlineColor; - outlineStyle.fontStrokeWidth = style.labelOutlineWidth; - delete outlineStyle.labelOutlineWidth; - this.drawText(featureId, outlineStyle, location); - } - - var resolution = this.getResolution(); - - var x = ((location.x - this.featureDx) / resolution + this.left); - var y = (location.y / resolution - this.top); - - var suffix = (drawOutline)?this.LABEL_OUTLINE_SUFFIX:this.LABEL_ID_SUFFIX; - var label = this.nodeFactory(featureId + suffix, "text"); - - label.setAttributeNS(null, "x", x); - label.setAttributeNS(null, "y", -y); - - if (style.fontColor) { - label.setAttributeNS(null, "fill", style.fontColor); - } - if (style.fontStrokeColor) { - label.setAttributeNS(null, "stroke", style.fontStrokeColor); - } - if (style.fontStrokeWidth) { - label.setAttributeNS(null, "stroke-width", style.fontStrokeWidth); - } - 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.fontStyle) { - label.setAttributeNS(null, "font-style", style.fontStyle); - } - if (style.labelSelect === true) { - label.setAttributeNS(null, "pointer-events", "visible"); - label._featureId = featureId; - } else { - label.setAttributeNS(null, "pointer-events", "none"); - } - var align = style.labelAlign || OpenLayers.Renderer.defaultSymbolizer.labelAlign; - 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"); - } - - var labelRows = style.label.split('\n'); - var numRows = labelRows.length; - while (label.childNodes.length > numRows) { - label.removeChild(label.lastChild); - } - for (var i = 0; i < numRows; i++) { - var tspan = this.nodeFactory(featureId + suffix + "_tspan_" + i, "tspan"); - if (style.labelSelect === true) { - tspan._featureId = featureId; - tspan._geometry = location; - tspan._geometryClass = location.CLASS_NAME; - } - if (OpenLayers.IS_GECKO === false) { - tspan.setAttributeNS(null, "baseline-shift", - OpenLayers.Renderer.SVG.LABEL_VSHIFT[align[1]] || "-35%"); - } - tspan.setAttribute("x", x); - if (i == 0) { - var vfactor = OpenLayers.Renderer.SVG.LABEL_VFACTOR[align[1]]; - if (vfactor == null) { - vfactor = -.5; - } - tspan.setAttribute("dy", (vfactor*(numRows-1)) + "em"); - } else { - tspan.setAttribute("dy", "1em"); - } - tspan.textContent = (labelRows[i] === '') ? ' ' : labelRows[i]; - if (!tspan.parentNode) { - label.appendChild(tspan); - } - } - - if (!label.parentNode) { - this.textRoot.appendChild(label); - } - }, - - /** - * Method: getComponentString - * - * Parameters: - * components - {Array()} 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 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 - {} original geometry of the - * invalid point - * goodComponent - {} 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 - this.featureDx) / resolution + this.left; - var y1 = this.top - goodComponent.y / resolution; - var x2 = (badComponent.x - this.featureDx) / 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 - {} - * - * Returns: - * {String} or false if point is outside the valid range - */ - getShortString: function(point) { - var resolution = this.getResolution(); - var x = ((point.x - this.featureDx) / 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: - * {DOMElement} - 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 - var existing = document.getElementById(id); - if (existing != null) { - return existing; - } - - 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 object - * - * Returns: - * {String} A feature id or undefined. - */ - 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 : undefined; - } - 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" -}; - -/** - * Constant: OpenLayers.Renderer.SVG.LABEL_VFACTOR - * {Object} - */ -OpenLayers.Renderer.SVG.LABEL_VFACTOR = { - "t": 0, - "b": -1 -}; - -/** - * Function: OpenLayers.Renderer.SVG.preventDefault - * *Deprecated*. Use method instead. - * Used to prevent default events (especially opening images in a new tab on - * ctrl-click) from being executed for externalGraphic symbols - */ -OpenLayers.Renderer.SVG.preventDefault = function(e) { - OpenLayers.Event.preventDefault(e); -}; -/* ====================================================================== - OpenLayers/Protocol/WFS/v1.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Protocol/WFS.js - */ - -/** - * Class: OpenLayers.Protocol.WFS.v1 - * Abstract class for for v1.0.0 and v1.1.0 protocol. - * - * Inherits from: - * - - */ -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" for WFS 1.0, and null for higher versions. - */ - 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 - * {} 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 - * during the first query if GML is used as readFormat and - * featurePrefix is provided and matches the prefix used by the server - * for this featureType). - * featurePrefix - {String} Feature namespace alias (optional - only used - * for writing if featureNS is provided). Default is 'feature'. - * geometryName - {String} Name of geometry attribute. The default is - * 'the_geom' for WFS 1.0, and null for higher versions. If - * null, it will be set to the name of the first geometry found in the - * first read operation. - * multi - {Boolean} If set to true, geometries will be casted to Multi - * geometries before they are written in a transaction. No casting will - * be done when reading features. - */ - 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 (!options.geometryName && parseFloat(this.format.version) > 1.0) { - this.setGeometryName(null); - } - }, - - /** - * 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). - * - * Parameters: - * options - {Object} Options for the read operation, in addition to the - * options set on the instance (options set here will take precedence). - * - * 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) - * - * To use a configured protocol to use WFS paging (if supported by the - * server), applications could do the following: - * - * (code) - * protocol.read({ - * startIndex: 0, - * count: 50 - * }); - * (end) - * - * To limit the attributes returned by the GetFeature request, applications - * can use the propertyNames option to specify the properties to include in - * the response: - * - * (code) - * protocol.read({ - * propertyNames: ["DURATION", "INTENSITY"] - * }); - * (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; - }, - - /** - * APIMethod: setFeatureType - * Change the feature type on the fly. - * - * Parameters: - * featureType - {String} Local (without prefix) feature typeName. - */ - setFeatureType: function(featureType) { - this.featureType = featureType; - this.format.featureType = featureType; - }, - - /** - * APIMethod: setGeometryName - * Sets the geometryName option after instantiation. - * - * Parameters: - * geometryName - {String} Name of geometry attribute. - */ - setGeometryName: function(geometryName) { - this.geometryName = geometryName; - this.format.geometryName = geometryName; - }, - - /** - * Method: handleRead - * Deal with response from the read request. - * - * Parameters: - * 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 - var result = this.parseResponse(request, options.readOptions); - if (result && result.success !== false) { - if (options.readOptions && options.readOptions.output == "object") { - OpenLayers.Util.extend(response, result); - } else { - response.features = result; - } - response.code = OpenLayers.Protocol.Response.SUCCESS; - } else { - // failure (service exception) - response.code = OpenLayers.Protocol.Response.FAILURE; - response.error = result; - } - } 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({})} or - * {} - * 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; - } - var result = (this.readFormat !== null) ? this.readFormat.read(doc) : - this.format.read(doc, options); - if (!this.featureNS) { - var format = this.readFormat || this.format; - this.featureNS = format.featureNS; - // no need to auto-configure again on subsequent reads - format.autoConfig = false; - if (!this.geometryName) { - this.setGeometryName(format.geometryName); - } - } - return result; - }, - - /** - * 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()} - * options - {Object} - * - * Valid options properties: - * nativeElements - {Array({Object})} Array of objects with information for writing - * out elements, these objects have vendorId, safeToIgnore and - * value properties. The element is intended to allow access to - * vendor specific capabilities of any particular web feature server or - * datastore. - * - * Returns: - * {} 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, - headers: options.headers, - 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 - {} 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 || []; - if (obj.success) { - response.code = OpenLayers.Protocol.Response.SUCCESS; - } else { - response.code = OpenLayers.Protocol.Response.FAILURE; - response.error = obj; - } - options.callback.call(options.scope, response); - } - }, - - /** - * Method: filterDelete - * Send a request that deletes all features by their filter. - * - * Parameters: - * 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 - {} - */ - abort: function(response) { - if (response) { - response.priv.abort(); - } - }, - - CLASS_NAME: "OpenLayers.Protocol.WFS.v1" -}); -/* ====================================================================== - OpenLayers/Request.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Events.js - * @requires OpenLayers/Request/XMLHttpRequest.js - */ - -/** - * TODO: deprecate me - * Use OpenLayers.Request.proxy instead. - */ -OpenLayers.ProxyHost = ""; - -/** - * Namespace: OpenLayers.Request - * The OpenLayers.Request namespace contains convenience methods for working - * with XMLHttpRequests. These methods work with a cross-browser - * W3C compliant class. - */ -if (!OpenLayers.Request) { - /** - * This allows for OpenLayers/Request/XMLHttpRequest.js to be included - * before or after this script. - */ - OpenLayers.Request = {}; -} -OpenLayers.Util.extend(OpenLayers.Request, { - - /** - * Constant: DEFAULT_CONFIG - * {Object} Default configuration for all requests. - */ - DEFAULT_CONFIG: { - method: "GET", - url: window.location.href, - async: true, - user: undefined, - password: undefined, - params: null, - proxy: OpenLayers.ProxyHost, - headers: {}, - data: null, - callback: function() {}, - success: null, - failure: null, - scope: null - }, - - /** - * Constant: URL_SPLIT_REGEX - */ - URL_SPLIT_REGEX: /([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/, - - /** - * APIProperty: events - * {} An events object that handles all - * events on the {} object. - * - * All event listeners will receive an event object with three properties: - * request - {} The request object. - * config - {Object} The config object sent to the specific request method. - * requestUrl - {String} The request url. - * - * Supported event types: - * complete - Triggered when we have a response from the request, if a - * listener returns false, no further response processing will take - * place. - * success - Triggered when the HTTP response has a success code (200-299). - * failure - Triggered when the HTTP response does not have a success code. - */ - events: new OpenLayers.Events(this), - - /** - * Method: makeSameOrigin - * Using the specified proxy, returns a same origin url of the provided url. - * - * Parameters: - * url - {String} An arbitrary url - * proxy {String|Function} The proxy to use to make the provided url a - * same origin url. - * - * Returns - * {String} the same origin url. If no proxy is provided, the returned url - * will be the same as the provided url. - */ - makeSameOrigin: function(url, proxy) { - var sameOrigin = url.indexOf("http") !== 0; - var urlParts = !sameOrigin && url.match(this.URL_SPLIT_REGEX); - if (urlParts) { - var location = window.location; - sameOrigin = - urlParts[1] == location.protocol && - urlParts[3] == location.hostname; - var uPort = urlParts[4], lPort = location.port; - if (uPort != 80 && uPort != "" || lPort != "80" && lPort != "") { - sameOrigin = sameOrigin && uPort == lPort; - } - } - if (!sameOrigin) { - if (proxy) { - if (typeof proxy == "function") { - url = proxy(url); - } else { - url = proxy + encodeURIComponent(url); - } - } else { - OpenLayers.Console.warn( - OpenLayers.i18n("proxyNeeded"), {url: url}); - } - } - return url; - }, - - /** - * APIMethod: issue - * Create a new XMLHttpRequest object, open it, set any headers, bind - * a callback to done state, and send any data. It is recommended that - * you use one , , , , , or . - * This method is only documented to provide detail on the configuration - * options available to all request methods. - * - * Parameters: - * config - {Object} Object containing properties for configuring the - * request. Allowed configuration properties are described below. - * This object is modified and should not be reused. - * - * Allowed config properties: - * method - {String} One of GET, POST, PUT, DELETE, HEAD, or - * OPTIONS. Default is GET. - * url - {String} URL for the request. - * async - {Boolean} Open an asynchronous request. Default is true. - * user - {String} User for relevant authentication scheme. Set - * to null to clear current user. - * password - {String} Password for relevant authentication scheme. - * Set to null to clear current password. - * proxy - {String} Optional proxy. Defaults to - * . - * params - {Object} Any key:value pairs to be appended to the - * url as a query string. Assumes url doesn't already include a query - * string or hash. Typically, this is only appropriate for - * requests where the query string will be appended to the url. - * Parameter values that are arrays will be - * concatenated with a comma (note that this goes against form-encoding) - * as is done with . - * headers - {Object} Object with header:value pairs to be set on - * the request. - * data - {String | Document} Optional data to send with the request. - * Typically, this is only used with and requests. - * Make sure to provide the appropriate "Content-Type" header for your - * data. For and requests, the content type defaults to - * "application-xml". If your data is a different content type, or - * if you are using a different HTTP method, set the "Content-Type" - * header to match your data type. - * callback - {Function} Function to call when request is done. - * To determine if the request failed, check request.status (200 - * indicates success). - * success - {Function} Optional function to call if request status is in - * the 200s. This will be called in addition to callback above and - * would typically only be used as an alternative. - * failure - {Function} Optional function to call if request status is not - * in the 200s. This will be called in addition to callback above and - * would typically only be used as an alternative. - * scope - {Object} If callback is a public method on some object, - * set the scope to that object. - * - * Returns: - * {XMLHttpRequest} Request object. To abort the request before a response - * is received, call abort() on the request object. - */ - issue: function(config) { - // apply default config - proxy host may have changed - var defaultConfig = OpenLayers.Util.extend( - this.DEFAULT_CONFIG, - {proxy: OpenLayers.ProxyHost} - ); - config = OpenLayers.Util.applyDefaults(config, defaultConfig); - - // Always set the "X-Requested-With" header to signal that this request - // was issued through the XHR-object. Since header keys are case - // insensitive and we want to allow overriding of the "X-Requested-With" - // header through the user we cannot use applyDefaults, but have to - // check manually whether we were called with a "X-Requested-With" - // header. - var customRequestedWithHeader = false, - headerKey; - for(headerKey in config.headers) { - if (config.headers.hasOwnProperty( headerKey )) { - if (headerKey.toLowerCase() === 'x-requested-with') { - customRequestedWithHeader = true; - } - } - } - if (customRequestedWithHeader === false) { - // we did not have a custom "X-Requested-With" header - config.headers['X-Requested-With'] = 'XMLHttpRequest'; - } - - // create request, open, and set headers - var request = new OpenLayers.Request.XMLHttpRequest(); - var url = OpenLayers.Util.urlAppend(config.url, - OpenLayers.Util.getParameterString(config.params || {})); - url = OpenLayers.Request.makeSameOrigin(url, config.proxy); - request.open( - config.method, url, config.async, config.user, config.password - ); - for(var header in config.headers) { - request.setRequestHeader(header, config.headers[header]); - } - - var events = this.events; - - // we want to execute runCallbacks with "this" as the - // execution scope - var self = this; - - request.onreadystatechange = function() { - if(request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) { - var proceed = events.triggerEvent( - "complete", - {request: request, config: config, requestUrl: url} - ); - if(proceed !== false) { - self.runCallbacks( - {request: request, config: config, requestUrl: url} - ); - } - } - }; - - // send request (optionally with data) and return - // call in a timeout for asynchronous requests so the return is - // available before readyState == 4 for cached docs - if(config.async === false) { - request.send(config.data); - } else { - window.setTimeout(function(){ - if (request.readyState !== 0) { // W3C: 0-UNSENT - request.send(config.data); - } - }, 0); - } - return request; - }, - - /** - * Method: runCallbacks - * Calls the complete, success and failure callbacks. Application - * can listen to the "complete" event, have the listener - * display a confirm window and always return false, and - * execute OpenLayers.Request.runCallbacks if the user - * hits "yes" in the confirm window. - * - * Parameters: - * options - {Object} Hash containing request, config and requestUrl keys - */ - runCallbacks: function(options) { - var request = options.request; - var config = options.config; - - // bind callbacks to readyState 4 (done) - var complete = (config.scope) ? - OpenLayers.Function.bind(config.callback, config.scope) : - config.callback; - - // optional success callback - var success; - if(config.success) { - success = (config.scope) ? - OpenLayers.Function.bind(config.success, config.scope) : - config.success; - } - - // optional failure callback - var failure; - if(config.failure) { - failure = (config.scope) ? - OpenLayers.Function.bind(config.failure, config.scope) : - config.failure; - } - - if (OpenLayers.Util.createUrlObject(config.url).protocol == "file:" && - request.responseText) { - request.status = 200; - } - complete(request); - - if (!request.status || (request.status >= 200 && request.status < 300)) { - this.events.triggerEvent("success", options); - if(success) { - success(request); - } - } - if(request.status && (request.status < 200 || request.status >= 300)) { - this.events.triggerEvent("failure", options); - if(failure) { - failure(request); - } - } - }, - - /** - * APIMethod: GET - * Send an HTTP GET request. Additional configuration properties are - * documented in the method, with the method property set - * to GET. - * - * Parameters: - * config - {Object} Object with properties for configuring the request. - * See the method for documentation of allowed properties. - * This object is modified and should not be reused. - * - * Returns: - * {XMLHttpRequest} Request object. - */ - GET: function(config) { - config = OpenLayers.Util.extend(config, {method: "GET"}); - return OpenLayers.Request.issue(config); - }, - - /** - * APIMethod: POST - * Send a POST request. Additional configuration properties are - * documented in the method, with the method property set - * to POST and "Content-Type" header set to "application/xml". - * - * Parameters: - * config - {Object} Object with properties for configuring the request. - * See the method for documentation of allowed properties. The - * default "Content-Type" header will be set to "application-xml" if - * none is provided. This object is modified and should not be reused. - * - * Returns: - * {XMLHttpRequest} Request object. - */ - POST: function(config) { - config = OpenLayers.Util.extend(config, {method: "POST"}); - // set content type to application/xml if it isn't already set - config.headers = config.headers ? config.headers : {}; - if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) { - config.headers["Content-Type"] = "application/xml"; - } - return OpenLayers.Request.issue(config); - }, - - /** - * APIMethod: PUT - * Send an HTTP PUT request. Additional configuration properties are - * documented in the method, with the method property set - * to PUT and "Content-Type" header set to "application/xml". - * - * Parameters: - * config - {Object} Object with properties for configuring the request. - * See the method for documentation of allowed properties. The - * default "Content-Type" header will be set to "application-xml" if - * none is provided. This object is modified and should not be reused. - * - * Returns: - * {XMLHttpRequest} Request object. - */ - PUT: function(config) { - config = OpenLayers.Util.extend(config, {method: "PUT"}); - // set content type to application/xml if it isn't already set - config.headers = config.headers ? config.headers : {}; - if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) { - config.headers["Content-Type"] = "application/xml"; - } - return OpenLayers.Request.issue(config); - }, - - /** - * APIMethod: DELETE - * Send an HTTP DELETE request. Additional configuration properties are - * documented in the method, with the method property set - * to DELETE. - * - * Parameters: - * config - {Object} Object with properties for configuring the request. - * See the method for documentation of allowed properties. - * This object is modified and should not be reused. - * - * Returns: - * {XMLHttpRequest} Request object. - */ - DELETE: function(config) { - config = OpenLayers.Util.extend(config, {method: "DELETE"}); - return OpenLayers.Request.issue(config); - }, - - /** - * APIMethod: HEAD - * Send an HTTP HEAD request. Additional configuration properties are - * documented in the method, with the method property set - * to HEAD. - * - * Parameters: - * config - {Object} Object with properties for configuring the request. - * See the method for documentation of allowed properties. - * This object is modified and should not be reused. - * - * Returns: - * {XMLHttpRequest} Request object. - */ - HEAD: function(config) { - config = OpenLayers.Util.extend(config, {method: "HEAD"}); - return OpenLayers.Request.issue(config); - }, - - /** - * APIMethod: OPTIONS - * Send an HTTP OPTIONS request. Additional configuration properties are - * documented in the method, with the method property set - * to OPTIONS. - * - * Parameters: - * config - {Object} Object with properties for configuring the request. - * See the method for documentation of allowed properties. - * This object is modified and should not be reused. - * - * Returns: - * {XMLHttpRequest} Request object. - */ - OPTIONS: function(config) { - config = OpenLayers.Util.extend(config, {method: "OPTIONS"}); - return OpenLayers.Request.issue(config); - } - -}); -/* ====================================================================== - OpenLayers/Request/XMLHttpRequest.js - ====================================================================== */ - -// XMLHttpRequest.js Copyright (C) 2010 Sergey Ilinsky (http://www.ilinsky.com) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @requires OpenLayers/Request.js - */ - -(function () { - - // Save reference to earlier defined object implementation (if any) - var oXMLHttpRequest = window.XMLHttpRequest; - - // Define on browser type - var bGecko = !!window.controllers, - bIE = window.document.all && !window.opera, - bIE7 = bIE && window.navigator.userAgent.match(/MSIE 7.0/); - - // Enables "XMLHttpRequest()" call next to "new XMLHttpReques()" - function fXMLHttpRequest() { - this._object = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP"); - this._listeners = []; - }; - - // Constructor - function cXMLHttpRequest() { - return new fXMLHttpRequest; - }; - cXMLHttpRequest.prototype = fXMLHttpRequest.prototype; - - // BUGFIX: Firefox with Firebug installed would break pages if not executed - if (bGecko && oXMLHttpRequest.wrapped) - cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped; - - // Constants - cXMLHttpRequest.UNSENT = 0; - cXMLHttpRequest.OPENED = 1; - cXMLHttpRequest.HEADERS_RECEIVED = 2; - cXMLHttpRequest.LOADING = 3; - cXMLHttpRequest.DONE = 4; - - // Public Properties - cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT; - cXMLHttpRequest.prototype.responseText = ''; - cXMLHttpRequest.prototype.responseXML = null; - cXMLHttpRequest.prototype.status = 0; - cXMLHttpRequest.prototype.statusText = ''; - - // Priority proposal - cXMLHttpRequest.prototype.priority = "NORMAL"; - - // Instance-level Events Handlers - cXMLHttpRequest.prototype.onreadystatechange = null; - - // Class-level Events Handlers - cXMLHttpRequest.onreadystatechange = null; - cXMLHttpRequest.onopen = null; - cXMLHttpRequest.onsend = null; - cXMLHttpRequest.onabort = null; - - // Public Methods - cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) { - // Delete headers, required when object is reused - delete this._headers; - - // When bAsync parameter value is omitted, use true as default - if (arguments.length < 3) - bAsync = true; - - // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests - this._async = bAsync; - - // Set the onreadystatechange handler - var oRequest = this, - nState = this.readyState, - fOnUnload; - - // BUGFIX: IE - memory leak on page unload (inter-page leak) - if (bIE && bAsync) { - fOnUnload = function() { - if (nState != cXMLHttpRequest.DONE) { - fCleanTransport(oRequest); - // Safe to abort here since onreadystatechange handler removed - oRequest.abort(); - } - }; - window.attachEvent("onunload", fOnUnload); - } - - // Add method sniffer - if (cXMLHttpRequest.onopen) - cXMLHttpRequest.onopen.apply(this, arguments); - - if (arguments.length > 4) - this._object.open(sMethod, sUrl, bAsync, sUser, sPassword); - else - if (arguments.length > 3) - this._object.open(sMethod, sUrl, bAsync, sUser); - else - this._object.open(sMethod, sUrl, bAsync); - - this.readyState = cXMLHttpRequest.OPENED; - fReadyStateChange(this); - - this._object.onreadystatechange = function() { - if (bGecko && !bAsync) - return; - - // Synchronize state - oRequest.readyState = oRequest._object.readyState; - - // - fSynchronizeValues(oRequest); - - // BUGFIX: Firefox fires unnecessary DONE when aborting - if (oRequest._aborted) { - // Reset readyState to UNSENT - oRequest.readyState = cXMLHttpRequest.UNSENT; - - // Return now - return; - } - - if (oRequest.readyState == cXMLHttpRequest.DONE) { - // Free up queue - delete oRequest._data; -/* if (bAsync) - fQueue_remove(oRequest);*/ - // - fCleanTransport(oRequest); -// Uncomment this block if you need a fix for IE cache -/* - // BUGFIX: IE - cache issue - if (!oRequest._object.getResponseHeader("Date")) { - // Save object to cache - oRequest._cached = oRequest._object; - - // Instantiate a new transport object - cXMLHttpRequest.call(oRequest); - - // Re-send request - if (sUser) { - if (sPassword) - oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword); - else - oRequest._object.open(sMethod, sUrl, bAsync, sUser); - } - else - oRequest._object.open(sMethod, sUrl, bAsync); - oRequest._object.setRequestHeader("If-Modified-Since", oRequest._cached.getResponseHeader("Last-Modified") || new window.Date(0)); - // Copy headers set - if (oRequest._headers) - for (var sHeader in oRequest._headers) - if (typeof oRequest._headers[sHeader] == "string") // Some frameworks prototype objects with functions - oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]); - - oRequest._object.onreadystatechange = function() { - // Synchronize state - oRequest.readyState = oRequest._object.readyState; - - if (oRequest._aborted) { - // - oRequest.readyState = cXMLHttpRequest.UNSENT; - - // Return - return; - } - - if (oRequest.readyState == cXMLHttpRequest.DONE) { - // Clean Object - fCleanTransport(oRequest); - - // get cached request - if (oRequest.status == 304) - oRequest._object = oRequest._cached; - - // - delete oRequest._cached; - - // - fSynchronizeValues(oRequest); - - // - fReadyStateChange(oRequest); - - // BUGFIX: IE - memory leak in interrupted - if (bIE && bAsync) - window.detachEvent("onunload", fOnUnload); - } - }; - oRequest._object.send(null); - - // Return now - wait until re-sent request is finished - return; - }; -*/ - // BUGFIX: IE - memory leak in interrupted - if (bIE && bAsync) - window.detachEvent("onunload", fOnUnload); - } - - // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice - if (nState != oRequest.readyState) - fReadyStateChange(oRequest); - - nState = oRequest.readyState; - } - }; - function fXMLHttpRequest_send(oRequest) { - oRequest._object.send(oRequest._data); - - // BUGFIX: Gecko - missing readystatechange calls in synchronous requests - if (bGecko && !oRequest._async) { - oRequest.readyState = cXMLHttpRequest.OPENED; - - // Synchronize state - fSynchronizeValues(oRequest); - - // Simulate missing states - while (oRequest.readyState < cXMLHttpRequest.DONE) { - oRequest.readyState++; - fReadyStateChange(oRequest); - // Check if we are aborted - if (oRequest._aborted) - return; - } - } - }; - cXMLHttpRequest.prototype.send = function(vData) { - // Add method sniffer - if (cXMLHttpRequest.onsend) - cXMLHttpRequest.onsend.apply(this, arguments); - - if (!arguments.length) - vData = null; - - // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required - // BUGFIX: IE - rewrites any custom mime-type to "text/xml" in case an XMLNode is sent - // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard) - if (vData && vData.nodeType) { - vData = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml; - if (!this._headers["Content-Type"]) - this._object.setRequestHeader("Content-Type", "application/xml"); - } - - this._data = vData; -/* - // Add to queue - if (this._async) - fQueue_add(this); - else*/ - fXMLHttpRequest_send(this); - }; - cXMLHttpRequest.prototype.abort = function() { - // Add method sniffer - if (cXMLHttpRequest.onabort) - cXMLHttpRequest.onabort.apply(this, arguments); - - // BUGFIX: Gecko - unnecessary DONE when aborting - if (this.readyState > cXMLHttpRequest.UNSENT) - this._aborted = true; - - this._object.abort(); - - // BUGFIX: IE - memory leak - fCleanTransport(this); - - this.readyState = cXMLHttpRequest.UNSENT; - - delete this._data; -/* if (this._async) - fQueue_remove(this);*/ - }; - cXMLHttpRequest.prototype.getAllResponseHeaders = function() { - return this._object.getAllResponseHeaders(); - }; - cXMLHttpRequest.prototype.getResponseHeader = function(sName) { - return this._object.getResponseHeader(sName); - }; - cXMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) { - // BUGFIX: IE - cache issue - if (!this._headers) - this._headers = {}; - this._headers[sName] = sValue; - - return this._object.setRequestHeader(sName, sValue); - }; - - // EventTarget interface implementation - cXMLHttpRequest.prototype.addEventListener = function(sName, fHandler, bUseCapture) { - for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) - if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture) - return; - // Add listener - this._listeners.push([sName, fHandler, bUseCapture]); - }; - - cXMLHttpRequest.prototype.removeEventListener = function(sName, fHandler, bUseCapture) { - for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) - if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture) - break; - // Remove listener - if (oListener) - this._listeners.splice(nIndex, 1); - }; - - cXMLHttpRequest.prototype.dispatchEvent = function(oEvent) { - var oEventPseudo = { - 'type': oEvent.type, - 'target': this, - 'currentTarget':this, - 'eventPhase': 2, - 'bubbles': oEvent.bubbles, - 'cancelable': oEvent.cancelable, - 'timeStamp': oEvent.timeStamp, - 'stopPropagation': function() {}, // There is no flow - 'preventDefault': function() {}, // There is no default action - 'initEvent': function() {} // Original event object should be initialized - }; - - // Execute onreadystatechange - if (oEventPseudo.type == "readystatechange" && this.onreadystatechange) - (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]); - - // Execute listeners - for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) - if (oListener[0] == oEventPseudo.type && !oListener[2]) - (oListener[1].handleEvent || oListener[1]).apply(this, [oEventPseudo]); - }; - - // - cXMLHttpRequest.prototype.toString = function() { - return '[' + "object" + ' ' + "XMLHttpRequest" + ']'; - }; - - cXMLHttpRequest.toString = function() { - return '[' + "XMLHttpRequest" + ']'; - }; - - // Helper function - function fReadyStateChange(oRequest) { - // Sniffing code - if (cXMLHttpRequest.onreadystatechange) - cXMLHttpRequest.onreadystatechange.apply(oRequest); - - // Fake event - oRequest.dispatchEvent({ - 'type': "readystatechange", - 'bubbles': false, - 'cancelable': false, - 'timeStamp': new Date + 0 - }); - }; - - function fGetDocument(oRequest) { - var oDocument = oRequest.responseXML, - sResponse = oRequest.responseText; - // Try parsing responseText - if (bIE && sResponse && oDocument && !oDocument.documentElement && oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)) { - oDocument = new window.ActiveXObject("Microsoft.XMLDOM"); - oDocument.async = false; - oDocument.validateOnParse = false; - oDocument.loadXML(sResponse); - } - // Check if there is no error in document - if (oDocument) - if ((bIE && oDocument.parseError != 0) || !oDocument.documentElement || (oDocument.documentElement && oDocument.documentElement.tagName == "parsererror")) - return null; - return oDocument; - }; - - function fSynchronizeValues(oRequest) { - try { oRequest.responseText = oRequest._object.responseText; } catch (e) {} - try { oRequest.responseXML = fGetDocument(oRequest._object); } catch (e) {} - try { oRequest.status = oRequest._object.status; } catch (e) {} - try { oRequest.statusText = oRequest._object.statusText; } catch (e) {} - }; - - function fCleanTransport(oRequest) { - // BUGFIX: IE - memory leak (on-page leak) - oRequest._object.onreadystatechange = new window.Function; - }; -/* - // Queue manager - var oQueuePending = {"CRITICAL":[],"HIGH":[],"NORMAL":[],"LOW":[],"LOWEST":[]}, - aQueueRunning = []; - function fQueue_add(oRequest) { - oQueuePending[oRequest.priority in oQueuePending ? oRequest.priority : "NORMAL"].push(oRequest); - // - setTimeout(fQueue_process); - }; - - function fQueue_remove(oRequest) { - for (var nIndex = 0, bFound = false; nIndex < aQueueRunning.length; nIndex++) - if (bFound) - aQueueRunning[nIndex - 1] = aQueueRunning[nIndex]; - else - if (aQueueRunning[nIndex] == oRequest) - bFound = true; - if (bFound) - aQueueRunning.length--; - // - setTimeout(fQueue_process); - }; - - function fQueue_process() { - if (aQueueRunning.length < 6) { - for (var sPriority in oQueuePending) { - if (oQueuePending[sPriority].length) { - var oRequest = oQueuePending[sPriority][0]; - oQueuePending[sPriority] = oQueuePending[sPriority].slice(1); - // - aQueueRunning.push(oRequest); - // Send request - fXMLHttpRequest_send(oRequest); - break; - } - } - } - }; -*/ - // Internet Explorer 5.0 (missing apply) - if (!window.Function.prototype.apply) { - window.Function.prototype.apply = function(oRequest, oArguments) { - if (!oArguments) - oArguments = []; - oRequest.__func = this; - oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]); - delete oRequest.__func; - }; - }; - - // Register new object with window - /** - * Class: OpenLayers.Request.XMLHttpRequest - * Standard-compliant (W3C) cross-browser implementation of the - * XMLHttpRequest object. From - * http://code.google.com/p/xmlhttprequest/. - */ - if (!OpenLayers.Request) { - /** - * This allows for OpenLayers/Request.js to be included - * before or after this script. - */ - OpenLayers.Request = {}; - } - OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest; -})(); -/* ====================================================================== - OpenLayers/Raster.js - ====================================================================== */ - -/** - * @requires OpenLayers/SingleFile.js - */ -OpenLayers.Raster = {}; -/* ====================================================================== - OpenLayers/Raster/Grid.js - ====================================================================== */ - -/** - * @requires OpenLayers/Raster.js - * @requires OpenLayers/BaseTypes/Class.js - */ - -OpenLayers.Raster.Grid = OpenLayers.Class({ - - /** - * Constant: EVENT_TYPES - * {Array(String)} Supported application event types. Register a listener - * for a particular event with the following syntax: - * (code) - * grid.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. - * - * Raster grid event types: - * update - Fired when the grid's underlying data is updated. - */ - EVENT_TYPES: ["update"], - - /** - * Constructor: OpenLayers.Raster.Grid - */ - initialize: function(config) { - OpenLayers.Util.extend(this, config); - this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES); - }, - - /** - * Method: getValue - */ - getValue: function(col, row) { - throw new Error("getValue must be defined") - }, - /** - * APIMethod: numCols - */ - numCols: function() { - throw new Error("numCols must be defined") - }, - /** - * APIMethod: numRows - */ - numRows: function() { - throw new Error("numRows must be defined") - }, - - /** - * APIMethod: forEach - * Iterate through call values in the grid. The provided function - * will be called with each cell value. - * - * Parameters: - * fn - {Function} - */ - forEach: function(fn) { - var cols = this.numCols(); - var rows = this.numRows(); - for (var j=0; j= this.getCount()) { - throw new Error("Bad grid index.") - } - var composite = this; - return new OpenLayers.Raster.Grid({ - numCols: function() { - return composite.numCols(); - }, - numRows: function() { - return composite.numRows(); - }, - getValue: function(col, row) { - return composite.getValue(col, row)[index]; - } - }); - }, - - - CLASS_NAME: "OpenLayers.Raster.Composite" - }; - -})()); - -OpenLayers.Raster.Composite.fromLayer = function(layer, options) { - var composite; - if (layer instanceof OpenLayers.Layer.Grid) { - composite = OpenLayers.Raster.Composite.fromGridLayer(layer); - } else if (layer instanceof OpenLayers.Layer.Vector) { - composite = OpenLayers.Raster.Composite.fromVectorLayer(layer, options); - } else { - throw new Error("Only Grid or Vector type layers can be used to create a raster"); - } - return composite; -}; - -OpenLayers.Raster.Composite.fromVectorLayer = function(layer, options) { - - var mapping = options && options.mapping || function(feature) { - return [255, 255, 255]; - }; - - var container = document.createElement("div"); - var renderer = new OpenLayers.Renderer.Canvas(container, { - hitDetection: false - }); - - var canvas = renderer.root; - var context = renderer.canvas; - - var composite = new OpenLayers.Raster.Composite({ - numCols: function() { - return canvas.width; - }, - numRows: function() { - return canvas.height; - }, - getCount: function() { - return 4; - }, - getValue: function(col, row) { - var pixelArray = getPixelArray(); - var cols = canvas.width; - var offset = 4 * (col + (row * cols)); - return Array.prototype.slice.apply(pixelArray, [offset, offset+4]); - }, - toDataURL: function() { - return canvas.toDataURL.apply(canvas, arguments); - } - }); - - var cache = {}; - function getPixelArray() { - if (!cache.pixelArray) { - var imageData = context.getImageData(0, 0, canvas.width, canvas.height); - cache.pixelArray = imageData.data; - } - return cache.pixelArray; - } - - function hex(value) { - value = Math.max(0, Math.min(255, value)); - return (3840 + value).toString(16).substring(1); - } - - var style = new OpenLayers.Style({ - stroke: false, - fillColor: "${getColor}", - fillOpacity: "${getOpacity}" - }, {context: { - getColor: function(feature) { - var rgba = mapping(feature); - return "#" + - hex(rgba[0]) + - hex(rgba[1]) + - hex(rgba[2]); - }, - getOpacity: function(feature) { - var rgba = mapping(feature); - return rgba[3] / 255; - } - }}); - - var clone = new OpenLayers.Layer.Vector(null, { - styleMap: new OpenLayers.StyleMap(style), - renderer: renderer - }); - - function triggerUpdate() { - cache = {}; - window.setTimeout(function() { - composite.events.triggerEvent("update"); - }, 0); - } - - function addFeatures(event) { - var features = event.features; - clone.addFeatures(features, {silent: true}); - - // features can only be added to one layer - // work around this by reassigning to original - for (var i=0, ii=features.length; i 1) ? Composite : Grid; - var grid = new Constructor({ - numCols: function() { - return getFirstGrid().numCols(); - }, - numRows: function() { - return getFirstGrid().numRows(); - }, - getValue: function(col, row) { - var values = new Array(len); - var arg; - for (var i=0; i - */ -OpenLayers.Control.DrawFeature = OpenLayers.Class(OpenLayers.Control, { - - /** - * Property: layer - * {} - */ - layer: null, - - /** - * Property: callbacks - * {Object} The functions that are sent to the handler for callback - */ - callbacks: null, - - /** - * APIProperty: events - * {} Events instance for listeners and triggering - * control specific events. - * - * Register a listener for a particular event with the following syntax: - * (code) - * control.events.register(type, obj, listener); - * (end) - * - * Supported event types (in addition to those from ): - * featureadded - Triggered when a feature is added - */ - - /** - * 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 - */ - - /** - * Constructor: OpenLayers.Control.DrawFeature - * - * Parameters: - * layer - {} - * handler - {} - * options - {Object} - */ - initialize: function(layer, handler, options) { - OpenLayers.Control.prototype.initialize.apply(this, [options]); - this.callbacks = OpenLayers.Util.extend( - { - done: this.drawFeature, - modify: function(vertex, feature) { - this.layer.events.triggerEvent( - "sketchmodified", {vertex: vertex, feature: feature} - ); - }, - create: function(vertex, feature) { - this.layer.events.triggerEvent( - "sketchstarted", {vertex: vertex, feature: feature} - ); - } - }, - this.callbacks - ); - this.layer = layer; - this.handlerOptions = this.handlerOptions || {}; - this.handlerOptions.layerOptions = OpenLayers.Util.applyDefaults( - this.handlerOptions.layerOptions, { - renderers: layer.renderers, rendererOptions: layer.rendererOptions - } - ); - if (!("multi" in this.handlerOptions)) { - this.handlerOptions.multi = this.multi; - } - 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}); - } - }, - - /** - * APIMethod: insertXY - * Insert a point in the current sketch given x & y coordinates. - * - * Parameters: - * x - {Number} The x-coordinate of the point. - * y - {Number} The y-coordinate of the point. - */ - insertXY: function(x, y) { - if (this.handler && this.handler.line) { - this.handler.insertXY(x, y); - } - }, - - /** - * APIMethod: insertDeltaXY - * Insert a point given offsets from the previously inserted point. - * - * Parameters: - * dx - {Number} The x-coordinate offset of the point. - * dy - {Number} The y-coordinate offset of the point. - */ - insertDeltaXY: function(dx, dy) { - if (this.handler && this.handler.line) { - this.handler.insertDeltaXY(dx, dy); - } - }, - - /** - * APIMethod: insertDirectionLength - * Insert a point in the current sketch given a direction and a length. - * - * Parameters: - * direction - {Number} Degrees clockwise from the positive x-axis. - * length - {Number} Distance from the previously drawn point. - */ - insertDirectionLength: function(direction, length) { - if (this.handler && this.handler.line) { - this.handler.insertDirectionLength(direction, length); - } - }, - - /** - * APIMethod: insertDeflectionLength - * Insert a point in the current sketch given a deflection and a length. - * The deflection should be degrees clockwise from the previously - * digitized segment. - * - * Parameters: - * deflection - {Number} Degrees clockwise from the previous segment. - * length - {Number} Distance from the previously drawn point. - */ - insertDeflectionLength: function(deflection, length) { - if (this.handler && this.handler.line) { - this.handler.insertDeflectionLength(deflection, length); - } - }, - - /** - * APIMethod: undo - * Remove the most recently added point in the current sketch geometry. - * - * Returns: - * {Boolean} An edit was undone. - */ - undo: function() { - return this.handler.undo && this.handler.undo(); - }, - - /** - * APIMethod: redo - * Reinsert the most recently removed point resulting from an call. - * The undo stack is deleted whenever a point is added by other means. - * - * Returns: - * {Boolean} An edit was redone. - */ - redo: function() { - return this.handler.redo && this.handler.redo(); - }, - - /** - * APIMethod: finishSketch - * Finishes the sketch without including the currently drawn point. - * This method can be called to terminate drawing programmatically - * instead of waiting for the user to end the sketch. - */ - finishSketch: function() { - this.handler.finishGeometry(); - }, - - /** - * APIMethod: cancel - * Cancel the current sketch. This removes the current sketch and keeps - * the drawing control active. - */ - cancel: function() { - this.handler.cancel(); - }, - - CLASS_NAME: "OpenLayers.Control.DrawFeature" -}); -/* ====================================================================== - OpenLayers/Handler/Polygon.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/Handler/Path.js - * @requires OpenLayers/Geometry/Polygon.js - */ - -/** - * Class: OpenLayers.Handler.Polygon - * Handler to draw a polygon on the map. Polygon is displayed on mouse down, - * moves on mouse move, and is finished on mouse up. - * - * Inherits from: - * - - * - - */ -OpenLayers.Handler.Polygon = OpenLayers.Class(OpenLayers.Handler.Path, { - - /** - * APIProperty: holeModifier - * {String} Key modifier to trigger hole digitizing. Acceptable values are - * "altKey", "shiftKey", or "ctrlKey". If not set, no hole digitizing - * will take place. Default is null. - */ - holeModifier: null, - - /** - * Property: drawingHole - * {Boolean} Currently drawing an interior ring. - */ - drawingHole: false, - - /** - * Property: polygon - * {} - */ - polygon: null, - - /** - * Constructor: OpenLayers.Handler.Polygon - * Create a Polygon Handler. - * - * Parameters: - * control - {} The control that owns this handler - * callbacks - {Object} An object with a properties whose values are - * functions. Various callbacks described below. - * options - {Object} An optional object with properties to be set on the - * handler - * - * Named callbacks: - * create - Called when a sketch is first created. Callback called with - * the creation point geometry and sketch feature. - * modify - Called with each move of a vertex with the vertex (point) - * geometry and the sketch feature. - * point - Called as each point is added. Receives the new point geometry. - * done - Called when the point drawing is finished. The callback will - * recieve a single argument, the polygon geometry. - * cancel - Called when the handler is deactivated while drawing. The - * cancel callback will receive a geometry. - */ - - /** - * Method: createFeature - * Add temporary geometries - * - * Parameters: - * pixel - {} The initial pixel location for the new - * feature. - */ - createFeature: function(pixel) { - var lonlat = this.layer.getLonLatFromViewPortPx(pixel); - var geometry = new OpenLayers.Geometry.Point( - lonlat.lon, lonlat.lat - ); - this.point = new OpenLayers.Feature.Vector(geometry); - this.line = new OpenLayers.Feature.Vector( - new OpenLayers.Geometry.LinearRing([this.point.geometry]) - ); - this.polygon = new OpenLayers.Feature.Vector( - new OpenLayers.Geometry.Polygon([this.line.geometry]) - ); - this.callback("create", [this.point.geometry, this.getSketch()]); - this.point.geometry.clearBounds(); - this.layer.addFeatures([this.polygon, this.point], {silent: true}); - }, - - /** - * Method: addPoint - * Add point to geometry. - * - * Parameters: - * pixel - {} The pixel location for the new point. - */ - addPoint: function(pixel) { - if(!this.drawingHole && this.holeModifier && - this.evt && this.evt[this.holeModifier]) { - var geometry = this.point.geometry; - var features = this.control.layer.features; - var candidate, polygon; - // look for intersections, last drawn gets priority - for (var i=features.length-1; i>=0; --i) { - candidate = features[i].geometry; - if ((candidate instanceof OpenLayers.Geometry.Polygon || - candidate instanceof OpenLayers.Geometry.MultiPolygon) && - candidate.intersects(geometry)) { - polygon = features[i]; - this.control.layer.removeFeatures([polygon], {silent: true}); - this.control.layer.events.registerPriority( - "sketchcomplete", this, this.finalizeInteriorRing - ); - this.control.layer.events.registerPriority( - "sketchmodified", this, this.enforceTopology - ); - polygon.geometry.addComponent(this.line.geometry); - this.polygon = polygon; - this.drawingHole = true; - break; - } - } - } - OpenLayers.Handler.Path.prototype.addPoint.apply(this, arguments); - }, - - /** - * Method: getCurrentPointIndex - * - * Returns: - * {Number} The index of the most recently drawn point. - */ - getCurrentPointIndex: function() { - return this.line.geometry.components.length - 2; - }, - - /** - * Method: enforceTopology - * Simple topology enforcement for drawing interior rings. Ensures vertices - * of interior rings are contained by exterior ring. Other topology - * rules are enforced in to allow drawing of - * rings that intersect only during the sketch (e.g. a "C" shaped ring - * that nearly encloses another ring). - */ - enforceTopology: function(event) { - var point = event.vertex; - var components = this.line.geometry.components; - // ensure that vertices of interior ring are contained by exterior ring - if (!this.polygon.geometry.intersects(point)) { - var last = components[components.length-3]; - point.x = last.x; - point.y = last.y; - } - }, - - /** - * Method: finishGeometry - * Finish the geometry and send it back to the control. - */ - finishGeometry: function() { - var index = this.line.geometry.components.length - 2; - this.line.geometry.removeComponent(this.line.geometry.components[index]); - this.removePoint(); - this.finalize(); - }, - - /** - * Method: finalizeInteriorRing - * Enforces that new ring has some area and doesn't contain vertices of any - * other rings. - */ - finalizeInteriorRing: function() { - var ring = this.line.geometry; - // ensure that ring has some area - var modified = (ring.getArea() !== 0); - if (modified) { - // ensure that new ring doesn't intersect any other rings - var rings = this.polygon.geometry.components; - for (var i=rings.length-2; i>=0; --i) { - if (ring.intersects(rings[i])) { - modified = false; - break; - } - } - if (modified) { - // ensure that new ring doesn't contain any other rings - var target; - outer: for (var i=rings.length-2; i>0; --i) { - var points = rings[i].components; - for (var j=0, jj=points.length; j} - */ - getSketch: function() { - return this.polygon; - }, - - /** - * Method: getGeometry - * Return the sketch geometry. If is true, this will return - * a multi-part geometry. - * - * Returns: - * {} - */ - getGeometry: function() { - var geometry = this.polygon && this.polygon.geometry; - if(geometry && this.multi) { - geometry = new OpenLayers.Geometry.MultiPolygon([geometry]); - } - return geometry; - }, - - CLASS_NAME: "OpenLayers.Handler.Polygon" -}); -/* ====================================================================== - OpenLayers/Control/DragFeature.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - - -/** - * @requires OpenLayers/Control.js - * @requires OpenLayers/Handler/Drag.js - * @requires OpenLayers/Handler/Feature.js - */ - -/** - * Class: OpenLayers.Control.DragFeature - * The DragFeature control moves a feature with a drag of the mouse. Create a - * new control with the constructor. - * - * Inherits From: - * - - */ -OpenLayers.Control.DragFeature = OpenLayers.Class(OpenLayers.Control, { - - /** - * APIProperty: geometryTypes - * {Array(String)} To restrict dragging to a limited set of geometry types, - * send a list of strings corresponding to the geometry class names. - */ - geometryTypes: null, - - /** - * APIProperty: onStart - * {Function} Define this function if you want to know when a drag starts. - * The function should expect to receive two arguments: the feature - * that is about to be dragged and the pixel location of the mouse. - * - * Parameters: - * feature - {} The feature that is about to be - * dragged. - * pixel - {} The pixel location of the mouse. - */ - onStart: function(feature, pixel) {}, - - /** - * APIProperty: onDrag - * {Function} Define this function if you want to know about each move of a - * feature. The function should expect to receive two arguments: the - * feature that is being dragged and the pixel location of the mouse. - * - * Parameters: - * feature - {} The feature that was dragged. - * pixel - {} The pixel location of the mouse. - */ - onDrag: function(feature, pixel) {}, - - /** - * APIProperty: onComplete - * {Function} Define this function if you want to know when a feature is - * done dragging. The function should expect to receive two arguments: - * the feature that is being dragged and the pixel location of the - * mouse. - * - * Parameters: - * feature - {} The feature that was dragged. - * pixel - {} The pixel location of the mouse. - */ - onComplete: function(feature, pixel) {}, - - /** - * APIProperty: onEnter - * {Function} Define this function if you want to know when the mouse - * goes over a feature and thereby makes this feature a candidate - * for dragging. - * - * Parameters: - * feature - {} The feature that is ready - * to be dragged. - */ - onEnter: function(feature) {}, - - /** - * APIProperty: onLeave - * {Function} Define this function if you want to know when the mouse - * goes out of the feature that was dragged. - * - * Parameters: - * feature - {} The feature that was dragged. - */ - onLeave: function(feature) {}, - - /** - * APIProperty: documentDrag - * {Boolean} If set to true, mouse dragging will continue even if the - * mouse cursor leaves the map viewport. Default is false. - */ - documentDrag: false, - - /** - * Property: layer - * {} - */ - layer: null, - - /** - * Property: feature - * {} - */ - feature: null, - - /** - * Property: dragCallbacks - * {Object} The functions that are sent to the drag handler for callback. - */ - dragCallbacks: {}, - - /** - * Property: featureCallbacks - * {Object} The functions that are sent to the feature handler for callback. - */ - featureCallbacks: {}, - - /** - * Property: lastPixel - * {} - */ - lastPixel: null, - - /** - * Constructor: OpenLayers.Control.DragFeature - * Create a new control to drag features. - * - * Parameters: - * layer - {} The layer containing features to be - * dragged. - * options - {Object} Optional object whose properties will be set on the - * control. - */ - initialize: function(layer, options) { - OpenLayers.Control.prototype.initialize.apply(this, [options]); - this.layer = layer; - this.handlers = { - drag: new OpenLayers.Handler.Drag( - this, OpenLayers.Util.extend({ - down: this.downFeature, - move: this.moveFeature, - up: this.upFeature, - out: this.cancel, - done: this.doneDragging - }, this.dragCallbacks), { - documentDrag: this.documentDrag - } - ), - feature: new OpenLayers.Handler.Feature( - this, this.layer, OpenLayers.Util.extend({ - // 'click' and 'clickout' callback are for the mobile - // support: no 'over' or 'out' in touch based browsers. - click: this.clickFeature, - clickout: this.clickoutFeature, - over: this.overFeature, - out: this.outFeature - }, this.featureCallbacks), - {geometryTypes: this.geometryTypes} - ) - }; - }, - - /** - * Method: clickFeature - * Called when the feature handler detects a click-in on a feature. - * - * Parameters: - * feature - {} - */ - clickFeature: function(feature) { - if (this.handlers.feature.touch && !this.over && this.overFeature(feature)) { - this.handlers.drag.dragstart(this.handlers.feature.evt); - // to let the events propagate to the feature handler (click callback) - this.handlers.drag.stopDown = false; - } - }, - - /** - * Method: clickoutFeature - * Called when the feature handler detects a click-out on a feature. - * - * Parameters: - * feature - {} - */ - clickoutFeature: function(feature) { - if (this.handlers.feature.touch && this.over) { - this.outFeature(feature); - this.handlers.drag.stopDown = true; - } - }, - - /** - * APIMethod: destroy - * Take care of things that are not handled in superclass - */ - destroy: function() { - this.layer = null; - OpenLayers.Control.prototype.destroy.apply(this, []); - }, - - /** - * APIMethod: activate - * Activate the control and the feature handler. - * - * Returns: - * {Boolean} Successfully activated the control and feature handler. - */ - activate: function() { - return (this.handlers.feature.activate() && - OpenLayers.Control.prototype.activate.apply(this, arguments)); - }, - - /** - * APIMethod: deactivate - * Deactivate the control and all handlers. - * - * Returns: - * {Boolean} Successfully deactivated the control. - */ - deactivate: function() { - // the return from the handlers is unimportant in this case - this.handlers.drag.deactivate(); - this.handlers.feature.deactivate(); - this.feature = null; - this.dragging = false; - this.lastPixel = null; - OpenLayers.Element.removeClass( - this.map.viewPortDiv, this.displayClass + "Over" - ); - return OpenLayers.Control.prototype.deactivate.apply(this, arguments); - }, - - /** - * Method: overFeature - * Called when the feature handler detects a mouse-over on a feature. - * This activates the drag handler. - * - * Parameters: - * feature - {} The selected feature. - * - * Returns: - * {Boolean} Successfully activated the drag handler. - */ - overFeature: function(feature) { - var activated = false; - if(!this.handlers.drag.dragging) { - this.feature = feature; - this.handlers.drag.activate(); - activated = true; - this.over = true; - OpenLayers.Element.addClass(this.map.viewPortDiv, this.displayClass + "Over"); - this.onEnter(feature); - } else { - if(this.feature.id == feature.id) { - this.over = true; - } else { - this.over = false; - } - } - return activated; - }, - - /** - * Method: downFeature - * Called when the drag handler detects a mouse-down. - * - * Parameters: - * pixel - {} Location of the mouse event. - */ - downFeature: function(pixel) { - this.lastPixel = pixel; - this.onStart(this.feature, pixel); - }, - - /** - * Method: moveFeature - * Called when the drag handler detects a mouse-move. Also calls the - * optional onDrag method. - * - * Parameters: - * pixel - {} Location of the mouse event. - */ - moveFeature: function(pixel) { - var res = this.map.getResolution(); - this.feature.geometry.move(res * (pixel.x - this.lastPixel.x), - res * (this.lastPixel.y - pixel.y)); - this.layer.drawFeature(this.feature); - this.lastPixel = pixel; - this.onDrag(this.feature, pixel); - }, - - /** - * Method: upFeature - * Called when the drag handler detects a mouse-up. - * - * Parameters: - * pixel - {} Location of the mouse event. - */ - upFeature: function(pixel) { - if(!this.over) { - this.handlers.drag.deactivate(); - } - }, - - /** - * Method: doneDragging - * Called when the drag handler is done dragging. - * - * Parameters: - * pixel - {} The last event pixel location. If this event - * came from a mouseout, this may not be in the map viewport. - */ - doneDragging: function(pixel) { - this.layer.events.triggerEvent("featuremodified", {feature: this.feature}); - this.onComplete(this.feature, pixel); - }, - - /** - * Method: outFeature - * Called when the feature handler detects a mouse-out on a feature. - * - * Parameters: - * feature - {} The feature that the mouse left. - */ - outFeature: function(feature) { - if(!this.handlers.drag.dragging) { - this.over = false; - this.handlers.drag.deactivate(); - OpenLayers.Element.removeClass( - this.map.viewPortDiv, this.displayClass + "Over" - ); - this.onLeave(feature); - this.feature = null; - } else { - if(this.feature.id == feature.id) { - this.over = false; - } - } - }, - - /** - * Method: cancel - * Called when the drag handler detects a mouse-out (from the map viewport). - */ - cancel: function() { - this.handlers.drag.deactivate(); - this.over = false; - }, - - /** - * Method: setMap - * Set the map property for the control and all handlers. - * - * Parameters: - * map - {} The control's map. - */ - setMap: function(map) { - this.handlers.drag.setMap(map); - this.handlers.feature.setMap(map); - OpenLayers.Control.prototype.setMap.apply(this, arguments); - }, - - CLASS_NAME: "OpenLayers.Control.DragFeature" -}); -/* ====================================================================== - OpenLayers/Protocol/WFS/v1_1_0.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/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 - * 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_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 - {} 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/LayerSwitcher.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Control.js - * @requires OpenLayers/Lang.js - * @requires OpenLayers/Console.js - * @requires OpenLayers/Events/buttonclick.js - */ - -/** - * Class: OpenLayers.Control.LayerSwitcher - * The LayerSwitcher control displays a table of contents for the map. This - * allows the user interface to switch between BaseLasyers and to show or hide - * Overlays. By default the switcher is shown minimized on the right edge of - * the map, the user may expand it by clicking on the handle. - * - * To create the LayerSwitcher outside of the map, pass the Id of a html div - * as the first argument to the constructor. - * - * Inherits from: - * - - */ -OpenLayers.Control.LayerSwitcher = - OpenLayers.Class(OpenLayers.Control, { - - /** - * APIProperty: roundedCorner - * {Boolean} If true the Rico library is used for rounding the corners - * of the layer switcher div, defaults to false. *Deprecated*. Use - * CSS3's border-radius instead. If this option is set to true the - * Rico/Corner.js script must be loaded in the page, and therefore - * listed in the build profile. - * - */ - roundedCorner: false, - - /** - * APIProperty: roundedCornerColor - * {String} The color of the rounded corners, only applies if roundedCorner - * is true, defaults to "darkblue". - */ - roundedCornerColor: "darkblue", - - /** - * Property: layerStates - * {Array(Object)} Basically a copy of the "state" of the map's layers - * the last time the control was drawn. We have this in order to avoid - * unnecessarily redrawing the control. - */ - layerStates: null, - - - // DOM Elements - - /** - * Property: layersDiv - * {DOMElement} - */ - layersDiv: null, - - /** - * Property: baseLayersDiv - * {DOMElement} - */ - baseLayersDiv: null, - - /** - * Property: baseLayers - * {Array(Object)} - */ - baseLayers: null, - - - /** - * Property: dataLbl - * {DOMElement} - */ - dataLbl: null, - - /** - * Property: dataLayersDiv - * {DOMElement} - */ - dataLayersDiv: null, - - /** - * Property: dataLayers - * {Array(Object)} - */ - dataLayers: null, - - - /** - * Property: minimizeDiv - * {DOMElement} - */ - minimizeDiv: null, - - /** - * Property: maximizeDiv - * {DOMElement} - */ - maximizeDiv: null, - - /** - * APIProperty: ascending - * {Boolean} - */ - ascending: true, - - /** - * Constructor: OpenLayers.Control.LayerSwitcher - * - * Parameters: - * options - {Object} - */ - initialize: function(options) { - OpenLayers.Control.prototype.initialize.apply(this, arguments); - this.layerStates = []; - - if(this.roundedCorner) { - OpenLayers.Console.warn('roundedCorner option is deprecated'); - } - }, - - /** - * APIMethod: destroy - */ - destroy: function() { - - //clear out layers info and unregister their events - this.clearLayersArray("base"); - this.clearLayersArray("data"); - - this.map.events.un({ - buttonclick: this.onButtonClick, - addlayer: this.redraw, - changelayer: this.redraw, - removelayer: this.redraw, - changebaselayer: this.redraw, - scope: this - }); - this.events.unregister("buttonclick", this, this.onButtonClick); - - OpenLayers.Control.prototype.destroy.apply(this, arguments); - }, - - /** - * Method: setMap - * - * Properties: - * map - {} - */ - setMap: function(map) { - OpenLayers.Control.prototype.setMap.apply(this, arguments); - - this.map.events.on({ - addlayer: this.redraw, - changelayer: this.redraw, - removelayer: this.redraw, - changebaselayer: this.redraw, - scope: this - }); - if (this.outsideViewport) { - this.events.attachToElement(this.div); - this.events.register("buttonclick", this, this.onButtonClick); - } else { - this.map.events.register("buttonclick", this, this.onButtonClick); - } - }, - - /** - * Method: draw - * - * Returns: - * {DOMElement} A reference to the DIV DOMElement containing the - * switcher tabs. - */ - draw: function() { - OpenLayers.Control.prototype.draw.apply(this); - - // create layout divs - this.loadContents(); - - // set mode to minimize - if(!this.outsideViewport) { - this.minimizeControl(); - } - - // populate div with current info - this.redraw(); - - return this.div; - }, - - /** - * Method: onButtonClick - * - * Parameters: - * evt - {Event} - */ - onButtonClick: function(evt) { - var button = evt.buttonElement; - if (button === this.minimizeDiv) { - this.minimizeControl(); - } else if (button === this.maximizeDiv) { - this.maximizeControl(); - } else if (button._layerSwitcher === this.id) { - if (button["for"]) { - button = document.getElementById(button["for"]); - } - if (!button.disabled) { - if (button.type == "radio") { - button.checked = true; - this.map.setBaseLayer(this.map.getLayer(button._layer)); - } else { - button.checked = !button.checked; - this.updateMap(); - } - } - } - }, - - /** - * Method: clearLayersArray - * User specifies either "base" or "data". we then clear all the - * corresponding listeners, the div, and reinitialize a new array. - * - * Parameters: - * layersType - {String} - */ - clearLayersArray: function(layersType) { - this[layersType + "LayersDiv"].innerHTML = ""; - this[layersType + "Layers"] = []; - }, - - - /** - * Method: checkRedraw - * Checks if the layer state has changed since the last redraw() call. - * - * Returns: - * {Boolean} The layer state changed since the last redraw() call. - */ - checkRedraw: function() { - var redraw = false; - if ( !this.layerStates.length || - (this.map.layers.length != this.layerStates.length) ) { - redraw = true; - } else { - for (var i=0, len=this.layerStates.length; i - */ -OpenLayers.Layer.Raster = OpenLayers.Class(OpenLayers.Layer, { - - needsUpdate: false, - - initialize: function(config) { - config = config || {}; - var data = config.data; - delete config.data; - OpenLayers.Layer.prototype.initialize.apply(this, [config.name, config]); - - this.canvas = document.createElement("canvas"); - this.canvas.style.position = "absolute"; - this.div.appendChild(this.canvas); - this.context = this.canvas.getContext("2d"); - if (data) { - this.setData(data); - } - - }, - - setData: function(data) { - this.clearData(); - this.data = data; - data.events.register("update", this, this.onDataUpdate); - }, - - clearData: function() { - if (this.data) { - this.data.events.unregister("update", this, this.onDataUpdate); - delete this.data; - } - }, - - moveTo: function() { - this.needsUpdate = true; - OpenLayers.Layer.prototype.moveTo.apply(this, arguments); - window.setTimeout(OpenLayers.Function.bind(this.afterMoveTo, this), 0); - }, - - afterMoveTo: function() { - if (this.needsUpdate) { - this.onDataUpdate(); - } - }, - - onDataUpdate: function() { - var map = this.map; - if (map) { - var size = map.getSize(); - var cols = this.data.numCols(); - var rows = this.data.numRows(); - var style = map.layerContainerDiv.style; - this.canvas.width = cols; - this.canvas.height = rows; - this.canvas.style.top = (-parseInt(style.top)) + "px"; - this.canvas.style.left = (-parseInt(style.left)) + "px"; - this.canvas.style.width = size.w + "px"; - this.canvas.style.height = size.h + "px"; - - var imageData = this.context.createImageData(cols, rows); - var data = imageData.data; - // TODO: provide shortcut for canvas based composites - this.data.forEach(function(value, index) { - var offset = 4 * index; - if (!value.length) { - value = [value, value, value]; - } - data[offset + 0] = value[0]; // red - data[offset + 1] = value[1]; // green - data[offset + 2] = value[2]; // blue - if (value.length > 3) { - data[offset + 3] = value[3]; // opacity - } else { - data[offset + 3] = 255; // assume opaque - } - }); - this.context.putImageData(imageData, 0, 0); - this.needsUpdate = false; - } - }, - - CLASS_NAME: "OpenLayers.Layer.Raster" - -}); +var OpenLayers={VERSION_NUMBER:"Release 2.13 dev",singleFile:true,_getScriptLocation:function(){for(var a=/(^|(.*?\/))(OpenLayers[^\/]*?\.js)(\?|$)/,b=document.getElementsByTagName("script"),c,d="",e=0,f=b.length;e0)c=parseFloat(a.toPrecision(b));return c},format:function(a,b,c,d){b=typeof b!="undefined"?b:0;c=typeof c!="undefined"?c:OpenLayers.Number.thousandsSeparator;d=typeof d!="undefined"?d:OpenLayers.Number.decimalSeparator;if(b!=null)a=parseFloat(a.toFixed(b));var e=a.toString().split(".");if(e.length==1&&b==null)b=0;a=e[0];if(c)for(var f=/(-?[0-9]+)([0-9]{3})/;f.test(a);)a=a.replace(f,"$1"+c+"$2"); +if(b==0)b=a;else{c=e.length>1?e[1]:"0";if(b!=null)c+=Array(b-c.length+1).join("0");b=a+d+c}return b}};OpenLayers.Function={bind:function(a,b){var c=Array.prototype.slice.apply(arguments,[2]);return function(){var d=c.concat(Array.prototype.slice.apply(arguments,[0]));return a.apply(b,d)}},bindAsEventListener:function(a,b){return function(c){return a.call(b,c||window.event)}},False:function(){return false},True:function(){return true},Void:function(){}}; +OpenLayers.Array={filter:function(a,b,c){var d=[];if(Array.prototype.filter)d=a.filter(b,c);else{var e=a.length;if(typeof b!="function")throw new TypeError;for(var f=0;f1){a=[d,b].concat(Array.prototype.slice.call(arguments).slice(1,a-1),c);OpenLayers.inherit.apply(null,a)}else d.prototype=c;return d}; +OpenLayers.inherit=function(a,b){var c=function(){};c.prototype=b.prototype;a.prototype=new c;var d,e;c=2;for(d=arguments.length;cthis.right)this.right=b.right;if(this.top==null||b.top>this.top)this.top=b.top}}},containsLonLat:function(a,b){if(typeof b==="boolean")b={inclusive:b};b=b||{};var c=this.contains(a.lon,a.lat,b.inclusive),d=b.worldBounds;if(d&&!c){c=d.getWidth();c=this.containsLonLat({lon:a.lon-Math.round((a.lon-(d.left+d.right)/2)/c)*c,lat:a.lat},{inclusive:b.inclusive})}return c},containsPixel:function(a, +b){return this.contains(a.x,a.y,b)},contains:function(a,b,c){if(c==null)c=true;if(a==null||b==null)return false;a=OpenLayers.Util.toFloat(a);b=OpenLayers.Util.toFloat(b);var d=false;return d=c?a>=this.left&&a<=this.right&&b>=this.bottom&&b<=this.top:a>this.left&&athis.bottom&&b=c.bottom&&a.top<=c.top||c.top>a.bottom&&c.top=c.left&&a.left<=c.right||c.left>=a.left&&c.left<=a.right;var f=a.right>=c.left&&a.right<=c.right||c.right>=a.left&&c.right<=a.right;d=(a.bottom>=c.bottom&&a.bottom<=c.top||c.bottom>=a.bottom&&c.bottom<=a.top||d)&&(e||f)}if(b.worldBounds&&!d){var g=b.worldBounds;e=g.getWidth();f=!g.containsBounds(c);g=!g.containsBounds(a);if(f&& +!g){a=a.add(-e,0);d=c.intersectsBounds(a,{inclusive:b.inclusive})}else if(g&&!f){c=c.add(-e,0);d=a.intersectsBounds(c,{inclusive:b.inclusive})}}return d},containsBounds:function(a,b,c){if(b==null)b=false;if(c==null)c=true;var d=this.contains(a.left,a.bottom,c),e=this.contains(a.right,a.bottom,c),f=this.contains(a.left,a.top,c);a=this.contains(a.right,a.top,c);return b?d||e||f||a:d&&e&&f&&a},determineQuadrant:function(a){var b="",c=this.getCenterLonLat();b+=a.lat=a.right&&e.right>a.right;)e=e.add(-f,0);c=e.left+c;if(ca.left&&e.right-d>a.right)e=e.add(-f,0)}return e},CLASS_NAME:"OpenLayers.Bounds"});OpenLayers.Bounds.fromString=function(a,b){var c=a.split(",");return OpenLayers.Bounds.fromArray(c,b)}; +OpenLayers.Bounds.fromArray=function(a,b){return b===true?new OpenLayers.Bounds(a[1],a[0],a[3],a[2]):new OpenLayers.Bounds(a[0],a[1],a[2],a[3])};OpenLayers.Bounds.fromSize=function(a){return new OpenLayers.Bounds(0,a.h,a.w,0)};OpenLayers.Bounds.oppositeQuadrant=function(a){var b="";b+=a.charAt(0)=="t"?"b":"t";b+=a.charAt(1)=="l"?"r":"l";return b};OpenLayers.Element={visible:function(a){return OpenLayers.Util.getElement(a).style.display!="none"},toggle:function(){for(var a=0,b=arguments.length;aa.right;)b.lon-=a.getWidth()}return b},CLASS_NAME:"OpenLayers.LonLat"}); +OpenLayers.LonLat.fromString=function(a){a=a.split(",");return new OpenLayers.LonLat(a[0],a[1])};OpenLayers.LonLat.fromArray=function(a){var b=OpenLayers.Util.isArray(a);return new OpenLayers.LonLat(b&&a[0],b&&a[1])};OpenLayers.Pixel=OpenLayers.Class({x:0,y:0,initialize:function(a,b){this.x=parseFloat(a);this.y=parseFloat(b)},toString:function(){return"x="+this.x+",y="+this.y},clone:function(){return new OpenLayers.Pixel(this.x,this.y)},equals:function(a){var b=false;if(a!=null)b=this.x==a.x&&this.y==a.y||isNaN(this.x)&&isNaN(this.y)&&isNaN(a.x)&&isNaN(a.y);return b},distanceTo:function(a){return Math.sqrt(Math.pow(this.x-a.x,2)+Math.pow(this.y-a.y,2))},add:function(a,b){if(a==null||b==null)throw new TypeError("Pixel.add cannot receive null values"); +return new OpenLayers.Pixel(this.x+a,this.y+b)},offset:function(a){var b=this.clone();if(a)b=this.add(a.x,a.y);return b},CLASS_NAME:"OpenLayers.Pixel"});OpenLayers.Size=OpenLayers.Class({w:0,h:0,initialize:function(a,b){this.w=parseFloat(a);this.h=parseFloat(b)},toString:function(){return"w="+this.w+",h="+this.h},clone:function(){return new OpenLayers.Size(this.w,this.h)},equals:function(a){var b=false;if(a!=null)b=this.w==a.w&&this.h==a.h||isNaN(this.w)&&isNaN(this.h)&&isNaN(a.w)&&isNaN(a.h);return b},CLASS_NAME:"OpenLayers.Size"});OpenLayers.Console={log:function(){},debug:function(){},info:function(){},warn:function(){},error:function(){},userError:function(a){alert(a)},assert:function(){},dir:function(){},dirxml:function(){},trace:function(){},group:function(){},groupEnd:function(){},time:function(){},timeEnd:function(){},profile:function(){},profileEnd:function(){},count:function(){},CLASS_NAME:"OpenLayers.Console"}; +(function(){for(var a=document.getElementsByTagName("script"),b=0,c=a.length;b=0;c--)a[c]==b&&a.splice(c,1);return a}; +OpenLayers.Util.indexOf=function(a,b){if(typeof a.indexOf=="function")return a.indexOf(b);else{for(var c=0,d=a.length;c=0&&parseFloat(h)<1){a.style.filter="alpha(opacity="+h*100+")";a.style.opacity=h}else if(parseFloat(h)==1){a.style.filter="";a.style.opacity=""}}; +OpenLayers.Util.createDiv=function(a,b,c,d,e,f,g,h){var i=document.createElement("div");if(d)i.style.backgroundImage="url("+d+")";a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="absolute");OpenLayers.Util.modifyDOMElement(i,a,b,c,e,f,g,h);return i}; +OpenLayers.Util.createImage=function(a,b,c,d,e,f,g,h){var i=document.createElement("img");a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="relative");OpenLayers.Util.modifyDOMElement(i,a,b,c,e,f,null,g);if(h){i.style.display="none";b=function(){i.style.display="";OpenLayers.Event.stopObservingElement(i)};OpenLayers.Event.observe(i,"load",b);OpenLayers.Event.observe(i,"error",b)}i.style.alt=a;i.galleryImg="no";if(d)i.src=d;return i};OpenLayers.IMAGE_RELOAD_ATTEMPTS=0; +OpenLayers.Util.alphaHackNeeded=null;OpenLayers.Util.alphaHack=function(){if(OpenLayers.Util.alphaHackNeeded==null){var a=navigator.appVersion.split("MSIE");a=parseFloat(a[1]);var b=false;try{b=!!document.body.filters}catch(c){}OpenLayers.Util.alphaHackNeeded=b&&a>=5.5&&a<7}return OpenLayers.Util.alphaHackNeeded}; +OpenLayers.Util.modifyAlphaImageDiv=function(a,b,c,d,e,f,g,h,i){OpenLayers.Util.modifyDOMElement(a,b,c,d,f,null,null,i);b=a.childNodes[0];if(e)b.src=e;OpenLayers.Util.modifyDOMElement(b,a.id+"_innerImage",null,d,"relative",g);if(OpenLayers.Util.alphaHack()){if(a.style.display!="none")a.style.display="inline-block";if(h==null)h="scale";a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+b.src+"', sizingMethod='"+h+"')";if(parseFloat(a.style.opacity)>=0&&parseFloat(a.style.opacity)< +1)a.style.filter+=" alpha(opacity="+a.style.opacity*100+")";b.style.filter="alpha(opacity=0)"}};OpenLayers.Util.createAlphaImageDiv=function(a,b,c,d,e,f,g,h,i){var j=OpenLayers.Util.createDiv();i=OpenLayers.Util.createImage(null,null,null,null,null,null,null,i);i.className="olAlphaImg";j.appendChild(i);OpenLayers.Util.modifyAlphaImageDiv(j,a,b,c,d,e,f,g,h);return j};OpenLayers.Util.upperCaseObject=function(a){var b={},c;for(c in a)b[c.toUpperCase()]=a[c];return b}; +OpenLayers.Util.applyDefaults=function(a,b){a=a||{};var c=typeof window.Event=="function"&&b instanceof window.Event,d;for(d in b)if(a[d]===undefined||!c&&b.hasOwnProperty&&b.hasOwnProperty(d)&&!a.hasOwnProperty(d))a[d]=b[d];if(!c&&b&&b.hasOwnProperty&&b.hasOwnProperty("toString")&&!a.hasOwnProperty("toString"))a.toString=b.toString;return a}; +OpenLayers.Util.getParameterString=function(a){var b=[],c;for(c in a){var d=a[c];if(d!=null&&typeof d!="function"){if(typeof d=="object"&&d.constructor==Array){for(var e=[],f,g=0,h=d.length;g1.0E-12&&--o>0;){var l=Math.sin(k),n=Math.cos(k),q=Math.sqrt(h*l*h*l+(g*j-i*h*n)*(g*j-i*h*n));if(q==0)return 0;n=i*j+g*h*n;var p=Math.atan2(q,n),r= +Math.asin(g*h*l/q),s=Math.cos(r)*Math.cos(r);l=n-2*i*j/s;var t=c/16*s*(4+c*(4-3*s));m=k;k=f+(1-t)*c*Math.sin(r)*(p+t*q*(l+t*n*(-1+2*l*l)))}if(o==0)return NaN;d=s*(d*d-e*e)/(e*e);c=d/1024*(256+d*(-128+d*(74-47*d)));return(e*(1+d/16384*(4096+d*(-768+d*(320-175*d))))*(p-c*q*(l+c/4*(n*(-1+2*l*l)-c/6*l*(-3+4*q*q)*(-3+4*l*l))))).toFixed(3)/1E3}; +OpenLayers.Util.destinationVincenty=function(a,b,c){var d=OpenLayers.Util,e=d.VincentyConstants,f=e.a,g=e.b;e=e.f;var h=a.lon,i=a.lat;a=d.rad(b);b=Math.sin(a);a=Math.cos(a);var j=(1-e)*Math.tan(d.rad(i));i=1/Math.sqrt(1+j*j);var k=j*i,m=Math.atan2(j,a);j=i*b;var o=1-j*j;f=o*(f*f-g*g)/(g*g);var l=1+f/16384*(4096+f*(-768+f*(320-175*f))),n=f/1024*(256+f*(-128+f*(74-47*f)));f=c/(g*l);for(var q=2*Math.PI;Math.abs(f-q)>1.0E-12;){var p=Math.cos(2*m+f),r=Math.sin(f),s=Math.cos(f),t=n*r*(p+n/4*(s*(-1+2*p* +p)-n/6*p*(-3+4*r*r)*(-3+4*p*p)));q=f;f=c/(g*l)+t}c=k*r-i*s*a;c=Math.atan2(k*s+i*r*a,(1-e)*Math.sqrt(j*j+c*c));g=e/16*o*(4+e*(4-3*o));return new OpenLayers.LonLat(h+d.deg(Math.atan2(r*b,i*s-k*r*a)-(1-g)*e*j*(f+g*r*(p+g*s*(-1+2*p*p)))),d.deg(c))}; +OpenLayers.Util.getParameters=function(a){a=a===null||a===undefined?window.location.href:a;var b="";if(OpenLayers.String.contains(a,"?")){b=a.indexOf("?")+1;var c=OpenLayers.String.contains(a,"#")?a.indexOf("#"):a.length;b=a.substring(b,c)}a={};b=b.split(/[&;]/);c=0;for(var d=b.length;c1?1/a:a};OpenLayers.Util.getResolutionFromScale=function(a,b){var c;if(a){if(b==null)b="degrees";c=1/(OpenLayers.Util.normalizeScale(a)*OpenLayers.INCHES_PER_UNIT[b]*OpenLayers.DOTS_PER_INCH)}return c}; +OpenLayers.Util.getScaleFromResolution=function(a,b){if(b==null)b="degrees";return a*OpenLayers.INCHES_PER_UNIT[b]*OpenLayers.DOTS_PER_INCH}; +OpenLayers.Util.pagePosition=function(a){var b=[0,0],c=OpenLayers.Util.getViewportElement();if(!a||a==window||a==c)return b;var d=OpenLayers.IS_GECKO&&document.getBoxObjectFor&&OpenLayers.Element.getStyle(a,"position")=="absolute"&&(a.style.top==""||a.style.left==""),e=null;if(a.getBoundingClientRect){a=a.getBoundingClientRect();e=c.scrollTop;b[0]=a.left+c.scrollLeft;b[1]=a.top+e}else if(document.getBoxObjectFor&&!d){a=document.getBoxObjectFor(a);c=document.getBoxObjectFor(c);b[0]=a.screenX-c.screenX; +b[1]=a.screenY-c.screenY}else{b[0]=a.offsetLeft;b[1]=a.offsetTop;e=a.offsetParent;if(e!=a)for(;e;){b[0]+=e.offsetLeft;b[1]+=e.offsetTop;e=e.offsetParent}c=OpenLayers.BROWSER_NAME;if(c=="opera"||c=="safari"&&OpenLayers.Element.getStyle(a,"position")=="absolute")b[1]-=document.body.offsetTop;for(e=a.offsetParent;e&&e!=document.body;){b[0]-=e.scrollLeft;if(c!="opera"||e.tagName!="TR")b[1]-=e.scrollTop;e=e.offsetParent}}return b}; +OpenLayers.Util.getViewportElement=function(){var a=arguments.callee.viewportElement;if(a==undefined){a=OpenLayers.BROWSER_NAME=="msie"&&document.compatMode!="CSS1Compat"?document.body:document.documentElement;arguments.callee.viewportElement=a}return a}; +OpenLayers.Util.isEquivalentUrl=function(a,b,c){c=c||{};OpenLayers.Util.applyDefaults(c,{ignoreCase:true,ignorePort80:true,ignoreHash:true});a=OpenLayers.Util.createUrlObject(a,c);b=OpenLayers.Util.createUrlObject(b,c);for(var d in a)if(d!=="args")if(a[d]!=b[d])return false;for(d in a.args){if(a.args[d]!=b.args[d])return false;delete b.args[d]}for(d in b.args)return false;return true}; +OpenLayers.Util.createUrlObject=function(a,b){b=b||{};if(!/^\w+:\/\//.test(a)){var c=window.location,d=c.port?":"+c.port:"";d=c.protocol+"//"+c.host.split(":").shift()+d;if(a.indexOf("/")===0)a=d+a;else{c=c.pathname.split("/");c.pop();a=d+c.join("/")+"/"+a}}if(b.ignoreCase)a=a.toLowerCase();c=document.createElement("a");c.href=a;d={};d.host=c.host.split(":").shift();d.protocol=c.protocol;d.port=b.ignorePort80?c.port=="80"||c.port=="0"?"":c.port:c.port==""||c.port=="0"?"80":c.port;d.hash=b.ignoreHash|| +c.hash==="#"?"":c.hash;var e=c.search;if(!e){e=a.indexOf("?");e=e!=-1?a.substr(e):""}d.args=OpenLayers.Util.getParameters(e);d.pathname=c.pathname.charAt(0)=="/"?c.pathname:"/"+c.pathname;return d};OpenLayers.Util.removeTail=function(a){var b=null;b=a.indexOf("?");var c=a.indexOf("#");return b=b==-1?c!=-1?a.substr(0,c):a:c!=-1?a.substr(0,Math.min(b,c)):a.substr(0,b)};OpenLayers.IS_GECKO=function(){var a=navigator.userAgent.toLowerCase();return a.indexOf("webkit")==-1&&a.indexOf("gecko")!=-1}(); +OpenLayers.CANVAS_SUPPORTED=function(){var a=document.createElement("canvas");return!!(a.getContext&&a.getContext("2d"))}();OpenLayers.BROWSER_NAME=function(){var a="",b=navigator.userAgent.toLowerCase();if(b.indexOf("opera")!=-1)a="opera";else if(b.indexOf("msie")!=-1)a="msie";else if(b.indexOf("safari")!=-1)a="safari";else if(b.indexOf("mozilla")!=-1)a=b.indexOf("firefox")!=-1?"firefox":"mozilla";return a}();OpenLayers.Util.getBrowserName=function(){return OpenLayers.BROWSER_NAME}; +OpenLayers.Util.getRenderedDimensions=function(a,b,c){var d,e,f=document.createElement("div");f.style.visibility="hidden";for(var g=c&&c.containerElement?c.containerElement:document.body,h=false,i=null,j=g;j&&j.tagName.toLowerCase()!="body";){var k=OpenLayers.Element.getStyle(j,"position");if(k=="absolute"){h=true;break}else if(k&&k!="static")break;j=j.parentNode}if(h&&(g.clientHeight===0||g.clientWidth===0)){i=document.createElement("div");i.style.visibility="hidden";i.style.position="absolute"; +i.style.overflow="visible";i.style.width=document.body.clientWidth+"px";i.style.height=document.body.clientHeight+"px";i.appendChild(f)}f.style.position="absolute";if(b)if(b.w){d=b.w;f.style.width=d+"px"}else if(b.h){e=b.h;f.style.height=e+"px"}if(c&&c.displayClass)f.className=c.displayClass;b=document.createElement("div");b.innerHTML=a;b.style.overflow="visible";if(b.childNodes){a=0;for(c=b.childNodes.length;a=60){f-=60;d+=1;if(d>=60){d-=60;e+=1}}if(e<10)e="0"+e;e=e+"\u00b0";if(c.indexOf("dm")>=0){if(d<10)d="0"+d;e+=d+"'";if(c.indexOf("dms")>=0){if(f<10)f="0"+f;e+=f+'"'}}e+=b=="lon"?a<0?OpenLayers.i18n("W"):OpenLayers.i18n("E"):a<0?OpenLayers.i18n("S"):OpenLayers.i18n("N");return e};OpenLayers.Event={observers:false,KEY_SPACE:32,KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,element:function(a){return a.target||a.srcElement},isSingleTouch:function(a){return a.touches&&a.touches.length==1},isMultiTouch:function(a){return a.touches&&a.touches.length>1},isLeftClick:function(a){return a.which&&a.which==1||a.button&&a.button==1},isRightClick:function(a){return a.which&&a.which==3||a.button&&a.button==2},stop:function(a, +b){b||OpenLayers.Event.preventDefault(a);if(a.stopPropagation)a.stopPropagation();else a.cancelBubble=true},preventDefault:function(a){if(a.preventDefault)a.preventDefault();else a.returnValue=false},findElement:function(a,b){for(var c=OpenLayers.Event.element(a);c.parentNode&&(!c.tagName||c.tagName.toUpperCase()!=b.toUpperCase());)c=c.parentNode;return c},observe:function(a,b,c,d){a=OpenLayers.Util.getElement(a);d=d||false;if(b=="keypress"&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)|| +a.attachEvent))b="keydown";if(!this.observers)this.observers={};if(!a._eventCacheID){var e="eventCacheID_";if(a.id)e=a.id+"_"+e;a._eventCacheID=OpenLayers.Util.createUniqueID(e)}e=a._eventCacheID;this.observers[e]||(this.observers[e]=[]);this.observers[e].push({element:a,name:b,observer:c,useCapture:d});if(a.addEventListener)a.addEventListener(b,c,d);else a.attachEvent&&a.attachEvent("on"+b,c)},stopObservingElement:function(a){a=OpenLayers.Util.getElement(a)._eventCacheID;this._removeElementObservers(OpenLayers.Event.observers[a])}, +_removeElementObservers:function(a){if(a)for(var b=a.length-1;b>=0;b--){var c=a[b];OpenLayers.Event.stopObserving.apply(this,[c.element,c.name,c.observer,c.useCapture])}},stopObserving:function(a,b,c,d){d=d||false;a=OpenLayers.Util.getElement(a);var e=a._eventCacheID;if(b=="keypress")if(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||a.detachEvent)b="keydown";var f=false,g=OpenLayers.Event.observers[e];if(g)for(var h=0;!f&&h=0;--a)this.target.register(this.events[a],this,this.buttonClick,{extension:true})},destroy:function(){for(var a=this.events.length-1;a>=0;--a)this.target.unregister(this.events[a],this, +this.buttonClick);delete this.target},getPressedButton:function(a){var b=3,c;do{if(OpenLayers.Element.hasClass(a,"olButton")){c=a;break}a=a.parentNode}while(--b>0&&a);return c},ignore:function(a){var b=3,c=false;do{if(a.nodeName.toLowerCase()==="a"){c=true;break}a=a.parentNode}while(--b>0&&a);return c},buttonClick:function(a){var b=true,c=OpenLayers.Event.element(a);if(c&&(OpenLayers.Event.isLeftClick(a)||!~a.type.indexOf("mouse")))if(c=this.getPressedButton(c)){if(a.type==="keydown")switch(a.keyCode){case OpenLayers.Event.KEY_RETURN:case OpenLayers.Event.KEY_SPACE:this.target.triggerEvent("buttonclick", +{buttonElement:c});OpenLayers.Event.stop(a);b=false}else if(this.startEvt){if(this.completeRegEx.test(a.type)){b=OpenLayers.Util.pagePosition(c);this.target.triggerEvent("buttonclick",{buttonElement:c,buttonXY:{x:this.startEvt.clientX-b[0],y:this.startEvt.clientY-b[1]}})}this.cancelRegEx.test(a.type)&&delete this.startEvt;OpenLayers.Event.stop(a);b=false}if(this.startRegEx.test(a.type)){this.startEvt=a;OpenLayers.Event.stop(a);b=false}}else{b=!this.ignore(OpenLayers.Event.element(a));delete this.startEvt}return b}});OpenLayers.Format=OpenLayers.Class({options:null,externalProjection:null,internalProjection:null,data:null,keepData:false,initialize:function(a){OpenLayers.Util.extend(this,a);this.options=a},destroy:function(){},read:function(){throw Error("Read not implemented.");},write:function(){throw Error("Write not implemented.");},CLASS_NAME:"OpenLayers.Format"});OpenLayers.Format.XML=OpenLayers.Class(OpenLayers.Format,{namespaces:null,namespaceAlias:null,defaultPrefix:null,readers:{},writers:{},xmldom:null,initialize:function(a){if(window.ActiveXObject)this.xmldom=new ActiveXObject("Microsoft.XMLDOM");OpenLayers.Format.prototype.initialize.apply(this,[a]);this.namespaces=OpenLayers.Util.extend({},this.namespaces);this.namespaceAlias={};for(var b in this.namespaces)this.namespaceAlias[this.namespaces[b]]=b},destroy:function(){this.xmldom=null;OpenLayers.Format.prototype.destroy.apply(this, +arguments)},setNamespace:function(a,b){this.namespaces[a]=b;this.namespaceAlias[b]=a},read:function(a){var b=a.indexOf("<");if(b>0)a=a.substring(b);b=OpenLayers.Util.Try(OpenLayers.Function.bind(function(){var c;c=window.ActiveXObject&&!this.xmldom?new ActiveXObject("Microsoft.XMLDOM"):this.xmldom;c.loadXML(a);return c},this),function(){return(new DOMParser).parseFromString(a,"text/xml")},function(){var c=new XMLHttpRequest;c.open("GET","data:text/xml;charset=utf-8,"+encodeURIComponent(a),false); +c.overrideMimeType&&c.overrideMimeType("text/xml");c.send(null);return c.responseXML});if(this.keepData)this.data=b;return b},write:function(a){if(this.xmldom)a=a.xml;else{var b=new XMLSerializer;if(a.nodeType==1){var c=document.implementation.createDocument("","",null);if(c.importNode)a=c.importNode(a,true);c.appendChild(a);a=b.serializeToString(c)}else a=b.serializeToString(a)}return a},createElementNS:function(a,b){return this.xmldom?typeof a=="string"?this.xmldom.createNode(1,b,a):this.xmldom.createNode(1, +b,""):document.createElementNS(a,b)},createTextNode:function(a){if(typeof a!=="string")a=String(a);return this.xmldom?this.xmldom.createTextNode(a):document.createTextNode(a)},getElementsByTagNameNS:function(a,b,c){var d=[];if(a.getElementsByTagNameNS)d=a.getElementsByTagNameNS(b,c);else{a=a.getElementsByTagName("*");for(var e,f,g=0,h=a.length;g0){d=a.substring(0,e);a=a.substring(e+1)}else{d=c?this.namespaceAlias[c.namespaceURI]:this.defaultPrefix;a=a}b=this.writers[d][a].apply(this,[b]);c&&c.appendChild(b);return b},getChildEl:function(a,b,c){return a&& +this.getThisOrNextEl(a.firstChild,b,c)},getNextEl:function(a,b,c){return a&&this.getThisOrNextEl(a.nextSibling,b,c)},getThisOrNextEl:function(a,b,c){a=a;a:for(;a;a=a.nextSibling)switch(a.nodeType){case 1:if((!b||b===(a.localName||a.nodeName.split(":").pop()))&&(!c||c===a.namespaceURI))break a;a=null;break a;case 3:if(/^\s*$/.test(a.nodeValue))break;case 4:case 6:case 12:case 10:case 11:a=null;break a}return a||null},lookupNamespaceURI:function(a,b){var c=null;if(a)if(a.lookupNamespaceURI)c=a.lookupNamespaceURI(b); +else a:switch(a.nodeType){case 1:if(a.namespaceURI!==null&&a.prefix===b){c=a.namespaceURI;break a}if(c=a.attributes.length)for(var d,e=0;e0){f=true;g=0;for(h=e.length;g0&&f==false)b.display="none";if(b.label!= +null&&typeof b.label!=="string")b.label=String(b.label);return b},applySymbolizer:function(a,b,c){var d=c.geometry?this.getSymbolizerPrefix(c.geometry):OpenLayers.Style.SYMBOLIZER_PREFIXES[0];a=a.symbolizer[d]||a.symbolizer;if(this.defaultsPerSymbolizer===true){d=this.defaultStyle;OpenLayers.Util.applyDefaults(a,{pointRadius:d.pointRadius});if(a.stroke===true||a.graphic===true)OpenLayers.Util.applyDefaults(a,{strokeWidth:d.strokeWidth,strokeColor:d.strokeColor,strokeOpacity:d.strokeOpacity,strokeDashstyle:d.strokeDashstyle, +strokeLinecap:d.strokeLinecap});if(a.fill===true||a.graphic===true)OpenLayers.Util.applyDefaults(a,{fillColor:d.fillColor,fillOpacity:d.fillOpacity});a.graphic===true&&OpenLayers.Util.applyDefaults(a,{pointRadius:this.defaultStyle.pointRadius,externalGraphic:this.defaultStyle.externalGraphic,graphicName:this.defaultStyle.graphicName,graphicOpacity:this.defaultStyle.graphicOpacity,graphicWidth:this.defaultStyle.graphicWidth,graphicHeight:this.defaultStyle.graphicHeight,graphicXOffset:this.defaultStyle.graphicXOffset, +graphicYOffset:this.defaultStyle.graphicYOffset})}return this.createLiterals(OpenLayers.Util.extend(b,a),c)},createLiterals:function(a,b){var c=OpenLayers.Util.extend({},b.attributes||b.data);OpenLayers.Util.extend(c,this.context);for(var d in this.propertyStyles)a[d]=OpenLayers.Style.createLiteral(a[d],c,b,d);return a},findPropertyStyles:function(){var a={};this.addPropertyStyles(a,this.defaultStyle);for(var b=this.rules,c,d,e=0,f=b.length;ethis.value;break;case OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO:b=a<=this.value;break;case OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO:b= +a>=this.value;break;case OpenLayers.Filter.Comparison.BETWEEN:b=a>=this.lowerBoundary&&a<=this.upperBoundary;break;case OpenLayers.Filter.Comparison.LIKE:b=RegExp(this.value,"gi").test(a)}return b},value2regex:function(a,b,c){if(a==".")throw Error("'.' is an unsupported wildCard character for OpenLayers.Filter.Comparison");a=a?a:"*";b=b?b:".";c=c?c:"!";this.value=this.value.replace(RegExp("\\"+c+"(.|$)","g"),"\\$1");this.value=this.value.replace(RegExp("\\"+b,"g"),".");this.value=this.value.replace(RegExp("\\"+ +a,"g"),".*");this.value=this.value.replace(RegExp("\\\\.\\*","g"),"\\"+a);return this.value=this.value.replace(RegExp("\\\\\\.","g"),"\\"+b)},regex2value:function(){var a=this.value;a=a.replace(/!/g,"!!");a=a.replace(/(\\)?\\\./g,function(b,c){return c?b:"!."});a=a.replace(/(\\)?\\\*/g,function(b,c){return c?b:"!*"});a=a.replace(/\\\\/g,"\\");return a=a.replace(/\.\*/g,"*")},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=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",CLASS_NAME:"OpenLayers.Format.Filter"});OpenLayers.Filter.Function=OpenLayers.Class(OpenLayers.Filter,{name:null,params:null,CLASS_NAME:"OpenLayers.Filter.Function"});OpenLayers.Format.Filter.v1=OpenLayers.Class(OpenLayers.Format.XML,{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"},defaultPrefix:"ogc",schemaLocation:null,initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){var b={};this.readers.ogc.Filter.apply(this,[a,b]);return b.filter},readers:{ogc:{_expression:function(a){for(var b="",c=a.firstChild;c;c= +c.nextSibling)switch(c.nodeType){case 1:a=this.readNode(c);if(a.property)b+="${"+a.property+"}";else if(a.value!==undefined)b+=a.value;break;case 3:case 4:b+=c.nodeValue}return b},Filter:function(a,b){var c={fids:[],filters:[]};this.readChildNodes(a,c);if(c.fids.length>0)b.filter=new OpenLayers.Filter.FeatureId({fids:c.fids});else if(c.filters.length>0)b.filter=c.filters[0]},FeatureId:function(a,b){var c=a.getAttribute("fid");c&&b.fids.push(c)},And:function(a,b){var c=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND}); +this.readChildNodes(a,c);b.filters.push(c)},Or:function(a,b){var c=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.OR});this.readChildNodes(a,c);b.filters.push(c)},Not:function(a,b){var c=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.NOT});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsLessThan:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LESS_THAN});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsGreaterThan:function(a, +b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.GREATER_THAN});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsLessThanOrEqualTo:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsGreaterThanOrEqualTo:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO});this.readChildNodes(a,c);b.filters.push(c)}, +PropertyIsBetween:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.BETWEEN});this.readChildNodes(a,c);b.filters.push(c)},Literal:function(a,b){b.value=OpenLayers.String.numericIf(this.getChildValue(a),true)},PropertyName:function(a,b){b.property=this.getChildValue(a)},LowerBoundary:function(a,b){b.lowerBoundary=OpenLayers.String.numericIf(this.readers.ogc._expression.call(this,a),true)},UpperBoundary:function(a,b){b.upperBoundary=OpenLayers.String.numericIf(this.readers.ogc._expression.call(this, +a),true)},Intersects:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.INTERSECTS)},Within:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.WITHIN)},Contains:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.CONTAINS)},DWithin:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.DWITHIN)},Distance:function(a,b){b.distance=parseInt(this.getChildValue(a));b.distanceUnits=a.getAttribute("units")},Function:function(){}}},readSpatial:function(a,b,c){c=new OpenLayers.Filter.Spatial({type:c}); +this.readChildNodes(a,c);c.value=c.components[0];delete c.components;b.filters.push(c)},writeOgcExpression:function(a,b){if(a instanceof OpenLayers.Filter.Function){var c=this.writeNode("Function",a,b);b.appendChild(c)}else this.writeNode("Literal",a,b);return b},write:function(a){return this.writers.ogc.Filter.apply(this,[a])},writeFeatureIdNodes:function(a,b){for(var c=0,d=a.fids.length;c":"PropertyIsGreaterThan", +"<=":"PropertyIsLessThanOrEqualTo",">=":"PropertyIsGreaterThanOrEqualTo","..":"PropertyIsBetween","~":"PropertyIsLike",BBOX:"BBOX",DWITHIN:"DWITHIN",WITHIN:"WITHIN",CONTAINS:"CONTAINS",INTERSECTS:"INTERSECTS",FID:"FeatureId"},CLASS_NAME:"OpenLayers.Format.Filter.v1"});OpenLayers.Geometry=OpenLayers.Class({id:null,parent:null,bounds:null,initialize:function(){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){this.bounds=this.id=null},clone:function(){return new OpenLayers.Geometry},setBounds:function(a){if(a)this.bounds=a.clone()},clearBounds:function(){this.bounds=null;this.parent&&this.parent.clearBounds()},extendBounds:function(a){this.getBounds()?this.bounds.extend(a):this.setBounds(a)},getBounds:function(){this.bounds==null&&this.calculateBounds(); +return this.bounds},calculateBounds:function(){},distanceTo:function(){},getVertices:function(){},atPoint:function(a,b,c){var d=false;if(this.getBounds()!=null&&a!=null){b=b!=null?b:0;c=c!=null?c:0;d=(new OpenLayers.Bounds(this.bounds.left-b,this.bounds.bottom-c,this.bounds.right+b,this.bounds.top+c)).containsLonLat(a)}return d},getLength:function(){return 0},getArea:function(){return 0},getCentroid:function(){return null},toString:function(){return OpenLayers.Format&&OpenLayers.Format.WKT?OpenLayers.Format.WKT.prototype.write(new OpenLayers.Feature.Vector(this)): +Object.prototype.toString.call(this)},CLASS_NAME:"OpenLayers.Geometry"});OpenLayers.Geometry.fromWKT=function(a){var b;if(OpenLayers.Format&&OpenLayers.Format.WKT){var c=OpenLayers.Geometry.fromWKT.format;if(!c){c=new OpenLayers.Format.WKT;OpenLayers.Geometry.fromWKT.format=c}a=c.read(a);if(a instanceof OpenLayers.Feature.Vector)b=a.geometry;else if(OpenLayers.Util.isArray(a)){b=a.length;c=Array(b);for(var d=0;d=0&&f<=1&&m>=0&&m<=1)if(d){h=a.x1+f*h;m=a.y1+f*i;e=new OpenLayers.Geometry.Point(h,m)}else e=true}if(c)if(e){if(d){a=[a,b];b=0;a:for(;b<2;++b){f=a[b];for(i=1;i<3;++i){h=f["x"+i];m=f["y"+i];d=Math.sqrt(Math.pow(h-e.x,2)+Math.pow(m-e.y,2));if(d=1){e=g;f=h}else{e=e+k*i;f=f+k*j}return{distance:Math.sqrt(Math.pow(e-c,2)+Math.pow(f-d,2)),x:e,y:f}};OpenLayers.Geometry.Point=OpenLayers.Class(OpenLayers.Geometry,{x:null,y:null,initialize:function(a,b){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.x=parseFloat(a);this.y=parseFloat(b)},clone:function(a){if(a==null)a=new OpenLayers.Geometry.Point(this.x,this.y);OpenLayers.Util.applyDefaults(a,this);return a},calculateBounds:function(){this.bounds=new OpenLayers.Bounds(this.x,this.y,this.x,this.y)},distanceTo:function(a,b){var c=!(b&&b.edge===false)&&b&&b.details,d,e,f,g,h;if(a instanceof +OpenLayers.Geometry.Point){e=this.x;f=this.y;g=a.x;h=a.y;d=Math.sqrt(Math.pow(e-g,2)+Math.pow(f-h,2));d=!c?d:{x0:e,y0:f,x1:g,y1:h,distance:d}}else{d=a.distanceTo(this,b);if(c)d={x0:d.x1,y0:d.y1,x1:d.x0,y1:d.y0,distance:d.distance}}return d},equals:function(a){var b=false;if(a!=null)b=this.x==a.x&&this.y==a.y||isNaN(this.x)&&isNaN(this.y)&&isNaN(a.x)&&isNaN(a.y);return b},toShortString:function(){return this.x+", "+this.y},move:function(a,b){this.x+=a;this.y+=b;this.clearBounds()},rotate:function(a, +b){a*=Math.PI/180;var c=this.distanceTo(b),d=a+Math.atan2(this.y-b.y,this.x-b.x);this.x=b.x+c*Math.cos(d);this.y=b.y+c*Math.sin(d);this.clearBounds()},getCentroid:function(){return new OpenLayers.Geometry.Point(this.x,this.y)},resize:function(a,b,c){c=c==undefined?1:c;this.x=b.x+a*c*(this.x-b.x);this.y=b.y+a*(this.y-b.y);this.clearBounds();return this},intersects:function(a){var b=false;return b=a.CLASS_NAME=="OpenLayers.Geometry.Point"?this.equals(a):a.intersects(this)},transform:function(a,b){if(a&& +b){OpenLayers.Projection.transform(this,a,b);this.bounds=null}return this},getVertices:function(){return[this]},CLASS_NAME:"OpenLayers.Geometry.Point"});OpenLayers.Geometry.Collection=OpenLayers.Class(OpenLayers.Geometry,{components:null,componentTypes:null,initialize:function(a){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.components=[];a!=null&&this.addComponents(a)},destroy:function(){this.components.length=0;this.components=null;OpenLayers.Geometry.prototype.destroy.apply(this,arguments)},clone:function(){for(var a=eval("new "+this.CLASS_NAME+"()"),b=0,c=this.components.length;b-1){if(b!=null&&b=0;--c)b=this.removeComponent(a[c])||b;return b},removeComponent:function(a){OpenLayers.Util.removeItem(this.components,a);this.clearBounds();return true},getLength:function(){for(var a=0,b=0,c=this.components.length;b0?h:e;c.push(f)}}a=b.length;if(d===0){for(g=0;g1)for(var b=1,c=this.components.length;b1)for(var d,e=1,f=b.components.length;e< +f;e++){c=b.components[e-1];d=b.components[e];a+=OpenLayers.Util.distVincenty({lon:c.x,lat:c.y},{lon:d.x,lat:d.y})}return a*1E3},CLASS_NAME:"OpenLayers.Geometry.Curve"});OpenLayers.Geometry.LineString=OpenLayers.Class(OpenLayers.Geometry.Curve,{removeComponent:function(){var a=this.components&&this.components.length>2;a&&OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,arguments);return a},intersects:function(a){var b=false,c=a.CLASS_NAME;if(c=="OpenLayers.Geometry.LineString"||c=="OpenLayers.Geometry.LinearRing"||c=="OpenLayers.Geometry.Point"){var d=this.getSortedSegments();a=c=="OpenLayers.Geometry.Point"?[{x1:a.x,y1:a.y,x2:a.x,y2:a.y}]:a.getSortedSegments(); +var e,f,g,h,i,j,k,m=0,o=d.length;a:for(;mf)break;if(!(i.x2Math.max(g,h)))if(!(Math.max(j,k)0){var p=a.x10){l.unshift(r,1);Array.prototype.splice.apply(h,l);r+=l.length-2}if(d)for(var s=0,t=o.points.length;s0&&n.length>0){n.push(k.clone()); +g.push(new OpenLayers.Geometry.LineString(n))}}else c=a.splitWith(this,b);if(h&&h.length>1)f=true;else h=[];if(g&&g.length>1)e=true;else g=[];if(f||e)c=d?[g,h]:h;return c},splitWith:function(a,b){return a.split(this,b)},getVertices:function(a){return a===true?[this.components[0],this.components[this.components.length-1]]:a===false?this.components.slice(1,this.components.length-1):this.components.slice()},distanceTo:function(a,b){var c=!(b&&b.edge===false)&&b&&b.details,d,e={},f=Number.POSITIVE_INFINITY; +if(a instanceof OpenLayers.Geometry.Point){for(var g=this.getSortedSegments(),h=a.x,i=a.y,j,k=0,m=g.length;kh&&(i>j.y1&&ij.y2))break}e=c?{distance:e.distance,x0:e.x,y0:e.y,x1:h,y1:i}:e.distance}else if(a instanceof OpenLayers.Geometry.LineString){g=this.getSortedSegments();h=a.getSortedSegments();var o,l,n=h.length,q={point:true};k=0;m=g.length;a:for(;kj){j=o;k=m}}if(j>i&&k!=g){e.push(k);c(f,g,k,i);c(f,k,h,i)}},d=b.length-1,e=[];e.push(0);for(e.push(d);b[0].equals(b[d]);){d--;e.push(d)}c(b, +0,d,a);a=[];e.sort(function(f,g){return f-g});for(d=0;d1)g=true;else i=[];if(j&&j.length>1)h=true;else j=[];if(g||h)c=d?[i,j]:j;return c},splitWith:function(a,b){var c=null,d=b&&b.mutual,e,f,g,h,i,j;if(a instanceof OpenLayers.Geometry.LineString){j=[];i=[a];for(var k=0,m=this.components.length;k1)h=true;else i=[];if(j&&j.length>1)g=true;else j=[];if(h||g)c=d?[i,j]:j;return c},CLASS_NAME:"OpenLayers.Geometry.MultiLineString"});OpenLayers.Geometry.LinearRing=OpenLayers.Class(OpenLayers.Geometry.LineString,{componentTypes:["OpenLayers.Geometry.Point"],addComponent:function(a,b){var c=false,d=this.components.pop();if(b!=null||!a.equals(d))c=OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,arguments);OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[this.components[0]]);return c},removeComponent:function(){var a=this.components&&this.components.length>3;if(a){this.components.pop();OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, +arguments);OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[this.components[0]])}return a},move:function(a,b){for(var c=0,d=this.components.length;c0&&a<=2)return this.components[0].clone();else if(a>2){var b=0,c=0,d=this.components[0].x,e=this.components[0].y,f=-1*this.getArea();if(f!=0){for(var g=0;g2){for(var b=a=0,c=this.components.length;b2){for(var d,e,f=0;f=g&&c<=h||g>=h&&c<=g&&c>=h){j=-1;break}}else{i=b((a-f)*((h- +g)/(f-e))+h,14);if(i==c)if(e=e&&a<=f||e>f&&a<=e&&a>=f){j=-1;break}if(!(i<=c))if(!(g!=h&&(iMath.max(g,h))))if(e=e&&af&&a=f)++j}}return j==-1?1:!!(j&1)},intersects:function(a){var b=false;if(a.CLASS_NAME=="OpenLayers.Geometry.Point")b=this.containsPoint(a);else if(a.CLASS_NAME=="OpenLayers.Geometry.LineString")b=a.intersects(this);else if(a.CLASS_NAME=="OpenLayers.Geometry.LinearRing")b=OpenLayers.Geometry.LineString.prototype.intersects.apply(this,[a]);else for(var c= +0,d=a.components.length;c0){a+=Math.abs(this.components[0].getArea());for(var b=1,c=this.components.length;b0){b+=Math.abs(this.components[0].getGeodesicArea(a));for(var c=1,d=this.components.length;c< +d;c++)b-=Math.abs(this.components[c].getGeodesicArea(a))}return b},containsPoint:function(a){var b=this.components.length,c=false;if(b>0){c=this.components[0].containsPoint(a);if(c!==1)if(c&&b>1)for(var d,e=1;e0){if(e=this.parseGeometry[c.toLowerCase()]){e=e.apply(this, +[d[0]]);this.internalProjection&&this.externalProjection&&e.transform(this.externalProjection,this.internalProjection)}else throw new TypeError("Unsupported geometry type: "+c);break}}var g;c=this.getElementsByTagNameNS(a,this.gmlns,"Box");for(f=0;f0){c=b[0].firstChild.nodeValue;c=c.replace(this.regExes.trimSpace,"");c=c.split(this.regExes.splitSpace)}if(c.length== +0){b=this.getElementsByTagNameNS(a,this.gmlns,"coordinates");if(b.length>0){c=b[0].firstChild.nodeValue;c=c.replace(this.regExes.removeSpace,"");c=c.split(",")}}if(c.length==0){b=this.getElementsByTagNameNS(a,this.gmlns,"coord");if(b.length>0){a=this.getElementsByTagNameNS(b[0],this.gmlns,"X");b=this.getElementsByTagNameNS(b[0],this.gmlns,"Y");if(a.length>0&&b.length>0)c=[a[0].firstChild.nodeValue,b[0].firstChild.nodeValue]}}if(c.length==2)c[2]=null;return this.xy?new OpenLayers.Geometry.Point(c[0], +c[1],c[2]):new OpenLayers.Geometry.Point(c[1],c[0],c[2])},multipoint:function(a){a=this.getElementsByTagNameNS(a,this.gmlns,"Point");var b=[];if(a.length>0)for(var c,d=0;d0){d=this.getChildValue(c[0]);d=d.replace(this.regExes.trimSpace,"");d=d.split(this.regExes.splitSpace); +var f=parseInt(c[0].getAttribute("dimension")),g,h,i;for(c=0;c0){d=this.getChildValue(c[0]);d=d.replace(this.regExes.trimSpace,"");d=d.replace(this.regExes.trimComma,",");f=d.split(this.regExes.splitSpace);for(c=0;c0)for(var c,d=0;d0)for(var c,d=0;d0)for(var c,d=0;d0){c=[];if(e.length>0){c=e[0].firstChild.nodeValue;c=c.replace(this.regExes.trimSpace,"");c=c.split(this.regExes.splitSpace)}if(c.length==2)c[2]=null;var f=this.xy?new OpenLayers.Geometry.Point(c[0],c[1],c[2]):new OpenLayers.Geometry.Point(c[1],c[0],c[2])}a=this.getElementsByTagNameNS(a,this.gmlns,"upperCorner");if(a.length>0){c=[];if(a.length>0){c=a[0].firstChild.nodeValue;c=c.replace(this.regExes.trimSpace,"");c=c.split(this.regExes.splitSpace)}if(c.length== +2)c[2]=null;var g=this.xy?new OpenLayers.Geometry.Point(c[0],c[1],c[2]):new OpenLayers.Geometry.Point(c[1],c[0],c[2])}if(f&&g){b.push(new OpenLayers.Geometry.Point(f.x,f.y));b.push(new OpenLayers.Geometry.Point(g.x,f.y));b.push(new OpenLayers.Geometry.Point(g.x,g.y));b.push(new OpenLayers.Geometry.Point(f.x,g.y));b.push(new OpenLayers.Geometry.Point(f.x,f.y));b=new OpenLayers.Geometry.LinearRing(b);d=new OpenLayers.Geometry.Polygon([b])}return d},box:function(a){var b=this.getElementsByTagNameNS(a, +this.gmlns,"coordinates");var c=a=null;if(b.length>0){b=b[0].firstChild.nodeValue;b=b.split(" ");if(b.length==2){a=b[0].split(",");c=b[1].split(",")}}if(a!==null&&c!==null)return new OpenLayers.Bounds(parseFloat(a[0]),parseFloat(a[1]),parseFloat(c[0]),parseFloat(c[1]))}},parseAttributes:function(a){var b={};a=a.firstChild;for(var c,d,e;a;){if(a.nodeType==1){a=a.childNodes;for(c=0;c0)b.bounds=c.components[0]},Point:function(a,b){var c={points:[]};this.readChildNodes(a,c);if(!b.components)b.components=[];b.components.push(c.points[0])},coordinates:function(a,b){var c=this.getChildValue(a).replace(this.regExes.trimSpace,"");c=c.replace(this.regExes.trimComma,",");c=c.split(this.regExes.splitSpace);for(var d,e=c.length,f=Array(e),g=0;g0)b.components= +[new OpenLayers.Geometry.MultiLineString(c.components)]},curveMember:function(a,b){this.readChildNodes(a,b)},MultiSurface:function(a,b){var c={components:[]};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);if(c.components.length>0)b.components=[new OpenLayers.Geometry.MultiPolygon(c.components)]},surfaceMember:function(a,b){this.readChildNodes(a,b)},surfaceMembers:function(a,b){this.readChildNodes(a,b)},pointMembers:function(a,b){this.readChildNodes(a,b)},lineStringMembers:function(a, +b){this.readChildNodes(a,b)},polygonMembers:function(a,b){this.readChildNodes(a,b)},geometryMembers:function(a,b){this.readChildNodes(a,b)},Envelope:function(a,b){var c={points:Array(2)};this.readChildNodes(a,c);if(!b.components)b.components=[];var d=c.points[0];c=c.points[1];b.components.push(new OpenLayers.Bounds(d.x,d.y,c.x,c.y))},lowerCorner:function(a,b){var c={};this.readers.gml.pos.apply(this,[a,c]);b.points[0]=c.points[0]},upperCorner:function(a,b){var c={};this.readers.gml.pos.apply(this, +[a,c]);b.points[1]=c.points[0]}},OpenLayers.Format.GML.Base.prototype.readers.gml),feature:OpenLayers.Format.GML.Base.prototype.readers.feature,wfs:OpenLayers.Format.GML.Base.prototype.readers.wfs},write:function(a){a=this.writeNode("gml:"+(OpenLayers.Util.isArray(a)?"featureMembers":"featureMember"),a);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{gml:OpenLayers.Util.applyDefaults({featureMembers:function(a){for(var b= +this.createElementNSPlus("gml:featureMembers"),c=0,d=a.length;c0?h:Number.POSITIVE_INFINITY;var j=++e,k=+new Date;f[j]=function(){if(f[j]&&+new Date-k<=h){g();f[j]&&d(f[j],i)}else delete f[j]};d(f[j],i);return j},stop:function(g){delete f[g]}}}(window);OpenLayers.Tween=OpenLayers.Class({easing:null,begin:null,finish:null,duration:null,callbacks:null,time:null,animationId:null,playing:false,initialize:function(a){this.easing=a?a:OpenLayers.Easing.Expo.easeOut},start:function(a,b,c,d){this.playing=true;this.begin=a;this.finish=b;this.duration=c;this.callbacks=d.callbacks;this.time=0;OpenLayers.Animation.stop(this.animationId);this.animationId=null;this.callbacks&&this.callbacks.start&&this.callbacks.start.call(this,this.begin);this.animationId=OpenLayers.Animation.start(OpenLayers.Function.bind(this.play, +this))},stop:function(){if(this.playing){this.callbacks&&this.callbacks.done&&this.callbacks.done.call(this,this.finish);OpenLayers.Animation.stop(this.animationId);this.animationId=null;this.playing=false}},play:function(){var a={},b;for(b in this.begin){var c=this.begin[b],d=this.finish[b];if(c==null||d==null||isNaN(c)||isNaN(d))throw new TypeError("invalid value for Tween");a[b]=this.easing.apply(this,[this.time,c,d-c,this.duration])}this.time++;this.callbacks&&this.callbacks.eachStep&&this.callbacks.eachStep.call(this, +a);this.time>this.duration&&this.stop()},CLASS_NAME:"OpenLayers.Tween"});OpenLayers.Easing={CLASS_NAME:"OpenLayers.Easing"};OpenLayers.Easing.Linear={easeIn:function(a,b,c,d){return c*a/d+b},easeOut:function(a,b,c,d){return c*a/d+b},easeInOut:function(a,b,c,d){return c*a/d+b},CLASS_NAME:"OpenLayers.Easing.Linear"}; +OpenLayers.Easing.Expo={easeIn:function(a,b,c,d){return a==0?b:c*Math.pow(2,10*(a/d-1))+b},easeOut:function(a,b,c,d){return a==d?b+c:c*(-Math.pow(2,-10*a/d)+1)+b},easeInOut:function(a,b,c,d){if(a==0)return b;if(a==d)return b+c;if((a/=d/2)<1)return c/2*Math.pow(2,10*(a-1))+b;return c/2*(-Math.pow(2,-10*--a)+2)+b},CLASS_NAME:"OpenLayers.Easing.Expo"}; +OpenLayers.Easing.Quad={easeIn:function(a,b,c,d){return c*(a/=d)*a+b},easeOut:function(a,b,c,d){return-c*(a/=d)*(a-2)+b},easeInOut:function(a,b,c,d){if((a/=d/2)<1)return c/2*a*a+b;return-c/2*(--a*(a-2)-1)+b},CLASS_NAME:"OpenLayers.Easing.Quad"};OpenLayers.Projection=OpenLayers.Class({proj:null,projCode:null,titleRegEx:/\+title=[^\+]*/,initialize:function(a,b){OpenLayers.Util.extend(this,b);this.projCode=a;if(typeof Proj4js=="object")this.proj=new Proj4js.Proj(a)},getCode:function(){return this.proj?this.proj.srsCode:this.projCode},getUnits:function(){return this.proj?this.proj.units:null},toString:function(){return this.getCode()},equals:function(a){a=a;var b=false;if(a){a instanceof OpenLayers.Projection||(a=new OpenLayers.Projection(a)); +if(typeof Proj4js=="object"&&this.proj.defData&&a.proj.defData)b=this.proj.defData.replace(this.titleRegEx,"")==a.proj.defData.replace(this.titleRegEx,"");else if(a.getCode){b=this.getCode();a=a.getCode();b=b==a||!!OpenLayers.Projection.transforms[b]&&OpenLayers.Projection.transforms[b][a]===OpenLayers.Projection.nullTransform}}return b},destroy:function(){delete this.proj;delete this.projCode},CLASS_NAME:"OpenLayers.Projection"});OpenLayers.Projection.transforms={}; +OpenLayers.Projection.defaults={"EPSG:4326":{units:"degrees",maxExtent:[-180,-90,180,90],yx:true},"CRS:84":{units:"degrees",maxExtent:[-180,-90,180,90]},"EPSG:900913":{units:"m",maxExtent:[-2.003750834E7,-2.003750834E7,2.003750834E7,2.003750834E7]}}; +OpenLayers.Projection.addTransform=function(a,b,c){if(c===OpenLayers.Projection.nullTransform){var d=OpenLayers.Projection.defaults[a];if(d&&!OpenLayers.Projection.defaults[b])OpenLayers.Projection.defaults[b]=d}OpenLayers.Projection.transforms[a]||(OpenLayers.Projection.transforms[a]={});OpenLayers.Projection.transforms[a][b]=c}; +OpenLayers.Projection.transform=function(a,b,c){if(b&&c){b instanceof OpenLayers.Projection||(b=new OpenLayers.Projection(b));c instanceof OpenLayers.Projection||(c=new OpenLayers.Projection(c));if(b.proj&&c.proj)a=Proj4js.transform(b.proj,c.proj,a);else{b=b.getCode();c=c.getCode();var d=OpenLayers.Projection.transforms;d[b]&&d[b][c]&&d[b][c](a)}}return a};OpenLayers.Projection.nullTransform=function(a){return a}; +(function(){function a(h){h.x=180*h.x/d;h.y=180/Math.PI*(2*Math.atan(Math.exp(h.y/d*Math.PI))-Math.PI/2);return h}function b(h){h.x=h.x*d/180;h.y=Math.log(Math.tan((90+h.y)*Math.PI/360))/Math.PI*d;return h}function c(h,i){var j=OpenLayers.Projection.addTransform,k=OpenLayers.Projection.nullTransform,m,o,l,n,q;m=0;for(o=i.length;m=0;--g)c(e[g],f);for(g=f.length-1;g>=0;--g)c(f[g],e)})();OpenLayers.Map=OpenLayers.Class({Z_INDEX_BASE:{BaseLayer:100,Overlay:325,Feature:725,Popup:750,Control:1E3},id:null,fractionalZoom:false,events:null,allOverlays:false,div:null,dragging:false,size:null,viewPortDiv:null,layerContainerOrigin:null,layerContainerDiv:null,layers:null,controls:null,popups:null,baseLayer:null,center:null,resolution:null,zoom:0,panRatio:1.5,options:null,tileSize:null,projection:"EPSG:4326",units:null,resolutions:null,maxResolution:null,minResolution:null,maxScale:null,minScale:null, +maxExtent:null,minExtent:null,restrictedExtent:null,numZoomLevels:16,theme:null,displayProjection:null,fallThrough:true,autoUpdateSize:true,panTween:null,eventListeners:null,panMethod:OpenLayers.Easing.Expo.easeOut,panDuration:50,paddingForPopups:null,layerContainerOriginPx:null,minPx:null,maxPx:null,initialize:function(a,b){if(arguments.length===1&&typeof a==="object")a=(b=a)&&b.div;this.tileSize=new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,OpenLayers.Map.TILE_HEIGHT);this.paddingForPopups=new OpenLayers.Bounds(15, +15,15,15);this.theme=OpenLayers._getScriptLocation()+"theme/default/style.css";this.options=OpenLayers.Util.extend({},b);OpenLayers.Util.extend(this,b);OpenLayers.Util.applyDefaults(this,OpenLayers.Projection.defaults[this.projection instanceof OpenLayers.Projection?this.projection.projCode:this.projection]);if(this.maxExtent&&!(this.maxExtent instanceof OpenLayers.Bounds))this.maxExtent=new OpenLayers.Bounds(this.maxExtent);if(this.minExtent&&!(this.minExtent instanceof OpenLayers.Bounds))this.minExtent= +new OpenLayers.Bounds(this.minExtent);if(this.restrictedExtent&&!(this.restrictedExtent instanceof OpenLayers.Bounds))this.restrictedExtent=new OpenLayers.Bounds(this.restrictedExtent);if(this.center&&!(this.center instanceof OpenLayers.LonLat))this.center=new OpenLayers.LonLat(this.center);this.layers=[];this.id=OpenLayers.Util.createUniqueID("OpenLayers.Map_");this.div=OpenLayers.Util.getElement(a);if(!this.div){this.div=document.createElement("div");this.div.style.height="1px";this.div.style.width= +"1px"}OpenLayers.Element.addClass(this.div,"olMap");var c=this.id+"_OpenLayers_ViewPort";this.viewPortDiv=OpenLayers.Util.createDiv(c,null,null,null,"relative",null,"hidden");this.viewPortDiv.style.width="100%";this.viewPortDiv.style.height="100%";this.viewPortDiv.className="olMapViewport";this.div.appendChild(this.viewPortDiv);this.events=new OpenLayers.Events(this,this.viewPortDiv,null,this.fallThrough,{includeXY:true});c=this.id+"_OpenLayers_Container";this.layerContainerDiv=OpenLayers.Util.createDiv(c); +this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE.Popup-1;this.layerContainerOriginPx={x:0,y:0};this.viewPortDiv.appendChild(this.layerContainerDiv);this.updateSize();this.eventListeners instanceof Object&&this.events.on(this.eventListeners);if(this.autoUpdateSize===true){this.updateSizeDestroy=OpenLayers.Function.bind(this.updateSize,this);OpenLayers.Event.observe(window,"resize",this.updateSizeDestroy)}if(this.theme){c=true;for(var d=document.getElementsByTagName("link"),e=0,f=d.length;e=0;--a)this.controls[a].destroy();this.controls=null}if(this.layers!=null){for(a=this.layers.length-1;a>=0;--a)this.layers[a].destroy(false);this.layers=null}this.viewPortDiv&&this.div.removeChild(this.viewPortDiv); +this.viewPortDiv=null;if(this.eventListeners){this.events.un(this.eventListeners);this.eventListeners=null}this.events.destroy();this.options=this.events=null},setOptions:function(a){var b=this.minPx&&a.restrictedExtent!=this.restrictedExtent;OpenLayers.Util.extend(this,a);b&&this.moveTo(this.getCachedCenter(),this.zoom,{forceZoomChange:true})},getTileSize:function(){return this.tileSize},getBy:function(a,b,c){var d=typeof c.test=="function";return OpenLayers.Array.filter(this[a],function(e){return e[b]== +c||d&&c.test(e[b])})},getLayersBy:function(a,b){return this.getBy("layers",a,b)},getLayersByName:function(a){return this.getLayersBy("name",a)},getLayersByClass:function(a){return this.getLayersBy("CLASS_NAME",a)},getControlsBy:function(a,b){return this.getBy("controls",a,b)},getControlsByClass:function(a){return this.getControlsBy("CLASS_NAME",a)},getLayer:function(a){for(var b=null,c=0,d=this.layers.length;cthis.layers.length)b=this.layers.length;if(c!=b){this.layers.splice(c,1);this.layers.splice(b,0,a);c=0;for(var d=this.layers.length;c=0;--c)this.removePopup(this.popups[c]);a.map=this;this.popups.push(a);if(c=a.draw()){c.style.zIndex=this.Z_INDEX_BASE.Popup+this.popups.length;this.layerContainerDiv.appendChild(c)}},removePopup:function(a){OpenLayers.Util.removeItem(this.popups,a);if(a.div)try{this.layerContainerDiv.removeChild(a.div)}catch(b){}a.map=null},getSize:function(){var a=null;if(this.size!=null)a=this.size.clone();return a},updateSize:function(){var a=this.getCurrentSize();if(a&& +!isNaN(a.h)&&!isNaN(a.w)){this.events.clearMouseCache();var b=this.getSize();if(b==null)this.size=b=a;if(!a.equals(b)){this.size=a;a=0;for(b=this.layers.length;a=this.minPx.x+h?Math.round(a):0;b=f<= +this.maxPx.y-i&&f>=this.minPx.y+i?Math.round(b):0;if(a||b){if(!this.dragging){this.dragging=true;this.events.triggerEvent("movestart")}this.center=null;if(a){this.layerContainerDiv.style.left=(this.layerContainerOriginPx.x-=a)+"px";this.minPx.x-=a;this.maxPx.x-=a}if(b){this.layerContainerDiv.style.top=(this.layerContainerOriginPx.y-=b)+"px";this.minPx.y-=b;this.maxPx.y-=b}d=0;for(e=this.layers.length;dc)if(this.fractionalZoom)a=this.getZoomForResolution(c);else for(var d=a|0,e=b.length;dthis.restrictedExtent.getWidth())a= +new OpenLayers.LonLat(g.lon,a.lat);else if(f.leftthis.restrictedExtent.right)a=a.add(this.restrictedExtent.right-f.right,0);if(f.getHeight()>this.restrictedExtent.getHeight())a=new OpenLayers.LonLat(a.lon,g.lat);else if(f.bottomthis.restrictedExtent.top)a=a.add(0,this.restrictedExtent.top-f.top)}}e=e||this.isValidZoomLevel(b)&& +b!=this.getZoom();f=this.isValidLonLat(a)&&!a.equals(this.center);if(e||f||d){d||this.events.triggerEvent("movestart");if(f){!e&&this.center&&this.centerLayerContainer(a);this.center=a.clone()}a=e?this.getResolutionForZoom(b):this.getResolution();if(e||this.layerContainerOrigin==null){this.layerContainerOrigin=this.getCachedCenter();f=this.layerContainerDiv.style;f.left="0px";f.top="0px";this.layerContainerOriginPx.x=0;this.layerContainerOriginPx.y=0;f=this.getMaxExtent({restricted:true});var h=f.getCenterLonLat(); +g=this.center.lon-h.lon;h=h.lat-this.center.lat;var i=Math.round(f.getWidth()/a),j=Math.round(f.getHeight()/a);this.minPx={x:(this.size.w-i)/2-g/a,y:(this.size.h-j)/2-h/a};this.maxPx={x:this.minPx.x+Math.round(f.getWidth()/a),y:this.minPx.y+Math.round(f.getHeight()/a)}}if(e){this.zoom=b;this.resolution=a}a=this.getExtent();if(this.baseLayer.visibility){this.baseLayer.moveTo(a,e,c.dragging);c.dragging||this.baseLayer.events.triggerEvent("moveend",{zoomChanged:e})}a=this.baseLayer.getExtent();for(b= +this.layers.length-1;b>=0;--b){f=this.layers[b];if(f!==this.baseLayer&&!f.isBaseLayer){g=f.calculateInRange();if(f.inRange!=g){(f.inRange=g)||f.display(false);this.events.triggerEvent("changelayer",{layer:f,property:"visibility"})}if(g&&f.visibility){f.moveTo(a,e,c.dragging);c.dragging||f.events.triggerEvent("moveend",{zoomChanged:e})}}}this.events.triggerEvent("move");d||this.events.triggerEvent("moveend");if(e){b=0;for(c=this.popups.length;b=0&&a0)a=this.layers[0].getResolution(); +return a},getUnits:function(){var a=null;if(this.baseLayer!=null)a=this.baseLayer.units;return a},getScale:function(){var a=null;if(this.baseLayer!=null){a=this.getResolution();a=OpenLayers.Util.getScaleFromResolution(a,this.baseLayer.units)}return a},getZoomForExtent:function(a,b){var c=null;if(this.baseLayer!=null)c=this.baseLayer.getZoomForExtent(a,b);return c},getResolutionForZoom:function(a){var b=null;if(this.baseLayer)b=this.baseLayer.getResolutionForZoom(a);return b},getZoomForResolution:function(a, +b){var c=null;if(this.baseLayer!=null)c=this.baseLayer.getZoomForResolution(a,b);return c},zoomTo:function(a){this.isValidZoomLevel(a)&&this.setCenter(null,a)},zoomIn:function(){this.zoomTo(this.getZoom()+1)},zoomOut:function(){this.zoomTo(this.getZoom()-1)},zoomToExtent:function(a,b){a instanceof OpenLayers.Bounds||(a=new OpenLayers.Bounds(a));var c=a.getCenterLonLat();if(this.baseLayer.wrapDateLine){c=this.getMaxExtent();for(a=a.clone();a.right=0){this.initResolutions();if(b&&this.map.baseLayer===this){this.map.setCenter(this.map.getCenter(),this.map.getZoomForResolution(c),false,true);this.map.events.triggerEvent("changebaselayer",{layer:this})}break}}},onMapResize:function(){},redraw:function(){var a=false;if(this.map){this.inRange=this.calculateInRange();var b=this.getExtent();if(b&&this.inRange&&this.visibility){this.moveTo(b,true,false);this.events.triggerEvent("moveend",{zoomChanged:true});a=true}}return a}, +moveTo:function(){var a=this.visibility;this.isBaseLayer||(a=a&&this.inRange);this.display(a)},moveByPx:function(){},setMap:function(a){if(this.map==null){this.map=a;this.maxExtent=this.maxExtent||this.map.maxExtent;this.minExtent=this.minExtent||this.map.minExtent;this.projection=this.projection||this.map.projection;if(typeof this.projection=="string")this.projection=new OpenLayers.Projection(this.projection);this.units=this.projection.getUnits()||this.units||this.map.units;this.initResolutions(); +if(!this.isBaseLayer){this.inRange=this.calculateInRange();this.div.style.display=this.visibility&&this.inRange?"":"none"}this.setTileSize()}},afterAdd:function(){},removeMap:function(){},getImageSize:function(){return this.imageSize||this.tileSize},setTileSize:function(a){this.tileSize=a=a?a:this.tileSize?this.tileSize:this.map.getTileSize();if(this.gutter)this.imageSize=new OpenLayers.Size(a.w+2*this.gutter,a.h+2*this.gutter)},getVisibility:function(){return this.visibility},setVisibility:function(a){if(a!= +this.visibility){this.visibility=a;this.display(a);this.redraw();this.map!=null&&this.map.events.triggerEvent("changelayer",{layer:this,property:"visibility"});this.events.triggerEvent("visibilitychanged")}},display:function(a){if(a!=(this.div.style.display!="none"))this.div.style.display=a&&this.calculateInRange()?"block":"none"},calculateInRange:function(){var a=false;if(this.alwaysInRange)a=true;else if(this.map){a=this.map.getResolution();a=a>=this.minResolution&&a<=this.maxResolution}return a}, +setIsBaseLayer:function(a){if(a!=this.isBaseLayer){this.isBaseLayer=a;this.map!=null&&this.map.events.triggerEvent("changebaselayer",{layer:this})}},initResolutions:function(){var a,b,c,d={},e=true;a=0;for(b=this.RESOLUTION_PROPERTIES.length;a=a){f=h;e=c}if(h<=a){g=h;break}}c=f-g;c=c>0?e+(f-a)/c:e}else{f=Number.POSITIVE_INFINITY;c=0;for(d=this.resolutions.length;cf)break;f=e}else if(this.resolutions[c]< +a)break;c=Math.max(0,c-1)}return c},getLonLatFromViewPortPx:function(a){var b=null,c=this.map;if(a!=null&&c.minPx){b=c.getResolution();var d=c.getMaxExtent({restricted:true});b=new OpenLayers.LonLat((a.x-c.minPx.x)*b+d.left,(c.minPx.y-a.y)*b+d.top);if(this.wrapDateLine)b=b.wrapDateLine(this.maxExtent)}return b},getViewPortPxFromLonLat:function(a,b){var c=null;if(a!=null){b=b||this.map.getResolution();c=this.map.calculateBounds(null,b);c=new OpenLayers.Pixel(1/b*(a.lon-c.left),1/b*(c.top-a.lat))}return c}, +setOpacity:function(a){if(a!=this.opacity){this.opacity=a;for(var b=this.div.childNodes,c=0,d=b.length;c=0&&i=0;c--){e=this.serverResolutions[c];d=Math.abs(e-a);if(d>b)break;b=d;f=e}a=f}return a},getServerZoom:function(){var a=this.getServerResolution();return this.serverResolutions? +OpenLayers.Util.indexOf(this.serverResolutions,a):this.map.getZoomForResolution(a)+(this.zoomOffset||0)},applyBackBuffer:function(a){this.backBufferTimerId!==null&&this.removeBackBuffer();var b=this.backBuffer;if(!b){b=this.createBackBuffer();if(!b)return;this.div.insertBefore(b,this.div.firstChild);this.backBuffer=b;var c=this.grid[0][0].bounds;this.backBufferLonLat={lon:c.left,lat:c.top};this.backBufferResolution=this.gridResolution}c=this.backBufferResolution/a;for(var d=b.childNodes,e,f=d.length- +1;f>=0;--f){e=d[f];e.style.top=(c*e._i*e._h|0)+"px";e.style.left=(c*e._j*e._w|0)+"px";e.style.width=Math.round(c*e._w)+"px";e.style.height=Math.round(c*e._h)+"px"}a=this.getViewPortPxFromLonLat(this.backBufferLonLat,a);c=this.map.layerContainerOriginPx.y;b.style.left=Math.round(a.x-this.map.layerContainerOriginPx.x)+"px";b.style.top=Math.round(a.y-c)+"px"},createBackBuffer:function(){var a;if(this.grid.length>0){a=document.createElement("div");a.id=this.div.id+"_bb";a.className="olBackBuffer";a.style.position= +"absolute";for(var b=0,c=this.grid.length;b=a.bottom-k*this.buffer||l-c.w*(a-1))this.shiftColumn(true,c);else if(b.x<-c.w*a)this.shiftColumn(false,c);else if(b.y>-c.h*(a-1))this.shiftRow(true,c);else if(b.y<-c.h*a)this.shiftRow(false,c);else break}},shiftRow:function(a, +b){for(var c=this.grid,d=c[a?0:this.grid.length-1],e=a?-1:1,f=this.getServerResolution()*-e*this.tileSize.h,g=a?c.pop():c.shift(),h=0,i=d.length;ha;){var e=this.grid.pop();c=0;for(d=e.length;cb;){e=this.grid[c];f=e.pop();this.destroyTile(f)}},onMapResize:function(){if(this.singleTile){this.clearGrid();this.setTileSize()}},getTileBounds:function(a){var b=this.maxExtent,c=this.getResolution(), +d=c*this.tileSize.w;c=c*this.tileSize.h;var e=this.getLonLatFromViewPortPx(a);a=b.left+d*Math.floor((e.lon-b.left)/d);b=b.bottom+c*Math.floor((e.lat-b.bottom)/c);return new OpenLayers.Bounds(a,b,a+d,b+c)},CLASS_NAME:"OpenLayers.Layer.Grid"});OpenLayers.Layer.XYZ=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:true,sphericalMercator:false,zoomOffset:0,serverResolutions:null,initialize:function(a,b,c){if(c&&c.sphericalMercator||this.sphericalMercator)c=OpenLayers.Util.extend({projection:"EPSG:900913",numZoomLevels:19},c);OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a||this.name,b||this.url,{},c])},clone:function(a){if(a==null)a=new OpenLayers.Layer.XYZ(this.name,this.url,this.getOptions());return a=OpenLayers.Layer.Grid.prototype.clone.apply(this, +[a])},getURL:function(a){a=this.getXYZ(a);var b=this.url;if(OpenLayers.Util.isArray(b))b=this.selectUrl(""+a.x+a.y+a.z,b);return OpenLayers.String.format(b,a)},getXYZ:function(a){var b=this.getServerResolution(),c=Math.round((a.left-this.maxExtent.left)/(b*this.tileSize.w));a=Math.round((this.maxExtent.top-a.top)/(b*this.tileSize.h));b=this.getServerZoom();if(this.wrapDateLine){var d=Math.pow(2,b);c=(c%d+d)%d}return{x:c,y:a,z:b}},setMap:function(){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"});OpenLayers.Layer.OSM=OpenLayers.Class(OpenLayers.Layer.XYZ,{name:"OpenStreetMap",url:["http://a.tile.openstreetmap.org/${z}/${x}/${y}.png","http://b.tile.openstreetmap.org/${z}/${x}/${y}.png","http://c.tile.openstreetmap.org/${z}/${x}/${y}.png"],attribution:"Data CC-By-SA by OpenStreetMap",sphericalMercator:true,wrapDateLine:true,tileOptions:null,initialize:function(){OpenLayers.Layer.XYZ.prototype.initialize.apply(this,arguments);this.tileOptions=OpenLayers.Util.extend({crossOriginKeyword:"anonymous"}, +this.options&&this.options.tileOptions)},clone:function(a){if(a==null)a=new OpenLayers.Layer.OSM(this.name,this.url,this.getOptions());return a=OpenLayers.Layer.XYZ.prototype.clone.apply(this,[a])},CLASS_NAME:"OpenLayers.Layer.OSM"});OpenLayers.Renderer=OpenLayers.Class({container:null,root:null,extent:null,locked:false,size:null,resolution:null,map:null,featureDx:0,initialize:function(a,b){this.container=OpenLayers.Util.getElement(a);OpenLayers.Util.extend(this,b)},destroy:function(){this.map=this.resolution=this.size=this.extent=this.container=null},supported:function(){return false},setExtent:function(a,b){this.extent=a.clone();if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){var c=a.getWidth()/this.map.getExtent().getWidth(); +a=a.scale(1/c);this.extent=a.wrapDateLine(this.map.getMaxExtent()).scale(c)}if(b)this.resolution=null;return true},setSize:function(a){this.size=a.clone();this.resolution=null},getResolution:function(){return this.resolution=this.resolution||this.map.getResolution()},drawFeature:function(a,b){if(b==null)b=a.style;if(a.geometry){var c=a.geometry.getBounds();if(c){var d;if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine)d=this.map.getMaxExtent();if(c.intersectsBounds(this.extent,{worldBounds:d}))this.calculateFeatureDx(c, +d);else b={display:"none"};c=this.drawGeometry(a.geometry,b,a.id);if(b.display!="none"&&b.label&&c!==false){d=a.geometry.getCentroid();if(b.labelXOffset||b.labelYOffset){var e=isNaN(b.labelXOffset)?0:b.labelXOffset,f=isNaN(b.labelYOffset)?0:b.labelYOffset,g=this.getResolution();d.move(e*g,f*g)}this.drawText(a.id,b,d)}else this.removeText(a.id);return c}}},calculateFeatureDx:function(a,b){this.featureDx=0;if(b){var c=b.getWidth();this.featureDx=Math.round(((a.left+a.right)/2-(this.extent.left+this.extent.right)/ +2)/c)*c}},drawGeometry:function(){},drawText:function(){},removeText:function(){},clear:function(){},getFeatureIdFromEvent:function(){},eraseFeatures:function(a){OpenLayers.Util.isArray(a)||(a=[a]);for(var b=0,c=a.length;b=16777216){this.hitOverflow=a-16777215;a=a%16777216+1}a="000000"+a.toString(16);var b=a.length;return a="#"+a.substring(b-6,b)},setHitContextStyle:function(a, +b,c,d){b=this.featureIdToHex(b);if(a=="fill"){this.hitContext.globalAlpha=1;this.hitContext.fillStyle=b}else if(a=="stroke"){this.hitContext.globalAlpha=1;this.hitContext.strokeStyle=b;if(typeof d==="undefined")this.hitContext.lineWidth=c.strokeWidth+2;else if(!isNaN(d))this.hitContext.lineWidth=c.strokeWidth+2/d}else{this.hitContext.globalAlpha=0;this.hitContext.lineWidth=1}},drawPoint:function(a,b,c){if(b.graphic!==false)if(b.externalGraphic)this.drawExternalGraphic(a,b,c);else if(b.graphicName&& +b.graphicName!="circle")this.drawNamedSymbol(a,b,c);else{var d=this.getLocalXY(a);a=d[0];d=d[1];if(!isNaN(a)&&!isNaN(d)){var e=Math.PI*2,f=b.pointRadius;if(b.fill!==false){this.setCanvasStyle("fill",b);this.canvas.beginPath();this.canvas.arc(a,d,f,0,e,true);this.canvas.fill();if(this.hitDetection){this.setHitContextStyle("fill",c,b);this.hitContext.beginPath();this.hitContext.arc(a,d,f,0,e,true);this.hitContext.fill()}}if(b.stroke!==false){this.setCanvasStyle("stroke",b);this.canvas.beginPath();this.canvas.arc(a, +d,f,0,e,true);this.canvas.stroke();if(this.hitDetection){this.setHitContextStyle("stroke",c,b);this.hitContext.beginPath();this.hitContext.arc(a,d,f,0,e,true);this.hitContext.stroke()}this.setCanvasStyle("reset")}}}},drawLineString:function(a,b,c){b=OpenLayers.Util.applyDefaults({fill:false},b);this.drawLinearRing(a,b,c)},drawLinearRing:function(a,b,c){if(b.fill!==false){this.setCanvasStyle("fill",b);this.renderPath(this.canvas,a,b,c,"fill");if(this.hitDetection){this.setHitContextStyle("fill",c, +b);this.renderPath(this.hitContext,a,b,c,"fill")}}if(b.stroke!==false){this.setCanvasStyle("stroke",b);this.renderPath(this.canvas,a,b,c,"stroke");if(this.hitDetection){this.setHitContextStyle("stroke",c,b);this.renderPath(this.hitContext,a,b,c,"stroke")}}this.setCanvasStyle("reset")},renderPath:function(a,b,c,d,e){b=b.components;c=b.length;a.beginPath();d=this.getLocalXY(b[0]);var f=d[1];if(!isNaN(d[0])&&!isNaN(f)){a.moveTo(d[0],d[1]);for(d=1;d1;){e=parseInt((c+d)/2);if(this.compare(this,a,OpenLayers.Util.getElement(this.order[e]))>0)c=e;else d=e}this.order.splice(d, +0,b);this.indices[b]=this.getZIndex(a);return this.getNextElement(d)},remove:function(a){a=a.id;var b=OpenLayers.Util.indexOf(this.order,a);if(b>=0){this.order.splice(b,1);delete this.indices[a];this.maxZIndex=this.order.length>0?this.indices[this.order[this.order.length-1]]:0}},clear:function(){this.order=[];this.indices={};this.maxZIndex=0},exists:function(a){return this.indices[a.id]!=null},getZIndex:function(a){return a._style.graphicZIndex},determineZIndex:function(a){var b=a._style.graphicZIndex; +if(b==null){b=this.maxZIndex;a._style.graphicZIndex=b}else if(b>this.maxZIndex)this.maxZIndex=b},getNextElement:function(a){a=a+1;if(aa.left&&f.righta.left&&f.left0},CLASS_NAME:"OpenLayers.Protocol.Response"}); +OpenLayers.Protocol.Response.SUCCESS=1;OpenLayers.Protocol.Response.FAILURE=0;OpenLayers.Protocol.WFS=function(a){a=OpenLayers.Util.applyDefaults(a,OpenLayers.Protocol.WFS.DEFAULTS);var b=OpenLayers.Protocol.WFS["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported WFS version: "+a.version;return new b(a)}; +OpenLayers.Protocol.WFS.fromWMSLayer=function(a,b){var c,d;c=a.params.LAYERS;c=(OpenLayers.Util.isArray(c)?c[0]:c).split(":");if(c.length>1)d=c[0];c=c.pop();d={url:a.url,featureType:c,featurePrefix:d,srsName:a.projection&&a.projection.getCode()||a.map&&a.map.getProjectionObject().getCode(),version:"1.1.0"};return new OpenLayers.Protocol.WFS(OpenLayers.Util.applyDefaults(b,d))};OpenLayers.Protocol.WFS.DEFAULTS={version:"1.0.0"};OpenLayers.Strategy=OpenLayers.Class({layer:null,options:null,active:null,autoActivate:true,autoDestroy:true,initialize:function(a){OpenLayers.Util.extend(this,a);this.options=a;this.active=false},destroy:function(){this.deactivate();this.options=this.layer=null},setLayer:function(a){this.layer=a},activate:function(){if(!this.active)return this.active=true;return false},deactivate:function(){if(this.active){this.active=false;return true}return false},CLASS_NAME:"OpenLayers.Strategy"});OpenLayers.Strategy.BBOX=OpenLayers.Class(OpenLayers.Strategy,{bounds:null,resolution:null,ratio:2,resFactor:null,response:null,activate:function(){var a=OpenLayers.Strategy.prototype.activate.call(this);if(a){this.layer.events.on({moveend:this.update,refresh:this.update,visibilitychanged:this.update,scope:this});this.update()}return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&this.layer.events.un({moveend:this.update,refresh:this.update,visibilitychanged:this.update, +scope:this});return a},update:function(a){var b=this.getMapBounds();if(b!==null&&(a&&a.force||this.layer.visibility&&this.layer.calculateInRange()&&this.invalidBounds(b))){this.calculateBounds(b);this.resolution=this.layer.map.getResolution();this.triggerRead(a)}},getMapBounds:function(){if(this.layer.map===null)return null;var a=this.layer.map.getExtent();if(a&&!this.layer.projection.equals(this.layer.map.getProjectionObject()))a=a.clone().transform(this.layer.map.getProjectionObject(),this.layer.projection); +return a},invalidBounds:function(a){a||(a=this.getMapBounds());a=!this.bounds||!this.bounds.containsBounds(a);if(!a&&this.resFactor){a=this.resolution/this.layer.map.getResolution();a=a>=this.resFactor||a<=1/this.resFactor}return a},calculateBounds:function(a){a||(a=this.getMapBounds());var b=a.getCenterLonLat(),c=a.getWidth()*this.ratio;a=a.getHeight()*this.ratio;this.bounds=new OpenLayers.Bounds(b.lon-c/2,b.lat-a/2,b.lon+c/2,b.lat+a/2)},triggerRead:function(a){if(this.response&&!(a&&a.noAbort=== +true)){this.layer.protocol.abort(this.response);this.layer.events.triggerEvent("loadend")}this.layer.events.triggerEvent("loadstart");this.response=this.layer.protocol.read(OpenLayers.Util.applyDefaults({filter:this.createFilter(),callback:this.merge,scope:this},a))},createFilter:function(){var a=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.BBOX,value:this.bounds,projection:this.layer.projection});if(this.layer.filter)a=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND, +filters:[this.layer.filter,a]});return a},merge:function(a){this.layer.destroyFeatures();var b=a.features;if(b&&b.length>0){var c=this.layer.projection,d=this.layer.map.getProjectionObject();if(!d.equals(c))for(var e,f=0,g=b.length;f-1},handle:function(a){if(this.feature&&!this.feature.layer)this.feature=null;var b=a.type,c=false,d=!!this.feature, +e=b=="click"||b=="dblclick"||b=="touchstart";if((this.feature=this.layer.getFeatureFromEvent(a))&&!this.feature.layer)this.feature=null;if(this.lastFeature&&!this.lastFeature.layer)this.lastFeature=null;if(this.feature){b==="touchstart"&&OpenLayers.Event.stop(a);a=this.feature!=this.lastFeature;if(this.geometryTypeMatches(this.feature)){if(d&&a){this.lastFeature&&this.triggerCallback(b,"out",[this.lastFeature]);this.triggerCallback(b,"in",[this.feature])}else if(!d||e)this.triggerCallback(b,"in", +[this.feature]);this.lastFeature=this.feature;c=true}else{if(this.lastFeature&&(d&&a||e))this.triggerCallback(b,"out",[this.lastFeature]);this.feature=null}}else if(this.lastFeature&&(d||e))this.triggerCallback(b,"out",[this.lastFeature]);return c},triggerCallback:function(a,b,c){if(b=this.EVENTMAP[a][b])if(a=="click"&&this.up&&this.down)Math.sqrt(Math.pow(this.up.x-this.down.x,2)+Math.pow(this.up.y-this.down.y,2))<=this.clickTolerance&&this.callback(b,c);else this.callback(b,c)},activate:function(){var a= +false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.moveLayerToTop();this.map.events.on({removelayer:this.handleMapEvents,changelayer:this.handleMapEvents,scope:this});a=true}return a},deactivate:function(){var a=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.moveLayerBack();this.up=this.down=this.lastFeature=this.feature=null;this.touch=false;this.map.events.un({removelayer:this.handleMapEvents,changelayer:this.handleMapEvents,scope:this});a=true}return a}, +handleMapEvents:function(a){if(a.type=="removelayer"||a.property=="order")this.moveLayerToTop()},moveLayerToTop:function(){this.layer.setZIndex(Math.max(this.map.Z_INDEX_BASE.Feature-1,this.layer.getZIndex())+1)},moveLayerBack:function(){var a=this.layer.getZIndex()-1;a>=this.map.Z_INDEX_BASE.Feature?this.layer.setZIndex(a):this.map.setLayerZIndex(this.layer,this.map.getLayerIndex(this.layer))},CLASS_NAME:"OpenLayers.Handler.Feature"});OpenLayers.StyleMap=OpenLayers.Class({styles:null,extendDefault:true,initialize:function(a,b){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"])};if(a instanceof OpenLayers.Style){this.styles["default"]=a;this.styles.select=a;this.styles.temporary=a; +this.styles["delete"]=a}else if(typeof a=="object")for(var c in a)if(a[c]instanceof OpenLayers.Style)this.styles[c]=a[c];else if(typeof a[c]=="object")this.styles[c]=new OpenLayers.Style(a[c]);else{this.styles["default"]=new OpenLayers.Style(a);this.styles.select=new OpenLayers.Style(a);this.styles.temporary=new OpenLayers.Style(a);this.styles["delete"]=new OpenLayers.Style(a);break}OpenLayers.Util.extend(this,b)},destroy:function(){for(var a in this.styles)this.styles[a].destroy();this.styles=null}, +createSymbolizer:function(a,b){a||(a=new OpenLayers.Feature.Vector);this.styles[b]||(b="default");a.renderIntent=b;var c={};if(this.extendDefault&&b!="default")c=this.styles["default"].createSymbolizer(a);return OpenLayers.Util.extend(c,this.styles[b].createSymbolizer(a))},addUniqueValueRules:function(a,b,c,d){var e=[],f;for(f in c)e.push(new OpenLayers.Rule({symbolizer:c[f],context:d,filter:new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO,property:b,value:f})}));this.styles[a].addRules(e)}, +CLASS_NAME:"OpenLayers.StyleMap"});OpenLayers.Layer.Vector=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:false,isFixed:false,features:null,filter:null,selectedFeatures:null,unrenderedFeatures:null,reportError:true,style:null,styleMap:null,strategies:null,protocol:null,renderers:["SVG","VML","Canvas"],renderer:null,rendererOptions:null,geometryType:null,drawn:false,ratio:1,initialize:function(){OpenLayers.Layer.prototype.initialize.apply(this,arguments);if(!this.renderer||!this.renderer.supported())this.assignRenderer();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={};if(this.strategies)for(var a=0,b=this.strategies.length;a=0;d--){this.renderer.locked=d!=0&&a[d-1].geometry?true:false;var e=a[d];delete this.unrenderedFeatures[e.id];c&&this.events.triggerEvent("beforefeatureremoved",{feature:e});this.features=OpenLayers.Util.removeItem(this.features,e);e.layer=null;e.geometry&&this.renderer.eraseFeatures(e);OpenLayers.Util.indexOf(this.selectedFeatures,e)!=-1&&OpenLayers.Util.removeItem(this.selectedFeatures,e); +c&&this.events.triggerEvent("featureremoved",{feature:e})}c&&this.events.triggerEvent("featuresremoved",{features:a})}},removeAllFeatures:function(a){a=!a||!a.silent;var b=this.features;a&&this.events.triggerEvent("beforefeaturesremoved",{features:b});for(var c,d=b.length-1;d>=0;d--){c=b[d];a&&this.events.triggerEvent("beforefeatureremoved",{feature:c});c.layer=null;a&&this.events.triggerEvent("featureremoved",{feature:c})}this.renderer.clear();this.features=[];this.unrenderedFeatures={};this.selectedFeatures= +[];a&&this.events.triggerEvent("featuresremoved",{features:b})},destroyFeatures:function(a,b){if(a==undefined)a=this.features;if(a){this.removeFeatures(a,b);for(var c=a.length-1;c>=0;c--)a[c].destroy()}},drawFeature:function(a,b){if(this.drawn){if(typeof b!="object"){if(!b&&a.state===OpenLayers.State.DELETE)b="delete";var c=b||a.renderIntent;(b=a.style||this.style)||(b=this.styleMap.createSymbolizer(a,c))}c=this.renderer.drawFeature(a,b);if(c===false||c===null)this.unrenderedFeatures[a.id]=a;else delete this.unrenderedFeatures[a.id]}}, +eraseFeatures:function(a){this.renderer.eraseFeatures(a)},getFeatureFromEvent:function(a){if(!this.renderer)throw Error("getFeatureFromEvent called on layer with no renderer. This usually means you destroyed a layer, but not some handler which is associated with it.");var b=null;if(a=this.renderer.getFeatureIdFromEvent(a))b=typeof a==="string"?this.getFeatureById(a):a;return b},getFeatureBy:function(a,b){for(var c=null,d=0,e=this.features.length;d0)for(var c=null,d=0,e=b.length;df;){d=c.selectedFeatures[f];if(!a||a.except!=d)this.unselect(d);else++f}}},clickFeature:function(a){if(!this.hover)if(OpenLayers.Util.indexOf(a.layer.selectedFeatures, +a)>-1)if(this.toggleSelect())this.unselect(a);else this.multipleSelect()||this.unselectAll({except:a});else{this.multipleSelect()||this.unselectAll({except:a});this.select(a)}},multipleSelect:function(){return this.multiple||this.handlers.feature.evt&&this.handlers.feature.evt[this.multipleKey]},toggleSelect:function(){return this.toggle||this.handlers.feature.evt&&this.handlers.feature.evt[this.toggleKey]},clickoutFeature:function(){!this.hover&&this.clickout&&this.unselectAll()},overFeature:function(a){var b= +a.layer;if(this.hover)if(this.highlightOnly)this.highlight(a);else OpenLayers.Util.indexOf(b.selectedFeatures,a)==-1&&this.select(a)},outFeature:function(a){if(this.hover)if(this.highlightOnly){if(a._lastHighlighter==this.id)if(a._prevHighlighter&&a._prevHighlighter!=this.id){delete a._lastHighlighter;var b=this.map.getControl(a._prevHighlighter);b&&b.highlight(a)}else this.unhighlight(a)}else this.unselect(a)},highlight:function(a){var b=a.layer;if(this.events.triggerEvent("beforefeaturehighlighted", +{feature:a})!==false){a._prevHighlighter=a._lastHighlighter;a._lastHighlighter=this.id;b.drawFeature(a,this.selectStyle||this.renderIntent);this.events.triggerEvent("featurehighlighted",{feature:a})}},unhighlight:function(a){var b=a.layer;if(a._prevHighlighter==undefined)delete a._lastHighlighter;else{if(a._prevHighlighter!=this.id)a._lastHighlighter=a._prevHighlighter;delete a._prevHighlighter}b.drawFeature(a,a.style||a.layer.style||"default");this.events.triggerEvent("featureunhighlighted",{feature:a})}, +select:function(a){var b=this.onBeforeSelect.call(this.scope,a),c=a.layer;if(b!==false){b=c.events.triggerEvent("beforefeatureselected",{feature:a});if(b!==false){c.selectedFeatures.push(a);this.highlight(a);if(!this.handlers.feature.lastFeature)this.handlers.feature.lastFeature=c.selectedFeatures[0];c.events.triggerEvent("featureselected",{feature:a});this.onSelect.call(this.scope,a)}}},unselect:function(a){var b=a.layer;this.unhighlight(a);OpenLayers.Util.removeItem(b.selectedFeatures,a);b.events.triggerEvent("featureunselected", +{feature:a});this.onUnselect.call(this.scope,a)},selectBox:function(a){if(a instanceof OpenLayers.Bounds){var b=this.map.getLonLatFromPixel({x:a.left,y:a.bottom});a=this.map.getLonLatFromPixel({x:a.right,y:a.top});b=new OpenLayers.Bounds(b.lon,b.lat,a.lon,a.lat);this.multipleSelect()||this.unselectAll();a=this.multiple;this.multiple=true;var c=this.layers||[this.layer];this.events.triggerEvent("boxselectionstart",{layers:c});for(var d,e=0;e-1)b.toGeometry().intersects(h.geometry)&&OpenLayers.Util.indexOf(d.selectedFeatures,h)==-1&&this.select(h)}}this.multiple=a;this.events.triggerEvent("boxselectionend",{layers:c})}},setMap:function(a){this.handlers.feature.setMap(a);this.box&&this.handlers.box.setMap(a);OpenLayers.Control.prototype.setMap.apply(this,arguments)},setLayer:function(a){var b=this.active;this.unselectAll(); +this.deactivate();if(this.layers){this.layer.destroy();this.layers=null}this.initLayer(a);this.handlers.feature.layer=this.layer;b&&this.activate()},CLASS_NAME:"OpenLayers.Control.SelectFeature"});OpenLayers.Handler.Point=OpenLayers.Class(OpenLayers.Handler,{point:null,layer:null,multi:false,citeCompliant:false,mouseDown:false,stoppedDown:null,lastDown:null,lastUp:null,persist:false,stopDown:false,stopUp:false,layerOptions:null,pixelTolerance:5,touch:false,lastTouchPx:null,initialize:function(a,b,c){if(!(c&&c.layerOptions&&c.layerOptions.styleMap))this.style=OpenLayers.Util.extend(OpenLayers.Feature.Vector.style["default"],{});OpenLayers.Handler.prototype.initialize.apply(this,arguments)}, +activate:function(){if(!OpenLayers.Handler.prototype.activate.apply(this,arguments))return false;var a=OpenLayers.Util.extend({displayInLayerSwitcher:false,calculateInRange:OpenLayers.Function.True,wrapDateLine:this.citeCompliant},this.layerOptions);this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,a);this.map.addLayer(this.layer);return true},createFeature:function(a){a=this.layer.getLonLatFromViewPortPx(a);a=new OpenLayers.Geometry.Point(a.lon,a.lat);this.point=new OpenLayers.Feature.Vector(a); +this.callback("create",[this.point.geometry,this.point]);this.point.geometry.clearBounds();this.layer.addFeatures([this.point],{silent:true})},deactivate:function(){if(!OpenLayers.Handler.prototype.deactivate.apply(this,arguments))return false;this.cancel();if(this.layer.map!=null){this.destroyFeature(true);this.layer.destroy(false)}this.layer=null;this.touch=false;return true},destroyFeature:function(a){if(this.layer&&(a||!this.persist))this.layer.destroyFeatures();this.point=null},destroyPersistedFeature:function(){var a= +this.layer;a&&a.features.length>1&&this.layer.features[0].destroy()},finalize:function(a){var b=a?"cancel":"done";this.mouseDown=false;this.lastTouchPx=this.lastUp=this.lastDown=null;this.callback(b,[this.geometryClone()]);this.destroyFeature(a)},cancel:function(){this.finalize(true)},click:function(a){OpenLayers.Event.stop(a);return false},dblclick:function(a){OpenLayers.Event.stop(a);return false},modifyFeature:function(a){this.point||this.createFeature(a);a=this.layer.getLonLatFromViewPortPx(a); +this.point.geometry.x=a.lon;this.point.geometry.y=a.lat;this.callback("modify",[this.point.geometry,this.point,false]);this.point.geometry.clearBounds();this.drawFeature()},drawFeature:function(){this.layer.drawFeature(this.point,this.style)},getGeometry:function(){var a=this.point&&this.point.geometry;if(a&&this.multi)a=new OpenLayers.Geometry.MultiPoint([a]);return a},geometryClone:function(){var a=this.getGeometry();return a&&a.clone()},mousedown:function(a){return this.down(a)},touchstart:function(a){if(!this.touch){this.touch= +true;this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,mousemove:this.mousemove,click:this.click,dblclick:this.dblclick,scope:this})}this.lastTouchPx=a.xy;return this.down(a)},mousemove:function(a){return this.move(a)},touchmove:function(a){this.lastTouchPx=a.xy;return this.move(a)},mouseup:function(a){return this.up(a)},touchend:function(a){a.xy=this.lastTouchPx;return this.up(a)},down:function(a){this.mouseDown=true;this.lastDown=a.xy;this.touch||this.modifyFeature(a.xy);this.stoppedDown= +this.stopDown;return!this.stopDown},move:function(a){if(!this.touch&&(!this.mouseDown||this.stoppedDown))this.modifyFeature(a.xy);return true},up:function(a){this.mouseDown=false;this.stoppedDown=this.stopDown;if(!this.checkModifiers(a))return true;if(this.lastUp&&this.lastUp.equals(a.xy))return true;if(this.lastDown&&this.passesTolerance(this.lastDown,a.xy,this.pixelTolerance)){this.touch&&this.modifyFeature(a.xy);this.persist&&this.destroyPersistedFeature();this.lastUp=a.xy;this.finalize();return!this.stopUp}else return true}, +mouseout:function(a){if(OpenLayers.Util.mouseLeft(a,this.map.viewPortDiv)){this.stoppedDown=this.stopDown;this.mouseDown=false}},passesTolerance:function(a,b,c){var d=true;if(c!=null&&a&&b)if(a.distanceTo(b)>c)d=false;return d},CLASS_NAME:"OpenLayers.Handler.Point"});OpenLayers.Handler.Path=OpenLayers.Class(OpenLayers.Handler.Point,{line:null,maxVertices:null,doubleTouchTolerance:20,freehand:false,freehandToggle:"shiftKey",timerId:null,redoStack:null,createFeature:function(a){a=this.layer.getLonLatFromViewPortPx(a);a=new OpenLayers.Geometry.Point(a.lon,a.lat);this.point=new OpenLayers.Feature.Vector(a);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})},destroyFeature:function(a){OpenLayers.Handler.Point.prototype.destroyFeature.call(this,a);this.line=null},destroyPersistedFeature:function(){var a=this.layer;a&&a.features.length>2&&this.layer.features[0].destroy()},removePoint:function(){this.point&&this.layer.removeFeatures([this.point])},addPoint:function(a){this.layer.removeFeatures([this.point]);a=this.layer.getLonLatFromViewPortPx(a);this.point=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(a.lon, +a.lat));this.line.geometry.addComponent(this.point.geometry,this.line.geometry.components.length);this.layer.addFeatures([this.point]);this.callback("point",[this.point.geometry,this.getGeometry()]);this.callback("modify",[this.point.geometry,this.getSketch()]);this.drawFeature();delete this.redoStack},insertXY:function(a,b){this.line.geometry.addComponent(new OpenLayers.Geometry.Point(a,b),this.getCurrentPointIndex());this.drawFeature();delete this.redoStack},insertDeltaXY:function(a,b){var c=this.line.geometry.components[this.getCurrentPointIndex()- +1];c&&!isNaN(c.x)&&!isNaN(c.y)&&this.insertXY(c.x+a,c.y+b)},insertDirectionLength:function(a,b){a*=Math.PI/180;this.insertDeltaXY(b*Math.cos(a),b*Math.sin(a))},insertDeflectionLength:function(a,b){var c=this.getCurrentPointIndex()-1;if(c>0){var d=this.line.geometry.components[c];c=this.line.geometry.components[c-1];this.insertDirectionLength(Math.atan2(d.y-c.y,d.x-c.x)*180/Math.PI+a,b)}},getCurrentPointIndex:function(){return this.line.geometry.components.length-1},undo:function(){var a=this.line.geometry, +b=a.components,c=this.getCurrentPointIndex()-1;b=b[c];if(a=a.removeComponent(b)){if(!this.redoStack)this.redoStack=[];this.redoStack.push(b);this.drawFeature()}return a},redo:function(){var a=this.redoStack&&this.redoStack.pop();if(a){this.line.geometry.addComponent(a,this.getCurrentPointIndex());this.drawFeature()}return!!a},freehandMode:function(a){return this.freehandToggle&&a[this.freehandToggle]?!this.freehand:this.freehand},modifyFeature:function(a,b){this.line||this.createFeature(a);var c= +this.layer.getLonLatFromViewPortPx(a);this.point.geometry.x=c.lon;this.point.geometry.y=c.lat;this.callback("modify",[this.point.geometry,this.getSketch(),b]);this.point.geometry.clearBounds();this.drawFeature()},drawFeature:function(){this.layer.drawFeature(this.line,this.style);this.layer.drawFeature(this.point,this.style)},getSketch:function(){return this.line},getGeometry:function(){var a=this.line&&this.line.geometry;if(a&&this.multi)a=new OpenLayers.Geometry.MultiLineString([a]);return a},touchstart:function(a){if(this.timerId&& +this.passesTolerance(this.lastTouchPx,a.xy,this.doubleTouchTolerance)){this.finishGeometry();window.clearTimeout(this.timerId);this.timerId=null;return false}else{if(this.timerId){window.clearTimeout(this.timerId);this.timerId=null}this.timerId=window.setTimeout(OpenLayers.Function.bind(function(){this.timerId=null},this),300);return OpenLayers.Handler.Point.prototype.touchstart.call(this,a)}},down:function(a){var b=this.stopDown;if(this.freehandMode(a)){b=true;if(this.touch){this.modifyFeature(a.xy, +!!this.lastUp);OpenLayers.Event.stop(a)}}if(!this.touch&&(!this.lastDown||!this.passesTolerance(this.lastDown,a.xy,this.pixelTolerance)))this.modifyFeature(a.xy,!!this.lastUp);this.mouseDown=true;this.lastDown=a.xy;this.stoppedDown=b;return!b},move:function(a){if(this.stoppedDown&&this.freehandMode(a)){this.persist&&this.destroyPersistedFeature();if(this.maxVertices&&this.line&&this.line.geometry.components.length===this.maxVertices){this.removePoint();this.finalize()}else this.addPoint(a.xy);return false}if(!this.touch&& +(!this.mouseDown||this.stoppedDown))this.modifyFeature(a.xy,!!this.lastUp);return true},up:function(a){if(this.mouseDown&&(!this.lastUp||!this.lastUp.equals(a.xy)))if(this.stoppedDown&&this.freehandMode(a)){this.persist&&this.destroyPersistedFeature();this.removePoint();this.finalize()}else if(this.passesTolerance(this.lastDown,a.xy,this.pixelTolerance)){this.touch&&this.modifyFeature(a.xy);this.lastUp==null&&this.persist&&this.destroyPersistedFeature();this.addPoint(a.xy);this.lastUp=a.xy;this.line.geometry.components.length=== +this.maxVertices+1&&this.finishGeometry()}this.stoppedDown=this.stopDown;this.mouseDown=false;return!this.stopUp},finishGeometry:function(){this.line.geometry.removeComponent(this.line.geometry.components[this.line.geometry.components.length-1]);this.removePoint();this.finalize()},dblclick:function(a){this.freehandMode(a)||this.finishGeometry();return false},CLASS_NAME:"OpenLayers.Handler.Path"});OpenLayers.Control.Attribution=OpenLayers.Class(OpenLayers.Control,{separator:", ",template:"${layers}",destroy:function(){this.map.events.un({removelayer:this.updateAttribution,addlayer:this.updateAttribution,changelayer:this.updateAttribution,changebaselayer:this.updateAttribution,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments)},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.map.events.on({changebaselayer:this.updateAttribution,changelayer:this.updateAttribution, +addlayer:this.updateAttribution,removelayer:this.updateAttribution,scope:this});this.updateAttribution();return this.div},updateAttribution:function(){var a=[];if(this.map&&this.map.layers){for(var b=0,c=this.map.layers.length;bthis.nbPoints&&this.points.pop()},end:function(a){for(var b,c=(new Date).getTime(),d=0,e=this.points.length,f;dthis.delay)break;b=f}if(b){d=(new Date).getTime()-b.tick;c=Math.sqrt(Math.pow(a.x-b.xy.x,2)+Math.pow(a.y-b.xy.y,2));d=c/d;if(!(d==0||d0)this.timeoutId=setTimeout(OpenLayers.Function.bind(this.removeTimeout,this),this.interval);this.dragging=true;this.move(a);this.callback("move",[a.xy]); +if(!this.oldOnselectstart){this.oldOnselectstart=document.onselectstart;document.onselectstart=OpenLayers.Function.False}this.last=a.xy}return true},dragend:function(a){if(this.started){if(this.documentDrag===true&&this.documentEvents){this.adjustXY(a);this.removeDocumentEvents()}var b=this.start!=this.last;this.dragging=this.started=false;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.up(a);this.callback("up",[a.xy]);b&&this.callback("done",[a.xy]);document.onselectstart= +this.oldOnselectstart}return true},down:function(){},move:function(){},up:function(){},out:function(){},mousedown:function(a){return this.dragstart(a)},touchstart:function(a){if(!this.touch){this.touch=true;this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,mousemove:this.mousemove,click:this.click,scope:this})}return this.dragstart(a)},mousemove:function(a){return this.dragmove(a)},touchmove:function(a){return this.dragmove(a)},removeTimeout:function(){this.timeoutId=null;this.dragging&& +this.mousemove(this.lastMoveEvt)},mouseup:function(a){return this.dragend(a)},touchend:function(a){a.xy=this.last;return this.dragend(a)},mouseout:function(a){if(this.started&&OpenLayers.Util.mouseLeft(a,this.map.viewPortDiv))if(this.documentDrag===true)this.addDocumentEvents();else{var b=this.start!=this.last;this.dragging=this.started=false;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.out(a);this.callback("out",[]);b&&this.callback("done",[a.xy]);if(document.onselectstart)document.onselectstart= +this.oldOnselectstart}return true},click:function(){return this.start==this.last},activate:function(){var a=false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.dragging=false;a=true}return a},deactivate:function(){var a=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.dragging=this.started=this.touch=false;this.last=this.start=null;a=true;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown")}return a},adjustXY:function(a){var b=OpenLayers.Util.pagePosition(this.map.viewPortDiv); +a.xy.x-=b[0];a.xy.y-=b[1]},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)},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=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,boxDivClassName:"olHandlerBoxZoomBox",boxOffsets:null,initialize:function(){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})},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);if(this.dragHandler){this.dragHandler.destroy();this.dragHandler= +null}},setMap:function(a){OpenLayers.Handler.prototype.setMap.apply(this,arguments);this.dragHandler&&this.dragHandler.setMap(a)},startBox:function(){this.callback("start",[]);this.zoomBox=OpenLayers.Util.createDiv("zoomBox",{x:-9999,y:-9999});this.zoomBox.className=this.boxDivClassName;this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE.Popup-1;this.map.viewPortDiv.appendChild(this.zoomBox);OpenLayers.Element.addClass(this.map.viewPortDiv,"olDrawBox")},moveBox:function(a){var b=this.dragHandler.start.x, +c=this.dragHandler.start.y,d=Math.abs(b-a.x),e=Math.abs(c-a.y),f=this.getBoxOffsets();this.zoomBox.style.width=d+f.width+1+"px";this.zoomBox.style.height=e+f.height+1+"px";this.zoomBox.style.left=(a.x5||Math.abs(this.dragHandler.start.y-a.y)>5){var b=this.dragHandler.start;a=new OpenLayers.Bounds(Math.min(b.x,a.x),Math.max(b.y,a.y),Math.max(b.x,a.x),Math.min(b.y, +a.y))}else a=this.dragHandler.start.clone();this.removeBox();this.callback("done",[a])},removeBox:function(){this.map.viewPortDiv.removeChild(this.zoomBox);this.boxOffsets=this.zoomBox=null;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDrawBox")},activate:function(){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.dragHandler.activate();return true}else return false},deactivate:function(){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.dragHandler.deactivate()&& +this.zoomBox&&this.removeBox();return true}else return false},getBoxOffsets:function(){if(!this.boxOffsets){var a=document.createElement("div");a.style.position="absolute";a.style.border="1px solid black";a.style.width="3px";document.body.appendChild(a);var b=a.clientWidth==3;document.body.removeChild(a);a=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-left-width"));var c=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-right-width")),d=parseInt(OpenLayers.Element.getStyle(this.zoomBox, +"border-top-width")),e=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-bottom-width"));this.boxOffsets={left:a,right:c,top:d,bottom:e,width:b===false?a+c:0,height:b===false?d+e:0}}return this.boxOffsets},CLASS_NAME:"OpenLayers.Handler.Box"});OpenLayers.Control.ZoomBox=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,out:false,keyMask:null,alwaysZoom:false,zoomOnClick:true,draw:function(){this.handler=new OpenLayers.Handler.Box(this,{done:this.zoomBox},{keyMask:this.keyMask})},zoomBox:function(a){if(a instanceof OpenLayers.Bounds){var b;if(this.out){b=Math.min(this.map.size.h/Math.abs(a.top-a.bottom),this.map.size.w/Math.abs(a.right-a.left));var c=this.map.getExtent(),d=this.map.getLonLatFromPixel(a.getCenterPixel()); +a=d.lon-c.getWidth()/2*b;var e=d.lon+c.getWidth()/2*b,f=d.lat-c.getHeight()/2*b;b=d.lat+c.getHeight()/2*b;b=new OpenLayers.Bounds(a,f,e,b)}else{b=this.map.getLonLatFromPixel({x:a.left,y:a.bottom});c=this.map.getLonLatFromPixel({x:a.right,y:a.top});b=new OpenLayers.Bounds(b.lon,b.lat,c.lon,c.lat)}c=this.map.getZoom();this.map.zoomToExtent(b);if(c==this.map.getZoom()&&this.alwaysZoom==true)this.map.zoomTo(c+(this.out?-1:1))}else if(this.zoomOnClick)this.out?this.map.setCenter(this.map.getLonLatFromPixel(a), +this.map.getZoom()-1):this.map.setCenter(this.map.getLonLatFromPixel(a),this.map.getZoom()+1)},CLASS_NAME:"OpenLayers.Control.ZoomBox"});OpenLayers.Control.DragPan=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:false,interval:1,documentDrag:false,kinetic:null,enableKinetic:false,kineticInterval:10,draw:function(){if(this.enableKinetic){var a={interval:this.kineticInterval};if(typeof this.enableKinetic==="object")a=OpenLayers.Util.extend(a,this.enableKinetic);this.kinetic=new OpenLayers.Kinetic(a)}this.handler=new OpenLayers.Handler.Drag(this,{move:this.panMap,done:this.panMapDone,down:this.panMapStart}, +{interval:this.interval,documentDrag:this.documentDrag})},panMapStart:function(){this.kinetic&&this.kinetic.begin()},panMap:function(a){this.kinetic&&this.kinetic.update(a);this.panned=true;this.map.pan(this.handler.last.x-a.x,this.handler.last.y-a.y,{dragging:true,animate:false})},panMapDone:function(a){if(this.panned){var b=null;if(this.kinetic)b=this.kinetic.end(a);this.map.pan(this.handler.last.x-a.x,this.handler.last.y-a.y,{dragging:!!b,animate:false});if(b){var c=this;this.kinetic.move(b,function(d, +e,f){c.map.pan(d,e,{dragging:!f,animate:false})})}this.panned=false}},CLASS_NAME:"OpenLayers.Control.DragPan"});OpenLayers.Handler.Click=OpenLayers.Class(OpenLayers.Handler,{delay:300,single:true,"double":false,pixelTolerance:0,dblclickTolerance:13,stopSingle:false,stopDouble:false,timerId:null,touch:false,down:null,last:null,first:null,rightclickTimerId:null,touchstart:function(a){if(!this.touch){this.unregisterMouseListeners();this.touch=true}this.down=this.getEventInfo(a);this.last=this.getEventInfo(a);return true},touchmove:function(a){this.last=this.getEventInfo(a);return true},touchend:function(a){if(this.down){a.xy= +this.last.xy;a.lastTouches=this.last.touches;this.handleSingle(a);this.down=null}return true},unregisterMouseListeners:function(){this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,click:this.click,dblclick:this.dblclick,scope:this})},mousedown:function(a){this.down=this.getEventInfo(a);this.last=this.getEventInfo(a);return true},mouseup:function(a){var b=true;if(this.checkModifiers(a)&&this.control.handleRightClicks&&OpenLayers.Event.isRightClick(a))b=this.rightclick(a);return b}, +rightclick:function(a){if(this.passesTolerance(a))if(this.rightclickTimerId!=null){this.clearTimer();this.callback("dblrightclick",[a]);return!this.stopDouble}else{a=this["double"]?OpenLayers.Util.extend({},a):this.callback("rightclick",[a]);a=OpenLayers.Function.bind(this.delayedRightCall,this,a);this.rightclickTimerId=window.setTimeout(a,this.delay)}return!this.stopSingle},delayedRightCall:function(a){this.rightclickTimerId=null;a&&this.callback("rightclick",[a])},click:function(a){if(!this.last)this.last= +this.getEventInfo(a);this.handleSingle(a);return!this.stopSingle},dblclick:function(a){this.handleDouble(a);return!this.stopDouble},handleDouble:function(a){if(this.passesDblclickTolerance(a)){this["double"]&&this.callback("dblclick",[a]);this.clearTimer()}},handleSingle:function(a){if(this.passesTolerance(a))if(this.timerId!=null){if(this.last.touches&&this.last.touches.length===1){this["double"]&&OpenLayers.Event.stop(a);this.handleDouble(a)}if(!this.last.touches||this.last.touches.length!==2)this.clearTimer()}else{this.first= +this.getEventInfo(a);this.queuePotentialClick(this.single?OpenLayers.Util.extend({},a):null)}},queuePotentialClick:function(a){this.timerId=window.setTimeout(OpenLayers.Function.bind(this.delayedCall,this,a),this.delay)},passesTolerance:function(a){var b=true;if(this.pixelTolerance!=null&&this.down&&this.down.xy)if((b=this.pixelTolerance>=this.down.xy.distanceTo(a.xy))&&this.touch&&this.down.touches.length===this.last.touches.length){a=0;for(var c=this.down.touches.length;athis.pixelTolerance){b=false;break}}return b},getTouchDistance:function(a,b){return Math.sqrt(Math.pow(a.clientX-b.clientX,2)+Math.pow(a.clientY-b.clientY,2))},passesDblclickTolerance:function(){var a=true;if(this.down&&this.first)a=this.down.xy.distanceTo(this.first.xy)<=this.dblclickTolerance;return a},clearTimer:function(){if(this.timerId!=null){window.clearTimeout(this.timerId);this.timerId=null}if(this.rightclickTimerId!=null){window.clearTimeout(this.rightclickTimerId); +this.rightclickTimerId=null}},delayedCall:function(a){this.timerId=null;a&&this.callback("click",[a])},getEventInfo:function(a){var b;if(a.touches){var c=a.touches.length;b=Array(c);for(var d,e=0;e=1.3&&!c.EXCEPTIONS)c.EXCEPTIONS="INIMAGE";e.push(a,b,c,d);OpenLayers.Layer.Grid.prototype.initialize.apply(this,e);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)); +if(!this.noMagic&&this.params.TRANSPARENT&&this.params.TRANSPARENT.toString().toLowerCase()=="true"){if(d==null||!d.isBaseLayer)this.isBaseLayer=false;if(this.params.FORMAT=="image/jpeg")this.params.FORMAT=OpenLayers.Util.alphaHack()?"image/gif":"image/png"}},clone:function(a){if(a==null)a=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.getOptions());return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},reverseAxisOrder:function(){var a=this.projection.getCode();return parseFloat(this.params.VERSION)>= +1.3&&!!(this.yx[a]||OpenLayers.Projection.defaults[a].yx)},getURL:function(a){a=this.adjustBounds(a);var b=this.getImageSize(),c={},d=this.reverseAxisOrder();c.BBOX=this.encodeBBOX?a.toBBOX(null,d):a.toArray(d);c.WIDTH=b.w;c.HEIGHT=b.h;return this.getFullRequestString(c)},mergeNewParams:function(a){a=[OpenLayers.Util.upperCaseObject(a)];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,a)},getFullRequestString:function(a){var b=this.map.getProjectionObject();b=this.projection&&this.projection.equals(b)? +this.projection.getCode():b.getCode();b=b=="none"?null:b;if(parseFloat(this.params.VERSION)>=1.3)this.params.CRS=b;else this.params.SRS=b;if(typeof this.params.TRANSPARENT=="boolean")a.TRANSPARENT=this.params.TRANSPARENT?"TRUE":"FALSE";return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments)},CLASS_NAME:"OpenLayers.Layer.WMS"});OpenLayers.Renderer.SVG=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"http://www.w3.org/2000/svg",xlinkns:"http://www.w3.org/1999/xlink",MAX_PIXEL:15E3,translationParameters:null,symbolMetrics:null,initialize:function(){if(this.supported()){OpenLayers.Renderer.Elements.prototype.initialize.apply(this,arguments);this.translationParameters={x:0,y:0};this.symbolMetrics={}}},supported:function(){return document.implementation&&(document.implementation.hasFeature("org.w3c.svg","1.0")||document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#SVG", +"1.1")||document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1"))},inValidRange:function(a,b,c){a=a+(c?0:this.translationParameters.x);b=b+(c?0:this.translationParameters.y);return a>=-this.MAX_PIXEL&&a<=this.MAX_PIXEL&&b>=-this.MAX_PIXEL&&b<=this.MAX_PIXEL},setExtent:function(a,b){var c=OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,arguments),d=this.getResolution(),e=-a.left/d;d=a.top/d;if(b){this.left=e;this.top=d;this.rendererRoot.setAttributeNS(null, +"viewBox","0 0 "+this.size.w+" "+this.size.h);this.translate(this.xOffset,0);return true}else{(e=this.translate(e-this.left+this.xOffset,d-this.top))||this.setExtent(a,true);return c&&e}},translate:function(a,b){if(this.inValidRange(a,b,true)){var c="";if(a||b)c="translate("+a+","+b+")";this.root.setAttributeNS(null,"transform",c);this.translationParameters={x:a,y:b};return true}else return false},setSize:function(){OpenLayers.Renderer.prototype.setSize.apply(this,arguments);this.rendererRoot.setAttributeNS(null, +"width",this.size.w);this.rendererRoot.setAttributeNS(null,"height",this.size.h)},getNodeType:function(a,b){var c=null;switch(a.CLASS_NAME){case "OpenLayers.Geometry.Point":c=b.externalGraphic?"image":this.isComplexSymbol(b.graphicName)?"svg":"circle";break;case "OpenLayers.Geometry.Rectangle":c="rect";break;case "OpenLayers.Geometry.LineString":c="polyline";break;case "OpenLayers.Geometry.LinearRing":c="polygon";break;case "OpenLayers.Geometry.Polygon":case "OpenLayers.Geometry.Curve":c="path"}return c}, +setStyle:function(a,b,c){b=b||a._style;c=c||a._options;var d=b.title||b.graphicTitle;if(d){a.setAttributeNS(null,"title",d);var e=a.getElementsByTagName("title");if(e.length>0)e[0].firstChild.textContent=d;else{e=this.nodeFactory(null,"title");e.textContent=d;a.appendChild(e)}}e=parseFloat(a.getAttributeNS(null,"r"));d=1;var f;if(a._geometryClass=="OpenLayers.Geometry.Point"&&e){a.style.visibility="";if(b.graphic===false)a.style.visibility="hidden";else if(b.externalGraphic){f=this.getPosition(a); +b.graphicWidth&&b.graphicHeight&&a.setAttributeNS(null,"preserveAspectRatio","none");e=b.graphicWidth||b.graphicHeight;var g=b.graphicHeight||b.graphicWidth;e=e?e:b.pointRadius*2;g=g?g:b.pointRadius*2;var h=b.graphicYOffset!=undefined?b.graphicYOffset:-(0.5*g),i=b.graphicOpacity||b.fillOpacity;a.setAttributeNS(null,"x",(f.x+(b.graphicXOffset!=undefined?b.graphicXOffset:-(0.5*e))).toFixed());a.setAttributeNS(null,"y",(f.y+h).toFixed());a.setAttributeNS(null,"width",e);a.setAttributeNS(null,"height", +g);a.setAttributeNS(this.xlinkns,"href",b.externalGraphic);a.setAttributeNS(null,"style","opacity: "+i);a.onclick=OpenLayers.Event.preventDefault}else if(this.isComplexSymbol(b.graphicName)){e=b.pointRadius*3;g=e*2;var j=this.importSymbol(b.graphicName);f=this.getPosition(a);d=this.symbolMetrics[j.id][0]*3/g;h=a.parentNode;i=a.nextSibling;h&&h.removeChild(a);a.firstChild&&a.removeChild(a.firstChild);a.appendChild(j.firstChild.cloneNode(true));a.setAttributeNS(null,"viewBox",j.getAttributeNS(null, +"viewBox"));a.setAttributeNS(null,"width",g);a.setAttributeNS(null,"height",g);a.setAttributeNS(null,"x",f.x-e);a.setAttributeNS(null,"y",f.y-e);if(i)h.insertBefore(a,i);else h&&h.appendChild(a)}else a.setAttributeNS(null,"r",b.pointRadius);e=b.rotation;if((e!==undefined||a._rotation!==undefined)&&f){a._rotation=e;e|=0;if(a.nodeName!=="svg")a.setAttributeNS(null,"transform","rotate("+e+" "+f.x+" "+f.y+")");else{f=this.symbolMetrics[j.id];a.firstChild.setAttributeNS(null,"transform","rotate("+e+" "+ +f[1]+" "+f[2]+")")}}}if(c.isFilled){a.setAttributeNS(null,"fill",b.fillColor);a.setAttributeNS(null,"fill-opacity",b.fillOpacity)}else a.setAttributeNS(null,"fill","none");if(c.isStroked){a.setAttributeNS(null,"stroke",b.strokeColor);a.setAttributeNS(null,"stroke-opacity",b.strokeOpacity);a.setAttributeNS(null,"stroke-width",b.strokeWidth*d);a.setAttributeNS(null,"stroke-linecap",b.strokeLinecap||"round");a.setAttributeNS(null,"stroke-linejoin","round");b.strokeDashstyle&&a.setAttributeNS(null,"stroke-dasharray", +this.dashStyle(b,d))}else a.setAttributeNS(null,"stroke","none");b.pointerEvents&&a.setAttributeNS(null,"pointer-events",b.pointerEvents);b.cursor!=null&&a.setAttributeNS(null,"cursor",b.cursor);return a},dashStyle:function(a,b){var c=a.strokeWidth*b,d=a.strokeDashstyle;switch(d){case "solid":return"none";case "dot":return[1,4*c].join();case "dash":return[4*c,4*c].join();case "dashdot":return[4*c,4*c,1,4*c].join();case "longdash":return[8*c,4*c].join();case "longdashdot":return[8*c,4*c,1,4*c].join(); +default:return OpenLayers.String.trim(d).replace(/\s+/g,",")}},createNode:function(a,b){var c=document.createElementNS(this.xmlns,a);b&&c.setAttributeNS(null,"id",b);return c},nodeTypeCompare:function(a,b){return b==a.nodeName},createRenderRoot:function(){var a=this.nodeFactory(this.container.id+"_svgRoot","svg");a.style.display="block";return a},createRoot:function(a){return this.nodeFactory(this.container.id+a,"g")},createDefs:function(){var a=this.nodeFactory(this.container.id+"_defs","defs"); +this.rendererRoot.appendChild(a);return a},drawPoint:function(a,b){return this.drawCircle(a,b,1)},drawCircle:function(a,b,c){var d=this.getResolution(),e=(b.x-this.featureDx)/d+this.left;b=this.top-b.y/d;if(this.inValidRange(e,b)){a.setAttributeNS(null,"cx",e);a.setAttributeNS(null,"cy",b);a.setAttributeNS(null,"r",c);return a}else return false},drawLineString:function(a,b){var c=this.getComponentsString(b.components);if(c.path){a.setAttributeNS(null,"points",c.path);return c.complete?a:null}else return false}, +drawLinearRing:function(a,b){var c=this.getComponentsString(b.components);if(c.path){a.setAttributeNS(null,"points",c.path);return c.complete?a:null}else return false},drawPolygon:function(a,b){for(var c="",d=true,e=true,f,g,h=0,i=b.components.length;hi;)f.removeChild(f.lastChild);for(var j=0;j0&&this.getShortString(a[h-1])&& +f.push(this.clipLine(a[h],a[h-1]));hd){i=(c-g)/(h-f);h=h<0?-d:d;c=g+(h-f)*i}if(c<-e||c>e){i=(h- +f)/(c-g);c=c<0?-e:e;h=f+(c-g)*i}return h+","+c},getShortString:function(a){var b=this.getResolution(),c=(a.x-this.featureDx)/b+this.left;a=this.top-a.y/b;return this.inValidRange(c,a)?c+","+a:false},getPosition:function(a){return{x:parseFloat(a.getAttributeNS(null,"cx")),y:parseFloat(a.getAttributeNS(null,"cy"))}},importSymbol:function(a){if(!this.defs)this.defs=this.createDefs();var b=this.container.id+"-"+a,c=document.getElementById(b);if(c!=null)return c;var d=OpenLayers.Renderer.symbol[a];if(!d)throw Error(a+ +" is not a valid symbol name");a=this.nodeFactory(b,"symbol");var e=this.nodeFactory(null,"polygon");a.appendChild(e);c=new OpenLayers.Bounds(Number.MAX_VALUE,Number.MAX_VALUE,0,0);for(var f=[],g,h,i=0;i1&&this.setGeometryName(null)},destroy:function(){this.options&&!this.options.format&&this.format.destroy();this.format=null;OpenLayers.Protocol.prototype.destroy.apply(this)},read:function(a){OpenLayers.Protocol.prototype.read.apply(this,arguments);a=OpenLayers.Util.extend({},a);OpenLayers.Util.applyDefaults(a,this.options||{});var b=new OpenLayers.Protocol.Response({requestType:"read"}), +c=OpenLayers.Format.XML.prototype.write.apply(this.format,[this.format.writeNode("wfs:GetFeature",a)]);b.priv=OpenLayers.Request.POST({url:a.url,callback:this.createCallback(this.handleRead,b,a),params:a.params,headers:a.headers,data:c});return b},setFeatureType:function(a){this.featureType=a;this.format.featureType=a},setGeometryName:function(a){this.geometryName=a;this.format.geometryName=a},handleRead:function(a,b){b=OpenLayers.Util.extend({},b);OpenLayers.Util.applyDefaults(b,this.options);if(b.callback){var c= +a.priv;if(c.status>=200&&c.status<300)if((c=this.parseResponse(c,b.readOptions))&&c.success!==false){if(b.readOptions&&b.readOptions.output=="object")OpenLayers.Util.extend(a,c);else a.features=c;a.code=OpenLayers.Protocol.Response.SUCCESS}else{a.code=OpenLayers.Protocol.Response.FAILURE;a.error=c}else a.code=OpenLayers.Protocol.Response.FAILURE;b.callback.call(b.scope,a)}},parseResponse:function(a,b){var c=a.responseXML;if(!c||!c.documentElement)c=a.responseText;if(!c||c.length<=0)return null;c= +this.readFormat!==null?this.readFormat.read(c):this.format.read(c,b);if(!this.featureNS){var d=this.readFormat||this.format;this.featureNS=d.featureNS;d.autoConfig=false;this.geometryName||this.setGeometryName(d.geometryName)}return c},commit:function(a,b){b=OpenLayers.Util.extend({},b);OpenLayers.Util.applyDefaults(b,this.options);var c=new OpenLayers.Protocol.Response({requestType:"commit",reqFeatures:a});c.priv=OpenLayers.Request.POST({url:b.url,headers:b.headers,data:this.format.write(a,b),callback:this.createCallback(this.handleCommit, +c,b)});return c},handleCommit:function(a,b){if(b.callback){var c=a.priv,d=c.responseXML;if(!d||!d.documentElement)d=c.responseText;c=this.format.read(d)||{};a.insertIds=c.insertIds||[];if(c.success)a.code=OpenLayers.Protocol.Response.SUCCESS;else{a.code=OpenLayers.Protocol.Response.FAILURE;a.error=c}b.callback.call(b.scope,a)}},filterDelete:function(a,b){b=OpenLayers.Util.extend({},b);OpenLayers.Util.applyDefaults(b,this.options);new OpenLayers.Protocol.Response({requestType:"commit"});var c=this.format.createElementNSPlus("wfs:Transaction", +{attributes:{service:"WFS",version:this.version}}),d=this.format.createElementNSPlus("wfs:Delete",{attributes:{typeName:(b.featureNS?this.featurePrefix+":":"")+b.featureType}});b.featureNS&&d.setAttribute("xmlns:"+this.featurePrefix,b.featureNS);var e=this.format.writeNode("ogc:Filter",a);d.appendChild(e);c.appendChild(d);c=OpenLayers.Format.XML.prototype.write.apply(this.format,[c]);return OpenLayers.Request.POST({url:this.url,callback:b.callback||function(){},data:c})},abort:function(a){a&&a.priv.abort()}, +CLASS_NAME:"OpenLayers.Protocol.WFS.v1"});OpenLayers.ProxyHost="";if(!OpenLayers.Request)OpenLayers.Request={}; +OpenLayers.Util.extend(OpenLayers.Request,{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},URL_SPLIT_REGEX:/([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/,events:new OpenLayers.Events(this),makeSameOrigin:function(a,b){var c=a.indexOf("http")!==0,d=!c&&a.match(this.URL_SPLIT_REGEX);if(d){var e=window.location;c=d[1]==e.protocol&& +d[3]==e.hostname;d=d[4];e=e.port;if(d!=80&&d!=""||e!="80"&&e!="")c=c&&d==e}if(!c)if(b)a=typeof b=="function"?b(a):b+encodeURIComponent(a);else OpenLayers.Console.warn(OpenLayers.i18n("proxyNeeded"),{url:a});return a},issue:function(a){var b=OpenLayers.Util.extend(this.DEFAULT_CONFIG,{proxy:OpenLayers.ProxyHost});a=OpenLayers.Util.applyDefaults(a,b);b=false;for(var c in a.headers)if(a.headers.hasOwnProperty(c))if(c.toLowerCase()==="x-requested-with")b=true;if(b===false)a.headers["X-Requested-With"]= +"XMLHttpRequest";var d=new OpenLayers.Request.XMLHttpRequest,e=OpenLayers.Util.urlAppend(a.url,OpenLayers.Util.getParameterString(a.params||{}));e=OpenLayers.Request.makeSameOrigin(e,a.proxy);d.open(a.method,e,a.async,a.user,a.password);for(var f in a.headers)d.setRequestHeader(f,a.headers[f]);var g=this.events,h=this;d.onreadystatechange=function(){d.readyState==OpenLayers.Request.XMLHttpRequest.DONE&&g.triggerEvent("complete",{request:d,config:a,requestUrl:e})!==false&&h.runCallbacks({request:d, +config:a,requestUrl:e})};a.async===false?d.send(a.data):window.setTimeout(function(){d.readyState!==0&&d.send(a.data)},0);return d},runCallbacks:function(a){var b=a.request,c=a.config,d=c.scope?OpenLayers.Function.bind(c.callback,c.scope):c.callback,e;if(c.success)e=c.scope?OpenLayers.Function.bind(c.success,c.scope):c.success;var f;if(c.failure)f=c.scope?OpenLayers.Function.bind(c.failure,c.scope):c.failure;if(OpenLayers.Util.createUrlObject(c.url).protocol=="file:"&&b.responseText)b.status=200; +d(b);if(!b.status||b.status>=200&&b.status<300){this.events.triggerEvent("success",a);e&&e(b)}if(b.status&&(b.status<200||b.status>=300)){this.events.triggerEvent("failure",a);f&&f(b)}},GET:function(a){a=OpenLayers.Util.extend(a,{method:"GET"});return OpenLayers.Request.issue(a)},POST:function(a){a=OpenLayers.Util.extend(a,{method:"POST"});a.headers=a.headers?a.headers:{};"CONTENT-TYPE"in OpenLayers.Util.upperCaseObject(a.headers)||(a.headers["Content-Type"]="application/xml");return OpenLayers.Request.issue(a)}, +PUT:function(a){a=OpenLayers.Util.extend(a,{method:"PUT"});a.headers=a.headers?a.headers:{};"CONTENT-TYPE"in OpenLayers.Util.upperCaseObject(a.headers)||(a.headers["Content-Type"]="application/xml");return OpenLayers.Request.issue(a)},DELETE:function(a){a=OpenLayers.Util.extend(a,{method:"DELETE"});return OpenLayers.Request.issue(a)},HEAD:function(a){a=OpenLayers.Util.extend(a,{method:"HEAD"});return OpenLayers.Request.issue(a)},OPTIONS:function(a){a=OpenLayers.Util.extend(a,{method:"OPTIONS"});return OpenLayers.Request.issue(a)}});(function(){function a(){this._object=f&&!i?new f:new window.ActiveXObject("Microsoft.XMLHTTP");this._listeners=[]}function b(){return new a}function c(j){b.onreadystatechange&&b.onreadystatechange.apply(j);j.dispatchEvent({type:"readystatechange",bubbles:false,cancelable:false,timeStamp:new Date+0})}function d(j){try{j.responseText=j._object.responseText}catch(k){}try{var m;a:{var o=j._object,l=o.responseXML,n=o.responseText;if(h&&n&&l&&!l.documentElement&&o.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)){l= +new window.ActiveXObject("Microsoft.XMLDOM");l.async=false;l.validateOnParse=false;l.loadXML(n)}if(l)if(h&&l.parseError!=0||!l.documentElement||l.documentElement&&l.documentElement.tagName=="parsererror"){m=null;break a}m=l}j.responseXML=m}catch(q){}try{j.status=j._object.status}catch(p){}try{j.statusText=j._object.statusText}catch(r){}}function e(j){j._object.onreadystatechange=new window.Function}var f=window.XMLHttpRequest,g=!!window.controllers,h=window.document.all&&!window.opera,i=h&&window.navigator.userAgent.match(/MSIE 7.0/); +b.prototype=a.prototype;if(g&&f.wrapped)b.wrapped=f.wrapped;b.UNSENT=0;b.OPENED=1;b.HEADERS_RECEIVED=2;b.LOADING=3;b.DONE=4;b.prototype.readyState=b.UNSENT;b.prototype.responseText="";b.prototype.responseXML=null;b.prototype.status=0;b.prototype.statusText="";b.prototype.priority="NORMAL";b.prototype.onreadystatechange=null;b.onreadystatechange=null;b.onopen=null;b.onsend=null;b.onabort=null;b.prototype.open=function(j,k,m,o,l){delete this._headers;if(arguments.length<3)m=true;this._async=m;var n= +this,q=this.readyState,p;if(h&&m){p=function(){if(q!=b.DONE){e(n);n.abort()}};window.attachEvent("onunload",p)}b.onopen&&b.onopen.apply(this,arguments);if(arguments.length>4)this._object.open(j,k,m,o,l);else arguments.length>3?this._object.open(j,k,m,o):this._object.open(j,k,m);this.readyState=b.OPENED;c(this);this._object.onreadystatechange=function(){if(!(g&&!m)){n.readyState=n._object.readyState;d(n);if(n._aborted)n.readyState=b.UNSENT;else{if(n.readyState==b.DONE){delete n._data;e(n);h&&m&&window.detachEvent("onunload", +p)}q!=n.readyState&&c(n);q=n.readyState}}}};b.prototype.send=function(j){b.onsend&&b.onsend.apply(this,arguments);arguments.length||(j=null);if(j&&j.nodeType){j=window.XMLSerializer?(new window.XMLSerializer).serializeToString(j):j.xml;this._headers["Content-Type"]||this._object.setRequestHeader("Content-Type","application/xml")}this._data=j;this._object.send(this._data);if(g&&!this._async){this.readyState=b.OPENED;for(d(this);this.readyStateb.UNSENT)this._aborted=true;this._object.abort();e(this);this.readyState=b.UNSENT;delete this._data};b.prototype.getAllResponseHeaders=function(){return this._object.getAllResponseHeaders()};b.prototype.getResponseHeader=function(j){return this._object.getResponseHeader(j)};b.prototype.setRequestHeader=function(j,k){if(!this._headers)this._headers={};this._headers[j]=k;return this._object.setRequestHeader(j, +k)};b.prototype.addEventListener=function(j,k,m){for(var o=0,l;l=this._listeners[o];o++)if(l[0]==j&&l[1]==k&&l[2]==m)return;this._listeners.push([j,k,m])};b.prototype.removeEventListener=function(j,k,m){for(var o=0,l;l=this._listeners[o];o++)if(l[0]==j&&l[1]==k&&l[2]==m)break;l&&this._listeners.splice(o,1)};b.prototype.dispatchEvent=function(j){j={type:j.type,target:this,currentTarget:this,eventPhase:2,bubbles:j.bubbles,cancelable:j.cancelable,timeStamp:j.timeStamp,stopPropagation:function(){},preventDefault:function(){}, +initEvent:function(){}};if(j.type=="readystatechange"&&this.onreadystatechange)(this.onreadystatechange.handleEvent||this.onreadystatechange).apply(this,[j]);for(var k=0,m;m=this._listeners[k];k++)if(m[0]==j.type&&!m[2])(m[1].handleEvent||m[1]).apply(this,[j])};b.prototype.toString=function(){return"[object XMLHttpRequest]"};b.toString=function(){return"[XMLHttpRequest]"};if(!window.Function.prototype.apply)window.Function.prototype.apply=function(j,k){k||(k=[]);j.__func=this;j.__func(k[0],k[1],k[2], +k[3],k[4]);delete j.__func};if(!OpenLayers.Request)OpenLayers.Request={};OpenLayers.Request.XMLHttpRequest=b})();OpenLayers.Raster={};OpenLayers.Raster.Grid=OpenLayers.Class({EVENT_TYPES:["update"],initialize:function(a){OpenLayers.Util.extend(this,a);this.events=new OpenLayers.Events(this,null,this.EVENT_TYPES)},getValue:function(){throw Error("getValue must be defined");},numCols:function(){throw Error("numCols must be defined");},numRows:function(){throw Error("numRows must be defined");},forEach:function(a){for(var b=this.numCols(),c=this.numRows(),d=0;d=this.getCount())throw Error("Bad grid index.");var c=this;return new OpenLayers.Raster.Grid({numCols:function(){return c.numCols()},numRows:function(){return c.numRows()},getValue:function(d,e){return c.getValue(d,e)[b]}})},CLASS_NAME:"OpenLayers.Raster.Composite"}}()); +OpenLayers.Raster.Composite.fromLayer=function(a,b){var c;if(a instanceof OpenLayers.Layer.Grid)c=OpenLayers.Raster.Composite.fromGridLayer(a);else if(a instanceof OpenLayers.Layer.Vector)c=OpenLayers.Raster.Composite.fromVectorLayer(a,b);else throw Error("Only Grid or Vector type layers can be used to create a raster");return c}; +OpenLayers.Raster.Composite.fromVectorLayer=function(a,b){function c(n){n=Math.max(0,Math.min(255,n));return(3840+n).toString(16).substring(1)}function d(){m={};window.setTimeout(function(){k.events.triggerEvent("update")},0)}function e(n){n=n.features;l.addFeatures(n,{silent:true});for(var q=0,p=n.length;q1?b:a)({numCols:function(){return d().numCols()},numRows:function(){return d().numRows()}, +getValue:function(j,k){for(var m=Array(f),o,l=0;l=0;--d){c=b[d].geometry;if((c instanceof OpenLayers.Geometry.Polygon||c instanceof OpenLayers.Geometry.MultiPolygon)&&c.intersects(a)){a=b[d];this.control.layer.removeFeatures([a],{silent:true});this.control.layer.events.registerPriority("sketchcomplete", +this,this.finalizeInteriorRing);this.control.layer.events.registerPriority("sketchmodified",this,this.enforceTopology);a.geometry.addComponent(this.line.geometry);this.polygon=a;this.drawingHole=true;break}}OpenLayers.Handler.Path.prototype.addPoint.apply(this,arguments)},getCurrentPointIndex:function(){return this.line.geometry.components.length-2},enforceTopology:function(a){a=a.vertex;var b=this.line.geometry.components;if(!this.polygon.geometry.intersects(a)){b=b[b.length-3];a.x=b.x;a.y=b.y}}, +finishGeometry:function(){this.line.geometry.removeComponent(this.line.geometry.components[this.line.geometry.components.length-2]);this.removePoint();this.finalize()},finalizeInteriorRing:function(){var a=this.line.geometry,b=a.getArea()!==0;if(b){for(var c=this.polygon.geometry.components,d=c.length-2;d>=0;--d)if(a.intersects(c[d])){b=false;break}if(b){d=c.length-2;a:for(;d>0;--d)for(var e=c[d].components,f=0,g=e.length;f3?f[3]:255});this.context.putImageData(b,0,0);this.needsUpdate=false}},CLASS_NAME:"OpenLayers.Layer.Raster"}); diff --git a/lib/OpenLayers/Layer/Raster.js b/lib/OpenLayers/Layer/Raster.js index de60a1425c..770e96472f 100644 --- a/lib/OpenLayers/Layer/Raster.js +++ b/lib/OpenLayers/Layer/Raster.js @@ -71,7 +71,8 @@ OpenLayers.Layer.Raster = OpenLayers.Class(OpenLayers.Layer, { var imageData = this.context.createImageData(cols, rows); var data = imageData.data; // TODO: provide shortcut for canvas based composites - this.data.forEach(function(value, index) { + this.data.forEach(function(value, i, j) { + var index = j * cols + i; var offset = 4 * index; if (!value.length) { value = [value, value, value]; From 5bb8cca2b95f29706b4d14422f2186a1d8c882a6 Mon Sep 17 00:00:00 2001 From: tschaub Date: Tue, 4 Sep 2012 17:32:44 -0600 Subject: [PATCH 22/36] Updated query example. --- examples/raster-query.html | 20 ++-- examples/raster-query.js | 190 ++++++++++++++++++++++++------------- 2 files changed, 133 insertions(+), 77 deletions(-) diff --git a/examples/raster-query.html b/examples/raster-query.html index bc76a0db14..df75f0140d 100644 --- a/examples/raster-query.html +++ b/examples/raster-query.html @@ -23,24 +23,22 @@

Query Grid Data

Raster, Grid, Query
-

This demo shows querying of pixel data.

+

This demo shows querying of raster data.

- Selected pixel value (RGBA): - none selected + Landcover Type + none

- Area selected: - none + Elevation + none

- This example uses a OpenLayers.Raster.Operation - to query composite data from a WMS layer. Click on the map to - query pixel data. The results of the query are displayed on - the map as a OpenLayers.Layer.Raster. -

-

+ This example uses two hidden layers to pull in landcover and elevation + data. Raster composites are generated from these layers and queried + with each move of the mouse. +

See the raster-query.js source for details on how this is done.

diff --git a/examples/raster-query.js b/examples/raster-query.js index 7cbb671159..8c3b62c9b2 100644 --- a/examples/raster-query.js +++ b/examples/raster-query.js @@ -1,81 +1,139 @@ +var op = OpenLayers.Raster.Operation; +var fromLayer = OpenLayers.Raster.Composite.fromLayer; -var osm = new OpenLayers.Layer.OSM(); -var veg = new OpenLayers.Layer.WMS( - "Vegetation", - "/geoserver/wms", - {layers: "za:za_vegetation", format: "image/png8", transparent: "TRUE"}, - {isBaseLayer: false, opacity: 0.5} +var streets = new OpenLayers.Layer.XYZ( + "OpenStreetMap", + [ + "http://otile1.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png", + "http://otile2.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png", + "http://otile3.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png", + "http://otile4.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png" + ], + { + attribution: "Tiles by MapQuest, Open Street Map and contributors, CC-BY-SA ", + transitionEffect: "resize" + } ); -var vegData = OpenLayers.Raster.Composite.fromLayer(veg); - -var pixelValues; -var Click = OpenLayers.Class(OpenLayers.Control, { - autoActivate: true, - initialize: function(options) { - OpenLayers.Control.prototype.initialize.apply(this, arguments); - this.handler = new OpenLayers.Handler.Click(this, {click: this.trigger}); - }, - trigger: function(event) { - var pixel = event.xy; - pixelValues = vegData.getValue(Math.round(pixel.x), Math.round(pixel.y)); - selected.events.triggerEvent("update"); +var imagery = new OpenLayers.Layer.XYZ( + "Imagery", + [ + "http://oatile1.mqcdn.com/naip/${z}/${x}/${y}.png", + "http://oatile2.mqcdn.com/naip/${z}/${x}/${y}.png", + "http://oatile3.mqcdn.com/naip/${z}/${x}/${y}.png", + "http://oatile4.mqcdn.com/naip/${z}/${x}/${y}.png" + ], + { + attribution: "Tiles by MapQuest ", + transitionEffect: "resize" } -}); +); -function close(a, b) { - return Math.abs(a - b) < 15; -} -var query = OpenLayers.Raster.Operation.create(function(vegValues) { - var rgba = [0, 0, 0, 0]; - if (pixelValues) { - if (close(vegValues[0], pixelValues[0]) && close(vegValues[1], pixelValues[1]) && - close(vegValues[2], pixelValues[2]) && close(vegValues[3], pixelValues[3])) { - rgba[3] = 150; - } - } - return rgba; -}); -var selected = query(vegData); +var ned = new OpenLayers.Layer.WMS( + "Elevation", + "/geoserver/wms", + {layers: "usgs:ned", format: "image/png", transparent: true}, + {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false} +); + +var nlcd = new OpenLayers.Layer.WMS( + "Land Cover", + "/geoserver/wms", + {layers: "usgs:nlcd", format: "image/png8", transparent: true}, + {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false} +); var map = new OpenLayers.Map({ div: "map", - theme: null, projection: "EPSG:900913", - units: "m", - maxExtent: new OpenLayers.Bounds(-20037508, -20037508, 20037508, 20037508), - maxResolution: 156543.0339, - controls: [ - new OpenLayers.Control.Navigation(), - new OpenLayers.Control.Zoom(), - new Click() - ], - layers: [ - osm, veg, new OpenLayers.Layer.Raster({name: "Selected", data: selected}) - ], - center: new OpenLayers.LonLat(2622095, -3512434), - zoom: 5 + layers: [streets, imagery, ned, nlcd], + restrictedExtent: [-8732354, 4647019, -8492897, 4782306], + center: [-8606289, 4714070], + zoom: 11 }); -selected.events.on({ - update: function() { - if (pixelValues) { - document.getElementById("output").innerHTML = "[" + pixelValues.join(", ") + "]"; - window.setTimeout(updateStats, 0); - } +map.addControl(new OpenLayers.Control.LayerSwitcher()); + +/** + * The NED dataset is symbolized by a color ramp that maps the following + * elevations to corresponding RGB values. This operation is used to + * invert the mapping - returning elevations in meters for a pixel RGB array. + * + * -20m : 0, 0, 0 + * 400m : 0, 0, 255 + * 820m : 0, 255, 255 + * 1240m : 255, 255, 255 + * + * Transparent pixels are areas of no data (grid value will be NaN). + */ +var getElevation = op.create(function(pixel) { + var elevation = NaN, + delta = 420, + min = -20; + + if (pixel[3] == 255) { + elevation = (delta * (pixel[0] + pixel[1] + pixel[2]) / 255) + min; } -}) + return [elevation]; +}); + +var elevation = getElevation(fromLayer(ned)); -function updateStats() { - var count = 0; - selected.forEach(function(value) { - if (value[3] > 0) { - ++count; +/** + * The NLCD dataset is symbolized according to landcover type. The mapping below + * links RGB values to landcover type. + */ +var classes = { + "255,255,255": null, + "0,0,0": null, // 0 + "73,109,163": "Open Water", // 11 + "224,204,204": "Developed, Open Space", // 21 + "219,153,130": "Developed, Low Intensity", // 22 + "242,0,0": "Developed, Medium Intensity", // 23 + "170,0,0": "Developed, High Intensity", // 24 + "181,175,163": "Barren Land (Rock/Sand/Clay)", // 31 + "107,170,102": "Deciduous Forest", // 41 + "28,102,51": "Evergreen Forest", // 42 + "186,204,145": "Mixed Forest", // 43 + "165,140,48": "Dwarf Scrub", // 51 + "209,186,130": "Shrub/Scrub", // 52 + "229,229,193": "Grassland/Herbaceous", // 71 + "201,201,119": "Sedge/Herbaceous", // 72 + "221,216,60": "Pasture/Hay", // 81 + "173,112,40": "Cultivated Crops", // 82 + "186,216,237": "Woody Wetlands", // 90 + "112,163,191": "Emergent Herbaceous Wetlands" // 95 +}; + +var getCover = op.create(function(pixel) { + var rgb = pixel.slice(0, 3).join(","); + return [classes[rgb]]; +}); + +var lc = fromLayer(nlcd); + +var landcover = getCover(lc); + + +var landcoverOutput = document.getElementById("landcover"); +var elevationOutput = document.getElementById("elevation"); + +// on every mousemove, update the landcover and elevation output +map.events.on({ + mousemove: function(event) { + if (!map.dragging) { + var x = Math.round(event.xy.x); + var y = Math.round(event.xy.y); + // get landcover type for mouse location + landcoverOutput.innerHTML = landcover.getValue(x, y) || "loading ..."; + // get elevation data for mouse location + var el = elevation.getValue(x, y); + if (!isNaN(el)) { + elevationOutput.innerHTML = Math.round(el) + " m2"; + } else { + elevationOutput.innerHTML = "loading ..." + } } - }); - var res = map.getResolution(); - var area = (count * res * res / 10e6).toFixed(0); - - document.getElementById("stats").innerHTML = area + " km2"; -} \ No newline at end of file + } +}); From 99415dea48c5f41d88566bd61406f9788c6ed470 Mon Sep 17 00:00:00 2001 From: tschaub Date: Tue, 4 Sep 2012 18:08:35 -0600 Subject: [PATCH 23/36] No updates while tiles loading. --- lib/OpenLayers/Raster/Composite.js | 44 ++++++++++++++++-------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/lib/OpenLayers/Raster/Composite.js b/lib/OpenLayers/Raster/Composite.js index fe97465d47..9ae55107f6 100644 --- a/lib/OpenLayers/Raster/Composite.js +++ b/lib/OpenLayers/Raster/Composite.js @@ -249,29 +249,31 @@ OpenLayers.Raster.Composite.fromGridLayer = function(layer) { } function update() { - cache = {}; - var map = layer.map; - var tileSize = layer.tileSize; - var mapSize = map.getSize(); - canvas.width = mapSize.w; - canvas.height = mapSize.h; - var mapBounds = map.getExtent(); - var tiles = layer.grid; - var array, tile, tileBounds, img, cornerLocation, cornerPixel; - for (var i=0, ii=tiles.length; i Date: Tue, 4 Sep 2012 18:08:56 -0600 Subject: [PATCH 24/36] Example updates. --- OpenLayers.js | 6 ++-- examples/raster-query.js | 5 +-- examples/raster-stats.html | 17 +++++++--- examples/raster-stats.js | 54 ++++++++++++++++++++++---------- examples/raster-zonal-stats.html | 4 +++ examples/raster-zonal-stats.js | 32 ++++++++++++++----- 6 files changed, 82 insertions(+), 36 deletions(-) diff --git a/OpenLayers.js b/OpenLayers.js index 54753b2772..41ef0cd002 100644 --- a/OpenLayers.js +++ b/OpenLayers.js @@ -606,9 +606,9 @@ OpenLayers.Raster.Composite.fromVectorLayer=function(a,b){function c(n){n=Math.m {hitDetection:false});var i=h.root,j=h.canvas,k=new OpenLayers.Raster.Composite({numCols:function(){return i.width},numRows:function(){return i.height},getCount:function(){return 4},getValue:function(n,q){if(!m.pixelArray){var p=j.getImageData(0,0,i.width,i.height);m.pixelArray=p.data}p=4*(n+q*i.width);return Array.prototype.slice.apply(m.pixelArray,[p,p+4])},toDataURL:function(){return i.toDataURL.apply(i,arguments)}}),m={},o=new OpenLayers.Style({stroke:false,fillColor:"${getColor}",fillOpacity:"${getOpacity}"}, {context:{getColor:function(n){n=g(n);return"#"+c(n[0])+c(n[1])+c(n[2])},getOpacity:function(n){return g(n)[3]/255}}}),l=new OpenLayers.Layer.Vector(null,{styleMap:new OpenLayers.StyleMap(o),renderer:h});e({features:a.features});a.events.on({featuresadded:e,featuresremoved:function(n){l.removeFeatures(n.features,{silent:true});d()},featuremodified:function(n){l.drawFeature(n.feature);d()}});if(a.map){l.setMap(a.map);a.map.events.register("moveend",null,f)}else a.events.register("added",null,function(){l.setMap(a.map); a.map.events.register("moveend",null,f)});return k}; -OpenLayers.Raster.Composite.fromGridLayer=function(a){function b(){window.setTimeout(c,0)}function c(){g={};var h=a.map,i=a.tileSize,j=h.getSize();d.width=j.w;d.height=j.h;j=h.getExtent();for(var k=a.grid,m,o,l,n=0,q=k.length;n1?b:a)({numCols:function(){return d().numCols()},numRows:function(){return d().numRows()}, +OpenLayers.Raster.Composite.fromGridLayer=function(a){function b(){window.setTimeout(c,0)}function c(){if(a.numLoadingTiles==0){g={};var h=a.map,i=a.tileSize,j=h.getSize();d.width=j.w;d.height=j.h;j=h.getExtent();for(var k=a.grid,m,o,l,n=0,q=k.length;n1?b:a)({numCols:function(){return d().numCols()},numRows:function(){return d().numRows()}, getValue:function(j,k){for(var m=Array(f),o,l=0;lOpenLayers Raster Stats Raster, Statistics
+

+ +

- + - - + +
Area (sq. m)Land Cover
Area (m2)Land Cover
areacoverareacover

- See the raster-stats.js source for - detail on generating statistics from raster data. + This example loads landcover data with a hidden WMS layer. A raster composite + is generated from this layer and landcover statistics are generated each time + the data is updated. +

+ See the raster-stats.js source for + detail on generating statistics from raster data.

diff --git a/examples/raster-stats.js b/examples/raster-stats.js index b5065a6b27..b295628678 100644 --- a/examples/raster-stats.js +++ b/examples/raster-stats.js @@ -1,3 +1,6 @@ +var op = OpenLayers.Raster.Operation; +var fromLayer = OpenLayers.Raster.Composite.fromLayer; + var streets = new OpenLayers.Layer.XYZ( "OpenStreetMap", [ @@ -31,24 +34,27 @@ var nlcd = new OpenLayers.Layer.WMS( "Land Cover", "/geoserver/wms", {layers: "usgs:nlcd", format: "image/png8"}, - {singleTile: true, isBaseLayer: false} + {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false} ); var map = new OpenLayers.Map({ div: "map", projection: "EPSG:900913", layers: [streets, imagery, nlcd], + restrictedExtent: [-8732354, 4647019, -8492897, 4782306], center: [-8606289, 4714070], zoom: 11 }); map.addControl(new OpenLayers.Control.LayerSwitcher()); -var data = OpenLayers.Raster.Composite.fromLayer(nlcd); - +/** + * The NLCD dataset is symbolized according to landcover type. The mapping below + * links RGB values to landcover type. + */ var classes = { - "255,255,255": "Background", - "0,0,0": "Background", // 0 + "255,255,255": null, + "0,0,0": null, // 0 "73,109,163": "Open Water", // 11 "224,204,204": "Developed, Open Space", // 21 "219,153,130": "Developed, Low Intensity", // 22 @@ -68,17 +74,25 @@ var classes = { "112,163,191": "Emergent Herbaceous Wetlands" // 95 }; +var getCover = op.create(function(pixel) { + var rgb = pixel.slice(0, 3).join(","); + return [classes[rgb]]; +}); + +var landcover = getCover(fromLayer(nlcd)); + var stats = {}; function generateStats() { stats = {}; var area = Math.pow(map.getResolution(), 2); - data.forEach(function(pixel) { - var rgb = pixel.slice(0, 3).join(","); - var cls = classes[rgb] || rgb - if (cls in stats) { - stats[cls] += area; - } else { - stats[cls] = area; + landcover.forEach(function(pixel) { + var cover = pixel[0]; + if (cover) { + if (cover in stats) { + stats[cover] += area; + } else { + stats[cover] = area; + } } }); displayStats(stats); @@ -88,10 +102,13 @@ var template = new jugl.Template("template"); var target = document.getElementById("stats"); function displayStats(stats) { var entries = []; - for (var cls in stats) { - entries.push([stats[cls], cls]); + for (var cover in stats) { + entries.push({ + cover: cover, + area: stats[cover] + }); } - entries.sort(function(a, b) {return b[0]-a[0]}); + entries.sort(function(a, b) {return b.area - a.area}); target.innerHTML = ""; template.process({ context: {entries: entries}, @@ -100,5 +117,10 @@ function displayStats(stats) { }); } -data.events.on({update: generateStats}); +landcover.events.on({update: generateStats}); + +// allow toggling of nlcd visibility +document.getElementById("show").onclick = function() { + nlcd.setOpacity(this.checked ? 1 : 0); +}; diff --git a/examples/raster-zonal-stats.html b/examples/raster-zonal-stats.html index 3a76579bcb..895ddbbaea 100644 --- a/examples/raster-zonal-stats.html +++ b/examples/raster-zonal-stats.html @@ -51,6 +51,10 @@

OpenLayers Raster Zonal Stats

Raster, Statistics
+

+
+ +

diff --git a/examples/raster-zonal-stats.js b/examples/raster-zonal-stats.js index abb113e1bb..a7b4949f80 100644 --- a/examples/raster-zonal-stats.js +++ b/examples/raster-zonal-stats.js @@ -34,21 +34,22 @@ var ned = new OpenLayers.Layer.WMS( "Elevation", "/geoserver/wms", {layers: "usgs:ned", format: "image/png", transparent: true}, - {singleTile: true, isBaseLayer: false} + {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false} ); var nlcd = new OpenLayers.Layer.WMS( "Land Cover", "/geoserver/wms", {layers: "usgs:nlcd", format: "image/png8", transparent: true}, - {singleTile: true, isBaseLayer: false} + {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false} ); var map = new OpenLayers.Map({ div: "map", projection: "EPSG:900913", layers: [streets, imagery, ned, nlcd], - center: [-8690522, 4714451], //[-8606289, 4714070], + center: [-8690522, 4714451], + restrictedExtent: [-8732354, 4647019, -8492897, 4782306], zoom: 11 }); @@ -100,12 +101,15 @@ var getZone = op.create(function(pixel) { return [zone]; }); -var elevation = getElevation(fromLayer(ned)); -var zones = getZone(elevation); +var zones = getZone(getElevation(fromLayer(ned))); +/** + * The NLCD dataset is symbolized according to landcover type. The mapping below + * links RGB values to landcover type. + */ var classes = { - "255,255,255": "Background", - "0,0,0": "Background", // 0 + "255,255,255": null, + "0,0,0": null, // 0 "73,109,163": "Open Water", // 11 "224,204,204": "Developed, Open Space", // 21 "219,153,130": "Developed, Low Intensity", // 22 @@ -127,7 +131,7 @@ var classes = { var getCover = op.create(function(pixel) { var rgb = pixel.slice(0, 3).join(","); - return [classes[rgb] || rgb]; + return [classes[rgb]]; }); var landcover = getCover(fromLayer(nlcd)); @@ -195,3 +199,15 @@ function displayStats(stats) { zoneCover.events.on({update: deferredStats}); map.addControl(new OpenLayers.Control.LayerSwitcher()); + + +// allow toggling of nlcd visibility +document.getElementById("show-nlcd").onclick = function() { + nlcd.setOpacity(this.checked ? 1 : 0); +}; + + +// allow toggling of nlcd visibility +document.getElementById("show-ned").onclick = function() { + ned.setOpacity(this.checked ? 1 : 0); +}; From 7971f2ba155a538447cf4eca34230d21b4257dcb Mon Sep 17 00:00:00 2001 From: tschaub Date: Tue, 4 Sep 2012 18:32:14 -0600 Subject: [PATCH 25/36] Layer switcher tweaks. --- examples/style.css | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/examples/style.css b/examples/style.css index 237f940248..d141838d2e 100644 --- a/examples/style.css +++ b/examples/style.css @@ -141,3 +141,15 @@ body { -webkit-text-size-adjust: none; } +/* LayerSwitcher modifications */ +.olControlLayerSwitcher .layersDiv { + border-radius: 10px 0 0 10px; + padding-bottom: 10px; + background: #130085; /* fallback for IE - IE6 requires background shorthand*/ + background: rgba(0, 60, 136, 0.75); + filter: alpha(opacity=80); +} +.olControlLayerSwitcher img { + opacity: 0.6; + filter: alpha(opacity=75); +} From 6a5f92e3ee8602c5eed3e77e2f9e497304588dee Mon Sep 17 00:00:00 2001 From: tschaub Date: Tue, 4 Sep 2012 19:37:12 -0600 Subject: [PATCH 26/36] Additional example updates. --- examples/raster-download.html | 3 +++ examples/raster-mask.html | 3 +++ examples/raster-mask.js | 6 +++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/examples/raster-download.html b/examples/raster-download.html index defc7b4854..9f578d49f6 100644 --- a/examples/raster-download.html +++ b/examples/raster-download.html @@ -32,6 +32,9 @@

Download Raster

+ This example creates a raster composite from a WMS layer. The data from the + raster composite can be used to generate download links in various different formats. +

See the raster-download.js source for details on how this is done.

diff --git a/examples/raster-mask.html b/examples/raster-mask.html index ccb125f50b..01b168834b 100644 --- a/examples/raster-mask.html +++ b/examples/raster-mask.html @@ -33,6 +33,9 @@

OpenLayers Raster Mask

Raster, Vector, Mask
+

+ +

diff --git a/examples/raster-mask.js b/examples/raster-mask.js index 3bf7973e88..bbc464fb0b 100644 --- a/examples/raster-mask.js +++ b/examples/raster-mask.js @@ -34,7 +34,7 @@ var nlcd = new OpenLayers.Layer.WMS( "Land Cover", "/geoserver/wms", {layers: "usgs:nlcd", format: "image/png8"}, - {singleTile: true, isBaseLayer: false} + {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false} ); @@ -197,5 +197,9 @@ tracts.events.on({ } }); +// allow toggling of nlcd visibility +document.getElementById("show").onclick = function() { + nlcd.setOpacity(this.checked ? 1 : 0); +}; From 5c514a6722590ee7c6dca6a857587be20dee5643 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Tue, 4 Sep 2012 21:36:53 -0600 Subject: [PATCH 27/36] Corrected units. --- examples/raster-query.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/raster-query.js b/examples/raster-query.js index d61b2c8347..097debf307 100644 --- a/examples/raster-query.js +++ b/examples/raster-query.js @@ -127,7 +127,7 @@ map.events.on({ // get elevation data for mouse location var el = elevation.getValue(x, y); if (!isNaN(el)) { - elevationOutput.innerHTML = Math.round(el) + " m2"; + elevationOutput.innerHTML = Math.round(el) + " m"; } else { elevationOutput.innerHTML = "loading ..." } From 3c9922e180a4f0ad933a461e5827c05a5c33b400 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Tue, 4 Sep 2012 22:54:19 -0600 Subject: [PATCH 28/36] Correct link. --- examples/raster-zonal-stats.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/raster-zonal-stats.html b/examples/raster-zonal-stats.html index 895ddbbaea..4eece9d02b 100644 --- a/examples/raster-zonal-stats.html +++ b/examples/raster-zonal-stats.html @@ -77,7 +77,7 @@

OpenLayers Raster Zonal Stats

- See the raster-zonal-stats.js source for + See the raster-zonal-stats.js source for detail on generating statistics from raster data.

From f104077c4e702bc38e96fbcbefd417de0e241eaa Mon Sep 17 00:00:00 2001 From: Tom Kunicki Date: Sat, 29 Sep 2012 23:02:51 -0500 Subject: [PATCH 29/36] optimize getValue(...) base on browser capabilities --- lib/OpenLayers/Raster/Composite.js | 40 +++++++++++++++++++----------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/lib/OpenLayers/Raster/Composite.js b/lib/OpenLayers/Raster/Composite.js index 9ae55107f6..dced9494ad 100644 --- a/lib/OpenLayers/Raster/Composite.js +++ b/lib/OpenLayers/Raster/Composite.js @@ -224,33 +224,20 @@ OpenLayers.Raster.Composite.fromGridLayer = function(layer) { getCount: function() { return 4; }, - getValue: function(col, row) { - var pixelArray = getPixelArray(); - var cols = canvas.width; - var offset = 4 * (col + (row * cols)); - return Array.prototype.slice.apply(pixelArray, [offset, offset+4]); + getValue: function() { + return [0,0,0,0]; }, toDataURL: function() { return canvas.toDataURL.apply(canvas, arguments); } }); - var cache = {}; - function getPixelArray() { - if (!cache.pixelArray) { - var imageData = context.getImageData(0, 0, canvas.width, canvas.height); - cache.pixelArray = imageData.data; - } - return cache.pixelArray; - } - function deferredUpdate() { window.setTimeout(update, 0); } function update() { if (layer.numLoadingTiles == 0) { - cache = {}; var map = layer.map; var tileSize = layer.tileSize; var mapSize = map.getSize(); @@ -272,6 +259,29 @@ OpenLayers.Raster.Composite.fromGridLayer = function(layer) { } } } + + var cols = canvas.width; + var pixelArray = context.getImageData(0, 0, canvas.width, canvas.height).data; + // generate closure with array access optimized dependent on broswer capability + if (pixelArray.subarray) { + // Chrome, Safari, Firefox, ... + composite.getValue = function(col, row) { + var offset = 4 * (col + (row * cols)); + return pixelArray.subarray(offset, offset+4); + } + } else if (pixelArray.slice) { + // IE 9, ... + composite.getValue = function(col, row) { + var offset = 4 * (col + (row * cols)); + return pixelArray.slice(offset, offset+4); + } + } else { + // fallback + composite.getValue = function(col, row) { + var offset = 4 * (col + (row * cols)); + return Array.prototype.slice.apply(pixelArray, [offset, offset+4]); + } + } composite.events.triggerEvent("update"); } } From d3d2ad4fa640d0859f63e5c7485cc2a658ca0060 Mon Sep 17 00:00:00 2001 From: Tom Kunicki Date: Sat, 29 Sep 2012 23:16:56 -0500 Subject: [PATCH 30/36] changes to support IE Canvas implementation --- lib/OpenLayers/Raster/Composite.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/OpenLayers/Raster/Composite.js b/lib/OpenLayers/Raster/Composite.js index dced9494ad..794b3aca23 100644 --- a/lib/OpenLayers/Raster/Composite.js +++ b/lib/OpenLayers/Raster/Composite.js @@ -255,7 +255,28 @@ OpenLayers.Raster.Composite.fromGridLayer = function(layer) { if (img && img.style.display !== "none" && mapBounds.intersectsBounds(tileBounds)) { cornerLocation = new OpenLayers.LonLat(tileBounds.left, tileBounds.top); cornerPixel = map.getPixelFromLonLat(cornerLocation); - context.drawImage(img, cornerPixel.x, cornerPixel.y, tileSize.w, tileSize.h); + + var underwritex = cornerPixel.x < 0 ? -cornerPixel.x : 0; + var underwritey = cornerPixel.y < 0 ? -cornerPixel.y : 0; + + var overwritex = cornerPixel.x + tileSize.w > canvas.width ? cornerPixel.x + tileSize.w - canvas.width : 0; + var overwritey = cornerPixel.y + tileSize.h > canvas.height ? cornerPixel.y + tileSize.h - canvas.height : 0; + + // only draw tile if it overlaps canvas... + if ((underwritex + overwritex) < tileSize.w && (underwritey + overwritey) < tileSize.h) { + + // adjust source and destination values based on image overlap of canvas (required for IE 9) + var sx = underwritex; + var sy = underwritey; + var sw = tileSize.w - underwritex - overwritex; + var sh = tileSize.h - underwritey - overwritey; + var dx = underwritex > 0 ? 0 : cornerPixel.x; + var dy = underwritey > 0 ? 0 : cornerPixel.y; + var dw = tileSize.w - underwritex - overwritex; + var dh = tileSize.h - underwritey - overwritey; + + context.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh); + } } } } From 02de016741ee0bcb9582f3610cca55222aa74bb3 Mon Sep 17 00:00:00 2001 From: Tom Kunicki Date: Sun, 30 Sep 2012 04:17:57 -0500 Subject: [PATCH 31/36] add simple implementation of wrapped grid when it's only operand to operation --- lib/OpenLayers/Raster/Operation.js | 124 +++++++++++++++++------------ 1 file changed, 75 insertions(+), 49 deletions(-) diff --git a/lib/OpenLayers/Raster/Operation.js b/lib/OpenLayers/Raster/Operation.js index 47d96c03ce..c8c08cec82 100644 --- a/lib/OpenLayers/Raster/Operation.js +++ b/lib/OpenLayers/Raster/Operation.js @@ -12,64 +12,90 @@ OpenLayers.Raster.Operation = (function() { var op = function() { var args = Array.prototype.slice.call(arguments); var len = args.length; + + if (len == 1) { + var operand = args[0]; + if (operand instanceof Grid) { + var result = new Grid({ + numCols: function() { + return operand.numCols(); + }, + numRows: function() { + return operand.numRows(); + }, + getValue: function(col, row) { + return fn(operand.getValue(col, row)); + }, + getCount: function() { + return 1; + } + }); + operand.events.register("update", null, function() { + result.events.triggerEvent("update"); + }); + return result; + } else { + throw new Error("Operation must be called with at least one grid."); + } + } else { + function getFirstGrid() { + var grid; + for (var i=0; i 1) ? Composite : Grid; - var grid = new Constructor({ - numCols: function() { - return getFirstGrid().numCols(); - }, - numRows: function() { - return getFirstGrid().numRows(); - }, - getValue: function(col, row) { - var values = new Array(len); - var arg; - for (var i=0; i 1) ? Composite : Grid; + var grid = new Constructor({ + numCols: function() { + return getFirstGrid().numCols(); + }, + numRows: function() { + return getFirstGrid().numRows(); + }, + getValue: function(col, row) { + var values = new Array(len); + var arg; + for (var i=0; i Date: Sun, 30 Sep 2012 04:21:48 -0500 Subject: [PATCH 32/36] added TypedArray support for raster and grid composite image i/o --- lib/OpenLayers/Layer/Raster.js | 33 +++++++++++++++--------------- lib/OpenLayers/Raster/Composite.js | 21 +++++++++++++------ 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/lib/OpenLayers/Layer/Raster.js b/lib/OpenLayers/Layer/Raster.js index 770e96472f..a3430ccae3 100644 --- a/lib/OpenLayers/Layer/Raster.js +++ b/lib/OpenLayers/Layer/Raster.js @@ -70,22 +70,23 @@ OpenLayers.Layer.Raster = OpenLayers.Class(OpenLayers.Layer, { var imageData = this.context.createImageData(cols, rows); var data = imageData.data; - // TODO: provide shortcut for canvas based composites - this.data.forEach(function(value, i, j) { - var index = j * cols + i; - var offset = 4 * index; - if (!value.length) { - value = [value, value, value]; - } - data[offset + 0] = value[0]; // red - data[offset + 1] = value[1]; // green - data[offset + 2] = value[2]; // blue - if (value.length > 3) { - data[offset + 3] = value[3]; // opacity - } else { - data[offset + 3] = 255; // assume opaque - } - }); + if (data.buffer) { + var dataBuffer = new ArrayBuffer(data.length); + var data8 = new Uint8ClampedArray(dataBuffer); + var data32 = new Uint32Array(dataBuffer); + this.data.forEach(function(value, i, j) { + data32[j* cols + i] = value; + }); + data.set(data8); + } else { + this.data.forEach(function(value, i, j) { + var offset = 4 * (j * cols + i); + data[offset + 0] = ( value & 0xff); // red + data[offset + 1] = ((value >> 8 ) & 0xff); // green + data[offset + 2] = ((value >> 16) & 0xff); // blue + data[offset + 3] = ((value >> 24) & 0xff); // alpha + }); + } this.context.putImageData(imageData, 0, 0); this.needsUpdate = false; } diff --git a/lib/OpenLayers/Raster/Composite.js b/lib/OpenLayers/Raster/Composite.js index 794b3aca23..df8f1a130f 100644 --- a/lib/OpenLayers/Raster/Composite.js +++ b/lib/OpenLayers/Raster/Composite.js @@ -282,25 +282,34 @@ OpenLayers.Raster.Composite.fromGridLayer = function(layer) { } var cols = canvas.width; - var pixelArray = context.getImageData(0, 0, canvas.width, canvas.height).data; + var data8 = context.getImageData(0, 0, canvas.width, canvas.height).data; // generate closure with array access optimized dependent on broswer capability - if (pixelArray.subarray) { + if (data8.buffer) { + var data32 = new Uint32Array(data8.buffer); + composite.getValue = function(col, row) { + var offset = (col + (row * cols)); + return data32[offset]; + } + } else if (data8.subarray) { // Chrome, Safari, Firefox, ... composite.getValue = function(col, row) { var offset = 4 * (col + (row * cols)); - return pixelArray.subarray(offset, offset+4); + var components = data8.subarray(offset, offset+4); + return components[3] << 24 | components[2] << 16 | components[1] << 8 | components[0]; } - } else if (pixelArray.slice) { + } else if (data8.slice) { // IE 9, ... composite.getValue = function(col, row) { var offset = 4 * (col + (row * cols)); - return pixelArray.slice(offset, offset+4); + var components = data8.slice(offset, offset+4); + return components[3] << 24 | components[2] << 16 | components[1] << 8 | components[0]; } } else { // fallback composite.getValue = function(col, row) { var offset = 4 * (col + (row * cols)); - return Array.prototype.slice.apply(pixelArray, [offset, offset+4]); + var components = Array.prototype.slice.apply(data8, [offset, offset+4]); + return components[3] << 24 | components[2] << 16 | components[1] << 8 | components[0]; } } composite.events.triggerEvent("update"); From be2410efb01d0f6bc74f82671b2024500986e7b8 Mon Sep 17 00:00:00 2001 From: Tom Kunicki Date: Tue, 2 Oct 2012 17:31:43 -0500 Subject: [PATCH 33/36] cleaned canvas context imagedata read and writes for browsers w/o TypdedArray support, implemented lazy imagedata access on read. --- lib/OpenLayers/Layer/Raster.js | 10 +++--- lib/OpenLayers/Raster/Composite.js | 52 +++++++++++++----------------- 2 files changed, 28 insertions(+), 34 deletions(-) diff --git a/lib/OpenLayers/Layer/Raster.js b/lib/OpenLayers/Layer/Raster.js index a3430ccae3..bb18c95eb6 100644 --- a/lib/OpenLayers/Layer/Raster.js +++ b/lib/OpenLayers/Layer/Raster.js @@ -80,11 +80,11 @@ OpenLayers.Layer.Raster = OpenLayers.Class(OpenLayers.Layer, { data.set(data8); } else { this.data.forEach(function(value, i, j) { - var offset = 4 * (j * cols + i); - data[offset + 0] = ( value & 0xff); // red - data[offset + 1] = ((value >> 8 ) & 0xff); // green - data[offset + 2] = ((value >> 16) & 0xff); // blue - data[offset + 3] = ((value >> 24) & 0xff); // alpha + var offset = (j * cols + i) << 2; + data[offset + 0] = ( value & 0xff); // red + data[offset + 1] = ((value >> 8 ) & 0xff); // green + data[offset + 2] = ((value >> 16) & 0xff); // blue + data[offset + 3] = ((value >>> 24)); // alpha }); } this.context.putImageData(imageData, 0, 0); diff --git a/lib/OpenLayers/Raster/Composite.js b/lib/OpenLayers/Raster/Composite.js index df8f1a130f..5de446138e 100644 --- a/lib/OpenLayers/Raster/Composite.js +++ b/lib/OpenLayers/Raster/Composite.js @@ -281,36 +281,30 @@ OpenLayers.Raster.Composite.fromGridLayer = function(layer) { } } - var cols = canvas.width; - var data8 = context.getImageData(0, 0, canvas.width, canvas.height).data; - // generate closure with array access optimized dependent on broswer capability - if (data8.buffer) { - var data32 = new Uint32Array(data8.buffer); - composite.getValue = function(col, row) { - var offset = (col + (row * cols)); - return data32[offset]; - } - } else if (data8.subarray) { - // Chrome, Safari, Firefox, ... - composite.getValue = function(col, row) { - var offset = 4 * (col + (row * cols)); - var components = data8.subarray(offset, offset+4); - return components[3] << 24 | components[2] << 16 | components[1] << 8 | components[0]; - } - } else if (data8.slice) { - // IE 9, ... - composite.getValue = function(col, row) { - var offset = 4 * (col + (row * cols)); - var components = data8.slice(offset, offset+4); - return components[3] << 24 | components[2] << 16 | components[1] << 8 | components[0]; - } - } else { - // fallback - composite.getValue = function(col, row) { - var offset = 4 * (col + (row * cols)); - var components = Array.prototype.slice.apply(data8, [offset, offset+4]); - return components[3] << 24 | components[2] << 16 | components[1] << 8 | components[0]; + // defer context.getImageData call until needed... + composite.getValue = function(col, row) { + var width = canvas.width; + var data8 = context.getImageData(0, 0, width, canvas.height).data; + var accessor; + // generate closure with array access optimized dependent on broswer capability + if (data8.buffer) { + var data32 = new Uint32Array(data8.buffer); + accessor = function(col, row) { + var offset = (col + (row * width)); + return data32[offset]; + } + } else { + accessor = function(col, row) { + var offset = (col + (row * width)) << 2; + return data8[offset + 3] << 24 | + data8[offset + 2] << 16 | + data8[offset + 1] << 8 | + data8[offset]; + } } + // replace current function with optimized accessor + composite.getValue = accessor; + return accessor(col, row); } composite.events.triggerEvent("update"); } From 08210caa71dbd32878f3d3ca7a0f03bc96e01424 Mon Sep 17 00:00:00 2001 From: Tom Kunicki Date: Wed, 3 Oct 2012 01:49:26 -0500 Subject: [PATCH 34/36] backport optimizations to pixels as component arrays (Uint8Clamped[]) Uint32 much faster but backwards compatibility --- lib/OpenLayers/Layer/Raster.js | 63 +++++++++++++++++++++++------- lib/OpenLayers/Raster/Composite.js | 20 +++++++++- 2 files changed, 68 insertions(+), 15 deletions(-) diff --git a/lib/OpenLayers/Layer/Raster.js b/lib/OpenLayers/Layer/Raster.js index bb18c95eb6..df06d07dad 100644 --- a/lib/OpenLayers/Layer/Raster.js +++ b/lib/OpenLayers/Layer/Raster.js @@ -70,23 +70,58 @@ OpenLayers.Layer.Raster = OpenLayers.Class(OpenLayers.Layer, { var imageData = this.context.createImageData(cols, rows); var data = imageData.data; - if (data.buffer) { - var dataBuffer = new ArrayBuffer(data.length); - var data8 = new Uint8ClampedArray(dataBuffer); - var data32 = new Uint32Array(dataBuffer); - this.data.forEach(function(value, i, j) { - data32[j* cols + i] = value; - }); - data.set(data8); + + var mutator; + var mutatorTest = this.data.getValue(0,0); + if (!mutatorTest.length) { + mutator = function(value, i, j) { + var offset = (j * cols + i) << 2; + data[offset + 0] = value; // red + data[offset + 1] = value; // green + data[offset + 2] = value; // blue + data[offset + 3] = 255; // alpha + } + } else if (mutatorTest.length == 3) { + mutator = function(value, i, j) { + var offset = (j * cols + i) << 2; + data[offset + 0] = value[0] // red + data[offset + 1] = value[1]; // green + data[offset + 2] = value[2]; // blue + data[offset + 3] = 255; // alpha + } } else { - this.data.forEach(function(value, i, j) { + mutator = function(value, i, j) { var offset = (j * cols + i) << 2; - data[offset + 0] = ( value & 0xff); // red - data[offset + 1] = ((value >> 8 ) & 0xff); // green - data[offset + 2] = ((value >> 16) & 0xff); // blue - data[offset + 3] = ((value >>> 24)); // alpha - }); + data[offset + 0] = value[0] // red + data[offset + 1] = value[1]; // green + data[offset + 2] = value[2]; // blue + data[offset + 3] = value[3]; // alpha + } } + /* + // The mutators below are exclusive to the implementations above. + // While significantly faster, the conversion of the pipeline from + // pixels as Uint8[] to Uint32 breaks backwards compatibility. + // NOTE: symetric implementation in OpenLayers.Raster.Composite +// if (data.buffer) { +// var dataBuffer = new ArrayBuffer(data.length); +// var data8 = new Uint8ClampedArray(dataBuffer); +// var data32 = new Uint32Array(dataBuffer); +// mutator = function(value, i, j) { +// data32[j* cols + i] = value; +// }); +// data.set(data8); +// } else { +// mutator = function(value, i, j) { +// var offset = (j * cols + i) << 2; +// data[offset + 0] = ( value & 0xff); // red +// data[offset + 1] = ((value >> 8 ) & 0xff); // green +// data[offset + 2] = ((value >> 16) & 0xff); // blue +// data[offset + 3] = ((value >>> 24)); // alpha +// }); +// } + */ + this.data.forEach(mutator); this.context.putImageData(imageData, 0, 0); this.needsUpdate = false; } diff --git a/lib/OpenLayers/Raster/Composite.js b/lib/OpenLayers/Raster/Composite.js index 5de446138e..e2f041bab1 100644 --- a/lib/OpenLayers/Raster/Composite.js +++ b/lib/OpenLayers/Raster/Composite.js @@ -225,7 +225,7 @@ OpenLayers.Raster.Composite.fromGridLayer = function(layer) { return 4; }, getValue: function() { - return [0,0,0,0]; + return 0; }, toDataURL: function() { return canvas.toDataURL.apply(canvas, arguments); @@ -287,6 +287,23 @@ OpenLayers.Raster.Composite.fromGridLayer = function(layer) { var data8 = context.getImageData(0, 0, width, canvas.height).data; var accessor; // generate closure with array access optimized dependent on broswer capability + + // avoiding per-call array instantiation is an important optimization. + // given *current* architecture this is safe. + var pixel = [0,0,0,0]; + accessor = function(col, row) { + var offset = (col + (row * width)) << 2; + pixel[3] = data8[offset + 3]; + pixel[2] = data8[offset + 2]; + pixel[1] = data8[offset + 1]; + pixel[0] = data8[offset]; + return pixel; + } + /* + // The accessors below are exclusive to the implementation above. + // While significantly faster, the conversion of the pipeline from + // pixels as Uint8[] to Uint32 breaks backwards compatibility. + // NOTE: symetric implementation in OpenLayers.Layer.Raster if (data8.buffer) { var data32 = new Uint32Array(data8.buffer); accessor = function(col, row) { @@ -302,6 +319,7 @@ OpenLayers.Raster.Composite.fromGridLayer = function(layer) { data8[offset]; } } + */ // replace current function with optimized accessor composite.getValue = accessor; return accessor(col, row); From 1d8238790debf1def54593f4e800904162cc24cd Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Wed, 17 Oct 2012 19:25:39 -0400 Subject: [PATCH 35/36] Update build for examples. --- OpenLayers.js | 1877 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 1295 insertions(+), 582 deletions(-) diff --git a/OpenLayers.js b/OpenLayers.js index 41ef0cd002..6fe09e825b 100644 --- a/OpenLayers.js +++ b/OpenLayers.js @@ -55,585 +55,1298 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ -var OpenLayers={VERSION_NUMBER:"Release 2.13 dev",singleFile:true,_getScriptLocation:function(){for(var a=/(^|(.*?\/))(OpenLayers[^\/]*?\.js)(\?|$)/,b=document.getElementsByTagName("script"),c,d="",e=0,f=b.length;e0)c=parseFloat(a.toPrecision(b));return c},format:function(a,b,c,d){b=typeof b!="undefined"?b:0;c=typeof c!="undefined"?c:OpenLayers.Number.thousandsSeparator;d=typeof d!="undefined"?d:OpenLayers.Number.decimalSeparator;if(b!=null)a=parseFloat(a.toFixed(b));var e=a.toString().split(".");if(e.length==1&&b==null)b=0;a=e[0];if(c)for(var f=/(-?[0-9]+)([0-9]{3})/;f.test(a);)a=a.replace(f,"$1"+c+"$2"); -if(b==0)b=a;else{c=e.length>1?e[1]:"0";if(b!=null)c+=Array(b-c.length+1).join("0");b=a+d+c}return b}};OpenLayers.Function={bind:function(a,b){var c=Array.prototype.slice.apply(arguments,[2]);return function(){var d=c.concat(Array.prototype.slice.apply(arguments,[0]));return a.apply(b,d)}},bindAsEventListener:function(a,b){return function(c){return a.call(b,c||window.event)}},False:function(){return false},True:function(){return true},Void:function(){}}; -OpenLayers.Array={filter:function(a,b,c){var d=[];if(Array.prototype.filter)d=a.filter(b,c);else{var e=a.length;if(typeof b!="function")throw new TypeError;for(var f=0;f1){a=[d,b].concat(Array.prototype.slice.call(arguments).slice(1,a-1),c);OpenLayers.inherit.apply(null,a)}else d.prototype=c;return d}; -OpenLayers.inherit=function(a,b){var c=function(){};c.prototype=b.prototype;a.prototype=new c;var d,e;c=2;for(d=arguments.length;cthis.right)this.right=b.right;if(this.top==null||b.top>this.top)this.top=b.top}}},containsLonLat:function(a,b){if(typeof b==="boolean")b={inclusive:b};b=b||{};var c=this.contains(a.lon,a.lat,b.inclusive),d=b.worldBounds;if(d&&!c){c=d.getWidth();c=this.containsLonLat({lon:a.lon-Math.round((a.lon-(d.left+d.right)/2)/c)*c,lat:a.lat},{inclusive:b.inclusive})}return c},containsPixel:function(a, -b){return this.contains(a.x,a.y,b)},contains:function(a,b,c){if(c==null)c=true;if(a==null||b==null)return false;a=OpenLayers.Util.toFloat(a);b=OpenLayers.Util.toFloat(b);var d=false;return d=c?a>=this.left&&a<=this.right&&b>=this.bottom&&b<=this.top:a>this.left&&athis.bottom&&b=c.bottom&&a.top<=c.top||c.top>a.bottom&&c.top=c.left&&a.left<=c.right||c.left>=a.left&&c.left<=a.right;var f=a.right>=c.left&&a.right<=c.right||c.right>=a.left&&c.right<=a.right;d=(a.bottom>=c.bottom&&a.bottom<=c.top||c.bottom>=a.bottom&&c.bottom<=a.top||d)&&(e||f)}if(b.worldBounds&&!d){var g=b.worldBounds;e=g.getWidth();f=!g.containsBounds(c);g=!g.containsBounds(a);if(f&& -!g){a=a.add(-e,0);d=c.intersectsBounds(a,{inclusive:b.inclusive})}else if(g&&!f){c=c.add(-e,0);d=a.intersectsBounds(c,{inclusive:b.inclusive})}}return d},containsBounds:function(a,b,c){if(b==null)b=false;if(c==null)c=true;var d=this.contains(a.left,a.bottom,c),e=this.contains(a.right,a.bottom,c),f=this.contains(a.left,a.top,c);a=this.contains(a.right,a.top,c);return b?d||e||f||a:d&&e&&f&&a},determineQuadrant:function(a){var b="",c=this.getCenterLonLat();b+=a.lat=a.right&&e.right>a.right;)e=e.add(-f,0);c=e.left+c;if(ca.left&&e.right-d>a.right)e=e.add(-f,0)}return e},CLASS_NAME:"OpenLayers.Bounds"});OpenLayers.Bounds.fromString=function(a,b){var c=a.split(",");return OpenLayers.Bounds.fromArray(c,b)}; -OpenLayers.Bounds.fromArray=function(a,b){return b===true?new OpenLayers.Bounds(a[1],a[0],a[3],a[2]):new OpenLayers.Bounds(a[0],a[1],a[2],a[3])};OpenLayers.Bounds.fromSize=function(a){return new OpenLayers.Bounds(0,a.h,a.w,0)};OpenLayers.Bounds.oppositeQuadrant=function(a){var b="";b+=a.charAt(0)=="t"?"b":"t";b+=a.charAt(1)=="l"?"r":"l";return b};OpenLayers.Element={visible:function(a){return OpenLayers.Util.getElement(a).style.display!="none"},toggle:function(){for(var a=0,b=arguments.length;aa.right;)b.lon-=a.getWidth()}return b},CLASS_NAME:"OpenLayers.LonLat"}); -OpenLayers.LonLat.fromString=function(a){a=a.split(",");return new OpenLayers.LonLat(a[0],a[1])};OpenLayers.LonLat.fromArray=function(a){var b=OpenLayers.Util.isArray(a);return new OpenLayers.LonLat(b&&a[0],b&&a[1])};OpenLayers.Pixel=OpenLayers.Class({x:0,y:0,initialize:function(a,b){this.x=parseFloat(a);this.y=parseFloat(b)},toString:function(){return"x="+this.x+",y="+this.y},clone:function(){return new OpenLayers.Pixel(this.x,this.y)},equals:function(a){var b=false;if(a!=null)b=this.x==a.x&&this.y==a.y||isNaN(this.x)&&isNaN(this.y)&&isNaN(a.x)&&isNaN(a.y);return b},distanceTo:function(a){return Math.sqrt(Math.pow(this.x-a.x,2)+Math.pow(this.y-a.y,2))},add:function(a,b){if(a==null||b==null)throw new TypeError("Pixel.add cannot receive null values"); -return new OpenLayers.Pixel(this.x+a,this.y+b)},offset:function(a){var b=this.clone();if(a)b=this.add(a.x,a.y);return b},CLASS_NAME:"OpenLayers.Pixel"});OpenLayers.Size=OpenLayers.Class({w:0,h:0,initialize:function(a,b){this.w=parseFloat(a);this.h=parseFloat(b)},toString:function(){return"w="+this.w+",h="+this.h},clone:function(){return new OpenLayers.Size(this.w,this.h)},equals:function(a){var b=false;if(a!=null)b=this.w==a.w&&this.h==a.h||isNaN(this.w)&&isNaN(this.h)&&isNaN(a.w)&&isNaN(a.h);return b},CLASS_NAME:"OpenLayers.Size"});OpenLayers.Console={log:function(){},debug:function(){},info:function(){},warn:function(){},error:function(){},userError:function(a){alert(a)},assert:function(){},dir:function(){},dirxml:function(){},trace:function(){},group:function(){},groupEnd:function(){},time:function(){},timeEnd:function(){},profile:function(){},profileEnd:function(){},count:function(){},CLASS_NAME:"OpenLayers.Console"}; -(function(){for(var a=document.getElementsByTagName("script"),b=0,c=a.length;b=0;c--)a[c]==b&&a.splice(c,1);return a}; -OpenLayers.Util.indexOf=function(a,b){if(typeof a.indexOf=="function")return a.indexOf(b);else{for(var c=0,d=a.length;c=0&&parseFloat(h)<1){a.style.filter="alpha(opacity="+h*100+")";a.style.opacity=h}else if(parseFloat(h)==1){a.style.filter="";a.style.opacity=""}}; -OpenLayers.Util.createDiv=function(a,b,c,d,e,f,g,h){var i=document.createElement("div");if(d)i.style.backgroundImage="url("+d+")";a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="absolute");OpenLayers.Util.modifyDOMElement(i,a,b,c,e,f,g,h);return i}; -OpenLayers.Util.createImage=function(a,b,c,d,e,f,g,h){var i=document.createElement("img");a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="relative");OpenLayers.Util.modifyDOMElement(i,a,b,c,e,f,null,g);if(h){i.style.display="none";b=function(){i.style.display="";OpenLayers.Event.stopObservingElement(i)};OpenLayers.Event.observe(i,"load",b);OpenLayers.Event.observe(i,"error",b)}i.style.alt=a;i.galleryImg="no";if(d)i.src=d;return i};OpenLayers.IMAGE_RELOAD_ATTEMPTS=0; -OpenLayers.Util.alphaHackNeeded=null;OpenLayers.Util.alphaHack=function(){if(OpenLayers.Util.alphaHackNeeded==null){var a=navigator.appVersion.split("MSIE");a=parseFloat(a[1]);var b=false;try{b=!!document.body.filters}catch(c){}OpenLayers.Util.alphaHackNeeded=b&&a>=5.5&&a<7}return OpenLayers.Util.alphaHackNeeded}; -OpenLayers.Util.modifyAlphaImageDiv=function(a,b,c,d,e,f,g,h,i){OpenLayers.Util.modifyDOMElement(a,b,c,d,f,null,null,i);b=a.childNodes[0];if(e)b.src=e;OpenLayers.Util.modifyDOMElement(b,a.id+"_innerImage",null,d,"relative",g);if(OpenLayers.Util.alphaHack()){if(a.style.display!="none")a.style.display="inline-block";if(h==null)h="scale";a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+b.src+"', sizingMethod='"+h+"')";if(parseFloat(a.style.opacity)>=0&&parseFloat(a.style.opacity)< -1)a.style.filter+=" alpha(opacity="+a.style.opacity*100+")";b.style.filter="alpha(opacity=0)"}};OpenLayers.Util.createAlphaImageDiv=function(a,b,c,d,e,f,g,h,i){var j=OpenLayers.Util.createDiv();i=OpenLayers.Util.createImage(null,null,null,null,null,null,null,i);i.className="olAlphaImg";j.appendChild(i);OpenLayers.Util.modifyAlphaImageDiv(j,a,b,c,d,e,f,g,h);return j};OpenLayers.Util.upperCaseObject=function(a){var b={},c;for(c in a)b[c.toUpperCase()]=a[c];return b}; -OpenLayers.Util.applyDefaults=function(a,b){a=a||{};var c=typeof window.Event=="function"&&b instanceof window.Event,d;for(d in b)if(a[d]===undefined||!c&&b.hasOwnProperty&&b.hasOwnProperty(d)&&!a.hasOwnProperty(d))a[d]=b[d];if(!c&&b&&b.hasOwnProperty&&b.hasOwnProperty("toString")&&!a.hasOwnProperty("toString"))a.toString=b.toString;return a}; -OpenLayers.Util.getParameterString=function(a){var b=[],c;for(c in a){var d=a[c];if(d!=null&&typeof d!="function"){if(typeof d=="object"&&d.constructor==Array){for(var e=[],f,g=0,h=d.length;g1.0E-12&&--o>0;){var l=Math.sin(k),n=Math.cos(k),q=Math.sqrt(h*l*h*l+(g*j-i*h*n)*(g*j-i*h*n));if(q==0)return 0;n=i*j+g*h*n;var p=Math.atan2(q,n),r= -Math.asin(g*h*l/q),s=Math.cos(r)*Math.cos(r);l=n-2*i*j/s;var t=c/16*s*(4+c*(4-3*s));m=k;k=f+(1-t)*c*Math.sin(r)*(p+t*q*(l+t*n*(-1+2*l*l)))}if(o==0)return NaN;d=s*(d*d-e*e)/(e*e);c=d/1024*(256+d*(-128+d*(74-47*d)));return(e*(1+d/16384*(4096+d*(-768+d*(320-175*d))))*(p-c*q*(l+c/4*(n*(-1+2*l*l)-c/6*l*(-3+4*q*q)*(-3+4*l*l))))).toFixed(3)/1E3}; -OpenLayers.Util.destinationVincenty=function(a,b,c){var d=OpenLayers.Util,e=d.VincentyConstants,f=e.a,g=e.b;e=e.f;var h=a.lon,i=a.lat;a=d.rad(b);b=Math.sin(a);a=Math.cos(a);var j=(1-e)*Math.tan(d.rad(i));i=1/Math.sqrt(1+j*j);var k=j*i,m=Math.atan2(j,a);j=i*b;var o=1-j*j;f=o*(f*f-g*g)/(g*g);var l=1+f/16384*(4096+f*(-768+f*(320-175*f))),n=f/1024*(256+f*(-128+f*(74-47*f)));f=c/(g*l);for(var q=2*Math.PI;Math.abs(f-q)>1.0E-12;){var p=Math.cos(2*m+f),r=Math.sin(f),s=Math.cos(f),t=n*r*(p+n/4*(s*(-1+2*p* -p)-n/6*p*(-3+4*r*r)*(-3+4*p*p)));q=f;f=c/(g*l)+t}c=k*r-i*s*a;c=Math.atan2(k*s+i*r*a,(1-e)*Math.sqrt(j*j+c*c));g=e/16*o*(4+e*(4-3*o));return new OpenLayers.LonLat(h+d.deg(Math.atan2(r*b,i*s-k*r*a)-(1-g)*e*j*(f+g*r*(p+g*s*(-1+2*p*p)))),d.deg(c))}; -OpenLayers.Util.getParameters=function(a){a=a===null||a===undefined?window.location.href:a;var b="";if(OpenLayers.String.contains(a,"?")){b=a.indexOf("?")+1;var c=OpenLayers.String.contains(a,"#")?a.indexOf("#"):a.length;b=a.substring(b,c)}a={};b=b.split(/[&;]/);c=0;for(var d=b.length;c1?1/a:a};OpenLayers.Util.getResolutionFromScale=function(a,b){var c;if(a){if(b==null)b="degrees";c=1/(OpenLayers.Util.normalizeScale(a)*OpenLayers.INCHES_PER_UNIT[b]*OpenLayers.DOTS_PER_INCH)}return c}; -OpenLayers.Util.getScaleFromResolution=function(a,b){if(b==null)b="degrees";return a*OpenLayers.INCHES_PER_UNIT[b]*OpenLayers.DOTS_PER_INCH}; -OpenLayers.Util.pagePosition=function(a){var b=[0,0],c=OpenLayers.Util.getViewportElement();if(!a||a==window||a==c)return b;var d=OpenLayers.IS_GECKO&&document.getBoxObjectFor&&OpenLayers.Element.getStyle(a,"position")=="absolute"&&(a.style.top==""||a.style.left==""),e=null;if(a.getBoundingClientRect){a=a.getBoundingClientRect();e=c.scrollTop;b[0]=a.left+c.scrollLeft;b[1]=a.top+e}else if(document.getBoxObjectFor&&!d){a=document.getBoxObjectFor(a);c=document.getBoxObjectFor(c);b[0]=a.screenX-c.screenX; -b[1]=a.screenY-c.screenY}else{b[0]=a.offsetLeft;b[1]=a.offsetTop;e=a.offsetParent;if(e!=a)for(;e;){b[0]+=e.offsetLeft;b[1]+=e.offsetTop;e=e.offsetParent}c=OpenLayers.BROWSER_NAME;if(c=="opera"||c=="safari"&&OpenLayers.Element.getStyle(a,"position")=="absolute")b[1]-=document.body.offsetTop;for(e=a.offsetParent;e&&e!=document.body;){b[0]-=e.scrollLeft;if(c!="opera"||e.tagName!="TR")b[1]-=e.scrollTop;e=e.offsetParent}}return b}; -OpenLayers.Util.getViewportElement=function(){var a=arguments.callee.viewportElement;if(a==undefined){a=OpenLayers.BROWSER_NAME=="msie"&&document.compatMode!="CSS1Compat"?document.body:document.documentElement;arguments.callee.viewportElement=a}return a}; -OpenLayers.Util.isEquivalentUrl=function(a,b,c){c=c||{};OpenLayers.Util.applyDefaults(c,{ignoreCase:true,ignorePort80:true,ignoreHash:true});a=OpenLayers.Util.createUrlObject(a,c);b=OpenLayers.Util.createUrlObject(b,c);for(var d in a)if(d!=="args")if(a[d]!=b[d])return false;for(d in a.args){if(a.args[d]!=b.args[d])return false;delete b.args[d]}for(d in b.args)return false;return true}; -OpenLayers.Util.createUrlObject=function(a,b){b=b||{};if(!/^\w+:\/\//.test(a)){var c=window.location,d=c.port?":"+c.port:"";d=c.protocol+"//"+c.host.split(":").shift()+d;if(a.indexOf("/")===0)a=d+a;else{c=c.pathname.split("/");c.pop();a=d+c.join("/")+"/"+a}}if(b.ignoreCase)a=a.toLowerCase();c=document.createElement("a");c.href=a;d={};d.host=c.host.split(":").shift();d.protocol=c.protocol;d.port=b.ignorePort80?c.port=="80"||c.port=="0"?"":c.port:c.port==""||c.port=="0"?"80":c.port;d.hash=b.ignoreHash|| -c.hash==="#"?"":c.hash;var e=c.search;if(!e){e=a.indexOf("?");e=e!=-1?a.substr(e):""}d.args=OpenLayers.Util.getParameters(e);d.pathname=c.pathname.charAt(0)=="/"?c.pathname:"/"+c.pathname;return d};OpenLayers.Util.removeTail=function(a){var b=null;b=a.indexOf("?");var c=a.indexOf("#");return b=b==-1?c!=-1?a.substr(0,c):a:c!=-1?a.substr(0,Math.min(b,c)):a.substr(0,b)};OpenLayers.IS_GECKO=function(){var a=navigator.userAgent.toLowerCase();return a.indexOf("webkit")==-1&&a.indexOf("gecko")!=-1}(); -OpenLayers.CANVAS_SUPPORTED=function(){var a=document.createElement("canvas");return!!(a.getContext&&a.getContext("2d"))}();OpenLayers.BROWSER_NAME=function(){var a="",b=navigator.userAgent.toLowerCase();if(b.indexOf("opera")!=-1)a="opera";else if(b.indexOf("msie")!=-1)a="msie";else if(b.indexOf("safari")!=-1)a="safari";else if(b.indexOf("mozilla")!=-1)a=b.indexOf("firefox")!=-1?"firefox":"mozilla";return a}();OpenLayers.Util.getBrowserName=function(){return OpenLayers.BROWSER_NAME}; -OpenLayers.Util.getRenderedDimensions=function(a,b,c){var d,e,f=document.createElement("div");f.style.visibility="hidden";for(var g=c&&c.containerElement?c.containerElement:document.body,h=false,i=null,j=g;j&&j.tagName.toLowerCase()!="body";){var k=OpenLayers.Element.getStyle(j,"position");if(k=="absolute"){h=true;break}else if(k&&k!="static")break;j=j.parentNode}if(h&&(g.clientHeight===0||g.clientWidth===0)){i=document.createElement("div");i.style.visibility="hidden";i.style.position="absolute"; -i.style.overflow="visible";i.style.width=document.body.clientWidth+"px";i.style.height=document.body.clientHeight+"px";i.appendChild(f)}f.style.position="absolute";if(b)if(b.w){d=b.w;f.style.width=d+"px"}else if(b.h){e=b.h;f.style.height=e+"px"}if(c&&c.displayClass)f.className=c.displayClass;b=document.createElement("div");b.innerHTML=a;b.style.overflow="visible";if(b.childNodes){a=0;for(c=b.childNodes.length;a=60){f-=60;d+=1;if(d>=60){d-=60;e+=1}}if(e<10)e="0"+e;e=e+"\u00b0";if(c.indexOf("dm")>=0){if(d<10)d="0"+d;e+=d+"'";if(c.indexOf("dms")>=0){if(f<10)f="0"+f;e+=f+'"'}}e+=b=="lon"?a<0?OpenLayers.i18n("W"):OpenLayers.i18n("E"):a<0?OpenLayers.i18n("S"):OpenLayers.i18n("N");return e};OpenLayers.Event={observers:false,KEY_SPACE:32,KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,element:function(a){return a.target||a.srcElement},isSingleTouch:function(a){return a.touches&&a.touches.length==1},isMultiTouch:function(a){return a.touches&&a.touches.length>1},isLeftClick:function(a){return a.which&&a.which==1||a.button&&a.button==1},isRightClick:function(a){return a.which&&a.which==3||a.button&&a.button==2},stop:function(a, -b){b||OpenLayers.Event.preventDefault(a);if(a.stopPropagation)a.stopPropagation();else a.cancelBubble=true},preventDefault:function(a){if(a.preventDefault)a.preventDefault();else a.returnValue=false},findElement:function(a,b){for(var c=OpenLayers.Event.element(a);c.parentNode&&(!c.tagName||c.tagName.toUpperCase()!=b.toUpperCase());)c=c.parentNode;return c},observe:function(a,b,c,d){a=OpenLayers.Util.getElement(a);d=d||false;if(b=="keypress"&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)|| -a.attachEvent))b="keydown";if(!this.observers)this.observers={};if(!a._eventCacheID){var e="eventCacheID_";if(a.id)e=a.id+"_"+e;a._eventCacheID=OpenLayers.Util.createUniqueID(e)}e=a._eventCacheID;this.observers[e]||(this.observers[e]=[]);this.observers[e].push({element:a,name:b,observer:c,useCapture:d});if(a.addEventListener)a.addEventListener(b,c,d);else a.attachEvent&&a.attachEvent("on"+b,c)},stopObservingElement:function(a){a=OpenLayers.Util.getElement(a)._eventCacheID;this._removeElementObservers(OpenLayers.Event.observers[a])}, -_removeElementObservers:function(a){if(a)for(var b=a.length-1;b>=0;b--){var c=a[b];OpenLayers.Event.stopObserving.apply(this,[c.element,c.name,c.observer,c.useCapture])}},stopObserving:function(a,b,c,d){d=d||false;a=OpenLayers.Util.getElement(a);var e=a._eventCacheID;if(b=="keypress")if(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||a.detachEvent)b="keydown";var f=false,g=OpenLayers.Event.observers[e];if(g)for(var h=0;!f&&h=0;--a)this.target.register(this.events[a],this,this.buttonClick,{extension:true})},destroy:function(){for(var a=this.events.length-1;a>=0;--a)this.target.unregister(this.events[a],this, -this.buttonClick);delete this.target},getPressedButton:function(a){var b=3,c;do{if(OpenLayers.Element.hasClass(a,"olButton")){c=a;break}a=a.parentNode}while(--b>0&&a);return c},ignore:function(a){var b=3,c=false;do{if(a.nodeName.toLowerCase()==="a"){c=true;break}a=a.parentNode}while(--b>0&&a);return c},buttonClick:function(a){var b=true,c=OpenLayers.Event.element(a);if(c&&(OpenLayers.Event.isLeftClick(a)||!~a.type.indexOf("mouse")))if(c=this.getPressedButton(c)){if(a.type==="keydown")switch(a.keyCode){case OpenLayers.Event.KEY_RETURN:case OpenLayers.Event.KEY_SPACE:this.target.triggerEvent("buttonclick", -{buttonElement:c});OpenLayers.Event.stop(a);b=false}else if(this.startEvt){if(this.completeRegEx.test(a.type)){b=OpenLayers.Util.pagePosition(c);this.target.triggerEvent("buttonclick",{buttonElement:c,buttonXY:{x:this.startEvt.clientX-b[0],y:this.startEvt.clientY-b[1]}})}this.cancelRegEx.test(a.type)&&delete this.startEvt;OpenLayers.Event.stop(a);b=false}if(this.startRegEx.test(a.type)){this.startEvt=a;OpenLayers.Event.stop(a);b=false}}else{b=!this.ignore(OpenLayers.Event.element(a));delete this.startEvt}return b}});OpenLayers.Format=OpenLayers.Class({options:null,externalProjection:null,internalProjection:null,data:null,keepData:false,initialize:function(a){OpenLayers.Util.extend(this,a);this.options=a},destroy:function(){},read:function(){throw Error("Read not implemented.");},write:function(){throw Error("Write not implemented.");},CLASS_NAME:"OpenLayers.Format"});OpenLayers.Format.XML=OpenLayers.Class(OpenLayers.Format,{namespaces:null,namespaceAlias:null,defaultPrefix:null,readers:{},writers:{},xmldom:null,initialize:function(a){if(window.ActiveXObject)this.xmldom=new ActiveXObject("Microsoft.XMLDOM");OpenLayers.Format.prototype.initialize.apply(this,[a]);this.namespaces=OpenLayers.Util.extend({},this.namespaces);this.namespaceAlias={};for(var b in this.namespaces)this.namespaceAlias[this.namespaces[b]]=b},destroy:function(){this.xmldom=null;OpenLayers.Format.prototype.destroy.apply(this, -arguments)},setNamespace:function(a,b){this.namespaces[a]=b;this.namespaceAlias[b]=a},read:function(a){var b=a.indexOf("<");if(b>0)a=a.substring(b);b=OpenLayers.Util.Try(OpenLayers.Function.bind(function(){var c;c=window.ActiveXObject&&!this.xmldom?new ActiveXObject("Microsoft.XMLDOM"):this.xmldom;c.loadXML(a);return c},this),function(){return(new DOMParser).parseFromString(a,"text/xml")},function(){var c=new XMLHttpRequest;c.open("GET","data:text/xml;charset=utf-8,"+encodeURIComponent(a),false); -c.overrideMimeType&&c.overrideMimeType("text/xml");c.send(null);return c.responseXML});if(this.keepData)this.data=b;return b},write:function(a){if(this.xmldom)a=a.xml;else{var b=new XMLSerializer;if(a.nodeType==1){var c=document.implementation.createDocument("","",null);if(c.importNode)a=c.importNode(a,true);c.appendChild(a);a=b.serializeToString(c)}else a=b.serializeToString(a)}return a},createElementNS:function(a,b){return this.xmldom?typeof a=="string"?this.xmldom.createNode(1,b,a):this.xmldom.createNode(1, -b,""):document.createElementNS(a,b)},createTextNode:function(a){if(typeof a!=="string")a=String(a);return this.xmldom?this.xmldom.createTextNode(a):document.createTextNode(a)},getElementsByTagNameNS:function(a,b,c){var d=[];if(a.getElementsByTagNameNS)d=a.getElementsByTagNameNS(b,c);else{a=a.getElementsByTagName("*");for(var e,f,g=0,h=a.length;g0){d=a.substring(0,e);a=a.substring(e+1)}else{d=c?this.namespaceAlias[c.namespaceURI]:this.defaultPrefix;a=a}b=this.writers[d][a].apply(this,[b]);c&&c.appendChild(b);return b},getChildEl:function(a,b,c){return a&& -this.getThisOrNextEl(a.firstChild,b,c)},getNextEl:function(a,b,c){return a&&this.getThisOrNextEl(a.nextSibling,b,c)},getThisOrNextEl:function(a,b,c){a=a;a:for(;a;a=a.nextSibling)switch(a.nodeType){case 1:if((!b||b===(a.localName||a.nodeName.split(":").pop()))&&(!c||c===a.namespaceURI))break a;a=null;break a;case 3:if(/^\s*$/.test(a.nodeValue))break;case 4:case 6:case 12:case 10:case 11:a=null;break a}return a||null},lookupNamespaceURI:function(a,b){var c=null;if(a)if(a.lookupNamespaceURI)c=a.lookupNamespaceURI(b); -else a:switch(a.nodeType){case 1:if(a.namespaceURI!==null&&a.prefix===b){c=a.namespaceURI;break a}if(c=a.attributes.length)for(var d,e=0;e0){f=true;g=0;for(h=e.length;g0&&f==false)b.display="none";if(b.label!= -null&&typeof b.label!=="string")b.label=String(b.label);return b},applySymbolizer:function(a,b,c){var d=c.geometry?this.getSymbolizerPrefix(c.geometry):OpenLayers.Style.SYMBOLIZER_PREFIXES[0];a=a.symbolizer[d]||a.symbolizer;if(this.defaultsPerSymbolizer===true){d=this.defaultStyle;OpenLayers.Util.applyDefaults(a,{pointRadius:d.pointRadius});if(a.stroke===true||a.graphic===true)OpenLayers.Util.applyDefaults(a,{strokeWidth:d.strokeWidth,strokeColor:d.strokeColor,strokeOpacity:d.strokeOpacity,strokeDashstyle:d.strokeDashstyle, -strokeLinecap:d.strokeLinecap});if(a.fill===true||a.graphic===true)OpenLayers.Util.applyDefaults(a,{fillColor:d.fillColor,fillOpacity:d.fillOpacity});a.graphic===true&&OpenLayers.Util.applyDefaults(a,{pointRadius:this.defaultStyle.pointRadius,externalGraphic:this.defaultStyle.externalGraphic,graphicName:this.defaultStyle.graphicName,graphicOpacity:this.defaultStyle.graphicOpacity,graphicWidth:this.defaultStyle.graphicWidth,graphicHeight:this.defaultStyle.graphicHeight,graphicXOffset:this.defaultStyle.graphicXOffset, -graphicYOffset:this.defaultStyle.graphicYOffset})}return this.createLiterals(OpenLayers.Util.extend(b,a),c)},createLiterals:function(a,b){var c=OpenLayers.Util.extend({},b.attributes||b.data);OpenLayers.Util.extend(c,this.context);for(var d in this.propertyStyles)a[d]=OpenLayers.Style.createLiteral(a[d],c,b,d);return a},findPropertyStyles:function(){var a={};this.addPropertyStyles(a,this.defaultStyle);for(var b=this.rules,c,d,e=0,f=b.length;ethis.value;break;case OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO:b=a<=this.value;break;case OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO:b= -a>=this.value;break;case OpenLayers.Filter.Comparison.BETWEEN:b=a>=this.lowerBoundary&&a<=this.upperBoundary;break;case OpenLayers.Filter.Comparison.LIKE:b=RegExp(this.value,"gi").test(a)}return b},value2regex:function(a,b,c){if(a==".")throw Error("'.' is an unsupported wildCard character for OpenLayers.Filter.Comparison");a=a?a:"*";b=b?b:".";c=c?c:"!";this.value=this.value.replace(RegExp("\\"+c+"(.|$)","g"),"\\$1");this.value=this.value.replace(RegExp("\\"+b,"g"),".");this.value=this.value.replace(RegExp("\\"+ -a,"g"),".*");this.value=this.value.replace(RegExp("\\\\.\\*","g"),"\\"+a);return this.value=this.value.replace(RegExp("\\\\\\.","g"),"\\"+b)},regex2value:function(){var a=this.value;a=a.replace(/!/g,"!!");a=a.replace(/(\\)?\\\./g,function(b,c){return c?b:"!."});a=a.replace(/(\\)?\\\*/g,function(b,c){return c?b:"!*"});a=a.replace(/\\\\/g,"\\");return a=a.replace(/\.\*/g,"*")},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=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",CLASS_NAME:"OpenLayers.Format.Filter"});OpenLayers.Filter.Function=OpenLayers.Class(OpenLayers.Filter,{name:null,params:null,CLASS_NAME:"OpenLayers.Filter.Function"});OpenLayers.Format.Filter.v1=OpenLayers.Class(OpenLayers.Format.XML,{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"},defaultPrefix:"ogc",schemaLocation:null,initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){var b={};this.readers.ogc.Filter.apply(this,[a,b]);return b.filter},readers:{ogc:{_expression:function(a){for(var b="",c=a.firstChild;c;c= -c.nextSibling)switch(c.nodeType){case 1:a=this.readNode(c);if(a.property)b+="${"+a.property+"}";else if(a.value!==undefined)b+=a.value;break;case 3:case 4:b+=c.nodeValue}return b},Filter:function(a,b){var c={fids:[],filters:[]};this.readChildNodes(a,c);if(c.fids.length>0)b.filter=new OpenLayers.Filter.FeatureId({fids:c.fids});else if(c.filters.length>0)b.filter=c.filters[0]},FeatureId:function(a,b){var c=a.getAttribute("fid");c&&b.fids.push(c)},And:function(a,b){var c=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND}); -this.readChildNodes(a,c);b.filters.push(c)},Or:function(a,b){var c=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.OR});this.readChildNodes(a,c);b.filters.push(c)},Not:function(a,b){var c=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.NOT});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsLessThan:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LESS_THAN});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsGreaterThan:function(a, -b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.GREATER_THAN});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsLessThanOrEqualTo:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsGreaterThanOrEqualTo:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO});this.readChildNodes(a,c);b.filters.push(c)}, -PropertyIsBetween:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.BETWEEN});this.readChildNodes(a,c);b.filters.push(c)},Literal:function(a,b){b.value=OpenLayers.String.numericIf(this.getChildValue(a),true)},PropertyName:function(a,b){b.property=this.getChildValue(a)},LowerBoundary:function(a,b){b.lowerBoundary=OpenLayers.String.numericIf(this.readers.ogc._expression.call(this,a),true)},UpperBoundary:function(a,b){b.upperBoundary=OpenLayers.String.numericIf(this.readers.ogc._expression.call(this, -a),true)},Intersects:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.INTERSECTS)},Within:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.WITHIN)},Contains:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.CONTAINS)},DWithin:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.DWITHIN)},Distance:function(a,b){b.distance=parseInt(this.getChildValue(a));b.distanceUnits=a.getAttribute("units")},Function:function(){}}},readSpatial:function(a,b,c){c=new OpenLayers.Filter.Spatial({type:c}); -this.readChildNodes(a,c);c.value=c.components[0];delete c.components;b.filters.push(c)},writeOgcExpression:function(a,b){if(a instanceof OpenLayers.Filter.Function){var c=this.writeNode("Function",a,b);b.appendChild(c)}else this.writeNode("Literal",a,b);return b},write:function(a){return this.writers.ogc.Filter.apply(this,[a])},writeFeatureIdNodes:function(a,b){for(var c=0,d=a.fids.length;c":"PropertyIsGreaterThan", -"<=":"PropertyIsLessThanOrEqualTo",">=":"PropertyIsGreaterThanOrEqualTo","..":"PropertyIsBetween","~":"PropertyIsLike",BBOX:"BBOX",DWITHIN:"DWITHIN",WITHIN:"WITHIN",CONTAINS:"CONTAINS",INTERSECTS:"INTERSECTS",FID:"FeatureId"},CLASS_NAME:"OpenLayers.Format.Filter.v1"});OpenLayers.Geometry=OpenLayers.Class({id:null,parent:null,bounds:null,initialize:function(){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){this.bounds=this.id=null},clone:function(){return new OpenLayers.Geometry},setBounds:function(a){if(a)this.bounds=a.clone()},clearBounds:function(){this.bounds=null;this.parent&&this.parent.clearBounds()},extendBounds:function(a){this.getBounds()?this.bounds.extend(a):this.setBounds(a)},getBounds:function(){this.bounds==null&&this.calculateBounds(); -return this.bounds},calculateBounds:function(){},distanceTo:function(){},getVertices:function(){},atPoint:function(a,b,c){var d=false;if(this.getBounds()!=null&&a!=null){b=b!=null?b:0;c=c!=null?c:0;d=(new OpenLayers.Bounds(this.bounds.left-b,this.bounds.bottom-c,this.bounds.right+b,this.bounds.top+c)).containsLonLat(a)}return d},getLength:function(){return 0},getArea:function(){return 0},getCentroid:function(){return null},toString:function(){return OpenLayers.Format&&OpenLayers.Format.WKT?OpenLayers.Format.WKT.prototype.write(new OpenLayers.Feature.Vector(this)): -Object.prototype.toString.call(this)},CLASS_NAME:"OpenLayers.Geometry"});OpenLayers.Geometry.fromWKT=function(a){var b;if(OpenLayers.Format&&OpenLayers.Format.WKT){var c=OpenLayers.Geometry.fromWKT.format;if(!c){c=new OpenLayers.Format.WKT;OpenLayers.Geometry.fromWKT.format=c}a=c.read(a);if(a instanceof OpenLayers.Feature.Vector)b=a.geometry;else if(OpenLayers.Util.isArray(a)){b=a.length;c=Array(b);for(var d=0;d=0&&f<=1&&m>=0&&m<=1)if(d){h=a.x1+f*h;m=a.y1+f*i;e=new OpenLayers.Geometry.Point(h,m)}else e=true}if(c)if(e){if(d){a=[a,b];b=0;a:for(;b<2;++b){f=a[b];for(i=1;i<3;++i){h=f["x"+i];m=f["y"+i];d=Math.sqrt(Math.pow(h-e.x,2)+Math.pow(m-e.y,2));if(d=1){e=g;f=h}else{e=e+k*i;f=f+k*j}return{distance:Math.sqrt(Math.pow(e-c,2)+Math.pow(f-d,2)),x:e,y:f}};OpenLayers.Geometry.Point=OpenLayers.Class(OpenLayers.Geometry,{x:null,y:null,initialize:function(a,b){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.x=parseFloat(a);this.y=parseFloat(b)},clone:function(a){if(a==null)a=new OpenLayers.Geometry.Point(this.x,this.y);OpenLayers.Util.applyDefaults(a,this);return a},calculateBounds:function(){this.bounds=new OpenLayers.Bounds(this.x,this.y,this.x,this.y)},distanceTo:function(a,b){var c=!(b&&b.edge===false)&&b&&b.details,d,e,f,g,h;if(a instanceof -OpenLayers.Geometry.Point){e=this.x;f=this.y;g=a.x;h=a.y;d=Math.sqrt(Math.pow(e-g,2)+Math.pow(f-h,2));d=!c?d:{x0:e,y0:f,x1:g,y1:h,distance:d}}else{d=a.distanceTo(this,b);if(c)d={x0:d.x1,y0:d.y1,x1:d.x0,y1:d.y0,distance:d.distance}}return d},equals:function(a){var b=false;if(a!=null)b=this.x==a.x&&this.y==a.y||isNaN(this.x)&&isNaN(this.y)&&isNaN(a.x)&&isNaN(a.y);return b},toShortString:function(){return this.x+", "+this.y},move:function(a,b){this.x+=a;this.y+=b;this.clearBounds()},rotate:function(a, -b){a*=Math.PI/180;var c=this.distanceTo(b),d=a+Math.atan2(this.y-b.y,this.x-b.x);this.x=b.x+c*Math.cos(d);this.y=b.y+c*Math.sin(d);this.clearBounds()},getCentroid:function(){return new OpenLayers.Geometry.Point(this.x,this.y)},resize:function(a,b,c){c=c==undefined?1:c;this.x=b.x+a*c*(this.x-b.x);this.y=b.y+a*(this.y-b.y);this.clearBounds();return this},intersects:function(a){var b=false;return b=a.CLASS_NAME=="OpenLayers.Geometry.Point"?this.equals(a):a.intersects(this)},transform:function(a,b){if(a&& -b){OpenLayers.Projection.transform(this,a,b);this.bounds=null}return this},getVertices:function(){return[this]},CLASS_NAME:"OpenLayers.Geometry.Point"});OpenLayers.Geometry.Collection=OpenLayers.Class(OpenLayers.Geometry,{components:null,componentTypes:null,initialize:function(a){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.components=[];a!=null&&this.addComponents(a)},destroy:function(){this.components.length=0;this.components=null;OpenLayers.Geometry.prototype.destroy.apply(this,arguments)},clone:function(){for(var a=eval("new "+this.CLASS_NAME+"()"),b=0,c=this.components.length;b-1){if(b!=null&&b=0;--c)b=this.removeComponent(a[c])||b;return b},removeComponent:function(a){OpenLayers.Util.removeItem(this.components,a);this.clearBounds();return true},getLength:function(){for(var a=0,b=0,c=this.components.length;b0?h:e;c.push(f)}}a=b.length;if(d===0){for(g=0;g1)for(var b=1,c=this.components.length;b1)for(var d,e=1,f=b.components.length;e< -f;e++){c=b.components[e-1];d=b.components[e];a+=OpenLayers.Util.distVincenty({lon:c.x,lat:c.y},{lon:d.x,lat:d.y})}return a*1E3},CLASS_NAME:"OpenLayers.Geometry.Curve"});OpenLayers.Geometry.LineString=OpenLayers.Class(OpenLayers.Geometry.Curve,{removeComponent:function(){var a=this.components&&this.components.length>2;a&&OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,arguments);return a},intersects:function(a){var b=false,c=a.CLASS_NAME;if(c=="OpenLayers.Geometry.LineString"||c=="OpenLayers.Geometry.LinearRing"||c=="OpenLayers.Geometry.Point"){var d=this.getSortedSegments();a=c=="OpenLayers.Geometry.Point"?[{x1:a.x,y1:a.y,x2:a.x,y2:a.y}]:a.getSortedSegments(); -var e,f,g,h,i,j,k,m=0,o=d.length;a:for(;mf)break;if(!(i.x2Math.max(g,h)))if(!(Math.max(j,k)0){var p=a.x10){l.unshift(r,1);Array.prototype.splice.apply(h,l);r+=l.length-2}if(d)for(var s=0,t=o.points.length;s0&&n.length>0){n.push(k.clone()); -g.push(new OpenLayers.Geometry.LineString(n))}}else c=a.splitWith(this,b);if(h&&h.length>1)f=true;else h=[];if(g&&g.length>1)e=true;else g=[];if(f||e)c=d?[g,h]:h;return c},splitWith:function(a,b){return a.split(this,b)},getVertices:function(a){return a===true?[this.components[0],this.components[this.components.length-1]]:a===false?this.components.slice(1,this.components.length-1):this.components.slice()},distanceTo:function(a,b){var c=!(b&&b.edge===false)&&b&&b.details,d,e={},f=Number.POSITIVE_INFINITY; -if(a instanceof OpenLayers.Geometry.Point){for(var g=this.getSortedSegments(),h=a.x,i=a.y,j,k=0,m=g.length;kh&&(i>j.y1&&ij.y2))break}e=c?{distance:e.distance,x0:e.x,y0:e.y,x1:h,y1:i}:e.distance}else if(a instanceof OpenLayers.Geometry.LineString){g=this.getSortedSegments();h=a.getSortedSegments();var o,l,n=h.length,q={point:true};k=0;m=g.length;a:for(;kj){j=o;k=m}}if(j>i&&k!=g){e.push(k);c(f,g,k,i);c(f,k,h,i)}},d=b.length-1,e=[];e.push(0);for(e.push(d);b[0].equals(b[d]);){d--;e.push(d)}c(b, -0,d,a);a=[];e.sort(function(f,g){return f-g});for(d=0;d1)g=true;else i=[];if(j&&j.length>1)h=true;else j=[];if(g||h)c=d?[i,j]:j;return c},splitWith:function(a,b){var c=null,d=b&&b.mutual,e,f,g,h,i,j;if(a instanceof OpenLayers.Geometry.LineString){j=[];i=[a];for(var k=0,m=this.components.length;k1)h=true;else i=[];if(j&&j.length>1)g=true;else j=[];if(h||g)c=d?[i,j]:j;return c},CLASS_NAME:"OpenLayers.Geometry.MultiLineString"});OpenLayers.Geometry.LinearRing=OpenLayers.Class(OpenLayers.Geometry.LineString,{componentTypes:["OpenLayers.Geometry.Point"],addComponent:function(a,b){var c=false,d=this.components.pop();if(b!=null||!a.equals(d))c=OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,arguments);OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[this.components[0]]);return c},removeComponent:function(){var a=this.components&&this.components.length>3;if(a){this.components.pop();OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this, -arguments);OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[this.components[0]])}return a},move:function(a,b){for(var c=0,d=this.components.length;c0&&a<=2)return this.components[0].clone();else if(a>2){var b=0,c=0,d=this.components[0].x,e=this.components[0].y,f=-1*this.getArea();if(f!=0){for(var g=0;g2){for(var b=a=0,c=this.components.length;b2){for(var d,e,f=0;f=g&&c<=h||g>=h&&c<=g&&c>=h){j=-1;break}}else{i=b((a-f)*((h- -g)/(f-e))+h,14);if(i==c)if(e=e&&a<=f||e>f&&a<=e&&a>=f){j=-1;break}if(!(i<=c))if(!(g!=h&&(iMath.max(g,h))))if(e=e&&af&&a=f)++j}}return j==-1?1:!!(j&1)},intersects:function(a){var b=false;if(a.CLASS_NAME=="OpenLayers.Geometry.Point")b=this.containsPoint(a);else if(a.CLASS_NAME=="OpenLayers.Geometry.LineString")b=a.intersects(this);else if(a.CLASS_NAME=="OpenLayers.Geometry.LinearRing")b=OpenLayers.Geometry.LineString.prototype.intersects.apply(this,[a]);else for(var c= -0,d=a.components.length;c0){a+=Math.abs(this.components[0].getArea());for(var b=1,c=this.components.length;b0){b+=Math.abs(this.components[0].getGeodesicArea(a));for(var c=1,d=this.components.length;c< -d;c++)b-=Math.abs(this.components[c].getGeodesicArea(a))}return b},containsPoint:function(a){var b=this.components.length,c=false;if(b>0){c=this.components[0].containsPoint(a);if(c!==1)if(c&&b>1)for(var d,e=1;e0){if(e=this.parseGeometry[c.toLowerCase()]){e=e.apply(this, -[d[0]]);this.internalProjection&&this.externalProjection&&e.transform(this.externalProjection,this.internalProjection)}else throw new TypeError("Unsupported geometry type: "+c);break}}var g;c=this.getElementsByTagNameNS(a,this.gmlns,"Box");for(f=0;f0){c=b[0].firstChild.nodeValue;c=c.replace(this.regExes.trimSpace,"");c=c.split(this.regExes.splitSpace)}if(c.length== -0){b=this.getElementsByTagNameNS(a,this.gmlns,"coordinates");if(b.length>0){c=b[0].firstChild.nodeValue;c=c.replace(this.regExes.removeSpace,"");c=c.split(",")}}if(c.length==0){b=this.getElementsByTagNameNS(a,this.gmlns,"coord");if(b.length>0){a=this.getElementsByTagNameNS(b[0],this.gmlns,"X");b=this.getElementsByTagNameNS(b[0],this.gmlns,"Y");if(a.length>0&&b.length>0)c=[a[0].firstChild.nodeValue,b[0].firstChild.nodeValue]}}if(c.length==2)c[2]=null;return this.xy?new OpenLayers.Geometry.Point(c[0], -c[1],c[2]):new OpenLayers.Geometry.Point(c[1],c[0],c[2])},multipoint:function(a){a=this.getElementsByTagNameNS(a,this.gmlns,"Point");var b=[];if(a.length>0)for(var c,d=0;d0){d=this.getChildValue(c[0]);d=d.replace(this.regExes.trimSpace,"");d=d.split(this.regExes.splitSpace); -var f=parseInt(c[0].getAttribute("dimension")),g,h,i;for(c=0;c0){d=this.getChildValue(c[0]);d=d.replace(this.regExes.trimSpace,"");d=d.replace(this.regExes.trimComma,",");f=d.split(this.regExes.splitSpace);for(c=0;c0)for(var c,d=0;d0)for(var c,d=0;d0)for(var c,d=0;d0){c=[];if(e.length>0){c=e[0].firstChild.nodeValue;c=c.replace(this.regExes.trimSpace,"");c=c.split(this.regExes.splitSpace)}if(c.length==2)c[2]=null;var f=this.xy?new OpenLayers.Geometry.Point(c[0],c[1],c[2]):new OpenLayers.Geometry.Point(c[1],c[0],c[2])}a=this.getElementsByTagNameNS(a,this.gmlns,"upperCorner");if(a.length>0){c=[];if(a.length>0){c=a[0].firstChild.nodeValue;c=c.replace(this.regExes.trimSpace,"");c=c.split(this.regExes.splitSpace)}if(c.length== -2)c[2]=null;var g=this.xy?new OpenLayers.Geometry.Point(c[0],c[1],c[2]):new OpenLayers.Geometry.Point(c[1],c[0],c[2])}if(f&&g){b.push(new OpenLayers.Geometry.Point(f.x,f.y));b.push(new OpenLayers.Geometry.Point(g.x,f.y));b.push(new OpenLayers.Geometry.Point(g.x,g.y));b.push(new OpenLayers.Geometry.Point(f.x,g.y));b.push(new OpenLayers.Geometry.Point(f.x,f.y));b=new OpenLayers.Geometry.LinearRing(b);d=new OpenLayers.Geometry.Polygon([b])}return d},box:function(a){var b=this.getElementsByTagNameNS(a, -this.gmlns,"coordinates");var c=a=null;if(b.length>0){b=b[0].firstChild.nodeValue;b=b.split(" ");if(b.length==2){a=b[0].split(",");c=b[1].split(",")}}if(a!==null&&c!==null)return new OpenLayers.Bounds(parseFloat(a[0]),parseFloat(a[1]),parseFloat(c[0]),parseFloat(c[1]))}},parseAttributes:function(a){var b={};a=a.firstChild;for(var c,d,e;a;){if(a.nodeType==1){a=a.childNodes;for(c=0;c0)b.bounds=c.components[0]},Point:function(a,b){var c={points:[]};this.readChildNodes(a,c);if(!b.components)b.components=[];b.components.push(c.points[0])},coordinates:function(a,b){var c=this.getChildValue(a).replace(this.regExes.trimSpace,"");c=c.replace(this.regExes.trimComma,",");c=c.split(this.regExes.splitSpace);for(var d,e=c.length,f=Array(e),g=0;g0)b.components= -[new OpenLayers.Geometry.MultiLineString(c.components)]},curveMember:function(a,b){this.readChildNodes(a,b)},MultiSurface:function(a,b){var c={components:[]};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);if(c.components.length>0)b.components=[new OpenLayers.Geometry.MultiPolygon(c.components)]},surfaceMember:function(a,b){this.readChildNodes(a,b)},surfaceMembers:function(a,b){this.readChildNodes(a,b)},pointMembers:function(a,b){this.readChildNodes(a,b)},lineStringMembers:function(a, -b){this.readChildNodes(a,b)},polygonMembers:function(a,b){this.readChildNodes(a,b)},geometryMembers:function(a,b){this.readChildNodes(a,b)},Envelope:function(a,b){var c={points:Array(2)};this.readChildNodes(a,c);if(!b.components)b.components=[];var d=c.points[0];c=c.points[1];b.components.push(new OpenLayers.Bounds(d.x,d.y,c.x,c.y))},lowerCorner:function(a,b){var c={};this.readers.gml.pos.apply(this,[a,c]);b.points[0]=c.points[0]},upperCorner:function(a,b){var c={};this.readers.gml.pos.apply(this, -[a,c]);b.points[1]=c.points[0]}},OpenLayers.Format.GML.Base.prototype.readers.gml),feature:OpenLayers.Format.GML.Base.prototype.readers.feature,wfs:OpenLayers.Format.GML.Base.prototype.readers.wfs},write:function(a){a=this.writeNode("gml:"+(OpenLayers.Util.isArray(a)?"featureMembers":"featureMember"),a);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{gml:OpenLayers.Util.applyDefaults({featureMembers:function(a){for(var b= -this.createElementNSPlus("gml:featureMembers"),c=0,d=a.length;c0?h:Number.POSITIVE_INFINITY;var j=++e,k=+new Date;f[j]=function(){if(f[j]&&+new Date-k<=h){g();f[j]&&d(f[j],i)}else delete f[j]};d(f[j],i);return j},stop:function(g){delete f[g]}}}(window);OpenLayers.Tween=OpenLayers.Class({easing:null,begin:null,finish:null,duration:null,callbacks:null,time:null,animationId:null,playing:false,initialize:function(a){this.easing=a?a:OpenLayers.Easing.Expo.easeOut},start:function(a,b,c,d){this.playing=true;this.begin=a;this.finish=b;this.duration=c;this.callbacks=d.callbacks;this.time=0;OpenLayers.Animation.stop(this.animationId);this.animationId=null;this.callbacks&&this.callbacks.start&&this.callbacks.start.call(this,this.begin);this.animationId=OpenLayers.Animation.start(OpenLayers.Function.bind(this.play, -this))},stop:function(){if(this.playing){this.callbacks&&this.callbacks.done&&this.callbacks.done.call(this,this.finish);OpenLayers.Animation.stop(this.animationId);this.animationId=null;this.playing=false}},play:function(){var a={},b;for(b in this.begin){var c=this.begin[b],d=this.finish[b];if(c==null||d==null||isNaN(c)||isNaN(d))throw new TypeError("invalid value for Tween");a[b]=this.easing.apply(this,[this.time,c,d-c,this.duration])}this.time++;this.callbacks&&this.callbacks.eachStep&&this.callbacks.eachStep.call(this, -a);this.time>this.duration&&this.stop()},CLASS_NAME:"OpenLayers.Tween"});OpenLayers.Easing={CLASS_NAME:"OpenLayers.Easing"};OpenLayers.Easing.Linear={easeIn:function(a,b,c,d){return c*a/d+b},easeOut:function(a,b,c,d){return c*a/d+b},easeInOut:function(a,b,c,d){return c*a/d+b},CLASS_NAME:"OpenLayers.Easing.Linear"}; -OpenLayers.Easing.Expo={easeIn:function(a,b,c,d){return a==0?b:c*Math.pow(2,10*(a/d-1))+b},easeOut:function(a,b,c,d){return a==d?b+c:c*(-Math.pow(2,-10*a/d)+1)+b},easeInOut:function(a,b,c,d){if(a==0)return b;if(a==d)return b+c;if((a/=d/2)<1)return c/2*Math.pow(2,10*(a-1))+b;return c/2*(-Math.pow(2,-10*--a)+2)+b},CLASS_NAME:"OpenLayers.Easing.Expo"}; -OpenLayers.Easing.Quad={easeIn:function(a,b,c,d){return c*(a/=d)*a+b},easeOut:function(a,b,c,d){return-c*(a/=d)*(a-2)+b},easeInOut:function(a,b,c,d){if((a/=d/2)<1)return c/2*a*a+b;return-c/2*(--a*(a-2)-1)+b},CLASS_NAME:"OpenLayers.Easing.Quad"};OpenLayers.Projection=OpenLayers.Class({proj:null,projCode:null,titleRegEx:/\+title=[^\+]*/,initialize:function(a,b){OpenLayers.Util.extend(this,b);this.projCode=a;if(typeof Proj4js=="object")this.proj=new Proj4js.Proj(a)},getCode:function(){return this.proj?this.proj.srsCode:this.projCode},getUnits:function(){return this.proj?this.proj.units:null},toString:function(){return this.getCode()},equals:function(a){a=a;var b=false;if(a){a instanceof OpenLayers.Projection||(a=new OpenLayers.Projection(a)); -if(typeof Proj4js=="object"&&this.proj.defData&&a.proj.defData)b=this.proj.defData.replace(this.titleRegEx,"")==a.proj.defData.replace(this.titleRegEx,"");else if(a.getCode){b=this.getCode();a=a.getCode();b=b==a||!!OpenLayers.Projection.transforms[b]&&OpenLayers.Projection.transforms[b][a]===OpenLayers.Projection.nullTransform}}return b},destroy:function(){delete this.proj;delete this.projCode},CLASS_NAME:"OpenLayers.Projection"});OpenLayers.Projection.transforms={}; -OpenLayers.Projection.defaults={"EPSG:4326":{units:"degrees",maxExtent:[-180,-90,180,90],yx:true},"CRS:84":{units:"degrees",maxExtent:[-180,-90,180,90]},"EPSG:900913":{units:"m",maxExtent:[-2.003750834E7,-2.003750834E7,2.003750834E7,2.003750834E7]}}; -OpenLayers.Projection.addTransform=function(a,b,c){if(c===OpenLayers.Projection.nullTransform){var d=OpenLayers.Projection.defaults[a];if(d&&!OpenLayers.Projection.defaults[b])OpenLayers.Projection.defaults[b]=d}OpenLayers.Projection.transforms[a]||(OpenLayers.Projection.transforms[a]={});OpenLayers.Projection.transforms[a][b]=c}; -OpenLayers.Projection.transform=function(a,b,c){if(b&&c){b instanceof OpenLayers.Projection||(b=new OpenLayers.Projection(b));c instanceof OpenLayers.Projection||(c=new OpenLayers.Projection(c));if(b.proj&&c.proj)a=Proj4js.transform(b.proj,c.proj,a);else{b=b.getCode();c=c.getCode();var d=OpenLayers.Projection.transforms;d[b]&&d[b][c]&&d[b][c](a)}}return a};OpenLayers.Projection.nullTransform=function(a){return a}; -(function(){function a(h){h.x=180*h.x/d;h.y=180/Math.PI*(2*Math.atan(Math.exp(h.y/d*Math.PI))-Math.PI/2);return h}function b(h){h.x=h.x*d/180;h.y=Math.log(Math.tan((90+h.y)*Math.PI/360))/Math.PI*d;return h}function c(h,i){var j=OpenLayers.Projection.addTransform,k=OpenLayers.Projection.nullTransform,m,o,l,n,q;m=0;for(o=i.length;m=0;--g)c(e[g],f);for(g=f.length-1;g>=0;--g)c(f[g],e)})();OpenLayers.Map=OpenLayers.Class({Z_INDEX_BASE:{BaseLayer:100,Overlay:325,Feature:725,Popup:750,Control:1E3},id:null,fractionalZoom:false,events:null,allOverlays:false,div:null,dragging:false,size:null,viewPortDiv:null,layerContainerOrigin:null,layerContainerDiv:null,layers:null,controls:null,popups:null,baseLayer:null,center:null,resolution:null,zoom:0,panRatio:1.5,options:null,tileSize:null,projection:"EPSG:4326",units:null,resolutions:null,maxResolution:null,minResolution:null,maxScale:null,minScale:null, -maxExtent:null,minExtent:null,restrictedExtent:null,numZoomLevels:16,theme:null,displayProjection:null,fallThrough:true,autoUpdateSize:true,panTween:null,eventListeners:null,panMethod:OpenLayers.Easing.Expo.easeOut,panDuration:50,paddingForPopups:null,layerContainerOriginPx:null,minPx:null,maxPx:null,initialize:function(a,b){if(arguments.length===1&&typeof a==="object")a=(b=a)&&b.div;this.tileSize=new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,OpenLayers.Map.TILE_HEIGHT);this.paddingForPopups=new OpenLayers.Bounds(15, -15,15,15);this.theme=OpenLayers._getScriptLocation()+"theme/default/style.css";this.options=OpenLayers.Util.extend({},b);OpenLayers.Util.extend(this,b);OpenLayers.Util.applyDefaults(this,OpenLayers.Projection.defaults[this.projection instanceof OpenLayers.Projection?this.projection.projCode:this.projection]);if(this.maxExtent&&!(this.maxExtent instanceof OpenLayers.Bounds))this.maxExtent=new OpenLayers.Bounds(this.maxExtent);if(this.minExtent&&!(this.minExtent instanceof OpenLayers.Bounds))this.minExtent= -new OpenLayers.Bounds(this.minExtent);if(this.restrictedExtent&&!(this.restrictedExtent instanceof OpenLayers.Bounds))this.restrictedExtent=new OpenLayers.Bounds(this.restrictedExtent);if(this.center&&!(this.center instanceof OpenLayers.LonLat))this.center=new OpenLayers.LonLat(this.center);this.layers=[];this.id=OpenLayers.Util.createUniqueID("OpenLayers.Map_");this.div=OpenLayers.Util.getElement(a);if(!this.div){this.div=document.createElement("div");this.div.style.height="1px";this.div.style.width= -"1px"}OpenLayers.Element.addClass(this.div,"olMap");var c=this.id+"_OpenLayers_ViewPort";this.viewPortDiv=OpenLayers.Util.createDiv(c,null,null,null,"relative",null,"hidden");this.viewPortDiv.style.width="100%";this.viewPortDiv.style.height="100%";this.viewPortDiv.className="olMapViewport";this.div.appendChild(this.viewPortDiv);this.events=new OpenLayers.Events(this,this.viewPortDiv,null,this.fallThrough,{includeXY:true});c=this.id+"_OpenLayers_Container";this.layerContainerDiv=OpenLayers.Util.createDiv(c); -this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE.Popup-1;this.layerContainerOriginPx={x:0,y:0};this.viewPortDiv.appendChild(this.layerContainerDiv);this.updateSize();this.eventListeners instanceof Object&&this.events.on(this.eventListeners);if(this.autoUpdateSize===true){this.updateSizeDestroy=OpenLayers.Function.bind(this.updateSize,this);OpenLayers.Event.observe(window,"resize",this.updateSizeDestroy)}if(this.theme){c=true;for(var d=document.getElementsByTagName("link"),e=0,f=d.length;e=0;--a)this.controls[a].destroy();this.controls=null}if(this.layers!=null){for(a=this.layers.length-1;a>=0;--a)this.layers[a].destroy(false);this.layers=null}this.viewPortDiv&&this.div.removeChild(this.viewPortDiv); -this.viewPortDiv=null;if(this.eventListeners){this.events.un(this.eventListeners);this.eventListeners=null}this.events.destroy();this.options=this.events=null},setOptions:function(a){var b=this.minPx&&a.restrictedExtent!=this.restrictedExtent;OpenLayers.Util.extend(this,a);b&&this.moveTo(this.getCachedCenter(),this.zoom,{forceZoomChange:true})},getTileSize:function(){return this.tileSize},getBy:function(a,b,c){var d=typeof c.test=="function";return OpenLayers.Array.filter(this[a],function(e){return e[b]== -c||d&&c.test(e[b])})},getLayersBy:function(a,b){return this.getBy("layers",a,b)},getLayersByName:function(a){return this.getLayersBy("name",a)},getLayersByClass:function(a){return this.getLayersBy("CLASS_NAME",a)},getControlsBy:function(a,b){return this.getBy("controls",a,b)},getControlsByClass:function(a){return this.getControlsBy("CLASS_NAME",a)},getLayer:function(a){for(var b=null,c=0,d=this.layers.length;cthis.layers.length)b=this.layers.length;if(c!=b){this.layers.splice(c,1);this.layers.splice(b,0,a);c=0;for(var d=this.layers.length;c=0;--c)this.removePopup(this.popups[c]);a.map=this;this.popups.push(a);if(c=a.draw()){c.style.zIndex=this.Z_INDEX_BASE.Popup+this.popups.length;this.layerContainerDiv.appendChild(c)}},removePopup:function(a){OpenLayers.Util.removeItem(this.popups,a);if(a.div)try{this.layerContainerDiv.removeChild(a.div)}catch(b){}a.map=null},getSize:function(){var a=null;if(this.size!=null)a=this.size.clone();return a},updateSize:function(){var a=this.getCurrentSize();if(a&& -!isNaN(a.h)&&!isNaN(a.w)){this.events.clearMouseCache();var b=this.getSize();if(b==null)this.size=b=a;if(!a.equals(b)){this.size=a;a=0;for(b=this.layers.length;a=this.minPx.x+h?Math.round(a):0;b=f<= -this.maxPx.y-i&&f>=this.minPx.y+i?Math.round(b):0;if(a||b){if(!this.dragging){this.dragging=true;this.events.triggerEvent("movestart")}this.center=null;if(a){this.layerContainerDiv.style.left=(this.layerContainerOriginPx.x-=a)+"px";this.minPx.x-=a;this.maxPx.x-=a}if(b){this.layerContainerDiv.style.top=(this.layerContainerOriginPx.y-=b)+"px";this.minPx.y-=b;this.maxPx.y-=b}d=0;for(e=this.layers.length;dc)if(this.fractionalZoom)a=this.getZoomForResolution(c);else for(var d=a|0,e=b.length;dthis.restrictedExtent.getWidth())a= -new OpenLayers.LonLat(g.lon,a.lat);else if(f.leftthis.restrictedExtent.right)a=a.add(this.restrictedExtent.right-f.right,0);if(f.getHeight()>this.restrictedExtent.getHeight())a=new OpenLayers.LonLat(a.lon,g.lat);else if(f.bottomthis.restrictedExtent.top)a=a.add(0,this.restrictedExtent.top-f.top)}}e=e||this.isValidZoomLevel(b)&& -b!=this.getZoom();f=this.isValidLonLat(a)&&!a.equals(this.center);if(e||f||d){d||this.events.triggerEvent("movestart");if(f){!e&&this.center&&this.centerLayerContainer(a);this.center=a.clone()}a=e?this.getResolutionForZoom(b):this.getResolution();if(e||this.layerContainerOrigin==null){this.layerContainerOrigin=this.getCachedCenter();f=this.layerContainerDiv.style;f.left="0px";f.top="0px";this.layerContainerOriginPx.x=0;this.layerContainerOriginPx.y=0;f=this.getMaxExtent({restricted:true});var h=f.getCenterLonLat(); -g=this.center.lon-h.lon;h=h.lat-this.center.lat;var i=Math.round(f.getWidth()/a),j=Math.round(f.getHeight()/a);this.minPx={x:(this.size.w-i)/2-g/a,y:(this.size.h-j)/2-h/a};this.maxPx={x:this.minPx.x+Math.round(f.getWidth()/a),y:this.minPx.y+Math.round(f.getHeight()/a)}}if(e){this.zoom=b;this.resolution=a}a=this.getExtent();if(this.baseLayer.visibility){this.baseLayer.moveTo(a,e,c.dragging);c.dragging||this.baseLayer.events.triggerEvent("moveend",{zoomChanged:e})}a=this.baseLayer.getExtent();for(b= -this.layers.length-1;b>=0;--b){f=this.layers[b];if(f!==this.baseLayer&&!f.isBaseLayer){g=f.calculateInRange();if(f.inRange!=g){(f.inRange=g)||f.display(false);this.events.triggerEvent("changelayer",{layer:f,property:"visibility"})}if(g&&f.visibility){f.moveTo(a,e,c.dragging);c.dragging||f.events.triggerEvent("moveend",{zoomChanged:e})}}}this.events.triggerEvent("move");d||this.events.triggerEvent("moveend");if(e){b=0;for(c=this.popups.length;b=0&&a0)a=this.layers[0].getResolution(); -return a},getUnits:function(){var a=null;if(this.baseLayer!=null)a=this.baseLayer.units;return a},getScale:function(){var a=null;if(this.baseLayer!=null){a=this.getResolution();a=OpenLayers.Util.getScaleFromResolution(a,this.baseLayer.units)}return a},getZoomForExtent:function(a,b){var c=null;if(this.baseLayer!=null)c=this.baseLayer.getZoomForExtent(a,b);return c},getResolutionForZoom:function(a){var b=null;if(this.baseLayer)b=this.baseLayer.getResolutionForZoom(a);return b},getZoomForResolution:function(a, -b){var c=null;if(this.baseLayer!=null)c=this.baseLayer.getZoomForResolution(a,b);return c},zoomTo:function(a){this.isValidZoomLevel(a)&&this.setCenter(null,a)},zoomIn:function(){this.zoomTo(this.getZoom()+1)},zoomOut:function(){this.zoomTo(this.getZoom()-1)},zoomToExtent:function(a,b){a instanceof OpenLayers.Bounds||(a=new OpenLayers.Bounds(a));var c=a.getCenterLonLat();if(this.baseLayer.wrapDateLine){c=this.getMaxExtent();for(a=a.clone();a.right=0){this.initResolutions();if(b&&this.map.baseLayer===this){this.map.setCenter(this.map.getCenter(),this.map.getZoomForResolution(c),false,true);this.map.events.triggerEvent("changebaselayer",{layer:this})}break}}},onMapResize:function(){},redraw:function(){var a=false;if(this.map){this.inRange=this.calculateInRange();var b=this.getExtent();if(b&&this.inRange&&this.visibility){this.moveTo(b,true,false);this.events.triggerEvent("moveend",{zoomChanged:true});a=true}}return a}, -moveTo:function(){var a=this.visibility;this.isBaseLayer||(a=a&&this.inRange);this.display(a)},moveByPx:function(){},setMap:function(a){if(this.map==null){this.map=a;this.maxExtent=this.maxExtent||this.map.maxExtent;this.minExtent=this.minExtent||this.map.minExtent;this.projection=this.projection||this.map.projection;if(typeof this.projection=="string")this.projection=new OpenLayers.Projection(this.projection);this.units=this.projection.getUnits()||this.units||this.map.units;this.initResolutions(); -if(!this.isBaseLayer){this.inRange=this.calculateInRange();this.div.style.display=this.visibility&&this.inRange?"":"none"}this.setTileSize()}},afterAdd:function(){},removeMap:function(){},getImageSize:function(){return this.imageSize||this.tileSize},setTileSize:function(a){this.tileSize=a=a?a:this.tileSize?this.tileSize:this.map.getTileSize();if(this.gutter)this.imageSize=new OpenLayers.Size(a.w+2*this.gutter,a.h+2*this.gutter)},getVisibility:function(){return this.visibility},setVisibility:function(a){if(a!= -this.visibility){this.visibility=a;this.display(a);this.redraw();this.map!=null&&this.map.events.triggerEvent("changelayer",{layer:this,property:"visibility"});this.events.triggerEvent("visibilitychanged")}},display:function(a){if(a!=(this.div.style.display!="none"))this.div.style.display=a&&this.calculateInRange()?"block":"none"},calculateInRange:function(){var a=false;if(this.alwaysInRange)a=true;else if(this.map){a=this.map.getResolution();a=a>=this.minResolution&&a<=this.maxResolution}return a}, -setIsBaseLayer:function(a){if(a!=this.isBaseLayer){this.isBaseLayer=a;this.map!=null&&this.map.events.triggerEvent("changebaselayer",{layer:this})}},initResolutions:function(){var a,b,c,d={},e=true;a=0;for(b=this.RESOLUTION_PROPERTIES.length;a=a){f=h;e=c}if(h<=a){g=h;break}}c=f-g;c=c>0?e+(f-a)/c:e}else{f=Number.POSITIVE_INFINITY;c=0;for(d=this.resolutions.length;cf)break;f=e}else if(this.resolutions[c]< -a)break;c=Math.max(0,c-1)}return c},getLonLatFromViewPortPx:function(a){var b=null,c=this.map;if(a!=null&&c.minPx){b=c.getResolution();var d=c.getMaxExtent({restricted:true});b=new OpenLayers.LonLat((a.x-c.minPx.x)*b+d.left,(c.minPx.y-a.y)*b+d.top);if(this.wrapDateLine)b=b.wrapDateLine(this.maxExtent)}return b},getViewPortPxFromLonLat:function(a,b){var c=null;if(a!=null){b=b||this.map.getResolution();c=this.map.calculateBounds(null,b);c=new OpenLayers.Pixel(1/b*(a.lon-c.left),1/b*(c.top-a.lat))}return c}, -setOpacity:function(a){if(a!=this.opacity){this.opacity=a;for(var b=this.div.childNodes,c=0,d=b.length;c=0&&i=0;c--){e=this.serverResolutions[c];d=Math.abs(e-a);if(d>b)break;b=d;f=e}a=f}return a},getServerZoom:function(){var a=this.getServerResolution();return this.serverResolutions? -OpenLayers.Util.indexOf(this.serverResolutions,a):this.map.getZoomForResolution(a)+(this.zoomOffset||0)},applyBackBuffer:function(a){this.backBufferTimerId!==null&&this.removeBackBuffer();var b=this.backBuffer;if(!b){b=this.createBackBuffer();if(!b)return;this.div.insertBefore(b,this.div.firstChild);this.backBuffer=b;var c=this.grid[0][0].bounds;this.backBufferLonLat={lon:c.left,lat:c.top};this.backBufferResolution=this.gridResolution}c=this.backBufferResolution/a;for(var d=b.childNodes,e,f=d.length- -1;f>=0;--f){e=d[f];e.style.top=(c*e._i*e._h|0)+"px";e.style.left=(c*e._j*e._w|0)+"px";e.style.width=Math.round(c*e._w)+"px";e.style.height=Math.round(c*e._h)+"px"}a=this.getViewPortPxFromLonLat(this.backBufferLonLat,a);c=this.map.layerContainerOriginPx.y;b.style.left=Math.round(a.x-this.map.layerContainerOriginPx.x)+"px";b.style.top=Math.round(a.y-c)+"px"},createBackBuffer:function(){var a;if(this.grid.length>0){a=document.createElement("div");a.id=this.div.id+"_bb";a.className="olBackBuffer";a.style.position= -"absolute";for(var b=0,c=this.grid.length;b=a.bottom-k*this.buffer||l-c.w*(a-1))this.shiftColumn(true,c);else if(b.x<-c.w*a)this.shiftColumn(false,c);else if(b.y>-c.h*(a-1))this.shiftRow(true,c);else if(b.y<-c.h*a)this.shiftRow(false,c);else break}},shiftRow:function(a, -b){for(var c=this.grid,d=c[a?0:this.grid.length-1],e=a?-1:1,f=this.getServerResolution()*-e*this.tileSize.h,g=a?c.pop():c.shift(),h=0,i=d.length;ha;){var e=this.grid.pop();c=0;for(d=e.length;cb;){e=this.grid[c];f=e.pop();this.destroyTile(f)}},onMapResize:function(){if(this.singleTile){this.clearGrid();this.setTileSize()}},getTileBounds:function(a){var b=this.maxExtent,c=this.getResolution(), -d=c*this.tileSize.w;c=c*this.tileSize.h;var e=this.getLonLatFromViewPortPx(a);a=b.left+d*Math.floor((e.lon-b.left)/d);b=b.bottom+c*Math.floor((e.lat-b.bottom)/c);return new OpenLayers.Bounds(a,b,a+d,b+c)},CLASS_NAME:"OpenLayers.Layer.Grid"});OpenLayers.Layer.XYZ=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:true,sphericalMercator:false,zoomOffset:0,serverResolutions:null,initialize:function(a,b,c){if(c&&c.sphericalMercator||this.sphericalMercator)c=OpenLayers.Util.extend({projection:"EPSG:900913",numZoomLevels:19},c);OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a||this.name,b||this.url,{},c])},clone:function(a){if(a==null)a=new OpenLayers.Layer.XYZ(this.name,this.url,this.getOptions());return a=OpenLayers.Layer.Grid.prototype.clone.apply(this, -[a])},getURL:function(a){a=this.getXYZ(a);var b=this.url;if(OpenLayers.Util.isArray(b))b=this.selectUrl(""+a.x+a.y+a.z,b);return OpenLayers.String.format(b,a)},getXYZ:function(a){var b=this.getServerResolution(),c=Math.round((a.left-this.maxExtent.left)/(b*this.tileSize.w));a=Math.round((this.maxExtent.top-a.top)/(b*this.tileSize.h));b=this.getServerZoom();if(this.wrapDateLine){var d=Math.pow(2,b);c=(c%d+d)%d}return{x:c,y:a,z:b}},setMap:function(){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"});OpenLayers.Layer.OSM=OpenLayers.Class(OpenLayers.Layer.XYZ,{name:"OpenStreetMap",url:["http://a.tile.openstreetmap.org/${z}/${x}/${y}.png","http://b.tile.openstreetmap.org/${z}/${x}/${y}.png","http://c.tile.openstreetmap.org/${z}/${x}/${y}.png"],attribution:"Data CC-By-SA by OpenStreetMap",sphericalMercator:true,wrapDateLine:true,tileOptions:null,initialize:function(){OpenLayers.Layer.XYZ.prototype.initialize.apply(this,arguments);this.tileOptions=OpenLayers.Util.extend({crossOriginKeyword:"anonymous"}, -this.options&&this.options.tileOptions)},clone:function(a){if(a==null)a=new OpenLayers.Layer.OSM(this.name,this.url,this.getOptions());return a=OpenLayers.Layer.XYZ.prototype.clone.apply(this,[a])},CLASS_NAME:"OpenLayers.Layer.OSM"});OpenLayers.Renderer=OpenLayers.Class({container:null,root:null,extent:null,locked:false,size:null,resolution:null,map:null,featureDx:0,initialize:function(a,b){this.container=OpenLayers.Util.getElement(a);OpenLayers.Util.extend(this,b)},destroy:function(){this.map=this.resolution=this.size=this.extent=this.container=null},supported:function(){return false},setExtent:function(a,b){this.extent=a.clone();if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){var c=a.getWidth()/this.map.getExtent().getWidth(); -a=a.scale(1/c);this.extent=a.wrapDateLine(this.map.getMaxExtent()).scale(c)}if(b)this.resolution=null;return true},setSize:function(a){this.size=a.clone();this.resolution=null},getResolution:function(){return this.resolution=this.resolution||this.map.getResolution()},drawFeature:function(a,b){if(b==null)b=a.style;if(a.geometry){var c=a.geometry.getBounds();if(c){var d;if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine)d=this.map.getMaxExtent();if(c.intersectsBounds(this.extent,{worldBounds:d}))this.calculateFeatureDx(c, -d);else b={display:"none"};c=this.drawGeometry(a.geometry,b,a.id);if(b.display!="none"&&b.label&&c!==false){d=a.geometry.getCentroid();if(b.labelXOffset||b.labelYOffset){var e=isNaN(b.labelXOffset)?0:b.labelXOffset,f=isNaN(b.labelYOffset)?0:b.labelYOffset,g=this.getResolution();d.move(e*g,f*g)}this.drawText(a.id,b,d)}else this.removeText(a.id);return c}}},calculateFeatureDx:function(a,b){this.featureDx=0;if(b){var c=b.getWidth();this.featureDx=Math.round(((a.left+a.right)/2-(this.extent.left+this.extent.right)/ -2)/c)*c}},drawGeometry:function(){},drawText:function(){},removeText:function(){},clear:function(){},getFeatureIdFromEvent:function(){},eraseFeatures:function(a){OpenLayers.Util.isArray(a)||(a=[a]);for(var b=0,c=a.length;b=16777216){this.hitOverflow=a-16777215;a=a%16777216+1}a="000000"+a.toString(16);var b=a.length;return a="#"+a.substring(b-6,b)},setHitContextStyle:function(a, -b,c,d){b=this.featureIdToHex(b);if(a=="fill"){this.hitContext.globalAlpha=1;this.hitContext.fillStyle=b}else if(a=="stroke"){this.hitContext.globalAlpha=1;this.hitContext.strokeStyle=b;if(typeof d==="undefined")this.hitContext.lineWidth=c.strokeWidth+2;else if(!isNaN(d))this.hitContext.lineWidth=c.strokeWidth+2/d}else{this.hitContext.globalAlpha=0;this.hitContext.lineWidth=1}},drawPoint:function(a,b,c){if(b.graphic!==false)if(b.externalGraphic)this.drawExternalGraphic(a,b,c);else if(b.graphicName&& -b.graphicName!="circle")this.drawNamedSymbol(a,b,c);else{var d=this.getLocalXY(a);a=d[0];d=d[1];if(!isNaN(a)&&!isNaN(d)){var e=Math.PI*2,f=b.pointRadius;if(b.fill!==false){this.setCanvasStyle("fill",b);this.canvas.beginPath();this.canvas.arc(a,d,f,0,e,true);this.canvas.fill();if(this.hitDetection){this.setHitContextStyle("fill",c,b);this.hitContext.beginPath();this.hitContext.arc(a,d,f,0,e,true);this.hitContext.fill()}}if(b.stroke!==false){this.setCanvasStyle("stroke",b);this.canvas.beginPath();this.canvas.arc(a, -d,f,0,e,true);this.canvas.stroke();if(this.hitDetection){this.setHitContextStyle("stroke",c,b);this.hitContext.beginPath();this.hitContext.arc(a,d,f,0,e,true);this.hitContext.stroke()}this.setCanvasStyle("reset")}}}},drawLineString:function(a,b,c){b=OpenLayers.Util.applyDefaults({fill:false},b);this.drawLinearRing(a,b,c)},drawLinearRing:function(a,b,c){if(b.fill!==false){this.setCanvasStyle("fill",b);this.renderPath(this.canvas,a,b,c,"fill");if(this.hitDetection){this.setHitContextStyle("fill",c, -b);this.renderPath(this.hitContext,a,b,c,"fill")}}if(b.stroke!==false){this.setCanvasStyle("stroke",b);this.renderPath(this.canvas,a,b,c,"stroke");if(this.hitDetection){this.setHitContextStyle("stroke",c,b);this.renderPath(this.hitContext,a,b,c,"stroke")}}this.setCanvasStyle("reset")},renderPath:function(a,b,c,d,e){b=b.components;c=b.length;a.beginPath();d=this.getLocalXY(b[0]);var f=d[1];if(!isNaN(d[0])&&!isNaN(f)){a.moveTo(d[0],d[1]);for(d=1;d1;){e=parseInt((c+d)/2);if(this.compare(this,a,OpenLayers.Util.getElement(this.order[e]))>0)c=e;else d=e}this.order.splice(d, -0,b);this.indices[b]=this.getZIndex(a);return this.getNextElement(d)},remove:function(a){a=a.id;var b=OpenLayers.Util.indexOf(this.order,a);if(b>=0){this.order.splice(b,1);delete this.indices[a];this.maxZIndex=this.order.length>0?this.indices[this.order[this.order.length-1]]:0}},clear:function(){this.order=[];this.indices={};this.maxZIndex=0},exists:function(a){return this.indices[a.id]!=null},getZIndex:function(a){return a._style.graphicZIndex},determineZIndex:function(a){var b=a._style.graphicZIndex; -if(b==null){b=this.maxZIndex;a._style.graphicZIndex=b}else if(b>this.maxZIndex)this.maxZIndex=b},getNextElement:function(a){a=a+1;if(aa.left&&f.righta.left&&f.left0},CLASS_NAME:"OpenLayers.Protocol.Response"}); -OpenLayers.Protocol.Response.SUCCESS=1;OpenLayers.Protocol.Response.FAILURE=0;OpenLayers.Protocol.WFS=function(a){a=OpenLayers.Util.applyDefaults(a,OpenLayers.Protocol.WFS.DEFAULTS);var b=OpenLayers.Protocol.WFS["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported WFS version: "+a.version;return new b(a)}; -OpenLayers.Protocol.WFS.fromWMSLayer=function(a,b){var c,d;c=a.params.LAYERS;c=(OpenLayers.Util.isArray(c)?c[0]:c).split(":");if(c.length>1)d=c[0];c=c.pop();d={url:a.url,featureType:c,featurePrefix:d,srsName:a.projection&&a.projection.getCode()||a.map&&a.map.getProjectionObject().getCode(),version:"1.1.0"};return new OpenLayers.Protocol.WFS(OpenLayers.Util.applyDefaults(b,d))};OpenLayers.Protocol.WFS.DEFAULTS={version:"1.0.0"};OpenLayers.Strategy=OpenLayers.Class({layer:null,options:null,active:null,autoActivate:true,autoDestroy:true,initialize:function(a){OpenLayers.Util.extend(this,a);this.options=a;this.active=false},destroy:function(){this.deactivate();this.options=this.layer=null},setLayer:function(a){this.layer=a},activate:function(){if(!this.active)return this.active=true;return false},deactivate:function(){if(this.active){this.active=false;return true}return false},CLASS_NAME:"OpenLayers.Strategy"});OpenLayers.Strategy.BBOX=OpenLayers.Class(OpenLayers.Strategy,{bounds:null,resolution:null,ratio:2,resFactor:null,response:null,activate:function(){var a=OpenLayers.Strategy.prototype.activate.call(this);if(a){this.layer.events.on({moveend:this.update,refresh:this.update,visibilitychanged:this.update,scope:this});this.update()}return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&this.layer.events.un({moveend:this.update,refresh:this.update,visibilitychanged:this.update, -scope:this});return a},update:function(a){var b=this.getMapBounds();if(b!==null&&(a&&a.force||this.layer.visibility&&this.layer.calculateInRange()&&this.invalidBounds(b))){this.calculateBounds(b);this.resolution=this.layer.map.getResolution();this.triggerRead(a)}},getMapBounds:function(){if(this.layer.map===null)return null;var a=this.layer.map.getExtent();if(a&&!this.layer.projection.equals(this.layer.map.getProjectionObject()))a=a.clone().transform(this.layer.map.getProjectionObject(),this.layer.projection); -return a},invalidBounds:function(a){a||(a=this.getMapBounds());a=!this.bounds||!this.bounds.containsBounds(a);if(!a&&this.resFactor){a=this.resolution/this.layer.map.getResolution();a=a>=this.resFactor||a<=1/this.resFactor}return a},calculateBounds:function(a){a||(a=this.getMapBounds());var b=a.getCenterLonLat(),c=a.getWidth()*this.ratio;a=a.getHeight()*this.ratio;this.bounds=new OpenLayers.Bounds(b.lon-c/2,b.lat-a/2,b.lon+c/2,b.lat+a/2)},triggerRead:function(a){if(this.response&&!(a&&a.noAbort=== -true)){this.layer.protocol.abort(this.response);this.layer.events.triggerEvent("loadend")}this.layer.events.triggerEvent("loadstart");this.response=this.layer.protocol.read(OpenLayers.Util.applyDefaults({filter:this.createFilter(),callback:this.merge,scope:this},a))},createFilter:function(){var a=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.BBOX,value:this.bounds,projection:this.layer.projection});if(this.layer.filter)a=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND, -filters:[this.layer.filter,a]});return a},merge:function(a){this.layer.destroyFeatures();var b=a.features;if(b&&b.length>0){var c=this.layer.projection,d=this.layer.map.getProjectionObject();if(!d.equals(c))for(var e,f=0,g=b.length;f-1},handle:function(a){if(this.feature&&!this.feature.layer)this.feature=null;var b=a.type,c=false,d=!!this.feature, -e=b=="click"||b=="dblclick"||b=="touchstart";if((this.feature=this.layer.getFeatureFromEvent(a))&&!this.feature.layer)this.feature=null;if(this.lastFeature&&!this.lastFeature.layer)this.lastFeature=null;if(this.feature){b==="touchstart"&&OpenLayers.Event.stop(a);a=this.feature!=this.lastFeature;if(this.geometryTypeMatches(this.feature)){if(d&&a){this.lastFeature&&this.triggerCallback(b,"out",[this.lastFeature]);this.triggerCallback(b,"in",[this.feature])}else if(!d||e)this.triggerCallback(b,"in", -[this.feature]);this.lastFeature=this.feature;c=true}else{if(this.lastFeature&&(d&&a||e))this.triggerCallback(b,"out",[this.lastFeature]);this.feature=null}}else if(this.lastFeature&&(d||e))this.triggerCallback(b,"out",[this.lastFeature]);return c},triggerCallback:function(a,b,c){if(b=this.EVENTMAP[a][b])if(a=="click"&&this.up&&this.down)Math.sqrt(Math.pow(this.up.x-this.down.x,2)+Math.pow(this.up.y-this.down.y,2))<=this.clickTolerance&&this.callback(b,c);else this.callback(b,c)},activate:function(){var a= -false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.moveLayerToTop();this.map.events.on({removelayer:this.handleMapEvents,changelayer:this.handleMapEvents,scope:this});a=true}return a},deactivate:function(){var a=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.moveLayerBack();this.up=this.down=this.lastFeature=this.feature=null;this.touch=false;this.map.events.un({removelayer:this.handleMapEvents,changelayer:this.handleMapEvents,scope:this});a=true}return a}, -handleMapEvents:function(a){if(a.type=="removelayer"||a.property=="order")this.moveLayerToTop()},moveLayerToTop:function(){this.layer.setZIndex(Math.max(this.map.Z_INDEX_BASE.Feature-1,this.layer.getZIndex())+1)},moveLayerBack:function(){var a=this.layer.getZIndex()-1;a>=this.map.Z_INDEX_BASE.Feature?this.layer.setZIndex(a):this.map.setLayerZIndex(this.layer,this.map.getLayerIndex(this.layer))},CLASS_NAME:"OpenLayers.Handler.Feature"});OpenLayers.StyleMap=OpenLayers.Class({styles:null,extendDefault:true,initialize:function(a,b){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"])};if(a instanceof OpenLayers.Style){this.styles["default"]=a;this.styles.select=a;this.styles.temporary=a; -this.styles["delete"]=a}else if(typeof a=="object")for(var c in a)if(a[c]instanceof OpenLayers.Style)this.styles[c]=a[c];else if(typeof a[c]=="object")this.styles[c]=new OpenLayers.Style(a[c]);else{this.styles["default"]=new OpenLayers.Style(a);this.styles.select=new OpenLayers.Style(a);this.styles.temporary=new OpenLayers.Style(a);this.styles["delete"]=new OpenLayers.Style(a);break}OpenLayers.Util.extend(this,b)},destroy:function(){for(var a in this.styles)this.styles[a].destroy();this.styles=null}, -createSymbolizer:function(a,b){a||(a=new OpenLayers.Feature.Vector);this.styles[b]||(b="default");a.renderIntent=b;var c={};if(this.extendDefault&&b!="default")c=this.styles["default"].createSymbolizer(a);return OpenLayers.Util.extend(c,this.styles[b].createSymbolizer(a))},addUniqueValueRules:function(a,b,c,d){var e=[],f;for(f in c)e.push(new OpenLayers.Rule({symbolizer:c[f],context:d,filter:new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO,property:b,value:f})}));this.styles[a].addRules(e)}, -CLASS_NAME:"OpenLayers.StyleMap"});OpenLayers.Layer.Vector=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:false,isFixed:false,features:null,filter:null,selectedFeatures:null,unrenderedFeatures:null,reportError:true,style:null,styleMap:null,strategies:null,protocol:null,renderers:["SVG","VML","Canvas"],renderer:null,rendererOptions:null,geometryType:null,drawn:false,ratio:1,initialize:function(){OpenLayers.Layer.prototype.initialize.apply(this,arguments);if(!this.renderer||!this.renderer.supported())this.assignRenderer();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={};if(this.strategies)for(var a=0,b=this.strategies.length;a=0;d--){this.renderer.locked=d!=0&&a[d-1].geometry?true:false;var e=a[d];delete this.unrenderedFeatures[e.id];c&&this.events.triggerEvent("beforefeatureremoved",{feature:e});this.features=OpenLayers.Util.removeItem(this.features,e);e.layer=null;e.geometry&&this.renderer.eraseFeatures(e);OpenLayers.Util.indexOf(this.selectedFeatures,e)!=-1&&OpenLayers.Util.removeItem(this.selectedFeatures,e); -c&&this.events.triggerEvent("featureremoved",{feature:e})}c&&this.events.triggerEvent("featuresremoved",{features:a})}},removeAllFeatures:function(a){a=!a||!a.silent;var b=this.features;a&&this.events.triggerEvent("beforefeaturesremoved",{features:b});for(var c,d=b.length-1;d>=0;d--){c=b[d];a&&this.events.triggerEvent("beforefeatureremoved",{feature:c});c.layer=null;a&&this.events.triggerEvent("featureremoved",{feature:c})}this.renderer.clear();this.features=[];this.unrenderedFeatures={};this.selectedFeatures= -[];a&&this.events.triggerEvent("featuresremoved",{features:b})},destroyFeatures:function(a,b){if(a==undefined)a=this.features;if(a){this.removeFeatures(a,b);for(var c=a.length-1;c>=0;c--)a[c].destroy()}},drawFeature:function(a,b){if(this.drawn){if(typeof b!="object"){if(!b&&a.state===OpenLayers.State.DELETE)b="delete";var c=b||a.renderIntent;(b=a.style||this.style)||(b=this.styleMap.createSymbolizer(a,c))}c=this.renderer.drawFeature(a,b);if(c===false||c===null)this.unrenderedFeatures[a.id]=a;else delete this.unrenderedFeatures[a.id]}}, -eraseFeatures:function(a){this.renderer.eraseFeatures(a)},getFeatureFromEvent:function(a){if(!this.renderer)throw Error("getFeatureFromEvent called on layer with no renderer. This usually means you destroyed a layer, but not some handler which is associated with it.");var b=null;if(a=this.renderer.getFeatureIdFromEvent(a))b=typeof a==="string"?this.getFeatureById(a):a;return b},getFeatureBy:function(a,b){for(var c=null,d=0,e=this.features.length;d0)for(var c=null,d=0,e=b.length;df;){d=c.selectedFeatures[f];if(!a||a.except!=d)this.unselect(d);else++f}}},clickFeature:function(a){if(!this.hover)if(OpenLayers.Util.indexOf(a.layer.selectedFeatures, -a)>-1)if(this.toggleSelect())this.unselect(a);else this.multipleSelect()||this.unselectAll({except:a});else{this.multipleSelect()||this.unselectAll({except:a});this.select(a)}},multipleSelect:function(){return this.multiple||this.handlers.feature.evt&&this.handlers.feature.evt[this.multipleKey]},toggleSelect:function(){return this.toggle||this.handlers.feature.evt&&this.handlers.feature.evt[this.toggleKey]},clickoutFeature:function(){!this.hover&&this.clickout&&this.unselectAll()},overFeature:function(a){var b= -a.layer;if(this.hover)if(this.highlightOnly)this.highlight(a);else OpenLayers.Util.indexOf(b.selectedFeatures,a)==-1&&this.select(a)},outFeature:function(a){if(this.hover)if(this.highlightOnly){if(a._lastHighlighter==this.id)if(a._prevHighlighter&&a._prevHighlighter!=this.id){delete a._lastHighlighter;var b=this.map.getControl(a._prevHighlighter);b&&b.highlight(a)}else this.unhighlight(a)}else this.unselect(a)},highlight:function(a){var b=a.layer;if(this.events.triggerEvent("beforefeaturehighlighted", -{feature:a})!==false){a._prevHighlighter=a._lastHighlighter;a._lastHighlighter=this.id;b.drawFeature(a,this.selectStyle||this.renderIntent);this.events.triggerEvent("featurehighlighted",{feature:a})}},unhighlight:function(a){var b=a.layer;if(a._prevHighlighter==undefined)delete a._lastHighlighter;else{if(a._prevHighlighter!=this.id)a._lastHighlighter=a._prevHighlighter;delete a._prevHighlighter}b.drawFeature(a,a.style||a.layer.style||"default");this.events.triggerEvent("featureunhighlighted",{feature:a})}, -select:function(a){var b=this.onBeforeSelect.call(this.scope,a),c=a.layer;if(b!==false){b=c.events.triggerEvent("beforefeatureselected",{feature:a});if(b!==false){c.selectedFeatures.push(a);this.highlight(a);if(!this.handlers.feature.lastFeature)this.handlers.feature.lastFeature=c.selectedFeatures[0];c.events.triggerEvent("featureselected",{feature:a});this.onSelect.call(this.scope,a)}}},unselect:function(a){var b=a.layer;this.unhighlight(a);OpenLayers.Util.removeItem(b.selectedFeatures,a);b.events.triggerEvent("featureunselected", -{feature:a});this.onUnselect.call(this.scope,a)},selectBox:function(a){if(a instanceof OpenLayers.Bounds){var b=this.map.getLonLatFromPixel({x:a.left,y:a.bottom});a=this.map.getLonLatFromPixel({x:a.right,y:a.top});b=new OpenLayers.Bounds(b.lon,b.lat,a.lon,a.lat);this.multipleSelect()||this.unselectAll();a=this.multiple;this.multiple=true;var c=this.layers||[this.layer];this.events.triggerEvent("boxselectionstart",{layers:c});for(var d,e=0;e-1)b.toGeometry().intersects(h.geometry)&&OpenLayers.Util.indexOf(d.selectedFeatures,h)==-1&&this.select(h)}}this.multiple=a;this.events.triggerEvent("boxselectionend",{layers:c})}},setMap:function(a){this.handlers.feature.setMap(a);this.box&&this.handlers.box.setMap(a);OpenLayers.Control.prototype.setMap.apply(this,arguments)},setLayer:function(a){var b=this.active;this.unselectAll(); -this.deactivate();if(this.layers){this.layer.destroy();this.layers=null}this.initLayer(a);this.handlers.feature.layer=this.layer;b&&this.activate()},CLASS_NAME:"OpenLayers.Control.SelectFeature"});OpenLayers.Handler.Point=OpenLayers.Class(OpenLayers.Handler,{point:null,layer:null,multi:false,citeCompliant:false,mouseDown:false,stoppedDown:null,lastDown:null,lastUp:null,persist:false,stopDown:false,stopUp:false,layerOptions:null,pixelTolerance:5,touch:false,lastTouchPx:null,initialize:function(a,b,c){if(!(c&&c.layerOptions&&c.layerOptions.styleMap))this.style=OpenLayers.Util.extend(OpenLayers.Feature.Vector.style["default"],{});OpenLayers.Handler.prototype.initialize.apply(this,arguments)}, -activate:function(){if(!OpenLayers.Handler.prototype.activate.apply(this,arguments))return false;var a=OpenLayers.Util.extend({displayInLayerSwitcher:false,calculateInRange:OpenLayers.Function.True,wrapDateLine:this.citeCompliant},this.layerOptions);this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,a);this.map.addLayer(this.layer);return true},createFeature:function(a){a=this.layer.getLonLatFromViewPortPx(a);a=new OpenLayers.Geometry.Point(a.lon,a.lat);this.point=new OpenLayers.Feature.Vector(a); -this.callback("create",[this.point.geometry,this.point]);this.point.geometry.clearBounds();this.layer.addFeatures([this.point],{silent:true})},deactivate:function(){if(!OpenLayers.Handler.prototype.deactivate.apply(this,arguments))return false;this.cancel();if(this.layer.map!=null){this.destroyFeature(true);this.layer.destroy(false)}this.layer=null;this.touch=false;return true},destroyFeature:function(a){if(this.layer&&(a||!this.persist))this.layer.destroyFeatures();this.point=null},destroyPersistedFeature:function(){var a= -this.layer;a&&a.features.length>1&&this.layer.features[0].destroy()},finalize:function(a){var b=a?"cancel":"done";this.mouseDown=false;this.lastTouchPx=this.lastUp=this.lastDown=null;this.callback(b,[this.geometryClone()]);this.destroyFeature(a)},cancel:function(){this.finalize(true)},click:function(a){OpenLayers.Event.stop(a);return false},dblclick:function(a){OpenLayers.Event.stop(a);return false},modifyFeature:function(a){this.point||this.createFeature(a);a=this.layer.getLonLatFromViewPortPx(a); -this.point.geometry.x=a.lon;this.point.geometry.y=a.lat;this.callback("modify",[this.point.geometry,this.point,false]);this.point.geometry.clearBounds();this.drawFeature()},drawFeature:function(){this.layer.drawFeature(this.point,this.style)},getGeometry:function(){var a=this.point&&this.point.geometry;if(a&&this.multi)a=new OpenLayers.Geometry.MultiPoint([a]);return a},geometryClone:function(){var a=this.getGeometry();return a&&a.clone()},mousedown:function(a){return this.down(a)},touchstart:function(a){if(!this.touch){this.touch= -true;this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,mousemove:this.mousemove,click:this.click,dblclick:this.dblclick,scope:this})}this.lastTouchPx=a.xy;return this.down(a)},mousemove:function(a){return this.move(a)},touchmove:function(a){this.lastTouchPx=a.xy;return this.move(a)},mouseup:function(a){return this.up(a)},touchend:function(a){a.xy=this.lastTouchPx;return this.up(a)},down:function(a){this.mouseDown=true;this.lastDown=a.xy;this.touch||this.modifyFeature(a.xy);this.stoppedDown= -this.stopDown;return!this.stopDown},move:function(a){if(!this.touch&&(!this.mouseDown||this.stoppedDown))this.modifyFeature(a.xy);return true},up:function(a){this.mouseDown=false;this.stoppedDown=this.stopDown;if(!this.checkModifiers(a))return true;if(this.lastUp&&this.lastUp.equals(a.xy))return true;if(this.lastDown&&this.passesTolerance(this.lastDown,a.xy,this.pixelTolerance)){this.touch&&this.modifyFeature(a.xy);this.persist&&this.destroyPersistedFeature();this.lastUp=a.xy;this.finalize();return!this.stopUp}else return true}, -mouseout:function(a){if(OpenLayers.Util.mouseLeft(a,this.map.viewPortDiv)){this.stoppedDown=this.stopDown;this.mouseDown=false}},passesTolerance:function(a,b,c){var d=true;if(c!=null&&a&&b)if(a.distanceTo(b)>c)d=false;return d},CLASS_NAME:"OpenLayers.Handler.Point"});OpenLayers.Handler.Path=OpenLayers.Class(OpenLayers.Handler.Point,{line:null,maxVertices:null,doubleTouchTolerance:20,freehand:false,freehandToggle:"shiftKey",timerId:null,redoStack:null,createFeature:function(a){a=this.layer.getLonLatFromViewPortPx(a);a=new OpenLayers.Geometry.Point(a.lon,a.lat);this.point=new OpenLayers.Feature.Vector(a);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})},destroyFeature:function(a){OpenLayers.Handler.Point.prototype.destroyFeature.call(this,a);this.line=null},destroyPersistedFeature:function(){var a=this.layer;a&&a.features.length>2&&this.layer.features[0].destroy()},removePoint:function(){this.point&&this.layer.removeFeatures([this.point])},addPoint:function(a){this.layer.removeFeatures([this.point]);a=this.layer.getLonLatFromViewPortPx(a);this.point=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(a.lon, -a.lat));this.line.geometry.addComponent(this.point.geometry,this.line.geometry.components.length);this.layer.addFeatures([this.point]);this.callback("point",[this.point.geometry,this.getGeometry()]);this.callback("modify",[this.point.geometry,this.getSketch()]);this.drawFeature();delete this.redoStack},insertXY:function(a,b){this.line.geometry.addComponent(new OpenLayers.Geometry.Point(a,b),this.getCurrentPointIndex());this.drawFeature();delete this.redoStack},insertDeltaXY:function(a,b){var c=this.line.geometry.components[this.getCurrentPointIndex()- -1];c&&!isNaN(c.x)&&!isNaN(c.y)&&this.insertXY(c.x+a,c.y+b)},insertDirectionLength:function(a,b){a*=Math.PI/180;this.insertDeltaXY(b*Math.cos(a),b*Math.sin(a))},insertDeflectionLength:function(a,b){var c=this.getCurrentPointIndex()-1;if(c>0){var d=this.line.geometry.components[c];c=this.line.geometry.components[c-1];this.insertDirectionLength(Math.atan2(d.y-c.y,d.x-c.x)*180/Math.PI+a,b)}},getCurrentPointIndex:function(){return this.line.geometry.components.length-1},undo:function(){var a=this.line.geometry, -b=a.components,c=this.getCurrentPointIndex()-1;b=b[c];if(a=a.removeComponent(b)){if(!this.redoStack)this.redoStack=[];this.redoStack.push(b);this.drawFeature()}return a},redo:function(){var a=this.redoStack&&this.redoStack.pop();if(a){this.line.geometry.addComponent(a,this.getCurrentPointIndex());this.drawFeature()}return!!a},freehandMode:function(a){return this.freehandToggle&&a[this.freehandToggle]?!this.freehand:this.freehand},modifyFeature:function(a,b){this.line||this.createFeature(a);var c= -this.layer.getLonLatFromViewPortPx(a);this.point.geometry.x=c.lon;this.point.geometry.y=c.lat;this.callback("modify",[this.point.geometry,this.getSketch(),b]);this.point.geometry.clearBounds();this.drawFeature()},drawFeature:function(){this.layer.drawFeature(this.line,this.style);this.layer.drawFeature(this.point,this.style)},getSketch:function(){return this.line},getGeometry:function(){var a=this.line&&this.line.geometry;if(a&&this.multi)a=new OpenLayers.Geometry.MultiLineString([a]);return a},touchstart:function(a){if(this.timerId&& -this.passesTolerance(this.lastTouchPx,a.xy,this.doubleTouchTolerance)){this.finishGeometry();window.clearTimeout(this.timerId);this.timerId=null;return false}else{if(this.timerId){window.clearTimeout(this.timerId);this.timerId=null}this.timerId=window.setTimeout(OpenLayers.Function.bind(function(){this.timerId=null},this),300);return OpenLayers.Handler.Point.prototype.touchstart.call(this,a)}},down:function(a){var b=this.stopDown;if(this.freehandMode(a)){b=true;if(this.touch){this.modifyFeature(a.xy, -!!this.lastUp);OpenLayers.Event.stop(a)}}if(!this.touch&&(!this.lastDown||!this.passesTolerance(this.lastDown,a.xy,this.pixelTolerance)))this.modifyFeature(a.xy,!!this.lastUp);this.mouseDown=true;this.lastDown=a.xy;this.stoppedDown=b;return!b},move:function(a){if(this.stoppedDown&&this.freehandMode(a)){this.persist&&this.destroyPersistedFeature();if(this.maxVertices&&this.line&&this.line.geometry.components.length===this.maxVertices){this.removePoint();this.finalize()}else this.addPoint(a.xy);return false}if(!this.touch&& -(!this.mouseDown||this.stoppedDown))this.modifyFeature(a.xy,!!this.lastUp);return true},up:function(a){if(this.mouseDown&&(!this.lastUp||!this.lastUp.equals(a.xy)))if(this.stoppedDown&&this.freehandMode(a)){this.persist&&this.destroyPersistedFeature();this.removePoint();this.finalize()}else if(this.passesTolerance(this.lastDown,a.xy,this.pixelTolerance)){this.touch&&this.modifyFeature(a.xy);this.lastUp==null&&this.persist&&this.destroyPersistedFeature();this.addPoint(a.xy);this.lastUp=a.xy;this.line.geometry.components.length=== -this.maxVertices+1&&this.finishGeometry()}this.stoppedDown=this.stopDown;this.mouseDown=false;return!this.stopUp},finishGeometry:function(){this.line.geometry.removeComponent(this.line.geometry.components[this.line.geometry.components.length-1]);this.removePoint();this.finalize()},dblclick:function(a){this.freehandMode(a)||this.finishGeometry();return false},CLASS_NAME:"OpenLayers.Handler.Path"});OpenLayers.Control.Attribution=OpenLayers.Class(OpenLayers.Control,{separator:", ",template:"${layers}",destroy:function(){this.map.events.un({removelayer:this.updateAttribution,addlayer:this.updateAttribution,changelayer:this.updateAttribution,changebaselayer:this.updateAttribution,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments)},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.map.events.on({changebaselayer:this.updateAttribution,changelayer:this.updateAttribution, -addlayer:this.updateAttribution,removelayer:this.updateAttribution,scope:this});this.updateAttribution();return this.div},updateAttribution:function(){var a=[];if(this.map&&this.map.layers){for(var b=0,c=this.map.layers.length;bthis.nbPoints&&this.points.pop()},end:function(a){for(var b,c=(new Date).getTime(),d=0,e=this.points.length,f;dthis.delay)break;b=f}if(b){d=(new Date).getTime()-b.tick;c=Math.sqrt(Math.pow(a.x-b.xy.x,2)+Math.pow(a.y-b.xy.y,2));d=c/d;if(!(d==0||d0)this.timeoutId=setTimeout(OpenLayers.Function.bind(this.removeTimeout,this),this.interval);this.dragging=true;this.move(a);this.callback("move",[a.xy]); -if(!this.oldOnselectstart){this.oldOnselectstart=document.onselectstart;document.onselectstart=OpenLayers.Function.False}this.last=a.xy}return true},dragend:function(a){if(this.started){if(this.documentDrag===true&&this.documentEvents){this.adjustXY(a);this.removeDocumentEvents()}var b=this.start!=this.last;this.dragging=this.started=false;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.up(a);this.callback("up",[a.xy]);b&&this.callback("done",[a.xy]);document.onselectstart= -this.oldOnselectstart}return true},down:function(){},move:function(){},up:function(){},out:function(){},mousedown:function(a){return this.dragstart(a)},touchstart:function(a){if(!this.touch){this.touch=true;this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,mousemove:this.mousemove,click:this.click,scope:this})}return this.dragstart(a)},mousemove:function(a){return this.dragmove(a)},touchmove:function(a){return this.dragmove(a)},removeTimeout:function(){this.timeoutId=null;this.dragging&& -this.mousemove(this.lastMoveEvt)},mouseup:function(a){return this.dragend(a)},touchend:function(a){a.xy=this.last;return this.dragend(a)},mouseout:function(a){if(this.started&&OpenLayers.Util.mouseLeft(a,this.map.viewPortDiv))if(this.documentDrag===true)this.addDocumentEvents();else{var b=this.start!=this.last;this.dragging=this.started=false;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.out(a);this.callback("out",[]);b&&this.callback("done",[a.xy]);if(document.onselectstart)document.onselectstart= -this.oldOnselectstart}return true},click:function(){return this.start==this.last},activate:function(){var a=false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.dragging=false;a=true}return a},deactivate:function(){var a=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.dragging=this.started=this.touch=false;this.last=this.start=null;a=true;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown")}return a},adjustXY:function(a){var b=OpenLayers.Util.pagePosition(this.map.viewPortDiv); -a.xy.x-=b[0];a.xy.y-=b[1]},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)},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=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,boxDivClassName:"olHandlerBoxZoomBox",boxOffsets:null,initialize:function(){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})},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);if(this.dragHandler){this.dragHandler.destroy();this.dragHandler= -null}},setMap:function(a){OpenLayers.Handler.prototype.setMap.apply(this,arguments);this.dragHandler&&this.dragHandler.setMap(a)},startBox:function(){this.callback("start",[]);this.zoomBox=OpenLayers.Util.createDiv("zoomBox",{x:-9999,y:-9999});this.zoomBox.className=this.boxDivClassName;this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE.Popup-1;this.map.viewPortDiv.appendChild(this.zoomBox);OpenLayers.Element.addClass(this.map.viewPortDiv,"olDrawBox")},moveBox:function(a){var b=this.dragHandler.start.x, -c=this.dragHandler.start.y,d=Math.abs(b-a.x),e=Math.abs(c-a.y),f=this.getBoxOffsets();this.zoomBox.style.width=d+f.width+1+"px";this.zoomBox.style.height=e+f.height+1+"px";this.zoomBox.style.left=(a.x5||Math.abs(this.dragHandler.start.y-a.y)>5){var b=this.dragHandler.start;a=new OpenLayers.Bounds(Math.min(b.x,a.x),Math.max(b.y,a.y),Math.max(b.x,a.x),Math.min(b.y, -a.y))}else a=this.dragHandler.start.clone();this.removeBox();this.callback("done",[a])},removeBox:function(){this.map.viewPortDiv.removeChild(this.zoomBox);this.boxOffsets=this.zoomBox=null;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDrawBox")},activate:function(){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.dragHandler.activate();return true}else return false},deactivate:function(){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.dragHandler.deactivate()&& -this.zoomBox&&this.removeBox();return true}else return false},getBoxOffsets:function(){if(!this.boxOffsets){var a=document.createElement("div");a.style.position="absolute";a.style.border="1px solid black";a.style.width="3px";document.body.appendChild(a);var b=a.clientWidth==3;document.body.removeChild(a);a=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-left-width"));var c=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-right-width")),d=parseInt(OpenLayers.Element.getStyle(this.zoomBox, -"border-top-width")),e=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-bottom-width"));this.boxOffsets={left:a,right:c,top:d,bottom:e,width:b===false?a+c:0,height:b===false?d+e:0}}return this.boxOffsets},CLASS_NAME:"OpenLayers.Handler.Box"});OpenLayers.Control.ZoomBox=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,out:false,keyMask:null,alwaysZoom:false,zoomOnClick:true,draw:function(){this.handler=new OpenLayers.Handler.Box(this,{done:this.zoomBox},{keyMask:this.keyMask})},zoomBox:function(a){if(a instanceof OpenLayers.Bounds){var b;if(this.out){b=Math.min(this.map.size.h/Math.abs(a.top-a.bottom),this.map.size.w/Math.abs(a.right-a.left));var c=this.map.getExtent(),d=this.map.getLonLatFromPixel(a.getCenterPixel()); -a=d.lon-c.getWidth()/2*b;var e=d.lon+c.getWidth()/2*b,f=d.lat-c.getHeight()/2*b;b=d.lat+c.getHeight()/2*b;b=new OpenLayers.Bounds(a,f,e,b)}else{b=this.map.getLonLatFromPixel({x:a.left,y:a.bottom});c=this.map.getLonLatFromPixel({x:a.right,y:a.top});b=new OpenLayers.Bounds(b.lon,b.lat,c.lon,c.lat)}c=this.map.getZoom();this.map.zoomToExtent(b);if(c==this.map.getZoom()&&this.alwaysZoom==true)this.map.zoomTo(c+(this.out?-1:1))}else if(this.zoomOnClick)this.out?this.map.setCenter(this.map.getLonLatFromPixel(a), -this.map.getZoom()-1):this.map.setCenter(this.map.getLonLatFromPixel(a),this.map.getZoom()+1)},CLASS_NAME:"OpenLayers.Control.ZoomBox"});OpenLayers.Control.DragPan=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:false,interval:1,documentDrag:false,kinetic:null,enableKinetic:false,kineticInterval:10,draw:function(){if(this.enableKinetic){var a={interval:this.kineticInterval};if(typeof this.enableKinetic==="object")a=OpenLayers.Util.extend(a,this.enableKinetic);this.kinetic=new OpenLayers.Kinetic(a)}this.handler=new OpenLayers.Handler.Drag(this,{move:this.panMap,done:this.panMapDone,down:this.panMapStart}, -{interval:this.interval,documentDrag:this.documentDrag})},panMapStart:function(){this.kinetic&&this.kinetic.begin()},panMap:function(a){this.kinetic&&this.kinetic.update(a);this.panned=true;this.map.pan(this.handler.last.x-a.x,this.handler.last.y-a.y,{dragging:true,animate:false})},panMapDone:function(a){if(this.panned){var b=null;if(this.kinetic)b=this.kinetic.end(a);this.map.pan(this.handler.last.x-a.x,this.handler.last.y-a.y,{dragging:!!b,animate:false});if(b){var c=this;this.kinetic.move(b,function(d, -e,f){c.map.pan(d,e,{dragging:!f,animate:false})})}this.panned=false}},CLASS_NAME:"OpenLayers.Control.DragPan"});OpenLayers.Handler.Click=OpenLayers.Class(OpenLayers.Handler,{delay:300,single:true,"double":false,pixelTolerance:0,dblclickTolerance:13,stopSingle:false,stopDouble:false,timerId:null,touch:false,down:null,last:null,first:null,rightclickTimerId:null,touchstart:function(a){if(!this.touch){this.unregisterMouseListeners();this.touch=true}this.down=this.getEventInfo(a);this.last=this.getEventInfo(a);return true},touchmove:function(a){this.last=this.getEventInfo(a);return true},touchend:function(a){if(this.down){a.xy= -this.last.xy;a.lastTouches=this.last.touches;this.handleSingle(a);this.down=null}return true},unregisterMouseListeners:function(){this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,click:this.click,dblclick:this.dblclick,scope:this})},mousedown:function(a){this.down=this.getEventInfo(a);this.last=this.getEventInfo(a);return true},mouseup:function(a){var b=true;if(this.checkModifiers(a)&&this.control.handleRightClicks&&OpenLayers.Event.isRightClick(a))b=this.rightclick(a);return b}, -rightclick:function(a){if(this.passesTolerance(a))if(this.rightclickTimerId!=null){this.clearTimer();this.callback("dblrightclick",[a]);return!this.stopDouble}else{a=this["double"]?OpenLayers.Util.extend({},a):this.callback("rightclick",[a]);a=OpenLayers.Function.bind(this.delayedRightCall,this,a);this.rightclickTimerId=window.setTimeout(a,this.delay)}return!this.stopSingle},delayedRightCall:function(a){this.rightclickTimerId=null;a&&this.callback("rightclick",[a])},click:function(a){if(!this.last)this.last= -this.getEventInfo(a);this.handleSingle(a);return!this.stopSingle},dblclick:function(a){this.handleDouble(a);return!this.stopDouble},handleDouble:function(a){if(this.passesDblclickTolerance(a)){this["double"]&&this.callback("dblclick",[a]);this.clearTimer()}},handleSingle:function(a){if(this.passesTolerance(a))if(this.timerId!=null){if(this.last.touches&&this.last.touches.length===1){this["double"]&&OpenLayers.Event.stop(a);this.handleDouble(a)}if(!this.last.touches||this.last.touches.length!==2)this.clearTimer()}else{this.first= -this.getEventInfo(a);this.queuePotentialClick(this.single?OpenLayers.Util.extend({},a):null)}},queuePotentialClick:function(a){this.timerId=window.setTimeout(OpenLayers.Function.bind(this.delayedCall,this,a),this.delay)},passesTolerance:function(a){var b=true;if(this.pixelTolerance!=null&&this.down&&this.down.xy)if((b=this.pixelTolerance>=this.down.xy.distanceTo(a.xy))&&this.touch&&this.down.touches.length===this.last.touches.length){a=0;for(var c=this.down.touches.length;athis.pixelTolerance){b=false;break}}return b},getTouchDistance:function(a,b){return Math.sqrt(Math.pow(a.clientX-b.clientX,2)+Math.pow(a.clientY-b.clientY,2))},passesDblclickTolerance:function(){var a=true;if(this.down&&this.first)a=this.down.xy.distanceTo(this.first.xy)<=this.dblclickTolerance;return a},clearTimer:function(){if(this.timerId!=null){window.clearTimeout(this.timerId);this.timerId=null}if(this.rightclickTimerId!=null){window.clearTimeout(this.rightclickTimerId); -this.rightclickTimerId=null}},delayedCall:function(a){this.timerId=null;a&&this.callback("click",[a])},getEventInfo:function(a){var b;if(a.touches){var c=a.touches.length;b=Array(c);for(var d,e=0;e=1.3&&!c.EXCEPTIONS)c.EXCEPTIONS="INIMAGE";e.push(a,b,c,d);OpenLayers.Layer.Grid.prototype.initialize.apply(this,e);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)); -if(!this.noMagic&&this.params.TRANSPARENT&&this.params.TRANSPARENT.toString().toLowerCase()=="true"){if(d==null||!d.isBaseLayer)this.isBaseLayer=false;if(this.params.FORMAT=="image/jpeg")this.params.FORMAT=OpenLayers.Util.alphaHack()?"image/gif":"image/png"}},clone:function(a){if(a==null)a=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.getOptions());return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},reverseAxisOrder:function(){var a=this.projection.getCode();return parseFloat(this.params.VERSION)>= -1.3&&!!(this.yx[a]||OpenLayers.Projection.defaults[a].yx)},getURL:function(a){a=this.adjustBounds(a);var b=this.getImageSize(),c={},d=this.reverseAxisOrder();c.BBOX=this.encodeBBOX?a.toBBOX(null,d):a.toArray(d);c.WIDTH=b.w;c.HEIGHT=b.h;return this.getFullRequestString(c)},mergeNewParams:function(a){a=[OpenLayers.Util.upperCaseObject(a)];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,a)},getFullRequestString:function(a){var b=this.map.getProjectionObject();b=this.projection&&this.projection.equals(b)? -this.projection.getCode():b.getCode();b=b=="none"?null:b;if(parseFloat(this.params.VERSION)>=1.3)this.params.CRS=b;else this.params.SRS=b;if(typeof this.params.TRANSPARENT=="boolean")a.TRANSPARENT=this.params.TRANSPARENT?"TRUE":"FALSE";return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments)},CLASS_NAME:"OpenLayers.Layer.WMS"});OpenLayers.Renderer.SVG=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"http://www.w3.org/2000/svg",xlinkns:"http://www.w3.org/1999/xlink",MAX_PIXEL:15E3,translationParameters:null,symbolMetrics:null,initialize:function(){if(this.supported()){OpenLayers.Renderer.Elements.prototype.initialize.apply(this,arguments);this.translationParameters={x:0,y:0};this.symbolMetrics={}}},supported:function(){return document.implementation&&(document.implementation.hasFeature("org.w3c.svg","1.0")||document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#SVG", -"1.1")||document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1"))},inValidRange:function(a,b,c){a=a+(c?0:this.translationParameters.x);b=b+(c?0:this.translationParameters.y);return a>=-this.MAX_PIXEL&&a<=this.MAX_PIXEL&&b>=-this.MAX_PIXEL&&b<=this.MAX_PIXEL},setExtent:function(a,b){var c=OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,arguments),d=this.getResolution(),e=-a.left/d;d=a.top/d;if(b){this.left=e;this.top=d;this.rendererRoot.setAttributeNS(null, -"viewBox","0 0 "+this.size.w+" "+this.size.h);this.translate(this.xOffset,0);return true}else{(e=this.translate(e-this.left+this.xOffset,d-this.top))||this.setExtent(a,true);return c&&e}},translate:function(a,b){if(this.inValidRange(a,b,true)){var c="";if(a||b)c="translate("+a+","+b+")";this.root.setAttributeNS(null,"transform",c);this.translationParameters={x:a,y:b};return true}else return false},setSize:function(){OpenLayers.Renderer.prototype.setSize.apply(this,arguments);this.rendererRoot.setAttributeNS(null, -"width",this.size.w);this.rendererRoot.setAttributeNS(null,"height",this.size.h)},getNodeType:function(a,b){var c=null;switch(a.CLASS_NAME){case "OpenLayers.Geometry.Point":c=b.externalGraphic?"image":this.isComplexSymbol(b.graphicName)?"svg":"circle";break;case "OpenLayers.Geometry.Rectangle":c="rect";break;case "OpenLayers.Geometry.LineString":c="polyline";break;case "OpenLayers.Geometry.LinearRing":c="polygon";break;case "OpenLayers.Geometry.Polygon":case "OpenLayers.Geometry.Curve":c="path"}return c}, -setStyle:function(a,b,c){b=b||a._style;c=c||a._options;var d=b.title||b.graphicTitle;if(d){a.setAttributeNS(null,"title",d);var e=a.getElementsByTagName("title");if(e.length>0)e[0].firstChild.textContent=d;else{e=this.nodeFactory(null,"title");e.textContent=d;a.appendChild(e)}}e=parseFloat(a.getAttributeNS(null,"r"));d=1;var f;if(a._geometryClass=="OpenLayers.Geometry.Point"&&e){a.style.visibility="";if(b.graphic===false)a.style.visibility="hidden";else if(b.externalGraphic){f=this.getPosition(a); -b.graphicWidth&&b.graphicHeight&&a.setAttributeNS(null,"preserveAspectRatio","none");e=b.graphicWidth||b.graphicHeight;var g=b.graphicHeight||b.graphicWidth;e=e?e:b.pointRadius*2;g=g?g:b.pointRadius*2;var h=b.graphicYOffset!=undefined?b.graphicYOffset:-(0.5*g),i=b.graphicOpacity||b.fillOpacity;a.setAttributeNS(null,"x",(f.x+(b.graphicXOffset!=undefined?b.graphicXOffset:-(0.5*e))).toFixed());a.setAttributeNS(null,"y",(f.y+h).toFixed());a.setAttributeNS(null,"width",e);a.setAttributeNS(null,"height", -g);a.setAttributeNS(this.xlinkns,"href",b.externalGraphic);a.setAttributeNS(null,"style","opacity: "+i);a.onclick=OpenLayers.Event.preventDefault}else if(this.isComplexSymbol(b.graphicName)){e=b.pointRadius*3;g=e*2;var j=this.importSymbol(b.graphicName);f=this.getPosition(a);d=this.symbolMetrics[j.id][0]*3/g;h=a.parentNode;i=a.nextSibling;h&&h.removeChild(a);a.firstChild&&a.removeChild(a.firstChild);a.appendChild(j.firstChild.cloneNode(true));a.setAttributeNS(null,"viewBox",j.getAttributeNS(null, -"viewBox"));a.setAttributeNS(null,"width",g);a.setAttributeNS(null,"height",g);a.setAttributeNS(null,"x",f.x-e);a.setAttributeNS(null,"y",f.y-e);if(i)h.insertBefore(a,i);else h&&h.appendChild(a)}else a.setAttributeNS(null,"r",b.pointRadius);e=b.rotation;if((e!==undefined||a._rotation!==undefined)&&f){a._rotation=e;e|=0;if(a.nodeName!=="svg")a.setAttributeNS(null,"transform","rotate("+e+" "+f.x+" "+f.y+")");else{f=this.symbolMetrics[j.id];a.firstChild.setAttributeNS(null,"transform","rotate("+e+" "+ -f[1]+" "+f[2]+")")}}}if(c.isFilled){a.setAttributeNS(null,"fill",b.fillColor);a.setAttributeNS(null,"fill-opacity",b.fillOpacity)}else a.setAttributeNS(null,"fill","none");if(c.isStroked){a.setAttributeNS(null,"stroke",b.strokeColor);a.setAttributeNS(null,"stroke-opacity",b.strokeOpacity);a.setAttributeNS(null,"stroke-width",b.strokeWidth*d);a.setAttributeNS(null,"stroke-linecap",b.strokeLinecap||"round");a.setAttributeNS(null,"stroke-linejoin","round");b.strokeDashstyle&&a.setAttributeNS(null,"stroke-dasharray", -this.dashStyle(b,d))}else a.setAttributeNS(null,"stroke","none");b.pointerEvents&&a.setAttributeNS(null,"pointer-events",b.pointerEvents);b.cursor!=null&&a.setAttributeNS(null,"cursor",b.cursor);return a},dashStyle:function(a,b){var c=a.strokeWidth*b,d=a.strokeDashstyle;switch(d){case "solid":return"none";case "dot":return[1,4*c].join();case "dash":return[4*c,4*c].join();case "dashdot":return[4*c,4*c,1,4*c].join();case "longdash":return[8*c,4*c].join();case "longdashdot":return[8*c,4*c,1,4*c].join(); -default:return OpenLayers.String.trim(d).replace(/\s+/g,",")}},createNode:function(a,b){var c=document.createElementNS(this.xmlns,a);b&&c.setAttributeNS(null,"id",b);return c},nodeTypeCompare:function(a,b){return b==a.nodeName},createRenderRoot:function(){var a=this.nodeFactory(this.container.id+"_svgRoot","svg");a.style.display="block";return a},createRoot:function(a){return this.nodeFactory(this.container.id+a,"g")},createDefs:function(){var a=this.nodeFactory(this.container.id+"_defs","defs"); -this.rendererRoot.appendChild(a);return a},drawPoint:function(a,b){return this.drawCircle(a,b,1)},drawCircle:function(a,b,c){var d=this.getResolution(),e=(b.x-this.featureDx)/d+this.left;b=this.top-b.y/d;if(this.inValidRange(e,b)){a.setAttributeNS(null,"cx",e);a.setAttributeNS(null,"cy",b);a.setAttributeNS(null,"r",c);return a}else return false},drawLineString:function(a,b){var c=this.getComponentsString(b.components);if(c.path){a.setAttributeNS(null,"points",c.path);return c.complete?a:null}else return false}, -drawLinearRing:function(a,b){var c=this.getComponentsString(b.components);if(c.path){a.setAttributeNS(null,"points",c.path);return c.complete?a:null}else return false},drawPolygon:function(a,b){for(var c="",d=true,e=true,f,g,h=0,i=b.components.length;hi;)f.removeChild(f.lastChild);for(var j=0;j0&&this.getShortString(a[h-1])&& -f.push(this.clipLine(a[h],a[h-1]));hd){i=(c-g)/(h-f);h=h<0?-d:d;c=g+(h-f)*i}if(c<-e||c>e){i=(h- -f)/(c-g);c=c<0?-e:e;h=f+(c-g)*i}return h+","+c},getShortString:function(a){var b=this.getResolution(),c=(a.x-this.featureDx)/b+this.left;a=this.top-a.y/b;return this.inValidRange(c,a)?c+","+a:false},getPosition:function(a){return{x:parseFloat(a.getAttributeNS(null,"cx")),y:parseFloat(a.getAttributeNS(null,"cy"))}},importSymbol:function(a){if(!this.defs)this.defs=this.createDefs();var b=this.container.id+"-"+a,c=document.getElementById(b);if(c!=null)return c;var d=OpenLayers.Renderer.symbol[a];if(!d)throw Error(a+ -" is not a valid symbol name");a=this.nodeFactory(b,"symbol");var e=this.nodeFactory(null,"polygon");a.appendChild(e);c=new OpenLayers.Bounds(Number.MAX_VALUE,Number.MAX_VALUE,0,0);for(var f=[],g,h,i=0;i1&&this.setGeometryName(null)},destroy:function(){this.options&&!this.options.format&&this.format.destroy();this.format=null;OpenLayers.Protocol.prototype.destroy.apply(this)},read:function(a){OpenLayers.Protocol.prototype.read.apply(this,arguments);a=OpenLayers.Util.extend({},a);OpenLayers.Util.applyDefaults(a,this.options||{});var b=new OpenLayers.Protocol.Response({requestType:"read"}), -c=OpenLayers.Format.XML.prototype.write.apply(this.format,[this.format.writeNode("wfs:GetFeature",a)]);b.priv=OpenLayers.Request.POST({url:a.url,callback:this.createCallback(this.handleRead,b,a),params:a.params,headers:a.headers,data:c});return b},setFeatureType:function(a){this.featureType=a;this.format.featureType=a},setGeometryName:function(a){this.geometryName=a;this.format.geometryName=a},handleRead:function(a,b){b=OpenLayers.Util.extend({},b);OpenLayers.Util.applyDefaults(b,this.options);if(b.callback){var c= -a.priv;if(c.status>=200&&c.status<300)if((c=this.parseResponse(c,b.readOptions))&&c.success!==false){if(b.readOptions&&b.readOptions.output=="object")OpenLayers.Util.extend(a,c);else a.features=c;a.code=OpenLayers.Protocol.Response.SUCCESS}else{a.code=OpenLayers.Protocol.Response.FAILURE;a.error=c}else a.code=OpenLayers.Protocol.Response.FAILURE;b.callback.call(b.scope,a)}},parseResponse:function(a,b){var c=a.responseXML;if(!c||!c.documentElement)c=a.responseText;if(!c||c.length<=0)return null;c= -this.readFormat!==null?this.readFormat.read(c):this.format.read(c,b);if(!this.featureNS){var d=this.readFormat||this.format;this.featureNS=d.featureNS;d.autoConfig=false;this.geometryName||this.setGeometryName(d.geometryName)}return c},commit:function(a,b){b=OpenLayers.Util.extend({},b);OpenLayers.Util.applyDefaults(b,this.options);var c=new OpenLayers.Protocol.Response({requestType:"commit",reqFeatures:a});c.priv=OpenLayers.Request.POST({url:b.url,headers:b.headers,data:this.format.write(a,b),callback:this.createCallback(this.handleCommit, -c,b)});return c},handleCommit:function(a,b){if(b.callback){var c=a.priv,d=c.responseXML;if(!d||!d.documentElement)d=c.responseText;c=this.format.read(d)||{};a.insertIds=c.insertIds||[];if(c.success)a.code=OpenLayers.Protocol.Response.SUCCESS;else{a.code=OpenLayers.Protocol.Response.FAILURE;a.error=c}b.callback.call(b.scope,a)}},filterDelete:function(a,b){b=OpenLayers.Util.extend({},b);OpenLayers.Util.applyDefaults(b,this.options);new OpenLayers.Protocol.Response({requestType:"commit"});var c=this.format.createElementNSPlus("wfs:Transaction", -{attributes:{service:"WFS",version:this.version}}),d=this.format.createElementNSPlus("wfs:Delete",{attributes:{typeName:(b.featureNS?this.featurePrefix+":":"")+b.featureType}});b.featureNS&&d.setAttribute("xmlns:"+this.featurePrefix,b.featureNS);var e=this.format.writeNode("ogc:Filter",a);d.appendChild(e);c.appendChild(d);c=OpenLayers.Format.XML.prototype.write.apply(this.format,[c]);return OpenLayers.Request.POST({url:this.url,callback:b.callback||function(){},data:c})},abort:function(a){a&&a.priv.abort()}, -CLASS_NAME:"OpenLayers.Protocol.WFS.v1"});OpenLayers.ProxyHost="";if(!OpenLayers.Request)OpenLayers.Request={}; -OpenLayers.Util.extend(OpenLayers.Request,{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},URL_SPLIT_REGEX:/([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/,events:new OpenLayers.Events(this),makeSameOrigin:function(a,b){var c=a.indexOf("http")!==0,d=!c&&a.match(this.URL_SPLIT_REGEX);if(d){var e=window.location;c=d[1]==e.protocol&& -d[3]==e.hostname;d=d[4];e=e.port;if(d!=80&&d!=""||e!="80"&&e!="")c=c&&d==e}if(!c)if(b)a=typeof b=="function"?b(a):b+encodeURIComponent(a);else OpenLayers.Console.warn(OpenLayers.i18n("proxyNeeded"),{url:a});return a},issue:function(a){var b=OpenLayers.Util.extend(this.DEFAULT_CONFIG,{proxy:OpenLayers.ProxyHost});a=OpenLayers.Util.applyDefaults(a,b);b=false;for(var c in a.headers)if(a.headers.hasOwnProperty(c))if(c.toLowerCase()==="x-requested-with")b=true;if(b===false)a.headers["X-Requested-With"]= -"XMLHttpRequest";var d=new OpenLayers.Request.XMLHttpRequest,e=OpenLayers.Util.urlAppend(a.url,OpenLayers.Util.getParameterString(a.params||{}));e=OpenLayers.Request.makeSameOrigin(e,a.proxy);d.open(a.method,e,a.async,a.user,a.password);for(var f in a.headers)d.setRequestHeader(f,a.headers[f]);var g=this.events,h=this;d.onreadystatechange=function(){d.readyState==OpenLayers.Request.XMLHttpRequest.DONE&&g.triggerEvent("complete",{request:d,config:a,requestUrl:e})!==false&&h.runCallbacks({request:d, -config:a,requestUrl:e})};a.async===false?d.send(a.data):window.setTimeout(function(){d.readyState!==0&&d.send(a.data)},0);return d},runCallbacks:function(a){var b=a.request,c=a.config,d=c.scope?OpenLayers.Function.bind(c.callback,c.scope):c.callback,e;if(c.success)e=c.scope?OpenLayers.Function.bind(c.success,c.scope):c.success;var f;if(c.failure)f=c.scope?OpenLayers.Function.bind(c.failure,c.scope):c.failure;if(OpenLayers.Util.createUrlObject(c.url).protocol=="file:"&&b.responseText)b.status=200; -d(b);if(!b.status||b.status>=200&&b.status<300){this.events.triggerEvent("success",a);e&&e(b)}if(b.status&&(b.status<200||b.status>=300)){this.events.triggerEvent("failure",a);f&&f(b)}},GET:function(a){a=OpenLayers.Util.extend(a,{method:"GET"});return OpenLayers.Request.issue(a)},POST:function(a){a=OpenLayers.Util.extend(a,{method:"POST"});a.headers=a.headers?a.headers:{};"CONTENT-TYPE"in OpenLayers.Util.upperCaseObject(a.headers)||(a.headers["Content-Type"]="application/xml");return OpenLayers.Request.issue(a)}, -PUT:function(a){a=OpenLayers.Util.extend(a,{method:"PUT"});a.headers=a.headers?a.headers:{};"CONTENT-TYPE"in OpenLayers.Util.upperCaseObject(a.headers)||(a.headers["Content-Type"]="application/xml");return OpenLayers.Request.issue(a)},DELETE:function(a){a=OpenLayers.Util.extend(a,{method:"DELETE"});return OpenLayers.Request.issue(a)},HEAD:function(a){a=OpenLayers.Util.extend(a,{method:"HEAD"});return OpenLayers.Request.issue(a)},OPTIONS:function(a){a=OpenLayers.Util.extend(a,{method:"OPTIONS"});return OpenLayers.Request.issue(a)}});(function(){function a(){this._object=f&&!i?new f:new window.ActiveXObject("Microsoft.XMLHTTP");this._listeners=[]}function b(){return new a}function c(j){b.onreadystatechange&&b.onreadystatechange.apply(j);j.dispatchEvent({type:"readystatechange",bubbles:false,cancelable:false,timeStamp:new Date+0})}function d(j){try{j.responseText=j._object.responseText}catch(k){}try{var m;a:{var o=j._object,l=o.responseXML,n=o.responseText;if(h&&n&&l&&!l.documentElement&&o.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)){l= -new window.ActiveXObject("Microsoft.XMLDOM");l.async=false;l.validateOnParse=false;l.loadXML(n)}if(l)if(h&&l.parseError!=0||!l.documentElement||l.documentElement&&l.documentElement.tagName=="parsererror"){m=null;break a}m=l}j.responseXML=m}catch(q){}try{j.status=j._object.status}catch(p){}try{j.statusText=j._object.statusText}catch(r){}}function e(j){j._object.onreadystatechange=new window.Function}var f=window.XMLHttpRequest,g=!!window.controllers,h=window.document.all&&!window.opera,i=h&&window.navigator.userAgent.match(/MSIE 7.0/); -b.prototype=a.prototype;if(g&&f.wrapped)b.wrapped=f.wrapped;b.UNSENT=0;b.OPENED=1;b.HEADERS_RECEIVED=2;b.LOADING=3;b.DONE=4;b.prototype.readyState=b.UNSENT;b.prototype.responseText="";b.prototype.responseXML=null;b.prototype.status=0;b.prototype.statusText="";b.prototype.priority="NORMAL";b.prototype.onreadystatechange=null;b.onreadystatechange=null;b.onopen=null;b.onsend=null;b.onabort=null;b.prototype.open=function(j,k,m,o,l){delete this._headers;if(arguments.length<3)m=true;this._async=m;var n= -this,q=this.readyState,p;if(h&&m){p=function(){if(q!=b.DONE){e(n);n.abort()}};window.attachEvent("onunload",p)}b.onopen&&b.onopen.apply(this,arguments);if(arguments.length>4)this._object.open(j,k,m,o,l);else arguments.length>3?this._object.open(j,k,m,o):this._object.open(j,k,m);this.readyState=b.OPENED;c(this);this._object.onreadystatechange=function(){if(!(g&&!m)){n.readyState=n._object.readyState;d(n);if(n._aborted)n.readyState=b.UNSENT;else{if(n.readyState==b.DONE){delete n._data;e(n);h&&m&&window.detachEvent("onunload", -p)}q!=n.readyState&&c(n);q=n.readyState}}}};b.prototype.send=function(j){b.onsend&&b.onsend.apply(this,arguments);arguments.length||(j=null);if(j&&j.nodeType){j=window.XMLSerializer?(new window.XMLSerializer).serializeToString(j):j.xml;this._headers["Content-Type"]||this._object.setRequestHeader("Content-Type","application/xml")}this._data=j;this._object.send(this._data);if(g&&!this._async){this.readyState=b.OPENED;for(d(this);this.readyStateb.UNSENT)this._aborted=true;this._object.abort();e(this);this.readyState=b.UNSENT;delete this._data};b.prototype.getAllResponseHeaders=function(){return this._object.getAllResponseHeaders()};b.prototype.getResponseHeader=function(j){return this._object.getResponseHeader(j)};b.prototype.setRequestHeader=function(j,k){if(!this._headers)this._headers={};this._headers[j]=k;return this._object.setRequestHeader(j, -k)};b.prototype.addEventListener=function(j,k,m){for(var o=0,l;l=this._listeners[o];o++)if(l[0]==j&&l[1]==k&&l[2]==m)return;this._listeners.push([j,k,m])};b.prototype.removeEventListener=function(j,k,m){for(var o=0,l;l=this._listeners[o];o++)if(l[0]==j&&l[1]==k&&l[2]==m)break;l&&this._listeners.splice(o,1)};b.prototype.dispatchEvent=function(j){j={type:j.type,target:this,currentTarget:this,eventPhase:2,bubbles:j.bubbles,cancelable:j.cancelable,timeStamp:j.timeStamp,stopPropagation:function(){},preventDefault:function(){}, -initEvent:function(){}};if(j.type=="readystatechange"&&this.onreadystatechange)(this.onreadystatechange.handleEvent||this.onreadystatechange).apply(this,[j]);for(var k=0,m;m=this._listeners[k];k++)if(m[0]==j.type&&!m[2])(m[1].handleEvent||m[1]).apply(this,[j])};b.prototype.toString=function(){return"[object XMLHttpRequest]"};b.toString=function(){return"[XMLHttpRequest]"};if(!window.Function.prototype.apply)window.Function.prototype.apply=function(j,k){k||(k=[]);j.__func=this;j.__func(k[0],k[1],k[2], -k[3],k[4]);delete j.__func};if(!OpenLayers.Request)OpenLayers.Request={};OpenLayers.Request.XMLHttpRequest=b})();OpenLayers.Raster={};OpenLayers.Raster.Grid=OpenLayers.Class({EVENT_TYPES:["update"],initialize:function(a){OpenLayers.Util.extend(this,a);this.events=new OpenLayers.Events(this,null,this.EVENT_TYPES)},getValue:function(){throw Error("getValue must be defined");},numCols:function(){throw Error("numCols must be defined");},numRows:function(){throw Error("numRows must be defined");},forEach:function(a){for(var b=this.numCols(),c=this.numRows(),d=0;d=this.getCount())throw Error("Bad grid index.");var c=this;return new OpenLayers.Raster.Grid({numCols:function(){return c.numCols()},numRows:function(){return c.numRows()},getValue:function(d,e){return c.getValue(d,e)[b]}})},CLASS_NAME:"OpenLayers.Raster.Composite"}}()); -OpenLayers.Raster.Composite.fromLayer=function(a,b){var c;if(a instanceof OpenLayers.Layer.Grid)c=OpenLayers.Raster.Composite.fromGridLayer(a);else if(a instanceof OpenLayers.Layer.Vector)c=OpenLayers.Raster.Composite.fromVectorLayer(a,b);else throw Error("Only Grid or Vector type layers can be used to create a raster");return c}; -OpenLayers.Raster.Composite.fromVectorLayer=function(a,b){function c(n){n=Math.max(0,Math.min(255,n));return(3840+n).toString(16).substring(1)}function d(){m={};window.setTimeout(function(){k.events.triggerEvent("update")},0)}function e(n){n=n.features;l.addFeatures(n,{silent:true});for(var q=0,p=n.length;q1?b:a)({numCols:function(){return d().numCols()},numRows:function(){return d().numRows()}, -getValue:function(j,k){for(var m=Array(f),o,l=0;l=0;--d){c=b[d].geometry;if((c instanceof OpenLayers.Geometry.Polygon||c instanceof OpenLayers.Geometry.MultiPolygon)&&c.intersects(a)){a=b[d];this.control.layer.removeFeatures([a],{silent:true});this.control.layer.events.registerPriority("sketchcomplete", -this,this.finalizeInteriorRing);this.control.layer.events.registerPriority("sketchmodified",this,this.enforceTopology);a.geometry.addComponent(this.line.geometry);this.polygon=a;this.drawingHole=true;break}}OpenLayers.Handler.Path.prototype.addPoint.apply(this,arguments)},getCurrentPointIndex:function(){return this.line.geometry.components.length-2},enforceTopology:function(a){a=a.vertex;var b=this.line.geometry.components;if(!this.polygon.geometry.intersects(a)){b=b[b.length-3];a.x=b.x;a.y=b.y}}, -finishGeometry:function(){this.line.geometry.removeComponent(this.line.geometry.components[this.line.geometry.components.length-2]);this.removePoint();this.finalize()},finalizeInteriorRing:function(){var a=this.line.geometry,b=a.getArea()!==0;if(b){for(var c=this.polygon.geometry.components,d=c.length-2;d>=0;--d)if(a.intersects(c[d])){b=false;break}if(b){d=c.length-2;a:for(;d>0;--d)for(var e=c[d].components,f=0,g=e.length;f3?f[3]:255});this.context.putImageData(b,0,0);this.needsUpdate=false}},CLASS_NAME:"OpenLayers.Layer.Raster"}); +var OpenLayers={VERSION_NUMBER:"Release 2.13 dev",singleFile:true,_getScriptLocation:(function(){var r=new RegExp("(^|(.*?\\/))(OpenLayers[^\\/]*?\\.js)(\\?|$)"),s=document.getElementsByTagName('script'),src,m,l="";for(var i=0,len=s.length;i0){fig=parseFloat(num.toPrecision(sig));} +return fig;},format:function(num,dec,tsep,dsep){dec=(typeof dec!="undefined")?dec:0;tsep=(typeof tsep!="undefined")?tsep:OpenLayers.Number.thousandsSeparator;dsep=(typeof dsep!="undefined")?dsep:OpenLayers.Number.decimalSeparator;if(dec!=null){num=parseFloat(num.toFixed(dec));} +var parts=num.toString().split(".");if(parts.length==1&&dec==null){dec=0;} +var integer=parts[0];if(tsep){var thousands=/(-?[0-9]+)([0-9]{3})/;while(thousands.test(integer)){integer=integer.replace(thousands,"$1"+tsep+"$2");}} +var str;if(dec==0){str=integer;}else{var rem=parts.length>1?parts[1]:"0";if(dec!=null){rem=rem+new Array(dec-rem.length+1).join("0");} +str=integer+dsep+rem;} +return str;}};OpenLayers.Function={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);};},bindAsEventListener:function(func,object){return function(event){return func.call(object,event||window.event);};},False:function(){return false;},True:function(){return true;},Void:function(){}};OpenLayers.Array={filter:function(array,callback,caller){var selected=[];if(Array.prototype.filter){selected=array.filter(callback,caller);}else{var len=array.length;if(typeof callback!="function"){throw new TypeError();} +for(var i=0;i1){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;};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;ithis.right)){this.right=bounds.right;} +if((this.top==null)||(bounds.top>this.top)){this.top=bounds.top;}}}},containsLonLat:function(ll,options){if(typeof options==="boolean"){options={inclusive:options};} +options=options||{};var contains=this.contains(ll.lon,ll.lat,options.inclusive),worldBounds=options.worldBounds;if(worldBounds&&!contains){var worldWidth=worldBounds.getWidth();var worldCenterX=(worldBounds.left+worldBounds.right)/2;var worldsAway=Math.round((ll.lon-worldCenterX)/worldWidth);contains=this.containsLonLat({lon:ll.lon-worldsAway*worldWidth,lat:ll.lat},{inclusive:options.inclusive});} +return contains;},containsPixel:function(px,inclusive){return this.contains(px.x,px.y,inclusive);},contains:function(x,y,inclusive){if(inclusive==null){inclusive=true;} +if(x==null||y==null){return false;} +x=OpenLayers.Util.toFloat(x);y=OpenLayers.Util.toFloat(y);var contains=false;if(inclusive){contains=((x>=this.left)&&(x<=this.right)&&(y>=this.bottom)&&(y<=this.top));}else{contains=((x>this.left)&&(xthis.bottom)&&(y=self.bottom)&&(bounds.bottom<=self.top))||((self.bottom>=bounds.bottom)&&(self.bottom<=bounds.top)));var inTop=(((bounds.top>=self.bottom)&&(bounds.top<=self.top))||((self.top>bounds.bottom)&&(self.top=self.left)&&(bounds.left<=self.right))||((self.left>=bounds.left)&&(self.left<=bounds.right)));var inRight=(((bounds.right>=self.left)&&(bounds.right<=self.right))||((self.right>=bounds.left)&&(self.right<=bounds.right)));intersects=((inBottom||inTop)&&(inLeft||inRight));} +if(options.worldBounds&&!intersects){var world=options.worldBounds;var width=world.getWidth();var selfCrosses=!world.containsBounds(self);var boundsCrosses=!world.containsBounds(bounds);if(selfCrosses&&!boundsCrosses){bounds=bounds.add(-width,0);intersects=self.intersectsBounds(bounds,{inclusive:options.inclusive});}else if(boundsCrosses&&!selfCrosses){self=self.add(-width,0);intersects=bounds.intersectsBounds(self,{inclusive:options.inclusive});}} +return intersects;},containsBounds:function(bounds,partial,inclusive){if(partial==null){partial=false;} +if(inclusive==null){inclusive=true;} +var bottomLeft=this.contains(bounds.left,bounds.bottom,inclusive);var bottomRight=this.contains(bounds.right,bounds.bottom,inclusive);var topLeft=this.contains(bounds.left,bounds.top,inclusive);var topRight=this.contains(bounds.right,bounds.top,inclusive);return(partial)?(bottomLeft||bottomRight||topLeft||topRight):(bottomLeft&&bottomRight&&topLeft&&topRight);},determineQuadrant:function(lonlat){var quadrant="";var center=this.getCenterLonLat();quadrant+=(lonlat.lat=maxExtent.right&&newBounds.right>maxExtent.right){newBounds=newBounds.add(-width,0);} +var newLeft=newBounds.left+leftTolerance;if(newLeftmaxExtent.left&&newBounds.right-rightTolerance>maxExtent.right){newBounds=newBounds.add(-width,0);}} +return newBounds;},CLASS_NAME:"OpenLayers.Bounds"});OpenLayers.Bounds.fromString=function(str,reverseAxisOrder){var bounds=str.split(",");return OpenLayers.Bounds.fromArray(bounds,reverseAxisOrder);};OpenLayers.Bounds.fromArray=function(bbox,reverseAxisOrder){return reverseAxisOrder===true?new OpenLayers.Bounds(bbox[1],bbox[0],bbox[3],bbox[2]):new OpenLayers.Bounds(bbox[0],bbox[1],bbox[2],bbox[3]);};OpenLayers.Bounds.fromSize=function(size){return new OpenLayers.Bounds(0,size.h,size.w,0);};OpenLayers.Bounds.oppositeQuadrant=function(quadrant){var opp="";opp+=(quadrant.charAt(0)=='t')?'b':'t';opp+=(quadrant.charAt(1)=='l')?'r':'l';return opp;};OpenLayers.Element={visible:function(element){return OpenLayers.Util.getElement(element).style.display!='none';},toggle:function(){for(var i=0,len=arguments.length;imaxExtent.right){newLonLat.lon-=maxExtent.getWidth();}} +return newLonLat;},CLASS_NAME:"OpenLayers.LonLat"});OpenLayers.LonLat.fromString=function(str){var pair=str.split(",");return new OpenLayers.LonLat(pair[0],pair[1]);};OpenLayers.LonLat.fromArray=function(arr){var gotArr=OpenLayers.Util.isArray(arr),lon=gotArr&&arr[0],lat=gotArr&&arr[1];return new OpenLayers.LonLat(lon,lat);};OpenLayers.Pixel=OpenLayers.Class({x:0.0,y:0.0,initialize:function(x,y){this.x=parseFloat(x);this.y=parseFloat(y);},toString:function(){return("x="+this.x+",y="+this.y);},clone:function(){return new OpenLayers.Pixel(this.x,this.y);},equals:function(px){var equals=false;if(px!=null){equals=((this.x==px.x&&this.y==px.y)||(isNaN(this.x)&&isNaN(this.y)&&isNaN(px.x)&&isNaN(px.y)));} +return equals;},distanceTo:function(px){return Math.sqrt(Math.pow(this.x-px.x,2)+ +Math.pow(this.y-px.y,2));},add:function(x,y){if((x==null)||(y==null)){throw new TypeError('Pixel.add cannot receive null values');} +return new OpenLayers.Pixel(this.x+x,this.y+y);},offset:function(px){var newPx=this.clone();if(px){newPx=this.add(px.x,px.y);} +return newPx;},CLASS_NAME:"OpenLayers.Pixel"});OpenLayers.Size=OpenLayers.Class({w:0.0,h:0.0,initialize:function(w,h){this.w=parseFloat(w);this.h=parseFloat(h);},toString:function(){return("w="+this.w+",h="+this.h);},clone:function(){return new OpenLayers.Size(this.w,this.h);},equals:function(sz){var equals=false;if(sz!=null){equals=((this.w==sz.w&&this.h==sz.h)||(isNaN(this.w)&&isNaN(this.h)&&isNaN(sz.w)&&isNaN(sz.h)));} +return equals;},CLASS_NAME:"OpenLayers.Size"});OpenLayers.Console={log:function(){},debug:function(){},info:function(){},warn:function(){},error:function(){},userError:function(error){alert(error);},assert:function(){},dir:function(){},dirxml:function(){},trace:function(){},group:function(){},groupEnd:function(){},time:function(){},timeEnd:function(){},profile:function(){},profileEnd:function(){},count:function(){},CLASS_NAME:"OpenLayers.Console"};(function(){var scripts=document.getElementsByTagName("script");for(var i=0,len=scripts.length;i=0;i--){if(array[i]==item){array.splice(i,1);}} +return array;};OpenLayers.Util.indexOf=function(array,obj){if(typeof array.indexOf=="function"){return array.indexOf(obj);}else{for(var i=0,len=array.length;i=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='';}};OpenLayers.Util.createDiv=function(id,px,sz,imgURL,position,border,overflow,opacity){var dom=document.createElement('div');if(imgURL){dom.style.backgroundImage='url('+imgURL+')';} +if(!id){id=OpenLayers.Util.createUniqueID("OpenLayersDiv");} +if(!position){position="absolute";} +OpenLayers.Util.modifyDOMElement(dom,id,px,sz,position,border,overflow,opacity);return dom;};OpenLayers.Util.createImage=function(id,px,sz,imgURL,position,border,opacity,delayDisplay){var image=document.createElement("img");if(!id){id=OpenLayers.Util.createUniqueID("OpenLayersDiv");} +if(!position){position="relative";} +OpenLayers.Util.modifyDOMElement(image,id,px,sz,position,border,null,opacity);if(delayDisplay){image.style.display="none";function display(){image.style.display="";OpenLayers.Event.stopObservingElement(image);} +OpenLayers.Event.observe(image,"load",display);OpenLayers.Event.observe(image,"error",display);} +image.style.alt=id;image.galleryImg="no";if(imgURL){image.src=imgURL;} +return image;};OpenLayers.IMAGE_RELOAD_ATTEMPTS=0;OpenLayers.Util.alphaHackNeeded=null;OpenLayers.Util.alphaHack=function(){if(OpenLayers.Util.alphaHackNeeded==null){var arVersion=navigator.appVersion.split("MSIE");var version=parseFloat(arVersion[1]);var filter=false;try{filter=!!(document.body.filters);}catch(e){} +OpenLayers.Util.alphaHackNeeded=(filter&&(version>=5.5)&&(version<7));} +return OpenLayers.Util.alphaHackNeeded;};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)";}};OpenLayers.Util.createAlphaImageDiv=function(id,px,sz,imgURL,position,border,sizing,opacity,delayDisplay){var div=OpenLayers.Util.createDiv();var img=OpenLayers.Util.createImage(null,null,null,null,null,null,null,delayDisplay);img.className="olAlphaImg";div.appendChild(img);OpenLayers.Util.modifyAlphaImageDiv(div,id,px,sz,imgURL,position,border,sizing,opacity);return div;};OpenLayers.Util.upperCaseObject=function(object){var uObject={};for(var key in object){uObject[key.toUpperCase()]=object[key];} +return uObject;};OpenLayers.Util.applyDefaults=function(to,from){to=to||{};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];}} +if(!fromIsEvt&&from&&from.hasOwnProperty&&from.hasOwnProperty('toString')&&!to.hasOwnProperty('toString')){to.toString=from.toString;} +return to;};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){var encodedItemArray=[];var item;for(var itemIndex=0,len=value.length;itemIndex1e-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;} +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;} +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;return d;};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);return new OpenLayers.LonLat(lon1+u.deg(L),u.deg(lat2));};OpenLayers.Util.getParameters=function(url){url=(url===null||url===undefined)?window.location.href:url;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;i1.0)?(1.0/scale):scale;return normScale;};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;};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;};OpenLayers.Util.pagePosition=function(forElement){var pos=[0,0];var viewportElement=OpenLayers.Util.getViewportElement();if(!forElement||forElement==window||forElement==viewportElement){return pos;} +var BUGGY_GECKO_BOX_OBJECT=OpenLayers.IS_GECKO&&document.getBoxObjectFor&&OpenLayers.Element.getStyle(forElement,'position')=='absolute'&&(forElement.style.top==''||forElement.style.left=='');var parent=null;var box;if(forElement.getBoundingClientRect){box=forElement.getBoundingClientRect();var scrollTop=viewportElement.scrollTop;var scrollLeft=viewportElement.scrollLeft;pos[0]=box.left+scrollLeft;pos[1]=box.top+scrollTop;}else if(document.getBoxObjectFor&&!BUGGY_GECKO_BOX_OBJECT){box=document.getBoxObjectFor(forElement);var vpBox=document.getBoxObjectFor(viewportElement);pos[0]=box.screenX-vpBox.screenX;pos[1]=box.screenY-vpBox.screenY;}else{pos[0]=forElement.offsetLeft;pos[1]=forElement.offsetTop;parent=forElement.offsetParent;if(parent!=forElement){while(parent){pos[0]+=parent.offsetLeft;pos[1]+=parent.offsetTop;parent=parent.offsetParent;}} +var browser=OpenLayers.BROWSER_NAME;if(browser=="opera"||(browser=="safari"&&OpenLayers.Element.getStyle(forElement,'position')=='absolute')){pos[1]-=document.body.offsetTop;} +parent=forElement.offsetParent;while(parent&&parent!=document.body){pos[0]-=parent.scrollLeft;if(browser!="opera"||parent.tagName!='TR'){pos[1]-=parent.scrollTop;} +parent=parent.offsetParent;}} +return pos;};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.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);for(var key in urlObj1){if(key!=="args"){if(urlObj1[key]!=urlObj2[key]){return false;}}} +for(var key in urlObj1.args){if(urlObj1.args[key]!=urlObj2.args[key]){return false;} +delete urlObj2.args[key];} +for(var key in urlObj2.args){return false;} +return true;};OpenLayers.Util.createUrlObject=function(url,options){options=options||{};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){url=fullUrl+url;}else{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={};urlObject.host=a.host.split(":").shift();urlObject.protocol=a.protocol;if(options.ignorePort80){urlObject.port=(a.port=="80"||a.port=="0")?"":a.port;}else{urlObject.port=(a.port==""||a.port=="0")?"80":a.port;} +urlObject.hash=(options.ignoreHash||a.hash==="#")?"":a.hash;var queryString=a.search;if(!queryString){var qMark=url.indexOf("?");queryString=(qMark!=-1)?url.substr(qMark):"";} +urlObject.args=OpenLayers.Util.getParameters(queryString);urlObject.pathname=(a.pathname.charAt(0)=="/")?a.pathname:"/"+a.pathname;return urlObject;};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;};OpenLayers.IS_GECKO=(function(){var ua=navigator.userAgent.toLowerCase();return ua.indexOf("webkit")==-1&&ua.indexOf("gecko")!=-1;})();OpenLayers.CANVAS_SUPPORTED=(function(){var elem=document.createElement('canvas');return!!(elem.getContext&&elem.getContext('2d'));})();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;})();OpenLayers.Util.getBrowserName=function(){return OpenLayers.BROWSER_NAME;};OpenLayers.Util.getRenderedDimensions=function(contentHTML,size,options){var w,h;var container=document.createElement("div");container.style.visibility="hidden";var containerElement=(options&&options.containerElement)?options.containerElement:document.body;var parentHasPositionAbsolute=false;var superContainer=null;var parent=containerElement;while(parent&&parent.tagName.toLowerCase()!="body"){var parentPosition=OpenLayers.Element.getStyle(parent,"position");if(parentPosition=="absolute"){parentHasPositionAbsolute=true;break;}else if(parentPosition&&parentPosition!="static"){break;} +parent=parent.parentNode;} +if(parentHasPositionAbsolute&&(containerElement.clientHeight===0||containerElement.clientWidth===0)){superContainer=document.createElement("div");superContainer.style.visibility="hidden";superContainer.style.position="absolute";superContainer.style.overflow="visible";superContainer.style.width=document.body.clientWidth+"px";superContainer.style.height=document.body.clientHeight+"px";superContainer.appendChild(container);} +container.style.position="absolute";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";}} +if(options&&options.displayClass){container.className=options.displayClass;} +var content=document.createElement("div");content.innerHTML=contentHTML;content.style.overflow="visible";if(content.childNodes){for(var i=0,l=content.childNodes.length;i=60){coordinateseconds-=60;coordinateminutes+=1;if(coordinateminutes>=60){coordinateminutes-=60;coordinatedegrees+=1;}} +if(coordinatedegrees<10){coordinatedegrees="0"+coordinatedegrees;} +var str=coordinatedegrees+"\u00B0";if(dmsOption.indexOf('dm')>=0){if(coordinateminutes<10){coordinateminutes="0"+coordinateminutes;} +str+=coordinateminutes+"'";if(dmsOption.indexOf('dms')>=0){if(coordinateseconds<10){coordinateseconds="0"+coordinateseconds;} +str+=coordinateseconds+'"';}} +if(axis=="lon"){str+=coordinate<0?OpenLayers.i18n("W"):OpenLayers.i18n("E");}else{str+=coordinate<0?OpenLayers.i18n("S"):OpenLayers.i18n("N");} +return str;};OpenLayers.Event={observers:false,KEY_SPACE:32,KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,element:function(event){return event.target||event.srcElement;},isSingleTouch:function(event){return event.touches&&event.touches.length==1;},isMultiTouch:function(event){return event.touches&&event.touches.length>1;},isLeftClick:function(event){return(((event.which)&&(event.which==1))||((event.button)&&(event.button==1)));},isRightClick:function(event){return(((event.which)&&(event.which==3))||((event.button)&&(event.button==2)));},stop:function(event,allowDefault){if(!allowDefault){OpenLayers.Event.preventDefault(event);} +if(event.stopPropagation){event.stopPropagation();}else{event.cancelBubble=true;}},preventDefault:function(event){if(event.preventDefault){event.preventDefault();}else{event.returnValue=false;}},findElement:function(event,tagName){var element=OpenLayers.Event.element(event);while(element.parentNode&&(!element.tagName||(element.tagName.toUpperCase()!=tagName.toUpperCase()))){element=element.parentNode;} +return element;},observe:function(elementParam,name,observer,useCapture){var element=OpenLayers.Util.getElement(elementParam);useCapture=useCapture||false;if(name=='keypress'&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.attachEvent)){name='keydown';} +if(!this.observers){this.observers={};} +if(!element._eventCacheID){var idPrefix="eventCacheID_";if(element.id){idPrefix=element.id+"_"+idPrefix;} +element._eventCacheID=OpenLayers.Util.createUniqueID(idPrefix);} +var cacheID=element._eventCacheID;if(!this.observers[cacheID]){this.observers[cacheID]=[];} +this.observers[cacheID].push({'element':element,'name':name,'observer':observer,'useCapture':useCapture});if(element.addEventListener){element.addEventListener(name,observer,useCapture);}else if(element.attachEvent){element.attachEvent('on'+name,observer);}},stopObservingElement:function(elementParam){var element=OpenLayers.Util.getElement(elementParam);var cacheID=element._eventCacheID;this._removeElementObservers(OpenLayers.Event.observers[cacheID]);},_removeElementObservers:function(elementObservers){if(elementObservers){for(var i=elementObservers.length-1;i>=0;i--){var entry=elementObservers[i];OpenLayers.Event.stopObserving.apply(this,[entry.element,entry.name,entry.observer,entry.useCapture]);}}},stopObserving:function(elementParam,name,observer,useCapture){useCapture=useCapture||false;var element=OpenLayers.Util.getElement(elementParam);var cacheID=element._eventCacheID;if(name=='keypress'){if(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.detachEvent){name='keydown';}} +var foundEntry=false;var elementObservers=OpenLayers.Event.observers[cacheID];if(elementObservers){var i=0;while(!foundEntry&&i=0;--i){this.target.register(this.events[i],this,this.buttonClick,{extension:true});}},destroy:function(){for(var i=this.events.length-1;i>=0;--i){this.target.unregister(this.events[i],this,this.buttonClick);} +delete this.target;},getPressedButton:function(element){var depth=3,button;do{if(OpenLayers.Element.hasClass(element,"olButton")){button=element;break;} +element=element.parentNode;}while(--depth>0&&element);return button;},ignore:function(element){var depth=3,ignore=false;do{if(element.nodeName.toLowerCase()==='a'){ignore=true;break;} +element=element.parentNode;}while(--depth>0&&element);return ignore;},buttonClick:function(evt){var propagate=true,element=OpenLayers.Event.element(evt);if(element&&(OpenLayers.Event.isLeftClick(evt)||!~evt.type.indexOf("mouse"))){var button=this.getPressedButton(element);if(button){if(evt.type==="keydown"){switch(evt.keyCode){case OpenLayers.Event.KEY_RETURN:case OpenLayers.Event.KEY_SPACE:this.target.triggerEvent("buttonclick",{buttonElement:button});OpenLayers.Event.stop(evt);propagate=false;break;}}else if(this.startEvt){if(this.completeRegEx.test(evt.type)){var pos=OpenLayers.Util.pagePosition(button);this.target.triggerEvent("buttonclick",{buttonElement:button,buttonXY:{x:this.startEvt.clientX-pos[0],y:this.startEvt.clientY-pos[1]}});} +if(this.cancelRegEx.test(evt.type)){delete this.startEvt;} +OpenLayers.Event.stop(evt);propagate=false;} +if(this.startRegEx.test(evt.type)){this.startEvt=evt;OpenLayers.Event.stop(evt);propagate=false;}}else{propagate=!this.ignore(OpenLayers.Event.element(evt));delete this.startEvt;}} +return propagate;}});OpenLayers.Format=OpenLayers.Class({options:null,externalProjection:null,internalProjection:null,data:null,keepData:false,initialize:function(options){OpenLayers.Util.extend(this,options);this.options=options;},destroy:function(){},read:function(data){throw new Error('Read not implemented.');},write:function(object){throw new Error('Write not implemented.');},CLASS_NAME:"OpenLayers.Format"});OpenLayers.Format.XML=OpenLayers.Class(OpenLayers.Format,{namespaces:null,namespaceAlias:null,defaultPrefix:null,readers:{},writers:{},xmldom:null,initialize:function(options){if(window.ActiveXObject){this.xmldom=new ActiveXObject("Microsoft.XMLDOM");} +OpenLayers.Format.prototype.initialize.apply(this,[options]);this.namespaces=OpenLayers.Util.extend({},this.namespaces);this.namespaceAlias={};for(var alias in this.namespaces){this.namespaceAlias[this.namespaces[alias]]=alias;}},destroy:function(){this.xmldom=null;OpenLayers.Format.prototype.destroy.apply(this,arguments);},setNamespace:function(alias,uri){this.namespaces[alias]=uri;this.namespaceAlias[uri]=alias;},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;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;},write:function(node){var data;if(this.xmldom){data=node.xml;}else{var serializer=new XMLSerializer();if(node.nodeType==1){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;},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;},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;},getElementsByTagNameNS:function(node,uri,name){var elements=[];if(node.getElementsByTagNameNS){elements=node.getElementsByTagNameNS(uri,name);}else{var allNodes=node.getElementsByTagName("*");var potentialNode,fullName;for(var i=0,len=allNodes.length;i0){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;},getChildEl:function(node,name,uri){return node&&this.getThisOrNextEl(node.firstChild,name,uri);},getNextEl:function(node,name,uri){return node&&this.getThisOrNextEl(node.nextSibling,name,uri);},getThisOrNextEl:function(node,name,uri){outer:for(var sibling=node;sibling;sibling=sibling.nextSibling){switch(sibling.nodeType){case 1:if((!name||name===(sibling.localName||sibling.nodeName.split(":").pop()))&&(!uri||uri===sibling.namespaceURI)){break outer;} +sibling=null;break outer;case 3:if(/^\s*$/.test(sibling.nodeValue)){break;} +case 4:case 6:case 12:case 10:case 11:sibling=null;break outer;}} +return sibling||null;},lookupNamespaceURI:function(node,prefix){var uri=null;if(node){if(node.lookupNamespaceURI){uri=node.lookupNamespaceURI(prefix);}else{outer:switch(node.nodeType){case 1: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;i0){appliedRules=true;for(var i=0,len=elseRules.length;i0&&appliedRules==false){style.display="none";} +if(style.label!=null&&typeof style.label!=="string"){style.label=String(style.label);} +return style;},applySymbolizer:function(rule,style,feature){var symbolizerPrefix=feature.geometry?this.getSymbolizerPrefix(feature.geometry):OpenLayers.Style.SYMBOLIZER_PREFIXES[0];var symbolizer=rule.symbolizer[symbolizerPrefix]||rule.symbolizer;if(this.defaultsPerSymbolizer===true){var defaults=this.defaultStyle;OpenLayers.Util.applyDefaults(symbolizer,{pointRadius:defaults.pointRadius});if(symbolizer.stroke===true||symbolizer.graphic===true){OpenLayers.Util.applyDefaults(symbolizer,{strokeWidth:defaults.strokeWidth,strokeColor:defaults.strokeColor,strokeOpacity:defaults.strokeOpacity,strokeDashstyle:defaults.strokeDashstyle,strokeLinecap:defaults.strokeLinecap});} +if(symbolizer.fill===true||symbolizer.graphic===true){OpenLayers.Util.applyDefaults(symbolizer,{fillColor:defaults.fillColor,fillOpacity:defaults.fillOpacity});} +if(symbolizer.graphic===true){OpenLayers.Util.applyDefaults(symbolizer,{pointRadius:this.defaultStyle.pointRadius,externalGraphic:this.defaultStyle.externalGraphic,graphicName:this.defaultStyle.graphicName,graphicOpacity:this.defaultStyle.graphicOpacity,graphicWidth:this.defaultStyle.graphicWidth,graphicHeight:this.defaultStyle.graphicHeight,graphicXOffset:this.defaultStyle.graphicXOffset,graphicYOffset:this.defaultStyle.graphicYOffset});}} +return this.createLiterals(OpenLayers.Util.extend(style,symbolizer),feature);},createLiterals:function(style,feature){var context=OpenLayers.Util.extend({},feature.attributes||feature.data);OpenLayers.Util.extend(context,this.context);for(var i in this.propertyStyles){style[i]=OpenLayers.Style.createLiteral(style[i],context,feature,i);} +return style;},findPropertyStyles:function(){var propertyStyles={};var style=this.defaultStyle;this.addPropertyStyles(propertyStyles,style);var rules=this.rules;var symbolizer,value;for(var i=0,len=rules.length;ithis.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;},value2regex:function(wildCard,singleChar,escapeChar){if(wildCard=="."){throw new Error("'.' is an unsupported wildCard character for "+"OpenLayers.Filter.Comparison");} +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;},regex2value:function(){var value=this.value;value=value.replace(/!/g,"!!");value=value.replace(/(\\)?\\\./g,function($0,$1){return $1?$0:"!.";});value=value.replace(/(\\)?\\\*/g,function($0,$1){return $1?$0:"!*";});value=value.replace(/\\\\/g,"\\");value=value.replace(/\.\*/g,"*");return value;},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=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",CLASS_NAME:"OpenLayers.Format.Filter"});OpenLayers.Filter.Function=OpenLayers.Class(OpenLayers.Filter,{name:null,params:null,CLASS_NAME:"OpenLayers.Filter.Function"});OpenLayers.Format.Filter.v1=OpenLayers.Class(OpenLayers.Format.XML,{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"},defaultPrefix:"ogc",schemaLocation:null,initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data){var obj={};this.readers.ogc["Filter"].apply(this,[data,obj]);return obj.filter;},readers:{"ogc":{"_expression":function(node){var obj,value="";for(var child=node.firstChild;child;child=child.nextSibling){switch(child.nodeType){case 1:obj=this.readNode(child);if(obj.property){value+="${"+obj.property+"}";}else if(obj.value!==undefined){value+=obj.value;} +break;case 3:case 4:value+=child.nodeValue;}} +return value;},"Filter":function(node,parent){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),true);},"PropertyName":function(node,filter){filter.property=this.getChildValue(node);},"LowerBoundary":function(node,filter){filter.lowerBoundary=OpenLayers.String.numericIf(this.readers.ogc._expression.call(this,node),true);},"UpperBoundary":function(node,filter){filter.upperBoundary=OpenLayers.String.numericIf(this.readers.ogc._expression.call(this,node),true);},"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");},"Function":function(node,obj){return;}}},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);},writeOgcExpression:function(value,node){if(value instanceof OpenLayers.Filter.Function){var child=this.writeNode("Function",value,node);node.appendChild(child);}else{this.writeNode("Literal",value,node);} +return node;},write:function(filter){return this.writers.ogc["Filter"].apply(this,[filter]);},writeFeatureIdNodes:function(filter,node){for(var i=0,ii=filter.fids.length;i":"PropertyIsGreaterThan","<=":"PropertyIsLessThanOrEqualTo",">=":"PropertyIsGreaterThanOrEqualTo","..":"PropertyIsBetween","~":"PropertyIsLike","BBOX":"BBOX","DWITHIN":"DWITHIN","WITHIN":"WITHIN","CONTAINS":"CONTAINS","INTERSECTS":"INTERSECTS","FID":"FeatureId"},CLASS_NAME:"OpenLayers.Format.Filter.v1"});OpenLayers.Geometry=OpenLayers.Class({id:null,parent:null,bounds:null,initialize:function(){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){this.id=null;this.bounds=null;},clone:function(){return new OpenLayers.Geometry();},setBounds:function(bounds){if(bounds){this.bounds=bounds.clone();}},clearBounds:function(){this.bounds=null;if(this.parent){this.parent.clearBounds();}},extendBounds:function(newBounds){var bounds=this.getBounds();if(!bounds){this.setBounds(newBounds);}else{this.bounds.extend(newBounds);}},getBounds:function(){if(this.bounds==null){this.calculateBounds();} +return this.bounds;},calculateBounds:function(){},distanceTo:function(geometry,options){},getVertices:function(nodes){},atPoint:function(lonlat,toleranceLon,toleranceLat){var atPoint=false;var bounds=this.getBounds();if((bounds!=null)&&(lonlat!=null)){var dX=(toleranceLon!=null)?toleranceLon:0;var dY=(toleranceLat!=null)?toleranceLat:0;var toleranceBounds=new OpenLayers.Bounds(this.bounds.left-dX,this.bounds.bottom-dY,this.bounds.right+dX,this.bounds.top+dY);atPoint=toleranceBounds.containsLonLat(lonlat);} +return atPoint;},getLength:function(){return 0.0;},getArea:function(){return 0.0;},getCentroid:function(){return null;},toString:function(){var string;if(OpenLayers.Format&&OpenLayers.Format.WKT){string=OpenLayers.Format.WKT.prototype.write(new OpenLayers.Feature.Vector(this));}else{string=Object.prototype.toString.call(this);} +return string;},CLASS_NAME:"OpenLayers.Geometry"});OpenLayers.Geometry.fromWKT=function(wkt){var geom;if(OpenLayers.Format&&OpenLayers.Format.WKT){var format=OpenLayers.Geometry.fromWKT.format;if(!format){format=new OpenLayers.Format.WKT();OpenLayers.Geometry.fromWKT.format=format;} +var result=format.read(wkt);if(result instanceof OpenLayers.Feature.Vector){geom=result.geometry;}else if(OpenLayers.Util.isArray(result)){var len=result.length;var components=new Array(len);for(var i=0;i=0&&along1<=1&&along2>=0&&along2<=1){if(!point){intersection=true;}else{var x=seg1.x1+(along1*x12_11);var y=seg1.y1+(along1*y12_11);intersection=new OpenLayers.Geometry.Point(x,y);}}} +if(tolerance){var dist;if(intersection){if(point){var segs=[seg1,seg2];var seg,x,y;outer:for(var i=0;i<2;++i){seg=segs[i];for(var j=1;j<3;++j){x=seg["x"+j];y=seg["y"+j];dist=Math.sqrt(Math.pow(x-intersection.x,2)+ +Math.pow(y-intersection.y,2));if(dist=1.0){x=x2;y=y2;}else{x=x1+along*dx;y=y1+along*dy;} +return{distance:Math.sqrt(Math.pow(x-x0,2)+Math.pow(y-y0,2)),x:x,y:y};};OpenLayers.Geometry.Point=OpenLayers.Class(OpenLayers.Geometry,{x:null,y:null,initialize:function(x,y){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.x=parseFloat(x);this.y=parseFloat(y);},clone:function(obj){if(obj==null){obj=new OpenLayers.Geometry.Point(this.x,this.y);} +OpenLayers.Util.applyDefaults(obj,this);return obj;},calculateBounds:function(){this.bounds=new OpenLayers.Bounds(this.x,this.y,this.x,this.y);},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){result={x0:result.x1,y0:result.y1,x1:result.x0,y1:result.y0,distance:result.distance};}} +return result;},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;},toShortString:function(){return(this.x+", "+this.y);},move:function(x,y){this.x=this.x+x;this.y=this.y+y;this.clearBounds();},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();},getCentroid:function(){return new OpenLayers.Geometry.Point(this.x,this.y);},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;},intersects:function(geometry){var intersect=false;if(geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){intersect=this.equals(geometry);}else{intersect=geometry.intersects(this);} +return intersect;},transform:function(source,dest){if((source&&dest)){OpenLayers.Projection.transform(this,source,dest);this.bounds=null;} +return this;},getVertices:function(nodes){return[this];},CLASS_NAME:"OpenLayers.Geometry.Point"});OpenLayers.Geometry.Collection=OpenLayers.Class(OpenLayers.Geometry,{components:null,componentTypes:null,initialize:function(components){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.components=[];if(components!=null){this.addComponents(components);}},destroy:function(){this.components.length=0;this.components=null;OpenLayers.Geometry.prototype.destroy.apply(this,arguments);},clone:function(){var geometry=eval("new "+this.CLASS_NAME+"()");for(var i=0,len=this.components.length;i-1)){if(index!=null&&(index=0;--i){removed=this.removeComponent(components[i])||removed;} +return removed;},removeComponent:function(component){OpenLayers.Util.removeItem(this.components,component);this.clearBounds();return true;},getLength:function(){var length=0.0;for(var i=0,len=this.components.length;i0)?area:minArea;centroids.push(centroid);} +len=areas.length;if(areaSum===0){for(var i=0;i1)){for(var i=1,len=this.components.length;i1)){var p1,p2;for(var i=1,len=geom.components.length;i2);if(removed){OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,arguments);} +return removed;},intersects:function(geometry){var intersect=false;var type=geometry.CLASS_NAME;if(type=="OpenLayers.Geometry.LineString"||type=="OpenLayers.Geometry.LinearRing"||type=="OpenLayers.Geometry.Point"){var segs1=this.getSortedSegments();var segs2;if(type=="OpenLayers.Geometry.Point"){segs2=[{x1:geometry.x,y1:geometry.y,x2:geometry.x,y2:geometry.y}];}else{segs2=geometry.getSortedSegments();} +var seg1,seg1x1,seg1x2,seg1y1,seg1y2,seg2,seg2y1,seg2y2;outer:for(var i=0,len=segs1.length;iseg1x2){break;} +if(seg2.x2Math.max(seg1y1,seg1y2)){continue;} +if(Math.max(seg2y1,seg2y2)0){var xDir=seg.x10){lines.unshift(j,1);Array.prototype.splice.apply(targetParts,lines);j+=lines.length-2;} +if(mutual){for(var k=0,len=splits.points.length;k0&&points.length>0){points.push(vert2.clone());sourceParts.push(new OpenLayers.Geometry.LineString(points));}}else{results=target.splitWith(this,options);} +if(targetParts&&targetParts.length>1){targetSplit=true;}else{targetParts=[];} +if(sourceParts&&sourceParts.length>1){sourceSplit=true;}else{sourceParts=[];} +if(targetSplit||sourceSplit){if(mutual){results=[sourceParts,targetParts];}else{results=targetParts;}} +return results;},splitWith:function(geometry,options){return geometry.split(this,options);},getVertices:function(nodes){var vertices;if(nodes===true){vertices=[this.components[0],this.components[this.components.length-1]];}else if(nodes===false){vertices=this.components.slice(1,this.components.length-1);}else{vertices=this.components.slice();} +return vertices;},distanceTo:function(geometry,options){var edge=!(options&&options.edge===false);var details=edge&&options&&options.details;var result,best={};var min=Number.POSITIVE_INFINITY;if(geometry instanceof OpenLayers.Geometry.Point){var segs=this.getSortedSegments();var x=geometry.x;var y=geometry.y;var seg;for(var i=0,len=segs.length;ix&&((y>seg.y1&&yseg.y2))){break;}}} +if(details){best={distance:best.distance,x0:best.x,y0:best.y,x1:x,y1:y};}else{best=best.distance;}}else if(geometry instanceof OpenLayers.Geometry.LineString){var segs0=this.getSortedSegments();var segs1=geometry.getSortedSegments();var seg0,seg1,intersection,x0,y0;var len1=segs1.length;var interOptions={point:true};outer:for(var i=0,len=segs0.length;imaxDistance){maxDistance=distance;indexFarthest=index;}} +if(maxDistance>tolerance&&indexFarthest!=firstPoint){pointIndexsToKeep.push(indexFarthest);douglasPeuckerReduction(points,firstPoint,indexFarthest,tolerance);douglasPeuckerReduction(points,indexFarthest,lastPoint,tolerance);}};var perpendicularDistance=function(point1,point2,point){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=[];pointIndexsToKeep.push(firstPoint);pointIndexsToKeep.push(lastPoint);while(points[firstPoint].equals(points[lastPoint])){lastPoint--;pointIndexsToKeep.push(lastPoint);} +douglasPeuckerReduction(points,firstPoint,lastPoint,tolerance);var returnPoints=[];pointIndexsToKeep.sort(compareNumbers);for(var index=0;index1){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;},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;i1){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=OpenLayers.Class(OpenLayers.Geometry.LineString,{componentTypes:["OpenLayers.Geometry.Point"],addComponent:function(point,index){var added=false;var lastPoint=this.components.pop();if(index!=null||!point.equals(lastPoint)){added=OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,arguments);} +var firstPoint=this.components[0];OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[firstPoint]);return added;},removeComponent:function(point){var removed=this.components&&(this.components.length>3);if(removed){this.components.pop();OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,arguments);var firstPoint=this.components[0];OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[firstPoint]);} +return removed;},move:function(x,y){for(var i=0,len=this.components.length;i0&&len<=2){return this.components[0].clone();}else if(len>2){var sumX=0.0;var sumY=0.0;var x0=this.components[0].x;var y0=this.components[0].y;var area=-1*this.getArea();if(area!=0){for(var i=0;i2)){var sum=0.0;for(var i=0,len=this.components.length;i2){var p1,p2;for(var i=0;i=x1&&px<=x2)||x1>=x2&&(px<=x1&&px>=x2)){crosses=-1;break;}} +continue;} +cx=approx(getX(py,x1,y1,x2,y2),digs);if(cx==px){if(y1=y1&&py<=y2)||y1>y2&&(py<=y1&&py>=y2)){crosses=-1;break;}} +if(cx<=px){continue;} +if(x1!=x2&&(cxMath.max(x1,x2))){continue;} +if(y1=y1&&pyy2&&(py=y2)){++crosses;}} +var contained=(crosses==-1)?1:!!(crosses&1);return contained;},intersects:function(geometry){var intersect=false;if(geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){intersect=this.containsPoint(geometry);}else if(geometry.CLASS_NAME=="OpenLayers.Geometry.LineString"){intersect=geometry.intersects(this);}else if(geometry.CLASS_NAME=="OpenLayers.Geometry.LinearRing"){intersect=OpenLayers.Geometry.LineString.prototype.intersects.apply(this,[geometry]);}else{for(var i=0,len=geometry.components.length;i0)){area+=Math.abs(this.components[0].getArea());for(var i=1,len=this.components.length;i0)){area+=Math.abs(this.components[0].getGeodesicArea(projection));for(var i=1,len=this.components.length;i0){contained=this.components[0].containsPoint(point);if(contained!==1){if(contained&&numRings>1){var hole;for(var i=1;i0){parser=this.parseGeometry[type.toLowerCase()];if(parser){geometry=parser.apply(this,[nodeList[0]]);if(this.internalProjection&&this.externalProjection){geometry.transform(this.externalProjection,this.internalProjection);}}else{throw new TypeError("Unsupported geometry type: "+type);} +break;}} +var bounds;var boxNodes=this.getElementsByTagNameNS(node,this.gmlns,"Box");for(i=0;i0){coordString=nodeList[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.trimSpace,"");coords=coordString.split(this.regExes.splitSpace);} +if(coords.length==0){nodeList=this.getElementsByTagNameNS(node,this.gmlns,"coordinates");if(nodeList.length>0){coordString=nodeList[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.removeSpace,"");coords=coordString.split(",");}} +if(coords.length==0){nodeList=this.getElementsByTagNameNS(node,this.gmlns,"coord");if(nodeList.length>0){var xList=this.getElementsByTagNameNS(nodeList[0],this.gmlns,"X");var yList=this.getElementsByTagNameNS(nodeList[0],this.gmlns,"Y");if(xList.length>0&&yList.length>0){coords=[xList[0].firstChild.nodeValue,yList[0].firstChild.nodeValue];}}} +if(coords.length==2){coords[2]=null;} +if(this.xy){return new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]);} +else{return new OpenLayers.Geometry.Point(coords[1],coords[0],coords[2]);}},multipoint:function(node){var nodeList=this.getElementsByTagNameNS(node,this.gmlns,"Point");var components=[];if(nodeList.length>0){var point;for(var i=0;i0){coordString=this.getChildValue(nodeList[0]);coordString=coordString.replace(this.regExes.trimSpace,"");coords=coordString.split(this.regExes.splitSpace);var dim=parseInt(nodeList[0].getAttribute("dimension"));var j,x,y,z;for(var i=0;i0){coordString=this.getChildValue(nodeList[0]);coordString=coordString.replace(this.regExes.trimSpace,"");coordString=coordString.replace(this.regExes.trimComma,",");var pointList=coordString.split(this.regExes.splitSpace);for(var i=0;i0){var line;for(var i=0;i0){var ring;for(var i=0;i0){var polygon;for(var i=0;i0){var coords=[];if(lpoint.length>0){coordString=lpoint[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.trimSpace,"");coords=coordString.split(this.regExes.splitSpace);} +if(coords.length==2){coords[2]=null;} +if(this.xy){var lowerPoint=new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]);}else{var lowerPoint=new OpenLayers.Geometry.Point(coords[1],coords[0],coords[2]);}} +var upoint=this.getElementsByTagNameNS(node,this.gmlns,"upperCorner");if(upoint.length>0){var coords=[];if(upoint.length>0){coordString=upoint[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.trimSpace,"");coords=coordString.split(this.regExes.splitSpace);} +if(coords.length==2){coords[2]=null;} +if(this.xy){var upperPoint=new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]);}else{var upperPoint=new OpenLayers.Geometry.Point(coords[1],coords[0],coords[2]);}} +if(lowerPoint&&upperPoint){components.push(new OpenLayers.Geometry.Point(lowerPoint.x,lowerPoint.y));components.push(new OpenLayers.Geometry.Point(upperPoint.x,lowerPoint.y));components.push(new OpenLayers.Geometry.Point(upperPoint.x,upperPoint.y));components.push(new OpenLayers.Geometry.Point(lowerPoint.x,upperPoint.y));components.push(new OpenLayers.Geometry.Point(lowerPoint.x,lowerPoint.y));var ring=new OpenLayers.Geometry.LinearRing(components);envelope=new OpenLayers.Geometry.Polygon([ring]);} +return envelope;},box:function(node){var nodeList=this.getElementsByTagNameNS(node,this.gmlns,"coordinates");var coordString;var coords,beginPoint=null,endPoint=null;if(nodeList.length>0){coordString=nodeList[0].firstChild.nodeValue;coords=coordString.split(" ");if(coords.length==2){beginPoint=coords[0].split(",");endPoint=coords[1].split(",");}} +if(beginPoint!==null&&endPoint!==null){return new OpenLayers.Bounds(parseFloat(beginPoint[0]),parseFloat(beginPoint[1]),parseFloat(endPoint[0]),parseFloat(endPoint[1]));}}},parseAttributes:function(node){var attributes={};var childNode=node.firstChild;var children,i,child,grandchildren,grandchild,name,value;while(childNode){if(childNode.nodeType==1){children=childNode.childNodes;for(i=0;i0){obj.bounds=container.components[0];}},"Point":function(node,container){var obj={points:[]};this.readChildNodes(node,obj);if(!container.components){container.components=[];} +container.components.push(obj.points[0]);},"coordinates":function(node,obj){var str=this.getChildValue(node).replace(this.regExes.trimSpace,"");str=str.replace(this.regExes.trimComma,",");var pointList=str.split(this.regExes.splitSpace);var coords;var numPoints=pointList.length;var points=new Array(numPoints);for(var i=0;i0){container.components=[new OpenLayers.Geometry.MultiLineString(obj.components)];}},"curveMember":function(node,obj){this.readChildNodes(node,obj);},"MultiSurface":function(node,container){var obj={components:[]};this.readers.gml._inherit.apply(this,[node,obj,container]);this.readChildNodes(node,obj);if(obj.components.length>0){container.components=[new OpenLayers.Geometry.MultiPolygon(obj.components)];}},"surfaceMember":function(node,obj){this.readChildNodes(node,obj);},"surfaceMembers":function(node,obj){this.readChildNodes(node,obj);},"pointMembers":function(node,obj){this.readChildNodes(node,obj);},"lineStringMembers":function(node,obj){this.readChildNodes(node,obj);},"polygonMembers":function(node,obj){this.readChildNodes(node,obj);},"geometryMembers":function(node,obj){this.readChildNodes(node,obj);},"Envelope":function(node,container){var obj={points:new Array(2)};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));},"lowerCorner":function(node,container){var obj={};this.readers.gml.pos.apply(this,[node,obj]);container.points[0]=obj.points[0];},"upperCorner":function(node,container){var obj={};this.readers.gml.pos.apply(this,[node,obj]);container.points[1]=obj.points[0];}},OpenLayers.Format.GML.Base.prototype.readers["gml"]),"feature":OpenLayers.Format.GML.Base.prototype.readers["feature"],"wfs":OpenLayers.Format.GML.Base.prototype.readers["wfs"]},write:function(features){var name;if(OpenLayers.Util.isArray(features)){name="featureMembers";}else{name="featureMember";} +var root=this.writeNode("gml:"+name,features);this.setAttributeNS(root,this.namespaces["xsi"],"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[root]);},writers:{"gml":OpenLayers.Util.applyDefaults({"featureMembers":function(features){var node=this.createElementNSPlus("gml:featureMembers");for(var i=0,len=features.length;i0?duration:Number.POSITIVE_INFINITY;var id=++counter;var start=+new Date;loops[id]=function(){if(loops[id]&&+new Date-start<=duration){callback();if(loops[id]){requestFrame(loops[id],element);}}else{delete loops[id];}};requestFrame(loops[id],element);return id;} +function stop(id){delete loops[id];} +return{isNative:isNative,requestFrame:requestFrame,start:start,stop:stop};})(window);OpenLayers.Tween=OpenLayers.Class({easing:null,begin:null,finish:null,duration:null,callbacks:null,time:null,animationId:null,playing:false,initialize:function(easing){this.easing=(easing)?easing:OpenLayers.Easing.Expo.easeOut;},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;OpenLayers.Animation.stop(this.animationId);this.animationId=null;if(this.callbacks&&this.callbacks.start){this.callbacks.start.call(this,this.begin);} +this.animationId=OpenLayers.Animation.start(OpenLayers.Function.bind(this.play,this));},stop:function(){if(!this.playing){return;} +if(this.callbacks&&this.callbacks.done){this.callbacks.done.call(this,this.finish);} +OpenLayers.Animation.stop(this.animationId);this.animationId=null;this.playing=false;},play:function(){var value={};for(var i in this.begin){var b=this.begin[i];var f=this.finish[i];if(b==null||f==null||isNaN(b)||isNaN(f)){throw new TypeError('invalid value for Tween');} +var c=f-b;value[i]=this.easing.apply(this,[this.time,b,c,this.duration]);} +this.time++;if(this.callbacks&&this.callbacks.eachStep){this.callbacks.eachStep.call(this,value);} +if(this.time>this.duration){this.stop();}},CLASS_NAME:"OpenLayers.Tween"});OpenLayers.Easing={CLASS_NAME:"OpenLayers.Easing"};OpenLayers.Easing.Linear={easeIn:function(t,b,c,d){return c*t/d+b;},easeOut:function(t,b,c,d){return c*t/d+b;},easeInOut:function(t,b,c,d){return c*t/d+b;},CLASS_NAME:"OpenLayers.Easing.Linear"};OpenLayers.Easing.Expo={easeIn:function(t,b,c,d){return(t==0)?b:c*Math.pow(2,10*(t/d-1))+b;},easeOut:function(t,b,c,d){return(t==d)?b+c:c*(-Math.pow(2,-10*t/d)+1)+b;},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"};OpenLayers.Easing.Quad={easeIn:function(t,b,c,d){return c*(t/=d)*t+b;},easeOut:function(t,b,c,d){return-c*(t/=d)*(t-2)+b;},easeInOut:function(t,b,c,d){if((t/=d/2)<1)return c/2*t*t+b;return-c/2*((--t)*(t-2)-1)+b;},CLASS_NAME:"OpenLayers.Easing.Quad"};OpenLayers.Projection=OpenLayers.Class({proj:null,projCode:null,titleRegEx:/\+title=[^\+]*/,initialize:function(projCode,options){OpenLayers.Util.extend(this,options);this.projCode=projCode;if(typeof Proj4js=="object"){this.proj=new Proj4js.Proj(projCode);}},getCode:function(){return this.proj?this.proj.srsCode:this.projCode;},getUnits:function(){return this.proj?this.proj.units:null;},toString:function(){return this.getCode();},equals:function(projection){var p=projection,equals=false;if(p){if(!(p instanceof OpenLayers.Projection)){p=new OpenLayers.Projection(p);} +if((typeof Proj4js=="object")&&this.proj.defData&&p.proj.defData){equals=this.proj.defData.replace(this.titleRegEx,"")==p.proj.defData.replace(this.titleRegEx,"");}else if(p.getCode){var source=this.getCode(),target=p.getCode();equals=source==target||!!OpenLayers.Projection.transforms[source]&&OpenLayers.Projection.transforms[source][target]===OpenLayers.Projection.nullTransform;}} +return equals;},destroy:function(){delete this.proj;delete this.projCode;},CLASS_NAME:"OpenLayers.Projection"});OpenLayers.Projection.transforms={};OpenLayers.Projection.defaults={"EPSG:4326":{units:"degrees",maxExtent:[-180,-90,180,90],yx:true},"CRS:84":{units:"degrees",maxExtent:[-180,-90,180,90]},"EPSG:900913":{units:"m",maxExtent:[-20037508.34,-20037508.34,20037508.34,20037508.34]}};OpenLayers.Projection.addTransform=function(from,to,method){if(method===OpenLayers.Projection.nullTransform){var defaults=OpenLayers.Projection.defaults[from];if(defaults&&!OpenLayers.Projection.defaults[to]){OpenLayers.Projection.defaults[to]=defaults;}} +if(!OpenLayers.Projection.transforms[from]){OpenLayers.Projection.transforms[from]={};} +OpenLayers.Projection.transforms[from][to]=method;};OpenLayers.Projection.transform=function(point,source,dest){if(source&&dest){if(!(source instanceof OpenLayers.Projection)){source=new OpenLayers.Projection(source);} +if(!(dest instanceof OpenLayers.Projection)){dest=new OpenLayers.Projection(dest);} +if(source.proj&&dest.proj){point=Proj4js.transform(source.proj,dest.proj,point);}else{var sourceCode=source.getCode();var destCode=dest.getCode();var transforms=OpenLayers.Projection.transforms;if(transforms[sourceCode]&&transforms[sourceCode][destCode]){transforms[sourceCode][destCode](point);}}} +return point;};OpenLayers.Projection.nullTransform=function(point){return point;};(function(){var pole=20037508.34;function inverseMercator(xy){xy.x=180*xy.x/pole;xy.y=180/Math.PI*(2*Math.atan(Math.exp((xy.y/pole)*Math.PI))-Math.PI/2);return xy;} +function forwardMercator(xy){xy.x=xy.x*pole/180;xy.y=Math.log(Math.tan((90+xy.y)*Math.PI/360))/Math.PI*pole;return xy;} +function map(base,codes){var add=OpenLayers.Projection.addTransform;var same=OpenLayers.Projection.nullTransform;var i,len,code,other,j;for(i=0,len=codes.length;i=0;--i){map(mercator[i],geographic);} +for(i=geographic.length-1;i>=0;--i){map(geographic[i],mercator);}})();OpenLayers.Map=OpenLayers.Class({Z_INDEX_BASE:{BaseLayer:100,Overlay:325,Feature:725,Popup:750,Control:1000},id:null,fractionalZoom:false,events:null,allOverlays:false,div:null,dragging:false,size:null,viewPortDiv:null,layerContainerOrigin:null,layerContainerDiv:null,layers:null,controls:null,popups:null,baseLayer:null,center:null,resolution:null,zoom:0,panRatio:1.5,options:null,tileSize:null,projection:"EPSG:4326",units:null,resolutions:null,maxResolution:null,minResolution:null,maxScale:null,minScale:null,maxExtent:null,minExtent:null,restrictedExtent:null,numZoomLevels:16,theme:null,displayProjection:null,fallThrough:true,autoUpdateSize:true,panTween:null,eventListeners:null,panMethod:OpenLayers.Easing.Expo.easeOut,panDuration:50,paddingForPopups:null,layerContainerOriginPx:null,minPx:null,maxPx:null,initialize:function(div,options){if(arguments.length===1&&typeof div==="object"){options=div;div=options&&options.div;} +this.tileSize=new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,OpenLayers.Map.TILE_HEIGHT);this.paddingForPopups=new OpenLayers.Bounds(15,15,15,15);this.theme=OpenLayers._getScriptLocation()+'theme/default/style.css';this.options=OpenLayers.Util.extend({},options);OpenLayers.Util.extend(this,options);var projCode=this.projection instanceof OpenLayers.Projection?this.projection.projCode:this.projection;OpenLayers.Util.applyDefaults(this,OpenLayers.Projection.defaults[projCode]);if(this.maxExtent&&!(this.maxExtent instanceof OpenLayers.Bounds)){this.maxExtent=new OpenLayers.Bounds(this.maxExtent);} +if(this.minExtent&&!(this.minExtent instanceof OpenLayers.Bounds)){this.minExtent=new OpenLayers.Bounds(this.minExtent);} +if(this.restrictedExtent&&!(this.restrictedExtent instanceof OpenLayers.Bounds)){this.restrictedExtent=new OpenLayers.Bounds(this.restrictedExtent);} +if(this.center&&!(this.center instanceof OpenLayers.LonLat)){this.center=new OpenLayers.LonLat(this.center);} +this.layers=[];this.id=OpenLayers.Util.createUniqueID("OpenLayers.Map_");this.div=OpenLayers.Util.getElement(div);if(!this.div){this.div=document.createElement("div");this.div.style.height="1px";this.div.style.width="1px";} +OpenLayers.Element.addClass(this.div,'olMap');var id=this.id+"_OpenLayers_ViewPort";this.viewPortDiv=OpenLayers.Util.createDiv(id,null,null,null,"relative",null,"hidden");this.viewPortDiv.style.width="100%";this.viewPortDiv.style.height="100%";this.viewPortDiv.className="olMapViewport";this.div.appendChild(this.viewPortDiv);this.events=new OpenLayers.Events(this,this.viewPortDiv,null,this.fallThrough,{includeXY:true});id=this.id+"_OpenLayers_Container";this.layerContainerDiv=OpenLayers.Util.createDiv(id);this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;this.layerContainerOriginPx={x:0,y:0};this.viewPortDiv.appendChild(this.layerContainerDiv);this.updateSize();if(this.eventListeners instanceof Object){this.events.on(this.eventListeners);} +if(this.autoUpdateSize===true){this.updateSizeDestroy=OpenLayers.Function.bind(this.updateSize,this);OpenLayers.Event.observe(window,'resize',this.updateSizeDestroy);} +if(this.theme){var addNode=true;var nodes=document.getElementsByTagName('link');for(var i=0,len=nodes.length;i=0;--i){this.controls[i].destroy();} +this.controls=null;} +if(this.layers!=null){for(var i=this.layers.length-1;i>=0;--i){this.layers[i].destroy(false);} +this.layers=null;} +if(this.viewPortDiv){this.div.removeChild(this.viewPortDiv);} +this.viewPortDiv=null;if(this.eventListeners){this.events.un(this.eventListeners);this.eventListeners=null;} +this.events.destroy();this.events=null;this.options=null;},setOptions:function(options){var updatePxExtent=this.minPx&&options.restrictedExtent!=this.restrictedExtent;OpenLayers.Util.extend(this,options);updatePxExtent&&this.moveTo(this.getCachedCenter(),this.zoom,{forceZoomChange:true});},getTileSize:function(){return this.tileSize;},getBy:function(array,property,match){var test=(typeof match.test=="function");var found=OpenLayers.Array.filter(this[array],function(item){return item[property]==match||(test&&match.test(item[property]));});return found;},getLayersBy:function(property,match){return this.getBy("layers",property,match);},getLayersByName:function(match){return this.getLayersBy("name",match);},getLayersByClass:function(match){return this.getLayersBy("CLASS_NAME",match);},getControlsBy:function(property,match){return this.getBy("controls",property,match);},getControlsByClass:function(match){return this.getControlsBy("CLASS_NAME",match);},getLayer:function(id){var foundLayer=null;for(var i=0,len=this.layers.length;ithis.layers.length){idx=this.layers.length;} +if(base!=idx){this.layers.splice(base,1);this.layers.splice(idx,0,layer);for(var i=0,len=this.layers.length;i=0;--i){this.removePopup(this.popups[i]);}} +popup.map=this;this.popups.push(popup);var popupDiv=popup.draw();if(popupDiv){popupDiv.style.zIndex=this.Z_INDEX_BASE['Popup']+ +this.popups.length;this.layerContainerDiv.appendChild(popupDiv);}},removePopup:function(popup){OpenLayers.Util.removeItem(this.popups,popup);if(popup.div){try{this.layerContainerDiv.removeChild(popup.div);} +catch(e){}} +popup.map=null;},getSize:function(){var size=null;if(this.size!=null){size=this.size.clone();} +return size;},updateSize:function(){var newSize=this.getCurrentSize();if(newSize&&!isNaN(newSize.h)&&!isNaN(newSize.w)){this.events.clearMouseCache();var oldSize=this.getSize();if(oldSize==null){this.size=oldSize=newSize;} +if(!newSize.equals(oldSize)){this.size=newSize;for(var i=0,len=this.layers.length;i=this.minPx.x+xRestriction?Math.round(dx):0;dy=y<=this.maxPx.y-yRestriction&&y>=this.minPx.y+yRestriction?Math.round(dy):0;if(dx||dy){if(!this.dragging){this.dragging=true;this.events.triggerEvent("movestart");} +this.center=null;if(dx){this.layerContainerDiv.style.left=(this.layerContainerOriginPx.x-=dx)+"px";this.minPx.x-=dx;this.maxPx.x-=dx;} +if(dy){this.layerContainerDiv.style.top=(this.layerContainerOriginPx.y-=dy)+"px";this.minPx.y-=dy;this.maxPx.y-=dy;} +var layer,i,len;for(i=0,len=this.layers.length;imaxResolution){if(this.fractionalZoom){zoom=this.getZoomForResolution(maxResolution);}else{for(var i=zoom|0,ii=resolutions.length;ithis.restrictedExtent.getWidth()){lonlat=new OpenLayers.LonLat(maxCenter.lon,lonlat.lat);}else if(extent.leftthis.restrictedExtent.right){lonlat=lonlat.add(this.restrictedExtent.right- +extent.right,0);} +if(extent.getHeight()>this.restrictedExtent.getHeight()){lonlat=new OpenLayers.LonLat(lonlat.lon,maxCenter.lat);}else if(extent.bottomthis.restrictedExtent.top){lonlat=lonlat.add(0,this.restrictedExtent.top- +extent.top);}}} +var zoomChanged=forceZoomChange||((this.isValidZoomLevel(zoom))&&(zoom!=this.getZoom()));var centerChanged=(this.isValidLonLat(lonlat))&&(!lonlat.equals(this.center));if(zoomChanged||centerChanged||dragging){dragging||this.events.triggerEvent("movestart");if(centerChanged){if(!zoomChanged&&this.center){this.centerLayerContainer(lonlat);} +this.center=lonlat.clone();} +var res=zoomChanged?this.getResolutionForZoom(zoom):this.getResolution();if(zoomChanged||this.layerContainerOrigin==null){this.layerContainerOrigin=this.getCachedCenter();var style=this.layerContainerDiv.style;style.left="0px";style.top="0px";this.layerContainerOriginPx.x=0;this.layerContainerOriginPx.y=0;var maxExtent=this.getMaxExtent({restricted:true});var maxExtentCenter=maxExtent.getCenterLonLat();var lonDelta=this.center.lon-maxExtentCenter.lon;var latDelta=maxExtentCenter.lat-this.center.lat;var extentWidth=Math.round(maxExtent.getWidth()/res);var extentHeight=Math.round(maxExtent.getHeight()/res);this.minPx={x:(this.size.w-extentWidth)/2-lonDelta/res,y:(this.size.h-extentHeight)/2-latDelta/res};this.maxPx={x:this.minPx.x+Math.round(maxExtent.getWidth()/res),y:this.minPx.y+Math.round(maxExtent.getHeight()/res)};} +if(zoomChanged){this.zoom=zoom;this.resolution=res;} +var bounds=this.getExtent();if(this.baseLayer.visibility){this.baseLayer.moveTo(bounds,zoomChanged,options.dragging);options.dragging||this.baseLayer.events.triggerEvent("moveend",{zoomChanged:zoomChanged});} +bounds=this.baseLayer.getExtent();for(var i=this.layers.length-1;i>=0;--i){var layer=this.layers[i];if(layer!==this.baseLayer&&!layer.isBaseLayer){var inRange=layer.calculateInRange();if(layer.inRange!=inRange){layer.inRange=inRange;if(!inRange){layer.display(false);} +this.events.triggerEvent("changelayer",{layer:layer,property:"visibility"});} +if(inRange&&layer.visibility){layer.moveTo(bounds,zoomChanged,options.dragging);options.dragging||layer.events.triggerEvent("moveend",{zoomChanged:zoomChanged});}}} +this.events.triggerEvent("move");dragging||this.events.triggerEvent("moveend");if(zoomChanged){for(var i=0,len=this.popups.length;i=0)&&(zoomLevel0){resolution=this.layers[0].getResolution();} +return resolution;},getUnits:function(){var units=null;if(this.baseLayer!=null){units=this.baseLayer.units;} +return units;},getScale:function(){var scale=null;if(this.baseLayer!=null){var res=this.getResolution();var units=this.baseLayer.units;scale=OpenLayers.Util.getScaleFromResolution(res,units);} +return scale;},getZoomForExtent:function(bounds,closest){var zoom=null;if(this.baseLayer!=null){zoom=this.baseLayer.getZoomForExtent(bounds,closest);} +return zoom;},getResolutionForZoom:function(zoom){var resolution=null;if(this.baseLayer){resolution=this.baseLayer.getResolutionForZoom(zoom);} +return resolution;},getZoomForResolution:function(resolution,closest){var zoom=null;if(this.baseLayer!=null){zoom=this.baseLayer.getZoomForResolution(resolution,closest);} +return zoom;},zoomTo:function(zoom){if(this.isValidZoomLevel(zoom)){this.setCenter(null,zoom);}},zoomIn:function(){this.zoomTo(this.getZoom()+1);},zoomOut:function(){this.zoomTo(this.getZoom()-1);},zoomToExtent:function(bounds,closest){if(!(bounds instanceof OpenLayers.Bounds)){bounds=new OpenLayers.Bounds(bounds);} +var center=bounds.getCenterLonLat();if(this.baseLayer.wrapDateLine){var maxExtent=this.getMaxExtent();bounds=bounds.clone();while(bounds.right=0){this.initResolutions();if(reinitialize&&this.map.baseLayer===this){this.map.setCenter(this.map.getCenter(),this.map.getZoomForResolution(resolution),false,true);this.map.events.triggerEvent("changebaselayer",{layer:this});} +break;}}}},onMapResize:function(){},redraw:function(){var redrawn=false;if(this.map){this.inRange=this.calculateInRange();var extent=this.getExtent();if(extent&&this.inRange&&this.visibility){var zoomChanged=true;this.moveTo(extent,zoomChanged,false);this.events.triggerEvent("moveend",{"zoomChanged":zoomChanged});redrawn=true;}} +return redrawn;},moveTo:function(bounds,zoomChanged,dragging){var display=this.visibility;if(!this.isBaseLayer){display=display&&this.inRange;} +this.display(display);},moveByPx:function(dx,dy){},setMap:function(map){if(this.map==null){this.map=map;this.maxExtent=this.maxExtent||this.map.maxExtent;this.minExtent=this.minExtent||this.map.minExtent;this.projection=this.projection||this.map.projection;if(typeof this.projection=="string"){this.projection=new OpenLayers.Projection(this.projection);} +this.units=this.projection.getUnits()||this.units||this.map.units;this.initResolutions();if(!this.isBaseLayer){this.inRange=this.calculateInRange();var show=((this.visibility)&&(this.inRange));this.div.style.display=show?"":"none";} +this.setTileSize();}},afterAdd:function(){},removeMap:function(map){},getImageSize:function(bounds){return(this.imageSize||this.tileSize);},setTileSize:function(size){var tileSize=(size)?size:((this.tileSize)?this.tileSize:this.map.getTileSize());this.tileSize=tileSize;if(this.gutter){this.imageSize=new OpenLayers.Size(tileSize.w+(2*this.gutter),tileSize.h+(2*this.gutter));}},getVisibility:function(){return this.visibility;},setVisibility:function(visibility){if(visibility!=this.visibility){this.visibility=visibility;this.display(visibility);this.redraw();if(this.map!=null){this.map.events.triggerEvent("changelayer",{layer:this,property:"visibility"});} +this.events.triggerEvent("visibilitychanged");}},display:function(display){if(display!=(this.div.style.display!="none")){this.div.style.display=(display&&this.calculateInRange())?"block":"none";}},calculateInRange:function(){var inRange=false;if(this.alwaysInRange){inRange=true;}else{if(this.map){var resolution=this.map.getResolution();inRange=((resolution>=this.minResolution)&&(resolution<=this.maxResolution));}} +return inRange;},setIsBaseLayer:function(isBaseLayer){if(isBaseLayer!=this.isBaseLayer){this.isBaseLayer=isBaseLayer;if(this.map!=null){this.map.events.triggerEvent("changebaselayer",{layer:this});}}},initResolutions:function(){var i,len,p;var props={},alwaysInRange=true;for(i=0,len=this.RESOLUTION_PROPERTIES.length;i=resolution){highRes=res;lowZoom=i;} +if(res<=resolution){lowRes=res;highZoom=i;break;}} +var dRes=highRes-lowRes;if(dRes>0){zoom=lowZoom+((highRes-resolution)/dRes);}else{zoom=lowZoom;}}else{var diff;var minDiff=Number.POSITIVE_INFINITY;for(i=0,len=this.resolutions.length;iminDiff){break;} +minDiff=diff;}else{if(this.resolutions[i]=0&&row=0;i--){newResolution=this.serverResolutions[i];newDistance=Math.abs(newResolution-resolution);if(newDistance>distance){break;} +distance=newDistance;serverResolution=newResolution;} +resolution=serverResolution;} +return resolution;},getServerZoom:function(){var resolution=this.getServerResolution();return this.serverResolutions?OpenLayers.Util.indexOf(this.serverResolutions,resolution):this.map.getZoomForResolution(resolution)+(this.zoomOffset||0);},applyBackBuffer:function(resolution){if(this.backBufferTimerId!==null){this.removeBackBuffer();} +var backBuffer=this.backBuffer;if(!backBuffer){backBuffer=this.createBackBuffer();if(!backBuffer){return;} +this.div.insertBefore(backBuffer,this.div.firstChild);this.backBuffer=backBuffer;var topLeftTileBounds=this.grid[0][0].bounds;this.backBufferLonLat={lon:topLeftTileBounds.left,lat:topLeftTileBounds.top};this.backBufferResolution=this.gridResolution;} +var ratio=this.backBufferResolution/resolution;var tiles=backBuffer.childNodes,tile;for(var i=tiles.length-1;i>=0;--i){tile=tiles[i];tile.style.top=((ratio*tile._i*tile._h)|0)+'px';tile.style.left=((ratio*tile._j*tile._w)|0)+'px';tile.style.width=Math.round(ratio*tile._w)+'px';tile.style.height=Math.round(ratio*tile._h)+'px';} +var position=this.getViewPortPxFromLonLat(this.backBufferLonLat,resolution);var leftOffset=this.map.layerContainerOriginPx.x;var topOffset=this.map.layerContainerOriginPx.y;backBuffer.style.left=Math.round(position.x-leftOffset)+'px';backBuffer.style.top=Math.round(position.y-topOffset)+'px';},createBackBuffer:function(){var backBuffer;if(this.grid.length>0){backBuffer=document.createElement('div');backBuffer.id=this.div.id+'_bb';backBuffer.className='olBackBuffer';backBuffer.style.position='absolute';for(var i=0,lenI=this.grid.length;i=bounds.bottom-tilelat*this.buffer)||rowidx-tileSize.w*(buffer-1)){this.shiftColumn(true,tileSize);}else if(tlViewPort.x<-tileSize.w*buffer){this.shiftColumn(false,tileSize);}else if(tlViewPort.y>-tileSize.h*(buffer-1)){this.shiftRow(true,tileSize);}else if(tlViewPort.y<-tileSize.h*buffer){this.shiftRow(false,tileSize);}else{break;}}},shiftRow:function(prepend,tileSize){var modelRowIndex=(prepend)?0:(this.grid.length-1);var grid=this.grid;var modelRow=grid[modelRowIndex];var sign=prepend?-1:1;var deltaLat=this.getServerResolution()*-sign*this.tileSize.h;var row=(prepend)?grid.pop():grid.shift();for(var i=0,len=modelRow.length;irows){var row=this.grid.pop();for(i=0,l=row.length;icolumns){var row=this.grid[i];var tile=row.pop();this.destroyTile(tile);}}},onMapResize:function(){if(this.singleTile){this.clearGrid();this.setTileSize();}},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.XYZ=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:true,sphericalMercator:false,zoomOffset:0,serverResolutions:null,initialize:function(name,url,options){if(options&&options.sphericalMercator||this.sphericalMercator){options=OpenLayers.Util.extend({projection:"EPSG:900913",numZoomLevels:19},options);} +OpenLayers.Layer.Grid.prototype.initialize.apply(this,[name||this.name,url||this.url,{},options]);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.XYZ(this.name,this.url,this.getOptions());} +obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},getURL:function(bounds){var xyz=this.getXYZ(bounds);var url=this.url;if(OpenLayers.Util.isArray(url)){var s=''+xyz.x+xyz.y+xyz.z;url=this.selectUrl(s,url);} +return OpenLayers.String.format(url,xyz);},getXYZ:function(bounds){var res=this.getServerResolution();var x=Math.round((bounds.left-this.maxExtent.left)/(res*this.tileSize.w));var y=Math.round((this.maxExtent.top-bounds.top)/(res*this.tileSize.h));var z=this.getServerZoom();if(this.wrapDateLine){var limit=Math.pow(2,z);x=((x%limit)+limit)%limit;} +return{'x':x,'y':y,'z':z};},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"});OpenLayers.Layer.OSM=OpenLayers.Class(OpenLayers.Layer.XYZ,{name:"OpenStreetMap",url:['http://a.tile.openstreetmap.org/${z}/${x}/${y}.png','http://b.tile.openstreetmap.org/${z}/${x}/${y}.png','http://c.tile.openstreetmap.org/${z}/${x}/${y}.png'],attribution:"Data CC-By-SA by OpenStreetMap",sphericalMercator:true,wrapDateLine:true,tileOptions:null,initialize:function(name,url,options){OpenLayers.Layer.XYZ.prototype.initialize.apply(this,arguments);this.tileOptions=OpenLayers.Util.extend({crossOriginKeyword:'anonymous'},this.options&&this.options.tileOptions);},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=OpenLayers.Class({container:null,root:null,extent:null,locked:false,size:null,resolution:null,map:null,featureDx:0,initialize:function(containerID,options){this.container=OpenLayers.Util.getElement(containerID);OpenLayers.Util.extend(this,options);},destroy:function(){this.container=null;this.extent=null;this.size=null;this.resolution=null;this.map=null;},supported:function(){return false;},setExtent:function(extent,resolutionChanged){this.extent=extent.clone();if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){var ratio=extent.getWidth()/this.map.getExtent().getWidth(),extent=extent.scale(1/ratio);this.extent=extent.wrapDateLine(this.map.getMaxExtent()).scale(ratio);} +if(resolutionChanged){this.resolution=null;} +return true;},setSize:function(size){this.size=size.clone();this.resolution=null;},getResolution:function(){this.resolution=this.resolution||this.map.getResolution();return this.resolution;},drawFeature:function(feature,style){if(style==null){style=feature.style;} +if(feature.geometry){var bounds=feature.geometry.getBounds();if(bounds){var worldBounds;if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){worldBounds=this.map.getMaxExtent();} +if(!bounds.intersectsBounds(this.extent,{worldBounds:worldBounds})){style={display:"none"};}else{this.calculateFeatureDx(bounds,worldBounds);} +var rendered=this.drawGeometry(feature.geometry,style,feature.id);if(style.display!="none"&&style.label&&rendered!==false){var location=feature.geometry.getCentroid();if(style.labelXOffset||style.labelYOffset){var xOffset=isNaN(style.labelXOffset)?0:style.labelXOffset;var yOffset=isNaN(style.labelYOffset)?0:style.labelYOffset;var res=this.getResolution();location.move(xOffset*res,yOffset*res);} +this.drawText(feature.id,style,location);}else{this.removeText(feature.id);} +return rendered;}}},calculateFeatureDx:function(bounds,worldBounds){this.featureDx=0;if(worldBounds){var worldWidth=worldBounds.getWidth(),rendererCenterX=(this.extent.left+this.extent.right)/2,featureCenterX=(bounds.left+bounds.right)/2,worldsAway=Math.round((featureCenterX-rendererCenterX)/worldWidth);this.featureDx=worldsAway*worldWidth;}},drawGeometry:function(geometry,style,featureId){},drawText:function(featureId,style,location){},removeText:function(featureId){},clear:function(){},getFeatureIdFromEvent:function(evt){},eraseFeatures:function(features){if(!(OpenLayers.Util.isArray(features))){features=[features];} +for(var i=0,len=features.length;i=16777216){this.hitOverflow=id-16777215;id=id%16777216+1;} +var hex="000000"+id.toString(16);var len=hex.length;hex="#"+hex.substring(len-6,len);return hex;},setHitContextStyle:function(type,featureId,symbolizer,strokeScaling){var hex=this.featureIdToHex(featureId);if(type=="fill"){this.hitContext.globalAlpha=1.0;this.hitContext.fillStyle=hex;}else if(type=="stroke"){this.hitContext.globalAlpha=1.0;this.hitContext.strokeStyle=hex;if(typeof strokeScaling==="undefined"){this.hitContext.lineWidth=symbolizer.strokeWidth+2;}else{if(!isNaN(strokeScaling)){this.hitContext.lineWidth=symbolizer.strokeWidth+2.0/strokeScaling;}}}else{this.hitContext.globalAlpha=0;this.hitContext.lineWidth=1;}},drawPoint:function(geometry,style,featureId){if(style.graphic!==false){if(style.externalGraphic){this.drawExternalGraphic(geometry,style,featureId);}else if(style.graphicName&&(style.graphicName!="circle")){this.drawNamedSymbol(geometry,style,featureId);}else{var pt=this.getLocalXY(geometry);var p0=pt[0];var p1=pt[1];if(!isNaN(p0)&&!isNaN(p1)){var twoPi=Math.PI*2;var radius=style.pointRadius;if(style.fill!==false){this.setCanvasStyle("fill",style);this.canvas.beginPath();this.canvas.arc(p0,p1,radius,0,twoPi,true);this.canvas.fill();if(this.hitDetection){this.setHitContextStyle("fill",featureId,style);this.hitContext.beginPath();this.hitContext.arc(p0,p1,radius,0,twoPi,true);this.hitContext.fill();}} +if(style.stroke!==false){this.setCanvasStyle("stroke",style);this.canvas.beginPath();this.canvas.arc(p0,p1,radius,0,twoPi,true);this.canvas.stroke();if(this.hitDetection){this.setHitContextStyle("stroke",featureId,style);this.hitContext.beginPath();this.hitContext.arc(p0,p1,radius,0,twoPi,true);this.hitContext.stroke();} +this.setCanvasStyle("reset");}}}}},drawLineString:function(geometry,style,featureId){style=OpenLayers.Util.applyDefaults({fill:false},style);this.drawLinearRing(geometry,style,featureId);},drawLinearRing:function(geometry,style,featureId){if(style.fill!==false){this.setCanvasStyle("fill",style);this.renderPath(this.canvas,geometry,style,featureId,"fill");if(this.hitDetection){this.setHitContextStyle("fill",featureId,style);this.renderPath(this.hitContext,geometry,style,featureId,"fill");}} +if(style.stroke!==false){this.setCanvasStyle("stroke",style);this.renderPath(this.canvas,geometry,style,featureId,"stroke");if(this.hitDetection){this.setHitContextStyle("stroke",featureId,style);this.renderPath(this.hitContext,geometry,style,featureId,"stroke");}} +this.setCanvasStyle("reset");},renderPath:function(context,geometry,style,featureId,type){var components=geometry.components;var len=components.length;context.beginPath();var start=this.getLocalXY(components[0]);var x=start[0];var y=start[1];if(!isNaN(x)&&!isNaN(y)){context.moveTo(start[0],start[1]);for(var i=1;i1){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);return this.getNextElement(rightIndex);},remove:function(node){var nodeId=node.id;var arrayIndex=OpenLayers.Util.indexOf(this.order,nodeId);if(arrayIndex>=0){this.order.splice(arrayIndex,1);delete this.indices[nodeId];if(this.order.length>0){var lastId=this.order[this.order.length-1];this.maxZIndex=this.indices[lastId];}else{this.maxZIndex=0;}}},clear:function(){this.order=[];this.indices={};this.maxZIndex=0;},exists:function(node){return(this.indices[node.id]!=null);},getZIndex:function(node){return node._style.graphicZIndex;},determineZIndex:function(node){var zIndex=node._style.graphicZIndex;if(zIndex==null){zIndex=this.maxZIndex;node._style.graphicZIndex=zIndex;}else if(zIndex>this.maxZIndex){this.maxZIndex=zIndex;}},getNextElement:function(index){var nextIndex=index+1;if(nextIndexextent.left&&world.rightextent.left&&world.left0;},CLASS_NAME:"OpenLayers.Protocol.Response"});OpenLayers.Protocol.Response.SUCCESS=1;OpenLayers.Protocol.Response.FAILURE=0;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);};OpenLayers.Protocol.WFS.fromWMSLayer=function(layer,options){var typeName,featurePrefix;var param=layer.params["LAYERS"];var parts=(OpenLayers.Util.isArray(param)?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));};OpenLayers.Protocol.WFS.DEFAULTS={"version":"1.0.0"};OpenLayers.Strategy=OpenLayers.Class({layer:null,options:null,active:null,autoActivate:true,autoDestroy:true,initialize:function(options){OpenLayers.Util.extend(this,options);this.options=options;this.active=false;},destroy:function(){this.deactivate();this.layer=null;this.options=null;},setLayer:function(layer){this.layer=layer;},activate:function(){if(!this.active){this.active=true;return true;} +return false;},deactivate:function(){if(this.active){this.active=false;return true;} +return false;},CLASS_NAME:"OpenLayers.Strategy"});OpenLayers.Strategy.BBOX=OpenLayers.Class(OpenLayers.Strategy,{bounds:null,resolution:null,ratio:2,resFactor:null,response:null,activate:function(){var activated=OpenLayers.Strategy.prototype.activate.call(this);if(activated){this.layer.events.on({"moveend":this.update,"refresh":this.update,"visibilitychanged":this.update,scope:this});this.update();} +return activated;},deactivate:function(){var deactivated=OpenLayers.Strategy.prototype.deactivate.call(this);if(deactivated){this.layer.events.un({"moveend":this.update,"refresh":this.update,"visibilitychanged":this.update,scope:this});} +return deactivated;},update:function(options){var mapBounds=this.getMapBounds();if(mapBounds!==null&&((options&&options.force)||(this.layer.visibility&&this.layer.calculateInRange()&&this.invalidBounds(mapBounds)))){this.calculateBounds(mapBounds);this.resolution=this.layer.map.getResolution();this.triggerRead(options);}},getMapBounds:function(){if(this.layer.map===null){return null;} +var bounds=this.layer.map.getExtent();if(bounds&&!this.layer.projection.equals(this.layer.map.getProjectionObject())){bounds=bounds.clone().transform(this.layer.map.getProjectionObject(),this.layer.projection);} +return bounds;},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;},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));},triggerRead:function(options){if(this.response&&!(options&&options.noAbort===true)){this.layer.protocol.abort(this.response);this.layer.events.triggerEvent("loadend");} +this.layer.events.triggerEvent("loadstart");this.response=this.layer.protocol.read(OpenLayers.Util.applyDefaults({filter:this.createFilter(),callback:this.merge,scope:this},options));},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;},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-1;},handle:function(evt){if(this.feature&&!this.feature.layer){this.feature=null;} +var type=evt.type;var handled=false;var previouslyIn=!!(this.feature);var click=(type=="click"||type=="dblclick"||type=="touchstart");this.feature=this.layer.getFeatureFromEvent(evt);if(this.feature&&!this.feature.layer){this.feature=null;} +if(this.lastFeature&&!this.lastFeature.layer){this.lastFeature=null;} +if(this.feature){if(type==="touchstart"){OpenLayers.Event.stop(evt);} +var inNew=(this.feature!=this.lastFeature);if(this.geometryTypeMatches(this.feature)){if(previouslyIn&&inNew){if(this.lastFeature){this.triggerCallback(type,'out',[this.lastFeature]);} +this.triggerCallback(type,'in',[this.feature]);}else if(!previouslyIn||click){this.triggerCallback(type,'in',[this.feature]);} +this.lastFeature=this.feature;handled=true;}else{if(this.lastFeature&&(previouslyIn&&inNew||click)){this.triggerCallback(type,'out',[this.lastFeature]);} +this.feature=null;}}else{if(this.lastFeature&&(previouslyIn||click)){this.triggerCallback(type,'out',[this.lastFeature]);}} +return handled;},triggerCallback:function(type,mode,args){var key=this.EVENTMAP[type][mode];if(key){if(type=='click'&&this.up&&this.down){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);}}},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;},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.touch=false;this.map.events.un({"removelayer":this.handleMapEvents,"changelayer":this.handleMapEvents,scope:this});deactivated=true;} +return deactivated;},handleMapEvents:function(evt){if(evt.type=="removelayer"||evt.property=="order"){this.moveLayerToTop();}},moveLayerToTop:function(){var index=Math.max(this.map.Z_INDEX_BASE['Feature']-1,this.layer.getZIndex())+1;this.layer.setZIndex(index);},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.StyleMap=OpenLayers.Class({styles:null,extendDefault:true,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"])};if(style instanceof OpenLayers.Style){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){this.styles[key]=style[key];}else if(typeof style[key]=="object"){this.styles[key]=new OpenLayers.Style(style[key]);}else{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);},destroy:function(){for(var key in this.styles){this.styles[key].destroy();} +this.styles=null;},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));},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=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:false,isFixed:false,features:null,filter:null,selectedFeatures:null,unrenderedFeatures:null,reportError:true,style:null,styleMap:null,strategies:null,protocol:null,renderers:['SVG','VML','Canvas'],renderer:null,rendererOptions:null,geometryType:null,drawn:false,ratio:1,initialize:function(name,options){OpenLayers.Layer.prototype.initialize.apply(this,arguments);if(!this.renderer||!this.renderer.supported()){this.assignRenderer();} +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={};if(this.strategies){for(var i=0,len=this.strategies.length;i=0;i--){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.layer=null;if(feature.geometry){this.renderer.eraseFeatures(feature);} +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});}},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});}},destroyFeatures:function(features,options){var all=(features==undefined);if(all){features=this.features;} +if(features){this.removeFeatures(features,options);for(var i=features.length-1;i>=0;i--){features[i].destroy();}}},drawFeature:function(feature,style){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);}} +var drawn=this.renderer.drawFeature(feature,style);if(drawn===false||drawn===null){this.unrenderedFeatures[feature.id]=feature;}else{delete this.unrenderedFeatures[feature.id];}},eraseFeatures:function(features){this.renderer.eraseFeatures(features);},getFeatureFromEvent:function(evt){if(!this.renderer){throw new Error('getFeatureFromEvent called on layer with no '+'renderer. This usually means you destroyed a '+'layer, but not some handler which is associated '+'with it.');} +var feature=null;var featureId=this.renderer.getFeatureIdFromEvent(evt);if(featureId){if(typeof featureId==="string"){feature=this.getFeatureById(featureId);}else{feature=featureId;}} +return feature;},getFeatureBy:function(property,value){var feature=null;for(var i=0,len=this.features.length;i0)){var geometry=null;for(var i=0,len=features.length;inumExcept){feature=layer.selectedFeatures[numExcept];if(!options||options.except!=feature){this.unselect(feature);}else{++numExcept;}}}},clickFeature:function(feature){if(!this.hover){var selected=(OpenLayers.Util.indexOf(feature.layer.selectedFeatures,feature)>-1);if(selected){if(this.toggleSelect()){this.unselect(feature);}else if(!this.multipleSelect()){this.unselectAll({except:feature});}}else{if(!this.multipleSelect()){this.unselectAll({except:feature});} +this.select(feature);}}},multipleSelect:function(){return this.multiple||(this.handlers.feature.evt&&this.handlers.feature.evt[this.multipleKey]);},toggleSelect:function(){return this.toggle||(this.handlers.feature.evt&&this.handlers.feature.evt[this.toggleKey]);},clickoutFeature:function(feature){if(!this.hover&&this.clickout){this.unselectAll();}},overFeature:function(feature){var layer=feature.layer;if(this.hover){if(this.highlightOnly){this.highlight(feature);}else if(OpenLayers.Util.indexOf(layer.selectedFeatures,feature)==-1){this.select(feature);}}},outFeature:function(feature){if(this.hover){if(this.highlightOnly){if(feature._lastHighlighter==this.id){if(feature._prevHighlighter&&feature._prevHighlighter!=this.id){delete feature._lastHighlighter;var control=this.map.getControl(feature._prevHighlighter);if(control){control.highlight(feature);}}else{this.unhighlight(feature);}}}else{this.unselect(feature);}}},highlight:function(feature){var layer=feature.layer;var cont=this.events.triggerEvent("beforefeaturehighlighted",{feature:feature});if(cont!==false){feature._prevHighlighter=feature._lastHighlighter;feature._lastHighlighter=this.id;var style=this.selectStyle||this.renderIntent;layer.drawFeature(feature,style);this.events.triggerEvent("featurehighlighted",{feature:feature});}},unhighlight:function(feature){var layer=feature.layer;if(feature._prevHighlighter==undefined){delete feature._lastHighlighter;}else if(feature._prevHighlighter==this.id){delete feature._prevHighlighter;}else{feature._lastHighlighter=feature._prevHighlighter;delete feature._prevHighlighter;} +layer.drawFeature(feature,feature.style||feature.layer.style||"default");this.events.triggerEvent("featureunhighlighted",{feature:feature});},select:function(feature){var cont=this.onBeforeSelect.call(this.scope,feature);var layer=feature.layer;if(cont!==false){cont=layer.events.triggerEvent("beforefeatureselected",{feature:feature});if(cont!==false){layer.selectedFeatures.push(feature);this.highlight(feature);if(!this.handlers.feature.lastFeature){this.handlers.feature.lastFeature=layer.selectedFeatures[0];} +layer.events.triggerEvent("featureselected",{feature:feature});this.onSelect.call(this.scope,feature);}}},unselect:function(feature){var layer=feature.layer;this.unhighlight(feature);OpenLayers.Util.removeItem(layer.selectedFeatures,feature);layer.events.triggerEvent("featureunselected",{feature:feature});this.onUnselect.call(this.scope,feature);},selectBox:function(position){if(position instanceof OpenLayers.Bounds){var minXY=this.map.getLonLatFromPixel({x:position.left,y:position.bottom});var maxXY=this.map.getLonLatFromPixel({x:position.right,y:position.top});var bounds=new OpenLayers.Bounds(minXY.lon,minXY.lat,maxXY.lon,maxXY.lat);if(!this.multipleSelect()){this.unselectAll();} +var prevMultiple=this.multiple;this.multiple=true;var layers=this.layers||[this.layer];this.events.triggerEvent("boxselectionstart",{layers:layers});var layer;for(var l=0;l-1){if(bounds.toGeometry().intersects(feature.geometry)){if(OpenLayers.Util.indexOf(layer.selectedFeatures,feature)==-1){this.select(feature);}}}}} +this.multiple=prevMultiple;this.events.triggerEvent("boxselectionend",{layers:layers});}},setMap:function(map){this.handlers.feature.setMap(map);if(this.box){this.handlers.box.setMap(map);} +OpenLayers.Control.prototype.setMap.apply(this,arguments);},setLayer:function(layers){var isActive=this.active;this.unselectAll();this.deactivate();if(this.layers){this.layer.destroy();this.layers=null;} +this.initLayer(layers);this.handlers.feature.layer=this.layer;if(isActive){this.activate();}},CLASS_NAME:"OpenLayers.Control.SelectFeature"});OpenLayers.Handler.Point=OpenLayers.Class(OpenLayers.Handler,{point:null,layer:null,multi:false,citeCompliant:false,mouseDown:false,stoppedDown:null,lastDown:null,lastUp:null,persist:false,stopDown:false,stopUp:false,layerOptions:null,pixelTolerance:5,touch:false,lastTouchPx:null,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);},activate:function(){if(!OpenLayers.Handler.prototype.activate.apply(this,arguments)){return false;} +var options=OpenLayers.Util.extend({displayInLayerSwitcher:false,calculateInRange:OpenLayers.Function.True,wrapDateLine:this.citeCompliant},this.layerOptions);this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,options);this.map.addLayer(this.layer);return true;},createFeature:function(pixel){var lonlat=this.layer.getLonLatFromViewPortPx(pixel);var geometry=new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);this.point=new OpenLayers.Feature.Vector(geometry);this.callback("create",[this.point.geometry,this.point]);this.point.geometry.clearBounds();this.layer.addFeatures([this.point],{silent:true});},deactivate:function(){if(!OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){return false;} +this.cancel();if(this.layer.map!=null){this.destroyFeature(true);this.layer.destroy(false);} +this.layer=null;this.touch=false;return true;},destroyFeature:function(force){if(this.layer&&(force||!this.persist)){this.layer.destroyFeatures();} +this.point=null;},destroyPersistedFeature:function(){var layer=this.layer;if(layer&&layer.features.length>1){this.layer.features[0].destroy();}},finalize:function(cancel){var key=cancel?"cancel":"done";this.mouseDown=false;this.lastDown=null;this.lastUp=null;this.lastTouchPx=null;this.callback(key,[this.geometryClone()]);this.destroyFeature(cancel);},cancel:function(){this.finalize(true);},click:function(evt){OpenLayers.Event.stop(evt);return false;},dblclick:function(evt){OpenLayers.Event.stop(evt);return false;},modifyFeature:function(pixel){if(!this.point){this.createFeature(pixel);} +var lonlat=this.layer.getLonLatFromViewPortPx(pixel);this.point.geometry.x=lonlat.lon;this.point.geometry.y=lonlat.lat;this.callback("modify",[this.point.geometry,this.point,false]);this.point.geometry.clearBounds();this.drawFeature();},drawFeature:function(){this.layer.drawFeature(this.point,this.style);},getGeometry:function(){var geometry=this.point&&this.point.geometry;if(geometry&&this.multi){geometry=new OpenLayers.Geometry.MultiPoint([geometry]);} +return geometry;},geometryClone:function(){var geom=this.getGeometry();return geom&&geom.clone();},mousedown:function(evt){return this.down(evt);},touchstart:function(evt){if(!this.touch){this.touch=true;this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,mousemove:this.mousemove,click:this.click,dblclick:this.dblclick,scope:this});} +this.lastTouchPx=evt.xy;return this.down(evt);},mousemove:function(evt){return this.move(evt);},touchmove:function(evt){this.lastTouchPx=evt.xy;return this.move(evt);},mouseup:function(evt){return this.up(evt);},touchend:function(evt){evt.xy=this.lastTouchPx;return this.up(evt);},down:function(evt){this.mouseDown=true;this.lastDown=evt.xy;if(!this.touch){this.modifyFeature(evt.xy);} +this.stoppedDown=this.stopDown;return!this.stopDown;},move:function(evt){if(!this.touch&&(!this.mouseDown||this.stoppedDown)){this.modifyFeature(evt.xy);} +return true;},up:function(evt){this.mouseDown=false;this.stoppedDown=this.stopDown;if(!this.checkModifiers(evt)){return true;} +if(this.lastUp&&this.lastUp.equals(evt.xy)){return true;} +if(this.lastDown&&this.passesTolerance(this.lastDown,evt.xy,this.pixelTolerance)){if(this.touch){this.modifyFeature(evt.xy);} +if(this.persist){this.destroyPersistedFeature();} +this.lastUp=evt.xy;this.finalize();return!this.stopUp;}else{return true;}},mouseout:function(evt){if(OpenLayers.Util.mouseLeft(evt,this.map.viewPortDiv)){this.stoppedDown=this.stopDown;this.mouseDown=false;}},passesTolerance:function(pixel1,pixel2,tolerance){var passes=true;if(tolerance!=null&&pixel1&&pixel2){var dist=pixel1.distanceTo(pixel2);if(dist>tolerance){passes=false;}} +return passes;},CLASS_NAME:"OpenLayers.Handler.Point"});OpenLayers.Handler.Path=OpenLayers.Class(OpenLayers.Handler.Point,{line:null,maxVertices:null,doubleTouchTolerance:20,freehand:false,freehandToggle:'shiftKey',timerId:null,redoStack:null,createFeature:function(pixel){var lonlat=this.layer.getLonLatFromViewPortPx(pixel);var geometry=new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);this.point=new OpenLayers.Feature.Vector(geometry);this.line=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.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});},destroyFeature:function(force){OpenLayers.Handler.Point.prototype.destroyFeature.call(this,force);this.line=null;},destroyPersistedFeature:function(){var layer=this.layer;if(layer&&layer.features.length>2){this.layer.features[0].destroy();}},removePoint:function(){if(this.point){this.layer.removeFeatures([this.point]);}},addPoint:function(pixel){this.layer.removeFeatures([this.point]);var lonlat=this.layer.getLonLatFromViewPortPx(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.layer.addFeatures([this.point]);this.callback("point",[this.point.geometry,this.getGeometry()]);this.callback("modify",[this.point.geometry,this.getSketch()]);this.drawFeature();delete this.redoStack;},insertXY:function(x,y){this.line.geometry.addComponent(new OpenLayers.Geometry.Point(x,y),this.getCurrentPointIndex());this.drawFeature();delete this.redoStack;},insertDeltaXY:function(dx,dy){var previousIndex=this.getCurrentPointIndex()-1;var p0=this.line.geometry.components[previousIndex];if(p0&&!isNaN(p0.x)&&!isNaN(p0.y)){this.insertXY(p0.x+dx,p0.y+dy);}},insertDirectionLength:function(direction,length){direction*=Math.PI/180;var dx=length*Math.cos(direction);var dy=length*Math.sin(direction);this.insertDeltaXY(dx,dy);},insertDeflectionLength:function(deflection,length){var previousIndex=this.getCurrentPointIndex()-1;if(previousIndex>0){var p1=this.line.geometry.components[previousIndex];var p0=this.line.geometry.components[previousIndex-1];var theta=Math.atan2(p1.y-p0.y,p1.x-p0.x);this.insertDirectionLength((theta*180/Math.PI)+deflection,length);}},getCurrentPointIndex:function(){return this.line.geometry.components.length-1;},undo:function(){var geometry=this.line.geometry;var components=geometry.components;var index=this.getCurrentPointIndex()-1;var target=components[index];var undone=geometry.removeComponent(target);if(undone){if(!this.redoStack){this.redoStack=[];} +this.redoStack.push(target);this.drawFeature();} +return undone;},redo:function(){var target=this.redoStack&&this.redoStack.pop();if(target){this.line.geometry.addComponent(target,this.getCurrentPointIndex());this.drawFeature();} +return!!target;},freehandMode:function(evt){return(this.freehandToggle&&evt[this.freehandToggle])?!this.freehand:this.freehand;},modifyFeature:function(pixel,drawing){if(!this.line){this.createFeature(pixel);} +var lonlat=this.layer.getLonLatFromViewPortPx(pixel);this.point.geometry.x=lonlat.lon;this.point.geometry.y=lonlat.lat;this.callback("modify",[this.point.geometry,this.getSketch(),drawing]);this.point.geometry.clearBounds();this.drawFeature();},drawFeature:function(){this.layer.drawFeature(this.line,this.style);this.layer.drawFeature(this.point,this.style);},getSketch:function(){return this.line;},getGeometry:function(){var geometry=this.line&&this.line.geometry;if(geometry&&this.multi){geometry=new OpenLayers.Geometry.MultiLineString([geometry]);} +return geometry;},touchstart:function(evt){if(this.timerId&&this.passesTolerance(this.lastTouchPx,evt.xy,this.doubleTouchTolerance)){this.finishGeometry();window.clearTimeout(this.timerId);this.timerId=null;return false;}else{if(this.timerId){window.clearTimeout(this.timerId);this.timerId=null;} +this.timerId=window.setTimeout(OpenLayers.Function.bind(function(){this.timerId=null;},this),300);return OpenLayers.Handler.Point.prototype.touchstart.call(this,evt);}},down:function(evt){var stopDown=this.stopDown;if(this.freehandMode(evt)){stopDown=true;if(this.touch){this.modifyFeature(evt.xy,!!this.lastUp);OpenLayers.Event.stop(evt);}} +if(!this.touch&&(!this.lastDown||!this.passesTolerance(this.lastDown,evt.xy,this.pixelTolerance))){this.modifyFeature(evt.xy,!!this.lastUp);} +this.mouseDown=true;this.lastDown=evt.xy;this.stoppedDown=stopDown;return!stopDown;},move:function(evt){if(this.stoppedDown&&this.freehandMode(evt)){if(this.persist){this.destroyPersistedFeature();} +if(this.maxVertices&&this.line&&this.line.geometry.components.length===this.maxVertices){this.removePoint();this.finalize();}else{this.addPoint(evt.xy);} +return false;} +if(!this.touch&&(!this.mouseDown||this.stoppedDown)){this.modifyFeature(evt.xy,!!this.lastUp);} +return true;},up:function(evt){if(this.mouseDown&&(!this.lastUp||!this.lastUp.equals(evt.xy))){if(this.stoppedDown&&this.freehandMode(evt)){if(this.persist){this.destroyPersistedFeature();} +this.removePoint();this.finalize();}else{if(this.passesTolerance(this.lastDown,evt.xy,this.pixelTolerance)){if(this.touch){this.modifyFeature(evt.xy);} +if(this.lastUp==null&&this.persist){this.destroyPersistedFeature();} +this.addPoint(evt.xy);this.lastUp=evt.xy;if(this.line.geometry.components.length===this.maxVertices+1){this.finishGeometry();}}}} +this.stoppedDown=this.stopDown;this.mouseDown=false;return!this.stopUp;},finishGeometry:function(){var index=this.line.geometry.components.length-1;this.line.geometry.removeComponent(this.line.geometry.components[index]);this.removePoint();this.finalize();},dblclick:function(evt){if(!this.freehandMode(evt)){this.finishGeometry();} +return false;},CLASS_NAME:"OpenLayers.Handler.Path"});OpenLayers.Control.Attribution=OpenLayers.Class(OpenLayers.Control,{separator:", ",template:"${layers}",destroy:function(){this.map.events.un({"removelayer":this.updateAttribution,"addlayer":this.updateAttribution,"changelayer":this.updateAttribution,"changebaselayer":this.updateAttribution,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.map.events.on({'changebaselayer':this.updateAttribution,'changelayer':this.updateAttribution,'addlayer':this.updateAttribution,'removelayer':this.updateAttribution,scope:this});this.updateAttribution();return this.div;},updateAttribution:function(){var attributions=[];if(this.map&&this.map.layers){for(var i=0,len=this.map.layers.length;ithis.nbPoints){this.points.pop();}},end:function(xy){var last,now=new Date().getTime();for(var i=0,l=this.points.length,point;ithis.delay){break;} +last=point;} +if(!last){return;} +var time=new Date().getTime()-last.tick;var dist=Math.sqrt(Math.pow(xy.x-last.xy.x,2)+ +Math.pow(xy.y-last.xy.y,2));var speed=dist/time;if(speed==0||speed0){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=evt.xy;} +return true;},dragend: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;},down:function(evt){},move:function(evt){},up:function(evt){},out:function(evt){},mousedown:function(evt){return this.dragstart(evt);},touchstart:function(evt){if(!this.touch){this.touch=true;this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,mousemove:this.mousemove,click:this.click,scope:this});} +return this.dragstart(evt);},mousemove:function(evt){return this.dragmove(evt);},touchmove:function(evt){return this.dragmove(evt);},removeTimeout:function(){this.timeoutId=null;if(this.dragging){this.mousemove(this.lastMoveEvt);}},mouseup:function(evt){return this.dragend(evt);},touchend:function(evt){evt.xy=this.last;return this.dragend(evt);},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;},click:function(evt){return(this.start==this.last);},activate:function(){var activated=false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.dragging=false;activated=true;} +return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.touch=false;this.started=false;this.dragging=false;this.start=null;this.last=null;deactivated=true;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");} +return deactivated;},adjustXY:function(evt){var pos=OpenLayers.Util.pagePosition(this.map.viewPortDiv);evt.xy.x-=pos[0];evt.xy.y-=pos[1];},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);},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=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,boxDivClassName:'olHandlerBoxZoomBox',boxOffsets:null,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});},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);if(this.dragHandler){this.dragHandler.destroy();this.dragHandler=null;}},setMap:function(map){OpenLayers.Handler.prototype.setMap.apply(this,arguments);if(this.dragHandler){this.dragHandler.setMap(map);}},startBox:function(xy){this.callback("start",[]);this.zoomBox=OpenLayers.Util.createDiv('zoomBox',{x:-9999,y:-9999});this.zoomBox.className=this.boxDivClassName;this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE["Popup"]-1;this.map.viewPortDiv.appendChild(this.zoomBox);OpenLayers.Element.addClass(this.map.viewPortDiv,"olDrawBox");},moveBox:function(xy){var startX=this.dragHandler.start.x;var startY=this.dragHandler.start.y;var deltaX=Math.abs(startX-xy.x);var deltaY=Math.abs(startY-xy.y);var offset=this.getBoxOffsets();this.zoomBox.style.width=(deltaX+offset.width+1)+"px";this.zoomBox.style.height=(deltaY+offset.height+1)+"px";this.zoomBox.style.left=(xy.x5||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();} +this.removeBox();this.callback("done",[result]);},removeBox:function(){this.map.viewPortDiv.removeChild(this.zoomBox);this.zoomBox=null;this.boxOffsets=null;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDrawBox");},activate:function(){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.dragHandler.activate();return true;}else{return false;}},deactivate:function(){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){if(this.dragHandler.deactivate()){if(this.zoomBox){this.removeBox();}} +return true;}else{return false;}},getBoxOffsets:function(){if(!this.boxOffsets){var testDiv=document.createElement("div");testDiv.style.position="absolute";testDiv.style.border="1px solid black";testDiv.style.width="3px";document.body.appendChild(testDiv);var w3cBoxModel=testDiv.clientWidth==3;document.body.removeChild(testDiv);var left=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-left-width"));var right=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-right-width"));var top=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-top-width"));var bottom=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-bottom-width"));this.boxOffsets={left:left,right:right,top:top,bottom:bottom,width:w3cBoxModel===false?left+right:0,height:w3cBoxModel===false?top+bottom:0};} +return this.boxOffsets;},CLASS_NAME:"OpenLayers.Handler.Box"});OpenLayers.Control.ZoomBox=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,out:false,keyMask:null,alwaysZoom:false,zoomOnClick:true,draw:function(){this.handler=new OpenLayers.Handler.Box(this,{done:this.zoomBox},{keyMask:this.keyMask});},zoomBox:function(position){if(position instanceof OpenLayers.Bounds){var bounds;if(!this.out){var minXY=this.map.getLonLatFromPixel({x:position.left,y:position.bottom});var maxXY=this.map.getLonLatFromPixel({x:position.right,y:position.top});bounds=new OpenLayers.Bounds(minXY.lon,minXY.lat,maxXY.lon,maxXY.lat);}else{var pixWidth=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);} +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 if(this.zoomOnClick){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=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:false,interval:1,documentDrag:false,kinetic:null,enableKinetic:false,kineticInterval:10,draw:function(){if(this.enableKinetic){var config={interval:this.kineticInterval};if(typeof this.enableKinetic==="object"){config=OpenLayers.Util.extend(config,this.enableKinetic);} +this.kinetic=new OpenLayers.Kinetic(config);} +this.handler=new OpenLayers.Handler.Drag(this,{"move":this.panMap,"done":this.panMapDone,"down":this.panMapStart},{interval:this.interval,documentDrag:this.documentDrag});},panMapStart:function(){if(this.kinetic){this.kinetic.begin();}},panMap:function(xy){if(this.kinetic){this.kinetic.update(xy);} +this.panned=true;this.map.pan(this.handler.last.x-xy.x,this.handler.last.y-xy.y,{dragging:true,animate:false});},panMapDone:function(xy){if(this.panned){var res=null;if(this.kinetic){res=this.kinetic.end(xy);} +this.map.pan(this.handler.last.x-xy.x,this.handler.last.y-xy.y,{dragging:!!res,animate:false});if(res){var self=this;this.kinetic.move(res,function(x,y,end){self.map.pan(x,y,{dragging:!end,animate:false});});} +this.panned=false;}},CLASS_NAME:"OpenLayers.Control.DragPan"});OpenLayers.Handler.Click=OpenLayers.Class(OpenLayers.Handler,{delay:300,single:true,'double':false,pixelTolerance:0,dblclickTolerance:13,stopSingle:false,stopDouble:false,timerId:null,touch:false,down:null,last:null,first:null,rightclickTimerId:null,touchstart:function(evt){if(!this.touch){this.unregisterMouseListeners();this.touch=true;} +this.down=this.getEventInfo(evt);this.last=this.getEventInfo(evt);return true;},touchmove:function(evt){this.last=this.getEventInfo(evt);return true;},touchend:function(evt){if(this.down){evt.xy=this.last.xy;evt.lastTouches=this.last.touches;this.handleSingle(evt);this.down=null;} +return true;},unregisterMouseListeners:function(){this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,click:this.click,dblclick:this.dblclick,scope:this});},mousedown:function(evt){this.down=this.getEventInfo(evt);this.last=this.getEventInfo(evt);return true;},mouseup:function(evt){var propagate=true;if(this.checkModifiers(evt)&&this.control.handleRightClicks&&OpenLayers.Event.isRightClick(evt)){propagate=this.rightclick(evt);} +return propagate;},rightclick:function(evt){if(this.passesTolerance(evt)){if(this.rightclickTimerId!=null){this.clearTimer();this.callback('dblrightclick',[evt]);return!this.stopDouble;}else{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;},delayedRightCall:function(evt){this.rightclickTimerId=null;if(evt){this.callback('rightclick',[evt]);}},click:function(evt){if(!this.last){this.last=this.getEventInfo(evt);} +this.handleSingle(evt);return!this.stopSingle;},dblclick:function(evt){this.handleDouble(evt);return!this.stopDouble;},handleDouble:function(evt){if(this.passesDblclickTolerance(evt)){if(this["double"]){this.callback("dblclick",[evt]);} +this.clearTimer();}},handleSingle:function(evt){if(this.passesTolerance(evt)){if(this.timerId!=null){if(this.last.touches&&this.last.touches.length===1){if(this["double"]){OpenLayers.Event.stop(evt);} +this.handleDouble(evt);} +if(!this.last.touches||this.last.touches.length!==2){this.clearTimer();}}else{this.first=this.getEventInfo(evt);var clickEvent=this.single?OpenLayers.Util.extend({},evt):null;this.queuePotentialClick(clickEvent);}}},queuePotentialClick:function(evt){this.timerId=window.setTimeout(OpenLayers.Function.bind(this.delayedCall,this,evt),this.delay);},passesTolerance:function(evt){var passes=true;if(this.pixelTolerance!=null&&this.down&&this.down.xy){passes=this.pixelTolerance>=this.down.xy.distanceTo(evt.xy);if(passes&&this.touch&&this.down.touches.length===this.last.touches.length){for(var i=0,ii=this.down.touches.length;ithis.pixelTolerance){passes=false;break;}}}} +return passes;},getTouchDistance:function(from,to){return Math.sqrt(Math.pow(from.clientX-to.clientX,2)+ +Math.pow(from.clientY-to.clientY,2));},passesDblclickTolerance:function(evt){var passes=true;if(this.down&&this.first){passes=this.down.xy.distanceTo(this.first.xy)<=this.dblclickTolerance;} +return passes;},clearTimer:function(){if(this.timerId!=null){window.clearTimeout(this.timerId);this.timerId=null;} +if(this.rightclickTimerId!=null){window.clearTimeout(this.rightclickTimerId);this.rightclickTimerId=null;}},delayedCall:function(evt){this.timerId=null;if(evt){this.callback("click",[evt]);}},getEventInfo:function(evt){var touches;if(evt.touches){var len=evt.touches.length;touches=new Array(len);var touch;for(var i=0;i=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));if(!this.noMagic&&this.params.TRANSPARENT&&this.params.TRANSPARENT.toString().toLowerCase()=="true"){if((options==null)||(!options.isBaseLayer)){this.isBaseLayer=false;} +if(this.params.FORMAT=="image/jpeg"){this.params.FORMAT=OpenLayers.Util.alphaHack()?"image/gif":"image/png";}}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.getOptions());} +obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},reverseAxisOrder:function(){var projCode=this.projection.getCode();return parseFloat(this.params.VERSION)>=1.3&&!!(this.yx[projCode]||OpenLayers.Projection.defaults[projCode].yx);},getURL:function(bounds){bounds=this.adjustBounds(bounds);var imageSize=this.getImageSize();var newParams={};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;},mergeNewParams:function(newParams){var upperParams=OpenLayers.Util.upperCaseObject(newParams);var newArguments=[upperParams];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,newArguments);},getFullRequestString:function(newParams,altUrl){var mapProjection=this.map.getProjectionObject();var projectionCode=this.projection&&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;} +if(typeof this.params.TRANSPARENT=="boolean"){newParams.TRANSPARENT=this.params.TRANSPARENT?"TRUE":"FALSE";} +return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments);},CLASS_NAME:"OpenLayers.Layer.WMS"});OpenLayers.Renderer.SVG=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"http://www.w3.org/2000/svg",xlinkns:"http://www.w3.org/1999/xlink",MAX_PIXEL:15000,translationParameters:null,symbolMetrics:null,initialize:function(containerID){if(!this.supported()){return;} +OpenLayers.Renderer.Elements.prototype.initialize.apply(this,arguments);this.translationParameters={x:0,y:0};this.symbolMetrics={};},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")));},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);},setExtent:function(extent,resolutionChanged){var coordSysUnchanged=OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,arguments);var resolution=this.getResolution(),left=-extent.left/resolution,top=extent.top/resolution;if(resolutionChanged){this.left=left;this.top=top;var extentString="0 0 "+this.size.w+" "+this.size.h;this.rendererRoot.setAttributeNS(null,"viewBox",extentString);this.translate(this.xOffset,0);return true;}else{var inRange=this.translate(left-this.left+this.xOffset,top-this.top);if(!inRange){this.setExtent(extent,true);} +return coordSysUnchanged&&inRange;}},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;}},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);},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":nodeType="path";break;default:break;} +return nodeType;},setStyle:function(node,style,options){style=style||node._style;options=options||node._options;var title=style.title||style.graphicTitle;if(title){node.setAttributeNS(null,"title",title);var titleNode=node.getElementsByTagName("title");if(titleNode.length>0){titleNode[0].firstChild.textContent=title;}else{var label=this.nodeFactory(null,"title");label.textContent=title;node.appendChild(label);}} +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.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);node.onclick=OpenLayers.Event.preventDefault;}else if(this.isComplexSymbol(style.graphicName)){var offset=style.pointRadius*3;var size=offset*2;var src=this.importSymbol(style.graphicName);pos=this.getPosition(node);widthFactor=this.symbolMetrics[src.id][0]*3/size;var parent=node.parentNode;var nextSibling=node.nextSibling;if(parent){parent.removeChild(node);} +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);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[src.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");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;},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,",");}},createNode:function(type,id){var node=document.createElementNS(this.xmlns,type);if(id){node.setAttributeNS(null,"id",id);} +return node;},nodeTypeCompare:function(node,type){return(type==node.nodeName);},createRenderRoot:function(){var svg=this.nodeFactory(this.container.id+"_svgRoot","svg");svg.style.display="block";return svg;},createRoot:function(suffix){return this.nodeFactory(this.container.id+suffix,"g");},createDefs:function(){var defs=this.nodeFactory(this.container.id+"_defs","defs");this.rendererRoot.appendChild(defs);return defs;},drawPoint:function(node,geometry){return this.drawCircle(node,geometry,1);},drawCircle:function(node,geometry,radius){var resolution=this.getResolution();var x=((geometry.x-this.featureDx)/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;}},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;}},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;}},drawPolygon:function(node,geometry){var d="";var draw=true;var complete=true;var linearRingResult,path;for(var j=0,len=geometry.components.length;jnumRows){label.removeChild(label.lastChild);} +for(var i=0;i0){if(this.getShortString(components[i-1])){strings.push(this.clipLine(components[i],components[i-1]));}} +if(imaxX){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;},getShortString:function(point){var resolution=this.getResolution();var x=((point.x-this.featureDx)/resolution+this.left);var y=(this.top-point.y/resolution);if(this.inValidRange(x,y)){return x+","+y;}else{return false;}},getPosition:function(node){return({x:parseFloat(node.getAttributeNS(null,"cx")),y:parseFloat(node.getAttributeNS(null,"cy"))});},importSymbol:function(graphicName){if(!this.defs){this.defs=this.createDefs();} +var id=this.container.id+"-"+graphicName;var existing=document.getElementById(id);if(existing!=null){return existing;} +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;i1.0){this.setGeometryName(null);}},destroy:function(){if(this.options&&!this.options.format){this.format.destroy();} +this.format=null;OpenLayers.Protocol.prototype.destroy.apply(this);},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;},setFeatureType:function(featureType){this.featureType=featureType;this.format.featureType=featureType;},setGeometryName:function(geometryName){this.geometryName=geometryName;this.format.geometryName=geometryName;},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){var result=this.parseResponse(request,options.readOptions);if(result&&result.success!==false){if(options.readOptions&&options.readOptions.output=="object"){OpenLayers.Util.extend(response,result);}else{response.features=result;} +response.code=OpenLayers.Protocol.Response.SUCCESS;}else{response.code=OpenLayers.Protocol.Response.FAILURE;response.error=result;}}else{response.code=OpenLayers.Protocol.Response.FAILURE;} +options.callback.call(options.scope,response);}},parseResponse:function(request,options){var doc=request.responseXML;if(!doc||!doc.documentElement){doc=request.responseText;} +if(!doc||doc.length<=0){return null;} +var result=(this.readFormat!==null)?this.readFormat.read(doc):this.format.read(doc,options);if(!this.featureNS){var format=this.readFormat||this.format;this.featureNS=format.featureNS;format.autoConfig=false;if(!this.geometryName){this.setGeometryName(format.geometryName);}} +return result;},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,headers:options.headers,data:this.format.write(features,options),callback:this.createCallback(this.handleCommit,response,options)});return response;},handleCommit:function(response,options){if(options.callback){var request=response.priv;var data=request.responseXML;if(!data||!data.documentElement){data=request.responseText;} +var obj=this.format.read(data)||{};response.insertIds=obj.insertIds||[];if(obj.success){response.code=OpenLayers.Protocol.Response.SUCCESS;}else{response.code=OpenLayers.Protocol.Response.FAILURE;response.error=obj;} +options.callback.call(options.scope,response);}},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});},abort:function(response){if(response){response.priv.abort();}},CLASS_NAME:"OpenLayers.Protocol.WFS.v1"});OpenLayers.ProxyHost="";if(!OpenLayers.Request){OpenLayers.Request={};} +OpenLayers.Util.extend(OpenLayers.Request,{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},URL_SPLIT_REGEX:/([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/,events:new OpenLayers.Events(this),makeSameOrigin:function(url,proxy){var sameOrigin=url.indexOf("http")!==0;var urlParts=!sameOrigin&&url.match(this.URL_SPLIT_REGEX);if(urlParts){var location=window.location;sameOrigin=urlParts[1]==location.protocol&&urlParts[3]==location.hostname;var uPort=urlParts[4],lPort=location.port;if(uPort!=80&&uPort!=""||lPort!="80"&&lPort!=""){sameOrigin=sameOrigin&&uPort==lPort;}} +if(!sameOrigin){if(proxy){if(typeof proxy=="function"){url=proxy(url);}else{url=proxy+encodeURIComponent(url);}}else{OpenLayers.Console.warn(OpenLayers.i18n("proxyNeeded"),{url:url});}} +return url;},issue:function(config){var defaultConfig=OpenLayers.Util.extend(this.DEFAULT_CONFIG,{proxy:OpenLayers.ProxyHost});config=OpenLayers.Util.applyDefaults(config,defaultConfig);var customRequestedWithHeader=false,headerKey;for(headerKey in config.headers){if(config.headers.hasOwnProperty(headerKey)){if(headerKey.toLowerCase()==='x-requested-with'){customRequestedWithHeader=true;}}} +if(customRequestedWithHeader===false){config.headers['X-Requested-With']='XMLHttpRequest';} +var request=new OpenLayers.Request.XMLHttpRequest();var url=OpenLayers.Util.urlAppend(config.url,OpenLayers.Util.getParameterString(config.params||{}));url=OpenLayers.Request.makeSameOrigin(url,config.proxy);request.open(config.method,url,config.async,config.user,config.password);for(var header in config.headers){request.setRequestHeader(header,config.headers[header]);} +var events=this.events;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});}}};if(config.async===false){request.send(config.data);}else{window.setTimeout(function(){if(request.readyState!==0){request.send(config.data);}},0);} +return request;},runCallbacks:function(options){var request=options.request;var config=options.config;var complete=(config.scope)?OpenLayers.Function.bind(config.callback,config.scope):config.callback;var success;if(config.success){success=(config.scope)?OpenLayers.Function.bind(config.success,config.scope):config.success;} +var failure;if(config.failure){failure=(config.scope)?OpenLayers.Function.bind(config.failure,config.scope):config.failure;} +if(OpenLayers.Util.createUrlObject(config.url).protocol=="file:"&&request.responseText){request.status=200;} +complete(request);if(!request.status||(request.status>=200&&request.status<300)){this.events.triggerEvent("success",options);if(success){success(request);}} +if(request.status&&(request.status<200||request.status>=300)){this.events.triggerEvent("failure",options);if(failure){failure(request);}}},GET:function(config){config=OpenLayers.Util.extend(config,{method:"GET"});return OpenLayers.Request.issue(config);},POST:function(config){config=OpenLayers.Util.extend(config,{method:"POST"});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);},PUT:function(config){config=OpenLayers.Util.extend(config,{method:"PUT"});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);},DELETE:function(config){config=OpenLayers.Util.extend(config,{method:"DELETE"});return OpenLayers.Request.issue(config);},HEAD:function(config){config=OpenLayers.Util.extend(config,{method:"HEAD"});return OpenLayers.Request.issue(config);},OPTIONS:function(config){config=OpenLayers.Util.extend(config,{method:"OPTIONS"});return OpenLayers.Request.issue(config);}});(function(){var oXMLHttpRequest=window.XMLHttpRequest;var bGecko=!!window.controllers,bIE=window.document.all&&!window.opera,bIE7=bIE&&window.navigator.userAgent.match(/MSIE 7.0/);function fXMLHttpRequest(){this._object=oXMLHttpRequest&&!bIE7?new oXMLHttpRequest:new window.ActiveXObject("Microsoft.XMLHTTP");this._listeners=[];};function cXMLHttpRequest(){return new fXMLHttpRequest;};cXMLHttpRequest.prototype=fXMLHttpRequest.prototype;if(bGecko&&oXMLHttpRequest.wrapped) +cXMLHttpRequest.wrapped=oXMLHttpRequest.wrapped;cXMLHttpRequest.UNSENT=0;cXMLHttpRequest.OPENED=1;cXMLHttpRequest.HEADERS_RECEIVED=2;cXMLHttpRequest.LOADING=3;cXMLHttpRequest.DONE=4;cXMLHttpRequest.prototype.readyState=cXMLHttpRequest.UNSENT;cXMLHttpRequest.prototype.responseText='';cXMLHttpRequest.prototype.responseXML=null;cXMLHttpRequest.prototype.status=0;cXMLHttpRequest.prototype.statusText='';cXMLHttpRequest.prototype.priority="NORMAL";cXMLHttpRequest.prototype.onreadystatechange=null;cXMLHttpRequest.onreadystatechange=null;cXMLHttpRequest.onopen=null;cXMLHttpRequest.onsend=null;cXMLHttpRequest.onabort=null;cXMLHttpRequest.prototype.open=function(sMethod,sUrl,bAsync,sUser,sPassword){delete this._headers;if(arguments.length<3) +bAsync=true;this._async=bAsync;var oRequest=this,nState=this.readyState,fOnUnload;if(bIE&&bAsync){fOnUnload=function(){if(nState!=cXMLHttpRequest.DONE){fCleanTransport(oRequest);oRequest.abort();}};window.attachEvent("onunload",fOnUnload);} +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;oRequest.readyState=oRequest._object.readyState;fSynchronizeValues(oRequest);if(oRequest._aborted){oRequest.readyState=cXMLHttpRequest.UNSENT;return;} +if(oRequest.readyState==cXMLHttpRequest.DONE){delete oRequest._data;fCleanTransport(oRequest);if(bIE&&bAsync) +window.detachEvent("onunload",fOnUnload);} +if(nState!=oRequest.readyState) +fReadyStateChange(oRequest);nState=oRequest.readyState;}};function fXMLHttpRequest_send(oRequest){oRequest._object.send(oRequest._data);if(bGecko&&!oRequest._async){oRequest.readyState=cXMLHttpRequest.OPENED;fSynchronizeValues(oRequest);while(oRequest.readyStatecXMLHttpRequest.UNSENT) +this._aborted=true;this._object.abort();fCleanTransport(this);this.readyState=cXMLHttpRequest.UNSENT;delete this._data;};cXMLHttpRequest.prototype.getAllResponseHeaders=function(){return this._object.getAllResponseHeaders();};cXMLHttpRequest.prototype.getResponseHeader=function(sName){return this._object.getResponseHeader(sName);};cXMLHttpRequest.prototype.setRequestHeader=function(sName,sValue){if(!this._headers) +this._headers={};this._headers[sName]=sValue;return this._object.setRequestHeader(sName,sValue);};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;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;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(){},'preventDefault':function(){},'initEvent':function(){}};if(oEventPseudo.type=="readystatechange"&&this.onreadystatechange) +(this.onreadystatechange.handleEvent||this.onreadystatechange).apply(this,[oEventPseudo]);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"+']';};function fReadyStateChange(oRequest){if(cXMLHttpRequest.onreadystatechange) +cXMLHttpRequest.onreadystatechange.apply(oRequest);oRequest.dispatchEvent({'type':"readystatechange",'bubbles':false,'cancelable':false,'timeStamp':new Date+0});};function fGetDocument(oRequest){var oDocument=oRequest.responseXML,sResponse=oRequest.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);} +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){oRequest._object.onreadystatechange=new window.Function;};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;};};if(!OpenLayers.Request){OpenLayers.Request={};} +OpenLayers.Request.XMLHttpRequest=cXMLHttpRequest;})();OpenLayers.Raster={};OpenLayers.Raster.Grid=OpenLayers.Class({EVENT_TYPES:["update"],initialize:function(config){OpenLayers.Util.extend(this,config);this.events=new OpenLayers.Events(this,null,this.EVENT_TYPES);},getValue:function(col,row){throw new Error("getValue must be defined")},numCols:function(){throw new Error("numCols must be defined")},numRows:function(){throw new Error("numRows must be defined")},forEach:function(fn){var cols=this.numCols();var rows=this.numRows();for(var j=0;j=this.getCount()){throw new Error("Bad grid index.")} +var composite=this;return new OpenLayers.Raster.Grid({numCols:function(){return composite.numCols();},numRows:function(){return composite.numRows();},getValue:function(col,row){return composite.getValue(col,row)[index];}});},CLASS_NAME:"OpenLayers.Raster.Composite"};})());OpenLayers.Raster.Composite.fromLayer=function(layer,options){var composite;if(layer instanceof OpenLayers.Layer.Grid){composite=OpenLayers.Raster.Composite.fromGridLayer(layer);}else if(layer instanceof OpenLayers.Layer.Vector){composite=OpenLayers.Raster.Composite.fromVectorLayer(layer,options);}else{throw new Error("Only Grid or Vector type layers can be used to create a raster");} +return composite;};OpenLayers.Raster.Composite.fromVectorLayer=function(layer,options){var mapping=options&&options.mapping||function(feature){return[255,255,255,255]};var container=document.createElement("div");var renderer=new OpenLayers.Renderer.Canvas(container,{hitDetection:false});var canvas=renderer.root;var context=renderer.canvas;var composite=new OpenLayers.Raster.Composite({numCols:function(){return canvas.width;},numRows:function(){return canvas.height;},getCount:function(){return 4;},getValue:function(col,row){var pixelArray=getPixelArray();var cols=canvas.width;var offset=4*(col+(row*cols));return Array.prototype.slice.apply(pixelArray,[offset,offset+4]);},toDataURL:function(){return canvas.toDataURL.apply(canvas,arguments);}});var cache={};function getPixelArray(){if(!cache.pixelArray){var imageData=context.getImageData(0,0,canvas.width,canvas.height);cache.pixelArray=imageData.data;} +return cache.pixelArray;} +function hex(value){value=Math.max(0,Math.min(255,value));return(3840+value).toString(16).substring(1);} +var style=new OpenLayers.Style({stroke:false,fillColor:"${getColor}",fillOpacity:"${getOpacity}"},{context:{getColor:function(feature){var rgba=mapping(feature);return"#"+ +hex(rgba[0])+ +hex(rgba[1])+ +hex(rgba[2]);},getOpacity:function(feature){var rgba=mapping(feature);return rgba[3]/255;}}});var clone=new OpenLayers.Layer.Vector(null,{styleMap:new OpenLayers.StyleMap(style),renderer:renderer});function triggerUpdate(){cache={};window.setTimeout(function(){composite.events.triggerEvent("update");},0);} +function addFeatures(event){var features=event.features;clone.addFeatures(features,{silent:true});for(var i=0,ii=features.length;icanvas.width?cornerPixel.x+tileSize.w-canvas.width:0;var overwritey=cornerPixel.y+tileSize.h>canvas.height?cornerPixel.y+tileSize.h-canvas.height:0;if((underwritex+overwritex)0?0:cornerPixel.x;var dy=underwritey>0?0:cornerPixel.y;var dw=tileSize.w-underwritex-overwritex;var dh=tileSize.h-underwritey-overwritey;context.drawImage(img,sx,sy,sw,sh,dx,dy,dw,dh);}}}} +composite.getValue=function(col,row){var width=canvas.width;var data8=context.getImageData(0,0,width,canvas.height).data;var accessor;var pixel=[0,0,0,0];accessor=function(col,row){var offset=(col+(row*width))<<2;pixel[3]=data8[offset+3];pixel[2]=data8[offset+2];pixel[1]=data8[offset+1];pixel[0]=data8[offset];return pixel;} +composite.getValue=accessor;return accessor(col,row);} +composite.events.triggerEvent("update");}} +if(layer.map){layer.map.events.register("moveend",null,deferredUpdate);}else{layer.events.register("added",null,function(){layer.map.events.register("moveend",null,deferredUpdate);});} +layer.events.register("loadend",null,deferredUpdate);return composite;};OpenLayers.Raster.Operation=(function(){var Grid=OpenLayers.Raster.Grid;var Composite=OpenLayers.Raster.Composite;return{create:function(fn){var op=function(){var args=Array.prototype.slice.call(arguments);var len=args.length;if(len==1){var operand=args[0];if(operand instanceof Grid){var result=new Grid({numCols:function(){return operand.numCols();},numRows:function(){return operand.numRows();},getValue:function(col,row){return fn(operand.getValue(col,row));},getCount:function(){return 1;}});operand.events.register("update",null,function(){result.events.triggerEvent("update");});return result;}else{throw new Error("Operation must be called with at least one grid.");}}else{function getFirstGrid(){var grid;for(var i=0;i1)?Composite:Grid;var grid=new Constructor({numCols:function(){return getFirstGrid().numCols();},numRows:function(){return getFirstGrid().numRows();},getValue:function(col,row){var values=new Array(len);var arg;for(var i=0;i=0;--i){candidate=features[i].geometry;if((candidate instanceof OpenLayers.Geometry.Polygon||candidate instanceof OpenLayers.Geometry.MultiPolygon)&&candidate.intersects(geometry)){polygon=features[i];this.control.layer.removeFeatures([polygon],{silent:true});this.control.layer.events.registerPriority("sketchcomplete",this,this.finalizeInteriorRing);this.control.layer.events.registerPriority("sketchmodified",this,this.enforceTopology);polygon.geometry.addComponent(this.line.geometry);this.polygon=polygon;this.drawingHole=true;break;}}} +OpenLayers.Handler.Path.prototype.addPoint.apply(this,arguments);},getCurrentPointIndex:function(){return this.line.geometry.components.length-2;},enforceTopology:function(event){var point=event.vertex;var components=this.line.geometry.components;if(!this.polygon.geometry.intersects(point)){var last=components[components.length-3];point.x=last.x;point.y=last.y;}},finishGeometry:function(){var index=this.line.geometry.components.length-2;this.line.geometry.removeComponent(this.line.geometry.components[index]);this.removePoint();this.finalize();},finalizeInteriorRing:function(){var ring=this.line.geometry;var modified=(ring.getArea()!==0);if(modified){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){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 Date: Tue, 15 Oct 2013 15:36:46 -0600 Subject: [PATCH 36/36] Source updates for examples --- examples/raster-download.js | 5 +++-- examples/raster-from-vector.js | 3 ++- examples/raster-grid-layer.js | 5 +++-- examples/raster-magnify.js | 5 +++-- examples/raster-mask.js | 14 +++++++------- examples/raster-operations.js | 5 +++-- examples/raster-pdf.js | 5 +++-- examples/raster-query.js | 16 ++++++++-------- examples/raster-stats.js | 12 ++++++------ examples/raster-zonal-stats.js | 16 ++++++++-------- 10 files changed, 46 insertions(+), 40 deletions(-) diff --git a/examples/raster-download.js b/examples/raster-download.js index 607f89a088..610dbe628b 100644 --- a/examples/raster-download.js +++ b/examples/raster-download.js @@ -1,7 +1,8 @@ var marble = new OpenLayers.Layer.WMS( "Blue Marble", - "/geoserver/wms", - {layers: "topp:bluemarble", format: "image/png"} + "http://demo.opengeo.org/geoserver/wms", + {layers: "nasa:bluemarble", format: "image/png"}, + {tileOptions: {crossOriginKeyword: "anonymous"}} ); var data = OpenLayers.Raster.Composite.fromLayer(marble); diff --git a/examples/raster-from-vector.js b/examples/raster-from-vector.js index 36c0b4ebf2..9ec775d0b5 100644 --- a/examples/raster-from-vector.js +++ b/examples/raster-from-vector.js @@ -1,7 +1,8 @@ var marble = new OpenLayers.Layer.WMS( "Blue Marble", "http://demo.opengeo.org/geoserver/wms", - {layers: "topp:bluemarble", format: "image/png"} + {layers: "nasa:bluemarble", format: "image/png"}, + {tileOptions: {crossOriginKeyword: "anonymous"}} ); var vector = new OpenLayers.Layer.Vector("Vector Features"); diff --git a/examples/raster-grid-layer.js b/examples/raster-grid-layer.js index d9b3887a60..eda8f91a8a 100644 --- a/examples/raster-grid-layer.js +++ b/examples/raster-grid-layer.js @@ -6,8 +6,9 @@ var luminance = OpenLayers.Raster.Operation.create(function(rgba) { var marble = new OpenLayers.Layer.WMS( "Blue Marble", - "/geoserver/wms", - {layers: "topp:bluemarble", format: "image/png"} + "http://demo.opengeo.org/geoserver/wms", + {layers: "nasa:bluemarble", format: "image/png"}, + {tileOptions: {crossOriginKeyword: "anonymous"}} ); var raster = new OpenLayers.Layer.Raster({ diff --git a/examples/raster-magnify.js b/examples/raster-magnify.js index 02a11d1e3d..29eef6d669 100644 --- a/examples/raster-magnify.js +++ b/examples/raster-magnify.js @@ -1,7 +1,8 @@ var marble = new OpenLayers.Layer.WMS( "Blue Marble", - "/geoserver/wms", - {layers: "topp:bluemarble", format: "image/png"} + "http://demo.opengeo.org/geoserver/wms", + {layers: "nasa:bluemarble", format: "image/png"}, + {tileOptions: {crossOriginKeyword: "anonymous"}} ); var data = OpenLayers.Raster.Composite.fromLayer(marble); diff --git a/examples/raster-mask.js b/examples/raster-mask.js index bbc464fb0b..82693b41e7 100644 --- a/examples/raster-mask.js +++ b/examples/raster-mask.js @@ -18,10 +18,10 @@ var streets = new OpenLayers.Layer.XYZ( var imagery = new OpenLayers.Layer.XYZ( "Imagery", [ - "http://oatile1.mqcdn.com/naip/${z}/${x}/${y}.png", - "http://oatile2.mqcdn.com/naip/${z}/${x}/${y}.png", - "http://oatile3.mqcdn.com/naip/${z}/${x}/${y}.png", - "http://oatile4.mqcdn.com/naip/${z}/${x}/${y}.png" + "http://oatile1.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.png", + "http://oatile2.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.png", + "http://oatile3.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.png", + "http://oatile4.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.png" ], { attribution: "Tiles by MapQuest ", @@ -32,9 +32,9 @@ var imagery = new OpenLayers.Layer.XYZ( var nlcd = new OpenLayers.Layer.WMS( "Land Cover", - "/geoserver/wms", + "http://demo.opengeo.org/geoserver/wms", {layers: "usgs:nlcd", format: "image/png8"}, - {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false} + {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false, tileOptions: {crossOriginKeyword: "anonymous"}} ); @@ -42,7 +42,7 @@ var tracts = new OpenLayers.Layer.Vector("Census Tracts", { strategies: [new OpenLayers.Strategy.BBOX()], projection: new OpenLayers.Projection("EPSG:900913"), protocol: new OpenLayers.Protocol.WFS({ - url: "/geoserver/wfs", + url: "http://demo.opengeo.org/geoserver/wfs", version: "1.1.0", featureNS: "http://www.usgs.gov/", srsName: "EPSG:900913", diff --git a/examples/raster-operations.js b/examples/raster-operations.js index fb9455e925..9826b5dd15 100644 --- a/examples/raster-operations.js +++ b/examples/raster-operations.js @@ -74,8 +74,9 @@ var adjust = op.create(function(hsl, deltas) { var marble = new OpenLayers.Layer.WMS( "Blue Marble", - "/geoserver/wms", - {layers: "topp:bluemarble", format: "image/png"} + "http://demo.opengeo.org/geoserver/wms", + {layers: "nasa:bluemarble", format: "image/png"}, + {tileOptions: {crossOriginKeyword: "anonymous"}} ); var data = OpenLayers.Raster.Composite.fromLayer(marble); diff --git a/examples/raster-pdf.js b/examples/raster-pdf.js index c11ad56b7d..2b72712261 100644 --- a/examples/raster-pdf.js +++ b/examples/raster-pdf.js @@ -1,7 +1,8 @@ var marble = new OpenLayers.Layer.WMS( "Blue Marble", - "/geoserver/wms", - {layers: "topp:bluemarble", format: "image/png"} + "http://demo.opengeo.org/geoserver/wms", + {layers: "nasa:bluemarble", format: "image/png"}, + {tileOptions: {crossOriginKeyword: "anonymous"}} ); var data = OpenLayers.Raster.Composite.fromLayer(marble); diff --git a/examples/raster-query.js b/examples/raster-query.js index 097debf307..449c639f11 100644 --- a/examples/raster-query.js +++ b/examples/raster-query.js @@ -18,10 +18,10 @@ var streets = new OpenLayers.Layer.XYZ( var imagery = new OpenLayers.Layer.XYZ( "Imagery", [ - "http://oatile1.mqcdn.com/naip/${z}/${x}/${y}.png", - "http://oatile2.mqcdn.com/naip/${z}/${x}/${y}.png", - "http://oatile3.mqcdn.com/naip/${z}/${x}/${y}.png", - "http://oatile4.mqcdn.com/naip/${z}/${x}/${y}.png" + "http://oatile1.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.png", + "http://oatile2.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.png", + "http://oatile3.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.png", + "http://oatile4.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.png" ], { attribution: "Tiles by MapQuest ", @@ -32,16 +32,16 @@ var imagery = new OpenLayers.Layer.XYZ( var ned = new OpenLayers.Layer.WMS( "Elevation", - "/geoserver/wms", + "http://demo.opengeo.org/geoserver/wms", {layers: "usgs:ned", format: "image/png", transparent: true}, - {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false} + {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false, tileOptions: {crossOriginKeyword: "anonymous"}} ); var nlcd = new OpenLayers.Layer.WMS( "Land Cover", - "/geoserver/wms", + "http://demo.opengeo.org/geoserver/wms", {layers: "usgs:nlcd", format: "image/png8", transparent: true}, - {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false} + {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false, tileOptions: {crossOriginKeyword: "anonymous"}} ); var map = new OpenLayers.Map({ diff --git a/examples/raster-stats.js b/examples/raster-stats.js index b295628678..9ba822b4b9 100644 --- a/examples/raster-stats.js +++ b/examples/raster-stats.js @@ -18,10 +18,10 @@ var streets = new OpenLayers.Layer.XYZ( var imagery = new OpenLayers.Layer.XYZ( "Imagery", [ - "http://oatile1.mqcdn.com/naip/${z}/${x}/${y}.png", - "http://oatile2.mqcdn.com/naip/${z}/${x}/${y}.png", - "http://oatile3.mqcdn.com/naip/${z}/${x}/${y}.png", - "http://oatile4.mqcdn.com/naip/${z}/${x}/${y}.png" + "http://oatile1.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.png", + "http://oatile2.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.png", + "http://oatile3.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.png", + "http://oatile4.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.png" ], { attribution: "Tiles by MapQuest ", @@ -32,9 +32,9 @@ var imagery = new OpenLayers.Layer.XYZ( var nlcd = new OpenLayers.Layer.WMS( "Land Cover", - "/geoserver/wms", + "http://demo.opengeo.org/geoserver/wms", {layers: "usgs:nlcd", format: "image/png8"}, - {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false} + {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false, tileOptions: {crossOriginKeyword: "anonymous"}} ); var map = new OpenLayers.Map({ diff --git a/examples/raster-zonal-stats.js b/examples/raster-zonal-stats.js index a7b4949f80..cc3ae058b6 100644 --- a/examples/raster-zonal-stats.js +++ b/examples/raster-zonal-stats.js @@ -18,10 +18,10 @@ var streets = new OpenLayers.Layer.XYZ( var imagery = new OpenLayers.Layer.XYZ( "Imagery", [ - "http://oatile1.mqcdn.com/naip/${z}/${x}/${y}.png", - "http://oatile2.mqcdn.com/naip/${z}/${x}/${y}.png", - "http://oatile3.mqcdn.com/naip/${z}/${x}/${y}.png", - "http://oatile4.mqcdn.com/naip/${z}/${x}/${y}.png" + "http://oatile1.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.png", + "http://oatile2.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.png", + "http://oatile3.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.png", + "http://oatile4.mqcdn.com/tiles/1.0.0/sat/${z}/${x}/${y}.png" ], { attribution: "Tiles by MapQuest ", @@ -32,16 +32,16 @@ var imagery = new OpenLayers.Layer.XYZ( var ned = new OpenLayers.Layer.WMS( "Elevation", - "/geoserver/wms", + "http://demo.opengeo.org/geoserver/wms", {layers: "usgs:ned", format: "image/png", transparent: true}, - {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false} + {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false, tileOptions: {crossOriginKeyword: "anonymous"}} ); var nlcd = new OpenLayers.Layer.WMS( "Land Cover", - "/geoserver/wms", + "http://demo.opengeo.org/geoserver/wms", {layers: "usgs:nlcd", format: "image/png8", transparent: true}, - {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false} + {singleTile: true, isBaseLayer: false, opacity: 0, displayInLayerSwitcher: false, tileOptions: {crossOriginKeyword: "anonymous"}} ); var map = new OpenLayers.Map({