[fusion-commits] r1413 - in sandbox/aboudreault: . MapGuide
MapGuide/php MapServer MapServer/php common/php jx/lib lib
lib/OpenLayers lib/OpenLayers/Lang
lib/OpenLayers/theme/default lib/OpenLayers/theme/default/img
templates/mapguide/standard text/en text/fr widgets
widgets/BufferPanel widgets/Print widgets/Search
widgets/SelectWithin
svn_fusion at osgeo.org
svn_fusion at osgeo.org
Thu May 29 10:21:45 EDT 2008
Author: aboudreault
Date: 2008-05-29 10:21:40 -0400 (Thu, 29 May 2008)
New Revision: 1413
Added:
sandbox/aboudreault/configHeader.json
sandbox/aboudreault/lib/EventMgr.js
sandbox/aboudreault/lib/OpenLayers/Lang/
sandbox/aboudreault/lib/OpenLayers/Lang/de.js
sandbox/aboudreault/lib/OpenLayers/Lang/en-CA.js
sandbox/aboudreault/lib/OpenLayers/Lang/en.js
sandbox/aboudreault/lib/OpenLayers/Lang/fr.js
sandbox/aboudreault/lib/OpenLayers/OpenLayersUncompressed.js
sandbox/aboudreault/lib/OpenLayers/theme/default/img/blank.gif
sandbox/aboudreault/lib/OpenLayers/theme/default/img/editing_tool_bar.png
sandbox/aboudreault/lib/OpenLayers/theme/default/img/overview_replacement.gif
sandbox/aboudreault/lib/OpenLayers/theme/default/img/view_next_off.png
sandbox/aboudreault/lib/OpenLayers/theme/default/img/view_next_on.png
sandbox/aboudreault/lib/OpenLayers/theme/default/img/view_previous_off.png
sandbox/aboudreault/lib/OpenLayers/theme/default/img/view_previous_on.png
sandbox/aboudreault/lib/SingleFile.js
sandbox/aboudreault/parseAppDef.xsl
Removed:
sandbox/aboudreault/lib/OpenLayers/Lang/de.js
sandbox/aboudreault/lib/OpenLayers/Lang/en-CA.js
sandbox/aboudreault/lib/OpenLayers/Lang/en.js
sandbox/aboudreault/lib/OpenLayers/Lang/fr.js
sandbox/aboudreault/lib/OpenLayers/Strings/
sandbox/aboudreault/lib/utils.js
sandbox/aboudreault/widgets/CTRLClick.js
Modified:
sandbox/aboudreault/MapGuide/MapGuide.js
sandbox/aboudreault/MapGuide/php/Buffer.php
sandbox/aboudreault/MapGuide/php/Common.php
sandbox/aboudreault/MapGuide/php/CreateSession.php
sandbox/aboudreault/MapGuide/php/Query.php
sandbox/aboudreault/MapGuide/php/SaveMap.php
sandbox/aboudreault/MapServer/MapServer.js
sandbox/aboudreault/MapServer/php/CreateSession.php
sandbox/aboudreault/MapServer/php/LegendIcon.php
sandbox/aboudreault/build.xml
sandbox/aboudreault/common/php/Utilities.php
sandbox/aboudreault/common/php/Xml2JSON.php
sandbox/aboudreault/fusion.cfg
sandbox/aboudreault/jx/lib/jx_combined.js
sandbox/aboudreault/lib/ApplicationDefinition.js
sandbox/aboudreault/lib/ButtonBase.js
sandbox/aboudreault/lib/ButtonTool.js
sandbox/aboudreault/lib/CanvasTool.js
sandbox/aboudreault/lib/ClickTool.js
sandbox/aboudreault/lib/Error.js
sandbox/aboudreault/lib/MGBroker.js
sandbox/aboudreault/lib/Map.js
sandbox/aboudreault/lib/MenuBase.js
sandbox/aboudreault/lib/OpenLayers/OpenLayers.js
sandbox/aboudreault/lib/OpenLayers/OpenLayersCompressed.js
sandbox/aboudreault/lib/OpenLayers/theme/default/style.css
sandbox/aboudreault/lib/RectTool.js
sandbox/aboudreault/lib/Search.js
sandbox/aboudreault/lib/Widget.js
sandbox/aboudreault/lib/fusion.js
sandbox/aboudreault/templates/mapguide/standard/ApplicationDefinition.xml
sandbox/aboudreault/templates/mapguide/standard/index.html
sandbox/aboudreault/text/en/strings.json
sandbox/aboudreault/text/fr/strings.json
sandbox/aboudreault/widgets/About.js
sandbox/aboudreault/widgets/ActivityIndicator.js
sandbox/aboudreault/widgets/Buffer.js
sandbox/aboudreault/widgets/BufferPanel.js
sandbox/aboudreault/widgets/BufferPanel/Buffer.php
sandbox/aboudreault/widgets/CenterSelection.js
sandbox/aboudreault/widgets/ClearSelection.js
sandbox/aboudreault/widgets/ColorPicker.js
sandbox/aboudreault/widgets/CursorPosition.js
sandbox/aboudreault/widgets/EditableScale.js
sandbox/aboudreault/widgets/ExtentHistory.js
sandbox/aboudreault/widgets/Help.js
sandbox/aboudreault/widgets/InitialMapView.js
sandbox/aboudreault/widgets/InvokeScript.js
sandbox/aboudreault/widgets/InvokeURL.js
sandbox/aboudreault/widgets/LayerManager.js
sandbox/aboudreault/widgets/Legend.js
sandbox/aboudreault/widgets/LinkToView.js
sandbox/aboudreault/widgets/MapMenu.js
sandbox/aboudreault/widgets/Maptip.js
sandbox/aboudreault/widgets/Measure.js
sandbox/aboudreault/widgets/Navigator.js
sandbox/aboudreault/widgets/OverviewMap.js
sandbox/aboudreault/widgets/Pan.js
sandbox/aboudreault/widgets/PanOnClick.js
sandbox/aboudreault/widgets/PanQuery.js
sandbox/aboudreault/widgets/Print.js
sandbox/aboudreault/widgets/Print/printablepage.templ
sandbox/aboudreault/widgets/RefreshMap.js
sandbox/aboudreault/widgets/SaveMap.js
sandbox/aboudreault/widgets/Scalebar.js
sandbox/aboudreault/widgets/ScalebarDual.js
sandbox/aboudreault/widgets/Search.js
sandbox/aboudreault/widgets/Search/Search.php
sandbox/aboudreault/widgets/Select.js
sandbox/aboudreault/widgets/SelectPolygon.js
sandbox/aboudreault/widgets/SelectRadius.js
sandbox/aboudreault/widgets/SelectRadiusValue.js
sandbox/aboudreault/widgets/SelectWithin.js
sandbox/aboudreault/widgets/SelectWithin/SelectWithin.php
sandbox/aboudreault/widgets/SelectWithin/SelectWithinPanel.templ
sandbox/aboudreault/widgets/SelectionInfo.js
sandbox/aboudreault/widgets/SelectionPanel.js
sandbox/aboudreault/widgets/TaskPane.js
sandbox/aboudreault/widgets/ViewOptions.js
sandbox/aboudreault/widgets/ViewSize.js
sandbox/aboudreault/widgets/Zoom.js
sandbox/aboudreault/widgets/ZoomOnClick.js
sandbox/aboudreault/widgets/ZoomToSelection.js
Log:
Merge trunk in aboudreault sandbox
Modified: sandbox/aboudreault/MapGuide/MapGuide.js
===================================================================
--- sandbox/aboudreault/MapGuide/MapGuide.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/MapGuide/MapGuide.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -29,8 +29,7 @@
* Implements the map widget for MapGuide Open Source services.
*/
-Fusion.Maps.MapGuide = Class.create();
-Fusion.Maps.MapGuide.prototype = {
+Fusion.Maps.MapGuide = OpenLayers.Class(Fusion.Lib.EventMgr, {
arch: 'MapGuide',
session: [null],
bSingleTile: null,
@@ -51,10 +50,11 @@
//the resource id of the current MapDefinition
_sResourceId: null,
+
+ clientAgent: 'Fusion Viewer',
initialize : function(map, mapTag, isMapWidgetLayer) {
// console.log('MapGuide.initialize');
- Object.inheritFrom(this, Fusion.Lib.EventMgr, []);
this.registerEventID(Fusion.Event.MAP_SESSION_CREATED);
this.registerEventID(Fusion.Event.MAP_SELECTION_ON);
@@ -81,8 +81,8 @@
if (ctrlClickEnabled) {
this.map = this.mapWidget.oMapOL;
this.handler = new OpenLayers.Handler.Click(this,
- {click: this.mouseUpCRTLClick.bind(this)},
- {keyMask: OpenLayers.Handler.MOD_CTRL});
+ {click: OpenLayers.Function.bind(this.mouseUpCRTLClick, this)},
+ {keyMask: OpenLayers.Handler.MOD_CTRL});
this.handler.activate();
this.nTolerance = 2; //pixels, default pixel tolernace for a point click; TBD make this configurable
}
@@ -119,21 +119,22 @@
this.session[0] = this;
var sl = Fusion.getScriptLanguage();
var scriptURL = this.arch + '/' + sl + '/CreateSession.' + sl;
- var options = {onComplete: this.createSessionCB.bind(this)};
+ var options = {onSuccess: OpenLayers.Function.bind(this.createSessionCB, this)};
Fusion.ajaxRequest(scriptURL,options);
}
if (this.session[0] instanceof Fusion.Maps.MapGuide) {
// console.log('register for event');
- this.session[0].registerForEvent(Fusion.Event.MAP_SESSION_CREATED, this.mapSessionCreated.bind(this));
+ this.session[0].registerForEvent(Fusion.Event.MAP_SESSION_CREATED,
+ OpenLayers.Function.bind(this.mapSessionCreated, this));
} else {
this.mapSessionCreated();
}
},
- createSessionCB : function(r, json) {
- if (r.status == 200 && json) {
+ createSessionCB : function(xhr) {
+ if (xhr.status == 200) {
var o;
- eval('o='+r.responseText);
+ eval('o='+xhr.responseText);
this.session[0] = o.sessionId;
this.triggerEvent(Fusion.Event.MAP_SESSION_CREATED);
}
@@ -143,7 +144,7 @@
if (this.sMapResourceId != '') {
this.loadMap(this.sMapResourceId);
}
- window.setInterval(this.pingServer.bind(this), this.keepAliveInterval * 1000);
+ window.setInterval(OpenLayers.Function.bind(this.pingServer, this), this.keepAliveInterval * 1000);
},
sessionReady: function() {
@@ -204,20 +205,20 @@
var sessionid = this.getSessionID();
- var params = 'mapid='+resourceId+"&session="+sessionid;
- var options = {onSuccess: this.mapLoaded.bind(this), parameters:params};
+ var params = {'mapid': resourceId, "session": sessionid};
+ var options = {onSuccess: OpenLayers.Function.bind(this.mapLoaded,this),
+ parameters:params};
Fusion.ajaxRequest(loadmapScript, options);
},
- mapLoaded: function(r, json) {
- if (json) {
+ mapLoaded: function(r) {
+ if (r.status == 200) {
var o;
eval('o='+r.responseText);
this._sResourceId = o.mapId;
this._sMapname = o.mapName;
this._sMapTitle = o.mapTitle;
- this._fMetersperunit = o.metersPerUnit;
- this.mapWidget._fMetersperunit = this._fMetersperunit;
+ this.mapWidget.setMetersPerUnit(o.metersPerUnit);
this._oMaxExtent = OpenLayers.Bounds.fromArray(o.extent);
@@ -284,11 +285,13 @@
//set projection units and code if supplied
//TODO: consider passing the metersPerUnit value into the framework
//to allow for scaling that doesn't match any of the pre-canned units
- this.units = this.getClosestUnits(o.metersPerUnit);
+ this.units = Fusion.getClosestUnits(o.metersPerUnit);
//add in scales array if supplied
if (o.FiniteDisplayScales && o.FiniteDisplayScales.length>0) {
this.scales = o.FiniteDisplayScales;
+ this.mapWidget.fractionalZoom = false;
+ this.mapWidget.oMapOL.fractionalZoom = false;
}
//remove this layer if it was already created
@@ -315,29 +318,10 @@
this.triggerEvent(Fusion.Event.MAP_LOADED);
}
this.bMapLoaded = true;
- } else {
- Fusion.reportError( new Fusion.Error(Fusion.Error.FATAL,
- OpenLayers.String.translate('mapLoadError', r.responseText)));
}
this.mapWidget._removeWorker();
},
- getClosestUnits: function(metrsPerUnit) {
-
- var units = "degrees";
- var minDiff = 100000000;
- for (var key in OpenLayers.INCHES_PER_UNIT)
- {
- var newDiff = Math.abs((metrsPerUnit * 39.3701) - OpenLayers.INCHES_PER_UNIT[key]);
- if(newDiff < minDiff)
- {
- minDiff = newDiff;
- units = key;
- }
- }
- return units;
- },
-
//TBD: this function not yet converted for OL
reloadMap: function() {
@@ -357,24 +341,23 @@
var sessionid = this.getSessionID();
- var params = 'mapname='+this._sMapname+"&session="+sessionid;
- var options = {onSuccess: this.mapReloaded.bind(this),
- onException: this.reloadFailed.bind(this),
- parameters: params};
+ var params = {'mapname': this._sMapname, 'session': sessionid};
+ var options = {
+ onSuccess: OpenLayers.Function.bind(this.mapReloaded,this),
+ onException: OpenLayers.Function.bind(this.reloadFailed, this),
+ parameters: params};
Fusion.ajaxRequest(loadmapScript, options);
-
-
},
reloadFailed: function(r) {
Fusion.reportError( new Fusion.Error(Fusion.Error.FATAL,
- OpenLayers.String.translate('mapLoadError', r.transport.responseText)));
+ OpenLayers.i18n('mapLoadError', {'error':r.transport.responseText})));
this.mapWidget._removeWorker();
},
//TBD: this function not yet converted for OL
- mapReloaded: function(r,json) {
- if (json) {
+ mapReloaded: function(r) {
+ if (r.status == 200) {
var o;
eval('o='+r.responseText);
this.parseMapLayersAndGroups(o);
@@ -390,9 +373,6 @@
this.oldLayers = null;
this.mapWidget.triggerEvent(Fusion.Event.MAP_RELOADED);
this.drawMap();
- } else {
- Fusion.reportError( new Fusion.Error(Fusion.Error.FATAL,
- OpenLayers.String.translate('mapLoadError', r.responseText)));
}
this.mapWidget._removeWorker();
},
@@ -401,18 +381,20 @@
var sl = Fusion.getScriptLanguage();
var loadmapScript = this.arch + '/' + sl + '/SetLayers.' + sl;
- var sessionid = this.getSessionID();
+ var params = {
+ 'mapname': this._sMapname,
+ 'session': this.getSessionID(),
+ 'layerindex': aLayerIndex.join()
+ };
- var params = 'mapname='+this._sMapname+"&session="+sessionid;
- params += '&layerindex=' + aLayerIndex.join();
-
- var options = {onSuccess: this.mapLayersReset.bind(this, aLayerIndex),
- parameters: params};
+ var options = {
+ onSuccess: OpenLayers.Function.bind(this.mapLayersReset, this, aLayerIndex),
+ parameters: params};
Fusion.ajaxRequest(loadmapScript, options);
},
- mapLayersReset: function(aLayerIndex,r,json) {
- if (json) {
+ mapLayersReset: function(aLayerIndex,r) {
+ if (r.status == 200) {
var o;
eval('o='+r.responseText);
if (o.success) {
@@ -429,7 +411,7 @@
this.drawMap();
this.triggerEvent(Fusion.Event.MAP_LAYER_ORDER_CHANGED);
} else {
- alert(OpenLayers.String.translate('setLayersError', o.layerindex));
+ alert(OpenLayers.i18n('setLayersError', {'error':o.layerindex}));
}
}
},
@@ -464,7 +446,8 @@
return;
}
- var options = {
+ var params = {
+ ts : (new Date()).getTime(), //add a timestamp to prevent caching on the server
showLayers : this.aShowLayers.length > 0 ? this.aShowLayers.toString() : null,
hideLayers : this.aHideLayers.length > 0 ? this.aHideLayers.toString() : null,
showGroups : this.aShowGroups.length > 0 ? this.aShowGroups.toString() : null,
@@ -477,8 +460,7 @@
this.aHideGroups = [];
this.aRefreshLayers = [];
- this.oLayerOL.addOptions(options);
- this.oLayerOL.mergeNewParams({ts : (new Date()).getTime()});
+ this.oLayerOL.mergeNewParams(params);
if (this.queryLayer) this.queryLayer.redraw();
},
@@ -493,7 +475,8 @@
isBaseLayer : bIsBaseLayer,
maxExtent : this._oMaxExtent,
maxResolution : 'auto',
- ratio : this.ratio
+ ratio : this.ratio,
+ transitionEffect : 'resize'
};
//add in scales array if supplied
@@ -511,18 +494,20 @@
if ( bSingleTile ) {
params = { //single tile params
session : this.getSessionID(),
- mapname : this._sMapname
+ mapname : this._sMapname,
+ clientagent : this.clientAgent
};
- layerOptions.showLayers = this.aShowLayers.length > 0 ? this.aShowLayers.toString() : null;
- layerOptions.hideLayers = this.aHideLayers.length > 0 ? this.aHideLayers.toString() : null;
- layerOptions.showGroups = this.aShowGroups.length > 0 ? this.aShowGroups.toString() : null;
- layerOptions.hideGroups = this.aHideGroups.length > 0 ? this.aHideGroups.toString() : null;
- layerOptions.refreshLayers = this.aRefreshLayers.length > 0 ? this.aRefreshLayers.toString() : null;
+ params.showLayers = this.aShowLayers.length > 0 ? this.aShowLayers.toString() : null;
+ params.hideLayers = this.aHideLayers.length > 0 ? this.aHideLayers.toString() : null;
+ params.showGroups = this.aShowGroups.length > 0 ? this.aShowGroups.toString() : null;
+ params.hideGroups = this.aHideGroups.length > 0 ? this.aHideGroups.toString() : null;
+ params.refreshLayers = this.aRefreshLayers.length > 0 ? this.aRefreshLayers.toString() : null;
} else {
params = { //tiled version
mapdefinition: this._sResourceId,
- basemaplayergroupname: this.groupName //assumes only one group for now
+ basemaplayergroupname: this.groupName, //assumes only one group for now
+ clientagent : this.clientAgent
};
}
@@ -561,13 +546,13 @@
hasSelection: function() { return this.bSelectionOn; },
- getSelectionCB : function(userFunc, layers, startend, r, json) {
- if (json)
+ getSelectionCB : function(userFunc, layers, startend, r) {
+ if (r.status == 200)
{
var o;
eval("o="+r.responseText);
- var oSelection = new GxSelectionObject(o);
+ var oSelection = new Fusion.SelectionObject(o);
userFunc(oSelection);
}
@@ -641,10 +626,14 @@
this.mapWidget._addWorker();
var sl = Fusion.getScriptLanguage();
var setSelectionScript = this.arch + '/' + sl + '/SetSelection.' + sl;
- var params = 'mapname='+this.getMapName()+"&session="+this.getSessionID();
- params += '&selection=' + encodeURIComponent(selText);
- params += '&seq=' + Math.random();
- var options = {onSuccess: this.processQueryResults.bind(this, zoomTo), parameters:params, asynchronous:false};
+ var params = {
+ 'mapname': this.getMapName(),
+ 'session': this.getSessionID(),
+ 'selection': encodeURIComponent(selText),
+ 'seq': Math.random()
+ };
+ var options = {onSuccess: OpenLayers.Function.bind(this.processQueryResults, this, zoomTo),
+ parameters:params, asynchronous:false};
Fusion.ajaxRequest(setSelectionScript, options);
},
@@ -681,9 +670,14 @@
//this.mapWidget._addWorker();
// this._bSelectionIsLoading = true;
var s = this.arch + '/' + Fusion.getScriptLanguage() + "/Selection." + Fusion.getScriptLanguage() ;
- var params = {parameters:'session='+this.getSessionID()+'&mapname='+ this._sMapname +'&layers='+layers+'&startcount='+startcount,
- onComplete: this.getSelectionCB.bind(this, userFunc, layers, startcount)};
- Fusion.ajaxRequest(s, params);
+ var options = {
+ parameters: {'session': this.getSessionID(),
+ 'mapname': this._sMapname,
+ 'layers': layers,
+ 'startcount': startcount},
+ onSuccess: OpenLayers.Function.bind(this.getSelectionCB, this, userFunc, layers, startcount)
+ };
+ Fusion.ajaxRequest(s, options);
}
},
@@ -711,9 +705,13 @@
*/
clearSelection : function() {
if (this.hasSelection()) {
- var s = this.arch + '/' + Fusion.getScriptLanguage() + "/ClearSelection." + Fusion.getScriptLanguage() ;
- var params = {parameters:'session='+this.getSessionID()+'&mapname='+ this._sMapname, onComplete: this.selectionCleared.bind(this)};
- Fusion.ajaxRequest(s, params);
+ var s = this.arch + '/' + Fusion.getScriptLanguage() + "/ClearSelection." + Fusion.getScriptLanguage() ;
+ var options = {
+ parameters: {'session': this.getSessionID(),
+ 'mapname': this._sMapname},
+ onSuccess: OpenLayers.Function.bind(this.selectionCleared, this)
+ };
+ Fusion.ajaxRequest(s, options);
}
},
@@ -742,7 +740,8 @@
if (!this.queryLayer) {
this.queryLayer = this.createOLLayer("query layer", false, true);
this.mapWidget.oMapOL.addLayer(this.queryLayer);
- this.mapWidget.registerForEvent(Fusion.Event.MAP_LOADING, this.removeQueryLayer.bind(this));
+ this.mapWidget.registerForEvent(Fusion.Event.MAP_LOADING,
+ OpenLayers.Function.bind(this.removeQueryLayer, this));
} else {
this.queryLayer.setVisibility(true);
}
@@ -782,24 +781,32 @@
this.aLayers[j].selectedFeatureCount = 0;
}
- var geometry = options.geometry || '';
- var maxFeatures = options.maxFeatures || 0; //zero means select all features
var bPersistant = options.persistent || true;
- var selectionType = options.selectionType || this.selectionType;
- var filter = options.filter ? '&filter='+options.filter : '';
- var layers = options.layers || '';
- var extend = options.extendSelection ? '&extendselection=true' : '';
- var computed = options.computedProperties ? '&computed=true' : '';
var zoomTo = options.zoomTo ? true : false;
var sl = Fusion.getScriptLanguage();
var loadmapScript = this.arch + '/' + sl + '/Query.' + sl;
- var sessionid = this.getSessionID();
-
- var params = 'mapname='+this._sMapname+"&session="+sessionid+'&spatialfilter='+geometry+'&maxfeatures='+maxFeatures+filter+'&layers='+layers+'&variant='+selectionType+extend+computed;
- var options = {onSuccess: this.processQueryResults.bind(this, zoomTo),
- parameters: params};
- Fusion.ajaxRequest(loadmapScript, options);
+ var params = {
+ 'mapname': this._sMapname,
+ 'session': this.getSessionID(),
+ 'spatialfilter': options.geometry || '',
+ 'maxfeatures': options.maxFeatures || 0, //zero means select all features
+ 'layers': options.layers || '',
+ 'variant': options.selectionType || this.selectionType
+ }
+ if (options.filter) {
+ params.filter= options.filter;
+ }
+ if (options.extendSelection) {
+ params.extendselection = true;
+ }
+ if (options.computedProperties) {
+ params.computed = true;
+ }
+ var ajaxOptions = {
+ onSuccess: OpenLayers.Function.bind(this.processQueryResults, this, zoomTo),
+ parameters: params};
+ Fusion.ajaxRequest(loadmapScript, ajaxOptions);
},
processLayerEvents: function(layer, isEnabling) {
@@ -935,6 +942,7 @@
var persist = 0;
var selection = 'INTERSECTS';
var layerNames = '';
+ var layerAttributeFilter = 3;
var sep = '';
for (var i=0; i<this.aLayers.length; ++i) {
layerNames += sep + this.aLayers[i].layerName;
@@ -943,21 +951,24 @@
var r = new Fusion.Lib.MGRequest.MGQueryMapFeatures(this.mapWidget.getSessionID(),
this._sMapname,
sGeometry,
- maxFeatures, persist, selection, layerNames);
- Fusion.oBroker.dispatchRequest(r, this.crtlClickDisplay.bind(this));
+ maxFeatures, persist, selection, layerNames,
+ layerAttributeFilter);
+ var callback = OpenLayers.Function.bind(this.crtlClickDisplay, this);
+ Fusion.oBroker.dispatchRequest(r, OpenLayers.Function.bind(Fusion.xml2json, this, callback));
}
},
/**
* open a window if a URL is defined for the feature.
**/
- crtlClickDisplay: function(r) {
+ crtlClickDisplay: function(xhr) {
//console.log('ctrlclcik _display');
- if (r.responseXML) {
- var d = new DomNode(r.responseXML);
- var h = d.getNodeText('Hyperlink');
- if (h != '') {
- window.open(h, "");
+ if (xhr.status == 200) {
+ var o;
+ eval('o='+xhr.responseText);
+ var h = o['FeatureInformation']['Hyperlink'];
+ if (h) {
+ window.open(h[0], "");
}
}
},
@@ -965,7 +976,7 @@
pingServer: function() {
var s = this.arch + '/' + Fusion.getScriptLanguage() + "/Common." + Fusion.getScriptLanguage() ;
var params = {};
- params.parameters = 'session='+this.getSessionID();
+ params.parameters = {'session': this.getSessionID()};
Fusion.ajaxRequest(s, params);
},
getGroupInfoUrl: function(groupName) {
@@ -990,7 +1001,7 @@
}
return null;
}
-};
+});
/***************************************************************************
* Class: Fusion.Maps.MapGuide.Group
@@ -998,12 +1009,11 @@
* Implements the map layer groups for MapGuide services
*/
-Fusion.Maps.MapGuide.Group = Class.create();
-Fusion.Maps.MapGuide.Group.prototype = {
+Fusion.Maps.MapGuide.Group = OpenLayers.Class(Fusion.Widget.Map.Group, {
oMap: null,
initialize: function(o, oMap) {
this.uniqueId = o.uniqueId;
- Object.inheritFrom(this, Fusion.Widget.Map.Group.prototype, [o.groupName]);
+ Fusion.Widget.Map.Group.prototype.initialize.apply(this, [o.groupName]);
this.oMap = oMap;
this.groupName = o.groupName;
this.legendLabel = o.legendLabel;
@@ -1040,7 +1050,7 @@
isVisible: function() {
return this.visible;
}
-};
+});
/***************************************************************************
* Class: Fusion.Maps.MapGuide
@@ -1048,15 +1058,14 @@
* Implements individual map legend layers for MapGuide services
*/
-Fusion.Maps.MapGuide.Layer = Class.create();
-Fusion.Maps.MapGuide.Layer.prototype = {
+Fusion.Maps.MapGuide.Layer = OpenLayers.Class(Fusion.Widget.Map.Layer, {
scaleRanges: null,
oMap: null,
initialize: function(o, oMap) {
this.uniqueId = o.uniqueId;
- Object.inheritFrom(this, Fusion.Widget.Map.Layer.prototype, [o.layerName]);
+ Fusion.Widget.Map.Layer.prototype.initialize.apply(this, [o.layerName]);
this.oMap = oMap;
this.layerName = o.layerName;
this.uniqueId = o.uniqueId;
@@ -1135,7 +1144,7 @@
isVisible: function() {
return this.visible;
}
-};
+});
/***************************************************************************
* Class: Fusion.Maps.MapGuide
@@ -1143,8 +1152,7 @@
* Implements a scale range object for MapGuide services
*/
-Fusion.Maps.MapGuide.ScaleRange = Class.create();
-Fusion.Maps.MapGuide.ScaleRange.prototype = {
+Fusion.Maps.MapGuide.ScaleRange = OpenLayers.Class({
styles: null,
initialize: function(o, layerType) {
this.minScale = o.minScale;
@@ -1165,9 +1173,10 @@
}
},
contains: function(fScale) {
- return fScale >= this.minScale && fScale <= this.maxScale;
+ var testScale = Math.round(fScale);
+ return testScale >= this.minScale && testScale <= this.maxScale;
}
-};
+});
/***************************************************************************
* Class: Fusion.Maps.MapGuide
@@ -1175,8 +1184,8 @@
* Implements the legend style items to get a legend icon from the server
*/
-Fusion.Maps.MapGuide.StyleItem = Class.create();
-Fusion.Maps.MapGuide.StyleItem.prototype = {
+Fusion.Maps.MapGuide.StyleItem = OpenLayers.Class({
+ clientAgent: 'Fusion Viewer',
initialize: function(o, staticIcon) {
this.legendLabel = o.legendLabel;
this.filter = o.filter;
@@ -1192,6 +1201,6 @@
},
getLegendImageURL: function(fScale, layer) {
var url = Fusion.getConfigurationItem('mapguide', 'mapAgentUrl');
- return url + "OPERATION=GETLEGENDIMAGE&SESSION=" + layer.oMap.getSessionID() + "&VERSION=1.0.0&SCALE=" + fScale + "&LAYERDEFINITION=" + encodeURIComponent(layer.resourceId) + "&THEMECATEGORY=" + this.categoryIndex + "&TYPE=" + this.geometryType;
+ return url + "OPERATION=GETLEGENDIMAGE&SESSION=" + layer.oMap.getSessionID() + "&VERSION=1.0.0&SCALE=" + fScale + "&LAYERDEFINITION=" + encodeURIComponent(layer.resourceId) + "&THEMECATEGORY=" + this.categoryIndex + "&TYPE=" + this.geometryType + "&CLIENTAGENT=" + encodeURIComponent(this.clientAgent);
}
-};
+});
Modified: sandbox/aboudreault/MapGuide/php/Buffer.php
===================================================================
--- sandbox/aboudreault/MapGuide/php/Buffer.php 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/MapGuide/php/Buffer.php 2008-05-29 14:21:40 UTC (rev 1413)
@@ -158,12 +158,10 @@
$layerSrsWkt = $spatialContext->GetCoordinateSystemWkt();
/* skip this layer if the srs is empty */
if($layerSrsWkt == "") {
- $excludedLayers ++;
continue;
}
} else {
/* skip this layer if there is no spatial context at all */
- $excludedLayers ++;
continue;
}
@@ -182,7 +180,6 @@
//
if(($arbitraryDsSrs != $arbitraryMapSrs) || ($arbitraryDsSrs && ($dsSrsUnits != $mapSrsUnits)))
{
- $excludedLayers ++;
continue;
}
@@ -191,15 +188,19 @@
$dist = $layerCs->ConvertMetersToCoordinateSystemUnits($distance);
// calculate great circle unless data source srs is arbitrary
+ $verMajor = subStr(GetSiteVersion(), 0,1);
if(!$arbitraryDsSrs) {
- $measure = new MgCoordinateSystemMeasure($layerCs);
+ if ($verMajor == '1') {
+ $measure = new MgCoordinateSystemMeasure($layerCs);
+ } else {
+ $measure = $layerCs->GetMeasure();
+ }
} else {
$measure = null;
}
// create a SRS transformer if necessary.
if($layerSrsWkt != $srsDefMap) {
- $verMajor = subStr(GetSiteVersion(), 0,1);
if ($verMajor == '1') {
$srsXform = new MgCoordinateSystemTransform($layerCs, $srsMap);
} else {
Modified: sandbox/aboudreault/MapGuide/php/Common.php
===================================================================
--- sandbox/aboudreault/MapGuide/php/Common.php 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/MapGuide/php/Common.php 2008-05-29 14:21:40 UTC (rev 1413)
@@ -74,6 +74,8 @@
$username = isset($_REQUEST['username']) ? $_REQUEST['username'] : 'Anonymous';
$password = isset($_REQUEST['password']) ? $_REQUEST['password'] : '';
$user = new MgUserInformation($username, $password);
+ $user->SetClientIp(GetClientIp());
+ $user->SetClientAgent(GetClientAgent());
$siteConnection = new MgSiteConnection();
$siteConnection->Open($user);
} else {
@@ -90,9 +92,13 @@
/* current user is re-authenticating or not? */
if (isset($_REQUEST['username']) && isset($_REQUEST['password'])) {
$user = new MgUserInformation($_REQUEST['username'], $_REQUEST['password']);
+ $user->SetClientIp(GetClientIp());
+ $user->SetClientAgent(GetClientAgent());
$user->SetMgSessionId($sessionID);
} else {
$user = new MgUserInformation($sessionID);
+ $user->SetClientIp(GetClientIp());
+ $user->SetClientAgent(GetClientAgent());
}
/* open a connection to the site. This will generate exceptions if the user
@@ -118,7 +124,6 @@
echo "</Exception>";
exit;
} catch (MgUserNotFoundException $unfe) {
- header("HTTP/1.0 500 Internal Server Error");
header('Content-type: text/xml');
echo "<Exception>";
echo "<Type>User Not Found</Type>";
@@ -256,5 +261,29 @@
return $numberString;
}
+function GetClientIp()
+{
+ $clientIp = '';
+ if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)
+ && strcasecmp($_SERVER['HTTP_CLIENT_IP'], 'unknown') != 0)
+ {
+ $clientIp = $_SERVER['HTTP_CLIENT_IP'];
+ }
+ else if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)
+ && strcasecmp($_SERVER['HTTP_X_FORWARDED_FOR'], 'unknown') != 0)
+ {
+ $clientIp = $_SERVER['HTTP_X_FORWARDED_FOR'];
+ }
+ else if (array_key_exists('REMOTE_ADDR', $_SERVER))
+ {
+ $clientIp = $_SERVER['REMOTE_ADDR'];
+ }
+ return $clientIp;
+}
+function GetClientAgent()
+{
+ return "Fusion Viewer";
+}
+
?>
Modified: sandbox/aboudreault/MapGuide/php/CreateSession.php
===================================================================
--- sandbox/aboudreault/MapGuide/php/CreateSession.php 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/MapGuide/php/CreateSession.php 2008-05-29 14:21:40 UTC (rev 1413)
@@ -44,8 +44,10 @@
echo var2json($result);
/* start a php session in the web tier as well, using same session id */
- session_start($sessionId);
+ session_id(str_replace('_', '-', $sessionId));
+ session_start();
$_SESSION['username'] = $username;
+ loadFusionConfig();
} catch (MgException $e) {
echo "ERROR: " . $e->GetMessage() . "n";
Modified: sandbox/aboudreault/MapGuide/php/Query.php
===================================================================
--- sandbox/aboudreault/MapGuide/php/Query.php 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/MapGuide/php/Query.php 2008-05-29 14:21:40 UTC (rev 1413)
@@ -115,6 +115,7 @@
$className = $layerObj->GetFeatureClassName();
if (!$layerObj->GetSelectable() || !$layerObj->IsVisible() ||
+ $className=='RedlineSchema:Redline' ||
!$className || $className=='rasters:RasterType' ||$className=='') {
continue;
}
Modified: sandbox/aboudreault/MapGuide/php/SaveMap.php
===================================================================
--- sandbox/aboudreault/MapGuide/php/SaveMap.php 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/MapGuide/php/SaveMap.php 2008-05-29 14:21:40 UTC (rev 1413)
@@ -29,9 +29,14 @@
*****************************************************************************/
include('Common.php');
-$format = isset($_REQUEST['format']) ? $_REQUEST['format'] : 'png';
-$layout = isset($_REQUEST['layout']) ? $_REQUEST['layout'] : null;
-$scale = isset($_REQUEST['scale']) ? $_REQUEST['scale'] : null;
+$format = isset($_REQUEST['format']) ? $_REQUEST['format'] : 'png';
+$layout = isset($_REQUEST['layout']) ? $_REQUEST['layout'] : null;
+$scale = isset($_REQUEST['scale']) ? $_REQUEST['scale'] : null;
+$imgWidth = isset($_REQUEST['width']) ? $_REQUEST['width'] : null;
+$imgHeight = isset($_REQUEST['height']) ? $_REQUEST['height'] : null;
+$pageHeight = isset($_REQUEST['pageheight']) ? $_REQUEST['pageheight'] : 11;
+$pageWidth = isset($_REQUEST['pagewidth']) ? $_REQUEST['pagewidth'] : 8.5;
+$aMargins = isset($_REQUEST['margins']) ? explode(',',$_REQUEST['margins']) : array(0,0,0,0);
try
{
@@ -43,44 +48,41 @@
$selection = new MgSelection($map);
$selection->Open($resourceService, $mapName);
+ //compute center
+ $extent = $map->GetMapExtent();
+ $centerX = $extent->GetLowerLeftCoordinate()->GetX() + ($extent->GetWidth())/2;
+ $centerY = $extent->GetLowerLeftCoordinate()->GetY() + ($extent->GetHeight())/2;
+ $geomFactory = new MgGeometryFactory();
+ $center = $geomFactory->CreateCoordinateXY($centerX, $centerY);
+
if ($format == 'DWF') {
- $extent = $map->GetMapExtent();
$oLayout = null;
if ($layout) {
$layoutId = new MgResourceIdentifier($layout);
$layoutId->Validate();
$oLayout = new MgLayout($layoutId,'Map', 'meters');
- }
- $oPlotSpec = new MgPlotSpecification(8.5,11,MgPageUnitsType::Inches);
+ };
+ $oPlotSpec = new MgPlotSpecification($pageWidth,$pageHeight,MgPageUnitsType::Inches,
+ $aMargins[0],
+ $aMargins[1],
+ $aMargins[2],
+ $aMargins[3]
+ );
$dwfVersion = new MgDwfVersion('6.01','1.2');
if ($scale) {
- //compute center point and plot with the passed scale
-
- $centerX = $extent->GetLowerLeftCoordinate()->GetX() + ($extent->GetWidth())/2;
- $centerY = $extent->GetLowerLeftCoordinate()->GetY() + ($extent->GetHeight())/2;
- $geomFactory = new MgGeometryFactory();
- $center = $geomFactory->CreateCoordinateXY($centerX, $centerY);
+ //plot with the passed scale
- //echo $centerX.", ".$centerY;exit;
- //$metersPerUnit = $map->GetMetersPerUnit();
$coordSysFactory = new MgCoordinateSystemFactory();
$coordSystem = $coordSysFactory->Create($map->GetMapSRS());
$metersPerUnit = $coordSystem->ConvertCoordinateSystemUnitsToMeters(1.0);
$metersPerPixel = 1.0/(100.0 / 2.54 * $map->GetDisplayDpi());
- //echo $metersPerPixel; exit;
$height = $map->GetDisplayHeight();
$width = $map->GetDisplayWidth();
$mapWidth = $scale * $width * $metersPerPixel/$metersPerUnit;
$mapHeight = $scale * $height * $metersPerPixel/$metersPerUnit;
- //echo $mapWidth.", ".$mapHeight;exit;
-
- // $lowerLeft = $geomFactory->CreateCoordinateXY($center->GetX() - 0.5*$mapWidth,
- // $center->GetY() - 0.5*$mapHeight);
- // $topRight = $geomFactory->CreateCoordinateXY($center->GetX() + 0.5*$mapWidth,
- // $center->GetY() + 0.5*$mapHeight);
$extent = new MgEnvelope(
$center->GetX() - 0.5*$mapWidth,
$center->GetY() - 0.5*$mapHeight,
@@ -113,8 +115,18 @@
$dwfVersion);
}
} else {
- $oImg = $renderingService->RenderMap($map, $selection, $format);
- }
+ //render as an image
+ if (isset($imgHeight) && isset($imgWidth)) {
+ $scale = $map->GetViewScale();
+ $oImg = $renderingService->RenderMap($map, $selection,
+ $center, $scale,
+ $imgWidth, $imgHeight,
+ new MgColor(255,255,255),
+ $format);
+ }else{
+ $oImg = $renderingService->RenderMap($map, $selection, $format);
+ };
+ };
}
catch (MgException $e)
{
@@ -124,16 +136,8 @@
exit;
}
-/*
+header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
-header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
- // always modified
-header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1
-header("Cache-Control: post-check=0, pre-check=0", false);
-header("Pragma: no-cache"); // HTTP/1.0
-header( "Content-type: application/octet-stream" );
-header( "Content-Disposition: attachment; filename=$mapName.png" );
-*/
header( "Content-type: image/$format" );
header( "Content-disposition: attachment; filename=$mapName.$format" );
Modified: sandbox/aboudreault/MapServer/MapServer.js
===================================================================
--- sandbox/aboudreault/MapServer/MapServer.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/MapServer/MapServer.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,8 +30,7 @@
*/
Fusion.Event.MAP_LAYER_ORDER_CHANGED = Fusion.Event.lastEventId++;
-Fusion.Maps.MapServer = Class.create();
-Fusion.Maps.MapServer.prototype = {
+Fusion.Maps.MapServer = OpenLayers.Class(Fusion.Lib.EventMgr, {
arch: 'MapServer',
session: [null],
aShowLayers: null,
@@ -59,8 +58,14 @@
initialize : function(map, mapTag, isMapWidgetLayer) {
//console.log('Fusion.Maps.MapServer.initialize');
- Object.inheritFrom(this, Fusion.Lib.EventMgr, []);
+ /*
+ //Object.inheritFrom(this, Fusion.Lib.EventMgr, []);
+
+ prototype is not yet defined when this is called now omitting.
+ Fusion.Lib.EventMgr.prototype.initialize.apply(this, []);
+ */
+
this.registerEventID(Fusion.Event.MAP_SESSION_CREATED);
this.registerEventID(Fusion.Event.MAP_SELECTION_ON);
this.registerEventID(Fusion.Event.MAP_SELECTION_OFF);
@@ -112,18 +117,19 @@
this.session[0] = this;
var sl = Fusion.getScriptLanguage();
var scriptURL = this.arch + '/' + sl + '/CreateSession.' + sl;
- var options = {onComplete: this.createSessionCB.bind(this)};
+ var options = {onSuccess: OpenLayers.Function.bind(this.createSessionCB, this)};
Fusion.ajaxRequest(scriptURL,options);
}
if (this.session[0] instanceof Fusion.Maps.MapServer) {
- this.session[0].registerForEvent(Fusion.Event.MAP_SESSION_CREATED, this.mapSessionCreated.bind(this));
+ this.session[0].registerForEvent(Fusion.Event.MAP_SESSION_CREATED,
+ OpenLayers.Function.bind(this.mapSessionCreated, this));
} else {
this.mapSessionCreated();
}
},
- createSessionCB : function(r, json) {
- if (r.status == 200 && json) {
+ createSessionCB : function(r) {
+ if (r.status == 200) {
var o;
eval('o='+r.responseText);
this.session[0] = o.sessionId;
@@ -135,7 +141,8 @@
if (this.sMapFile != '') {
this.loadMap(this.sMapFile);
}
- window.setInterval(this.pingServer.bind(this), this.keepAliveInterval * 1000);
+ window.setInterval(OpenLayers.Function.bind(this.pingServer, this),
+ this.keepAliveInterval * 1000);
},
sessionReady: function() {
@@ -193,33 +200,29 @@
var sl = Fusion.getScriptLanguage();
var loadmapScript = this.arch + '/' + sl + '/LoadMap.' + sl;
-
- var sessionid = this.getSessionID();
-
- var metadata = '';
+ var params = {
+ 'mapfile': mapfile,
+ 'session': this.getSessionID()
+ };
if (this.mapMetadataKeys) {
- metadata += '&map_metadata='+this.mapMetadataKeys;
+ params.map_metadata = this.mapMetadataKeys;
}
if (this.layerMetadataKeys) {
- metadata += '&layer_metadata='+this.layerMetadataKeys;
+ params.layer_metadata = this.layerMetadataKeys;
}
-
- var params = 'mapfile='+mapfile+"&session="+sessionid+metadata;
- var options = {onSuccess: this.mapLoaded.bind(this),
- parameters: params};
+ var options = {onSuccess:OpenLayers.Function.bind(this.mapLoaded, this), parameters: params};
Fusion.ajaxRequest(loadmapScript, options);
},
- mapLoaded: function(r, json) {
- if (json)
+ mapLoaded: function(r) {
+ if (r.status == 200)
{
var o;
eval('o='+r.responseText);
this._sMapFile = o.mapId;
this._sMapname = o.mapName;
this._sMapTitle = o.mapTitle;
- this._fMetersperunit = o.metersPerUnit;
- this.mapWidget._fMetersperunit = this._fMetersperunit;
+ this.mapWidget.setMetersPerUnit(o.metersPerUnit);
this._sImageType = o.imagetype;
this.metadata = o.metadata;
@@ -248,32 +251,19 @@
OpenLayers.DOTS_PER_INCH = o.dpi;
}
+ //to allow for scaling that doesn't match any of the pre-canned units
+ this.units = Fusion.getClosestUnits(o.metersPerUnit);
+
var layerOptions = {
singleTile: true,
ratio: this.ratio,
+ units: this.units,
maxExtent : this._oMaxExtent,
- maxResolution : 'auto',
+ maxResolution : 'auto',
minScale : maxScale, //OL interpretation of min/max scale is reversed from Fusion
maxScale : minScale
};
- //set OpenLayer projection units and code if supplied (OL defaults units to degrees)
- if (o.metersPerUnit == 0.0254)
- layerOptions.units = 'inches';
- else if (o.metersPerUnit == 0.3048)
- layerOptions.units = 'ft';
- else if (o.metersPerUnit == 1609.344)
- layerOptions.units = 'mi';
- else if (o.metersPerUnit == 1)
- layerOptions.units = 'm';
- //layerOptions.projection = 'EPSG:42304'; //TODO: not necessary, but can this be supplied by LoadMap?
- else if (o.metersPerUnit == 1000)
- layerOptions.units = 'km';
- else if (o.metersPerUnit == 111118.7516)
- layerOptions.units = 'dd';
-
- //this.mapWidget.setMapOptions(oMapOptions);
-
//create the OL layer for this Map layer
var params = {
layers: this.aVisibleLayers.join(' '),
@@ -329,23 +319,23 @@
var sl = Fusion.getScriptLanguage();
var loadmapScript = this.arch + '/' + sl + '/LoadMap.' + sl;
- var sessionid = this.getSessionID();
- var metadata = '';
+ var params = {
+ 'mapname': this._sMapname,
+ 'session': this.getSessionID()
+ };
if (this.mapMetadataKeys) {
- metadata += '&map_metadata='+this.mapMetadataKeys;
+ params.map_metadata = this.mapMetadataKeys;
}
if (this.layerMetadataKeys) {
- metadata += '&layer_metadata='+this.layerMetadataKeys;
+ params.layer_metadata = this.layerMetadataKeys;
}
-
- var params = 'mapname='+this._sMapname+"&session="+sessionid+metadata;
- var options = {onSuccess: this.mapReloaded.bind(this),
+ var options = {onSuccess: OpenLayers.Function.bind(this.mapReloaded, this),
parameters: params};
Fusion.ajaxRequest(loadmapScript, options);
},
- mapReloaded: function(r,json) { /* update this with OL code */
- if (json) {
+ mapReloaded: function(r) {
+ if (r.status == 200) {
var o;
eval('o='+r.responseText);
@@ -363,7 +353,7 @@
this.mapWidget.triggerEvent(Fusion.Event.MAP_RELOADED);
} else {
Fusion.reportError( new Fusion.Error(Fusion.Error.FATAL,
- OpenLayers.String.translate('mapLoadError', r.responseText)));
+ OpenLayers.i18n('mapLoadError', {'error':r.responseText})));
}
this.mapWidget._removeWorker();
},
@@ -372,17 +362,18 @@
var sl = Fusion.getScriptLanguage();
var loadmapScript = this.arch + '/' + sl + '/SetLayers.' + sl;
- var sessionid = this.getSessionID();
- var params = 'mapname='+this._sMapname+"&session="+sessionid;
- params += '&layerindex=' + aLayerIndex.join();
-
- var options = {onSuccess: this.mapLayersReset.bind(this, aLayerIndex),
+ var params = {
+ 'mapname': this._sMapname,
+ 'session': this.getSessionID(),
+ 'layerindex': aLayerIndex.join()
+ };
+ var options = {onSuccess: OpenLayers.Function.bind(this.mapLayersReset, this, aLayerIndex),
parameters: params};
Fusion.ajaxRequest(loadmapScript, options);
},
- mapLayersReset: function(aLayerIndex,r,json) {
- if (json) {
+ mapLayersReset: function(aLayerIndex,r) {
+ if (r.status == 200) {
var o;
eval('o='+r.responseText);
if (o.success) {
@@ -401,7 +392,7 @@
this.drawMap();
this.triggerEvent(Fusion.Event.MAP_LAYER_ORDER_CHANGED);
} else {
- alert(OpenLayers.String.translate('setLayersError', o.layerindex));
+ alert(OpenLayers.i18n('setLayersError', {'error':o.layerindex}));
}
}
},
@@ -526,13 +517,13 @@
hasSelection: function() { return this.bSelectionOn; },
- getSelectionCB : function(userFunc, layers, startend, r, json) {
- if (json)
+ getSelectionCB : function(userFunc, layers, startend, r) {
+ if (r.status == 200)
{
var o;
eval("o="+r.responseText);
- var oSelection = new GxSelectionObject(o);
+ var oSelection = new Fusion.SelectionObject(o);
userFunc(oSelection);
}
},
@@ -608,9 +599,18 @@
if (userFunc)
{
var s = this.arch + '/' + Fusion.getScriptLanguage() + "/Selection." + Fusion.getScriptLanguage() ;
- var params = {parameters:'session='+this.getSessionID()+'&mapname='+ this._sMapname+ '&layers='+layers+'&startcount='+startcount+'&queryfile='+this._sQueryfile,
- onComplete: this.getSelectionCB.bind(this, userFunc, layers, startcount)};
- Fusion.ajaxRequest(s, params);
+ var params = {
+ 'mapname': this._sMapname,
+ 'session': this.getSessionID(),
+ 'layers': layers,
+ 'startcount': startcount,
+ 'queryfile': this._sQueryfile
+ };
+ var options = {
+ parameters:params,
+ onSuccess: OpenLayers.Function.bind(this.getSelectionCB, this, userFunc, layers, startcount)
+ };
+ Fusion.ajaxRequest(s, options);
}
},
@@ -637,9 +637,9 @@
/**
Call back function when slect functions are called (eg queryRect)
*/
- processQueryResults : function(zoomTo, r, json) {
+ processQueryResults : function(zoomTo, r) {
this.mapWidget._removeWorker();
- if (json) {
+ if (r.status == 200) {
var o;
eval("o="+r.responseText);
if (!o.hasSelection) {
@@ -678,58 +678,68 @@
for (var j=0; j<this.aLayers.length; ++j) {
this.aLayers[j].selectedFeatureCount = 0;
}
-
- var geometry = options.geometry || '';
- var maxFeatures = options.maxFeatures || -1;
+
var bPersistant = options.persistent || true;
- var selectionType = options.selectionType || this.selectionType;
- var filter = options.filter ? '&filter='+options.filter : '';
var layers = options.layers || '';
/* if no layes are given, query only visible layers. This is ususally the most common case*/
if (layers == '') {
layers = this.aVisibleLayers.join(',');
}
- var extend = options.extendSelection ? '&extendselection=true' : '';
- var computed = options.computedProperties ? '&computed=true' : '';
var zoomTo = options.zoomTo || false;
var sl = Fusion.getScriptLanguage();
- var loadmapScript = this.arch + '/' + sl + '/Query.' + sl;
-
- var sessionid = this.getSessionID();
-
- var params = 'mapname='+this._sMapname+"&session="+sessionid+'&spatialfilter='+geometry+'&maxfeatures='+maxFeatures+filter+'&layers='+layers+'&variant='+selectionType+extend;
- var options = {onSuccess: this.processQueryResults.bind(this, zoomTo),
- parameters: params};
- Fusion.ajaxRequest(loadmapScript, options);
+ var queryScript = this.arch + '/' + sl + '/Query.' + sl;
+
+ var params = {
+ 'mapname': this._sMapname,
+ 'session': this.getSessionID(),
+ 'spatialfilter': options.geometry || '',
+ 'maxfeatures': options.maxFeatures || -1, //-1 means select all features
+ 'layers': layers,
+ 'variant': options.selectionType || this.selectionType
+ }
+ if (options.filter) {
+ params.filter = options.filter;
+ }
+ if (options.extendSelection) {
+ params.extendselection = true;
+ }
+ if (options.computedProperties) {
+ params.computed = true;
+ }
+ var ajaxOptions = {
+ onSuccess: OpenLayers.Function.bind(this.processQueryResults, this, zoomTo),
+ parameters: params
+ };
+ Fusion.ajaxRequest(queryScript, ajaxOptions);
}
},
/**
- Do a query by attribute
+ Do a query by attribute
*/
search : function(options) {
this.mapWidget._addWorker();
//clear the selection count for the layers
for (var j=0; j<this.aLayers.length; ++j) {
- this.aLayers[j].selectedFeatureCount = 0;
+ this.aLayers[j].selectedFeatureCount = 0;
}
-
+
var matchlimit = options.matchlimit || -1;
var layer = options.layer || '';
var attribute = options.attribute || '';
var pattern = options.pattern || '';
var sl = Fusion.getScriptLanguage();
var loadmapScript = this.arch + '/' + sl + '/Search.' + sl;
-
+
var sessionid = this.getSessionID();
-
+
var params = 'mapname='+this._sMapname+"&session="+sessionid+'&matchlimit='+matchlimit+'&layer='+layer+'&attribute='+attribute+'&pattern='+pattern;
- var options = {onSuccess: this.processQueryResults.bind(this, false),
- parameters: params};
+ var options = {onSuccess: this.processQueryResults.bind(this, false),
+ parameters: params};
Fusion.ajaxRequest(loadmapScript, options);
},
-
+
loadStart: function() {
this.mapWidget._addWorker();
},
@@ -741,7 +751,7 @@
pingServer: function() {
var s = this.arch + '/' + Fusion.getScriptLanguage() + "/Common." + Fusion.getScriptLanguage() ;
var params = {};
- params.parameters = 'session='+this.getSessionID();
+ params.parameters = {'session': this.getSessionID()};
Fusion.ajaxRequest(s, params);
},
@@ -761,7 +771,7 @@
}
}
-};
+});
/******************************************************************************
@@ -770,12 +780,11 @@
* Implements the map layer groups for MapServer CGI services
*/
-Fusion.Maps.MapServer.Group = Class.create();
-Fusion.Maps.MapServer.Group.prototype = {
+Fusion.Maps.MapServer.Group = OpenLayers.Class(Fusion.Widget.Map.Group, {
oMap: null,
initialize: function(o, oMap) {
this.uniqueId = o.uniqueId;
- Object.inheritFrom(this, Fusion.Widget.Map.Group.prototype, [this.uniqueId]);
+ Fusion.Widget.Map.Group.prototype.initialize.apply(this, [o.groupName]);
this.oMap = oMap;
this.groupName = o.groupName;
this.legendLabel = o.legendLabel;
@@ -807,7 +816,7 @@
return this.visible && bParentVisible;
}
-};
+});
var MSLAYER_POINT_TYPE = 0;
var MSLAYER_LINE_TYPE = 1;
@@ -821,8 +830,7 @@
* Implements individual map legend layers for MapServer services
*/
-Fusion.Maps.MapServer.Layer = Class.create();
-Fusion.Maps.MapServer.Layer.prototype = {
+Fusion.Maps.MapServer.Layer = OpenLayers.Class(Fusion.Widget.Map.Group, {
scaleRanges: null,
@@ -830,7 +838,7 @@
initialize: function(o, oMap) {
this.uniqueId = o.uniqueId;
- Object.inheritFrom(this, Fusion.Widget.Map.Layer.prototype, [this.uniqueId]);
+ Fusion.Widget.Map.Layer.prototype.initialize.apply(this, [this.uniqueId]);
this.oMap = oMap;
this.layerName = o.layerName;
this.uniqueId = o.uniqueId;
@@ -903,7 +911,7 @@
return '';
}
}
-};
+});
/******************************************************************************
* Class: Fusion.Maps.MapServer.ScaleRange
@@ -911,8 +919,7 @@
* Implements a scale range object for MapServer services
*/
-Fusion.Maps.MapServer.ScaleRange = Class.create();
-Fusion.Maps.MapServer.ScaleRange.prototype = {
+Fusion.Maps.MapServer.ScaleRange = OpenLayers.Class({
styles: null,
initialize: function(o, bRaster) {
this.minScale = o.minScale;
@@ -944,9 +951,10 @@
}
},
contains: function(fScale) {
- return fScale >= this.minScale && fScale <= this.maxScale;
+ var testScale = Math.round(fScale);
+ return testScale >= this.minScale && testScale <= this.maxScale;
}
-};
+});
/******************************************************************************
* Class: Fusion.Maps.MapServer.StyleItem
@@ -954,8 +962,7 @@
* Implements the legend style items to get a legend icon from the server
*/
-Fusion.Maps.MapServer.StyleItem = Class.create();
-Fusion.Maps.MapServer.StyleItem.prototype = {
+Fusion.Maps.MapServer.StyleItem = OpenLayers.Class({
initialize: function(o, staticIcon) {
this.legendLabel = o.legendLabel;
this.filter = o.filter;
@@ -969,4 +976,4 @@
var params = 'mapname='+layer.oMap._sMapname+"&session="+sessionid + '&layername='+layer.resourceId + '&classindex='+this.index;
return url + '?'+params;
}
-};
+});
Modified: sandbox/aboudreault/MapServer/php/CreateSession.php
===================================================================
--- sandbox/aboudreault/MapServer/php/CreateSession.php 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/MapServer/php/CreateSession.php 2008-05-29 14:21:40 UTC (rev 1413)
@@ -34,6 +34,7 @@
initializeSession( "sid", "", "" );
$sessionId = session_id();
+loadFusionConfig();
header('Content-type: text/x-json');
header('X-JSON: true');
Modified: sandbox/aboudreault/MapServer/php/LegendIcon.php
===================================================================
--- sandbox/aboudreault/MapServer/php/LegendIcon.php 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/MapServer/php/LegendIcon.php 2008-05-29 14:21:40 UTC (rev 1413)
@@ -37,55 +37,37 @@
$legendIconCacheFile = "";
if (isset($_SESSION['maps']) && isset($_SESSION['maps'][$mapName])) {
- /* json decode only in PHP 5.2 and later */
- if (function_exists('json_decode')) {
- $configFile = realpath(dirname(__FILE__)."/../../config.json");
- if (file_exists($configFile)) {
- $configStr = file_get_contents($configFile);
- /* replace single quotes with double quotes */
- $configStr = str_replace("'", '"', $configStr);
- /* get rid of new lines, it just complicates things */
- $configStr = str_replace("\n", '', $configStr);
- /* get rid of embedded comments */
- $configStr = preg_replace("/\/\*.*\*\//U", "", $configStr);
- /* the regex after this one can't handle http: as a value, so mangle it. */
- $configStr = preg_replace("/http:/U", "http_", $configStr);
- /* quote unquoted attribute names */
- $configStr = preg_replace("/[^\"]{1}(\w*):/U", "\"$1\":", $configStr);
- /* decode the whole thing */
- $configObj = json_decode($configStr, false);
- /* if the legendIconCache dir is set */
- if (isset($configObj->mapserver->legendIconCacheDir)) {
- $legendIconCacheDir = $configObj->mapserver->legendIconCacheDir;
+ $configObj = $_SESSION['fusionConfig'];
+ /* if the legendIconCache dir is set */
+ if (isset($configObj->mapserver->legendIconCacheDir)) {
+ $legendIconCacheDir = $configObj->mapserver->legendIconCacheDir;
- // check for closing '/'
- $legendIconCacheDir = str_replace( '\\', '/', trim( $legendIconCacheDir ) );
- if ( substr( $legendIconCacheDir, -1 ) != '/' )
- {
- $legendIconCacheDir .= '/';
- }
+ // check for closing '/'
+ $legendIconCacheDir = str_replace( '\\', '/', trim( $legendIconCacheDir ) );
+ if ( substr( $legendIconCacheDir, -1 ) != '/' )
+ {
+ $legendIconCacheDir .= '/';
+ }
- $cacheLegendIcons = true;
- $str = file_get_contents($_SESSION['maps'][$mapName]);
- /* create a unique location for the map icons based on
- * the content of the of map file. If the content changes
- * then the icons should be rebuilt anyway
- */
- $legendIconCacheDir = $legendIconCacheDir.md5($str)."/";
- if (!is_dir($legendIconCacheDir)) {
- mkdir($legendIconCacheDir);
- }
- /* TODO: can we figure out what the content type is? */
- $legendIconCacheFile = $legendIconCacheDir."_".$REQUEST_VARS['layername']."_".$REQUEST_VARS['classindex'].".png";
- /* if the icon exists, return it */
- if (file_exists($legendIconCacheFile)) {
- /* TODO: can we figure out what the content type is? */
- header('Content-type: image/png');
- readfile($legendIconCacheFile);
- exit;
- }
- }
+ $cacheLegendIcons = true;
+ $str = file_get_contents($_SESSION['maps'][$mapName]);
+ /* create a unique location for the map icons based on
+ * the content of the of map file. If the content changes
+ * then the icons should be rebuilt anyway
+ */
+ $legendIconCacheDir = $legendIconCacheDir.md5($str)."/";
+ if (!is_dir($legendIconCacheDir)) {
+ mkdir($legendIconCacheDir);
}
+ /* TODO: can we figure out what the content type is? */
+ $legendIconCacheFile = $legendIconCacheDir."_".$REQUEST_VARS['layername']."_".$REQUEST_VARS['classindex'].".png";
+ /* if the icon exists, return it */
+ if (file_exists($legendIconCacheFile)) {
+ /* TODO: can we figure out what the content type is? */
+ header('Content-type: image/png');
+ readfile($legendIconCacheFile);
+ exit;
+ }
}
$oMap = ms_newMapObj($_SESSION['maps'][$mapName]);
Modified: sandbox/aboudreault/build.xml
===================================================================
--- sandbox/aboudreault/build.xml 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/build.xml 2008-05-29 14:21:40 UTC (rev 1413)
@@ -89,6 +89,7 @@
-->
<property name="jx-lib" value="jx"/>
+ <property name="YUIcompressor" value="C:\YUI\yuicompressor-2.3.5\build\yuicompressor-2.3.5.jar"/>
<!-- ==================== Prepare Target ================================== -->
@@ -113,6 +114,7 @@
<copy todir="${build.home}">
<fileset dir="${basedir}"
includes="config.json
+ configHeader.json
MapGuide/**
MapServer/**
common/**
@@ -120,8 +122,6 @@
docs/**
ext/**
lib/**
- redist/**
- samples/**
templates/**
text/**
widgets/**"
@@ -161,8 +161,7 @@
</exec>
</target>
- <!--
- <target description="Create documentation" name="docs2" depends="prepare">
+ <target description="Create documentation" name="widgetInfo" depends="prepare">
<delete dir="${build.home}/docs/widgetinfo"/>
<mkdir dir="${build.home}/docs/widgetinfo"/>
<xslt basedir="${basedir}/widgets/widgetinfo"
@@ -170,8 +169,70 @@
style="${basedir}/widgets/widgetinfo/widgetInfo.xsl"
excludes="WidgetInfoTemplate.xml widgetInfo.xsl"/>
</target>
- -->
+<!-- =================== prepare AppDef for single file build ================================== -->
+ <target description="convert AppDef to JSON" name="appDef2Json" if="appDef">
+ <echo message="converting ${appDef} to JSON"/>
+ <delete dir="${build.home}/appDefFileset.xml"/>
+
+ <!-- generate the list of files for this Application and load as a property -->
+ <xslt in="${appDef}"
+ out="${build.home}/appDefFileset.xml"
+ style="${basedir}/parseAppDef.xsl">
+ <param name="buildHome" expression="${build.home}"/>
+ </xslt>
+ <xmlproperty file="${build.home}/appDefFileset.xml"/>
+
+ <!-- convert the application definition file to JSON -->
+ <exec executable="php" os="Windows Vista, Windows XP"
+ output="${build.home}/appDef.json">
+ <arg line="common\php\Xml2JSON.php --file='${appDef}'"/>
+ </exec>
+
+ </target>
+
+<!-- =================== single file build ================================== -->
+ <target description="single file build" name="singleFile" depends="clean,prepare,appDef2Json">
+ <echo message="preparing single file build for ${appDef}"/>
+ <delete dir="${build.home}/lib/fusionSF.js"/>
+
+ <!-- merge everything into a single file -->
+ <concat destfile="${build.home}/lib/fusionSF.js" outputencoding="UTF-8">
+ <filelist dir="${build.home}/lib"
+ files=" SingleFile.js
+ fusion.js
+ OpenLayers/OpenLayers.js
+ ../jx/lib/jx_combined.js
+ excanvas/excanvas.js
+ Error.js
+ EventMgr.js
+ ApplicationDefinition.js
+ MGBroker.js
+ Widget.js
+ ButtonBase.js
+ MenuBase.js
+ ButtonTool.js
+ CanvasTool.js
+ ClickTool.js
+ RectTool.js
+ Search.js
+ Map.js"
+ />
+ <fileset dir="${build.home}/text" includes="**/*.json"/>
+ <filelist dir="${build.home}" files="${AppDef.Maps}"/>
+ <filelist dir="${build.home}" files="${AppDef.Widgets}"/>
+ <filelist dir="${build.home}" files="appDef.json configHeader.json config.json"/>
+ </concat>
+
+ <echo message="compressing..."/>
+ <java jar="${YUIcompressor}" fork="true"
+ output="${build.home}/lib/fusionSF-compressed.js">
+ <arg value="${build.home}/lib/fusionSF.js"/>
+ </java>
+ <!--exec executable="jsmin.exe" os="Windows Vista, Windows XP"
+ input="${build.home}/lib/fusionSF.js" output="${build.home}/lib/fusionSF-compressed.js"/-->
+ </target>
+
<!-- =================== Compress Target ================================== -->
@@ -179,8 +240,8 @@
<echo message="Concatenating into -lib version"/>
<concat destfile="${build.home}/lib/fusion-combined.js" outputencoding="UTF-8">
<filelist dir="${build.home}/lib"
- files=" utils.js
- Error.js
+ files=" Error.js
+ EventMgr.js
ApplicationDefinition.js
MGBroker.js
Widget.js
@@ -199,8 +260,12 @@
<fileset dir="${build.home}/widgets" includes="*.js **/*.js" excludes="Recenter.js"/>
</concat>
<echo message="compressing..."/>
- <exec executable="jsmin.exe" os="Windows Vista, Windows XP"
- input="${build.home}/lib/fusion-combined.js" output="${build.home}/lib/fusion-compressed.js"/>
+ <java jar="${YUIcompressor}" fork="true"
+ output="${build.home}/lib/fusionSF-compressed.js">
+ <arg value="${build.home}/lib/fusionSF.js"/>
+ </java>
+ <!--exec executable="jsmin.exe" os="Windows Vista, Windows XP"
+ input="${build.home}/lib/fusion-combined.js" output="${build.home}/lib/fusion-compressed.js"/-->
</target>
<!-- ==================== Deploy ========================================== -->
Modified: sandbox/aboudreault/common/php/Utilities.php
===================================================================
--- sandbox/aboudreault/common/php/Utilities.php 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/common/php/Utilities.php 2008-05-29 14:21:40 UTC (rev 1413)
@@ -241,4 +241,47 @@
return $szResult;
}
+
+function arguments($argv) {
+ $_ARG = array();
+ foreach ($argv as $arg) {
+ if (ereg('--[a-zA-Z0-9]*=.*',$arg)) {
+ $str = split("=",$arg); $arg = '';
+ $key = ereg_replace("--",'',$str[0]);
+ for ( $i = 1; $i < count($str); $i++ ) {
+ $arg .= $str[$i];
+ }
+ $_ARG[$key] = $arg;
+ } elseif(ereg('-[a-zA-Z0-9]',$arg)) {
+ $arg = ereg_replace("-",'',$arg);
+ $_ARG[$arg] = 'true';
+ }
+ }
+ return $_ARG;
+}
+
+function loadFusionConfig() {
+ /* json decode only in PHP 5.2 and later */
+ if (function_exists('json_decode')) {
+ $configFile = realpath(dirname(__FILE__)."/../../config.json");
+ if (file_exists($configFile)) {
+ $configStr = file_get_contents($configFile);
+ /* replace single quotes with double quotes */
+ $configStr = str_replace("'", '"', $configStr);
+ /* get rid of new lines, it just complicates things */
+ $configStr = str_replace("\n", '', $configStr);
+ /* get rid of embedded comments */
+ $configStr = preg_replace("/\/\*.*\*\//U", "", $configStr);
+ /* the regex after this one can't handle http: as a value, so mangle it. */
+ $configStr = preg_replace("/http:/U", "http_", $configStr);
+ /* quote unquoted attribute names */
+ $configStr = preg_replace("/[^\"]{1}(\w*):/U", "\"$1\":", $configStr);
+ /* decode the whole thing */
+ $_SESSION['fusionConfig'] = json_decode($configStr, false);
+ } else {
+ echo "config file not found";
+ }
+ }
+}
+
?>
\ No newline at end of file
Modified: sandbox/aboudreault/common/php/Xml2JSON.php
===================================================================
--- sandbox/aboudreault/common/php/Xml2JSON.php 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/common/php/Xml2JSON.php 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,15 +30,32 @@
if (isset($_FILES['xml'])) {
$xml = file_get_contents($_FILES['xml']['tmp_name']);
-} else {
+} elseif (isset($_SERVER['HTTP_HOST'])) {
$REQUEST_VARS = array_merge($_GET, $_POST);
-
if (!isset($REQUEST_VARS['xml'])) {
die('xml not set');
}
-
+ header('Content-type: text/plain');
+ header('X-JSON: true');
$xml = rawurldecode ($REQUEST_VARS['xml']);
$xml = str_replace('\"', '"', $xml);
+ $xml = str_replace('"', "'", $xml);
+} elseif (isset($argv)) {
+ $cliArgs = arguments($argv);
+ if (isset($cliArgs['obj'])) {
+ $jsObject = $cliArgs['obj'];
+ } else {
+ $jsObject = "Fusion.appDefJson";
+ }
+ if (isset($cliArgs['file'])) {
+ $xml = file_get_contents($cliArgs['file']);
+ if (!$xml) {
+ die('file not found:'.$cliArgs['file']);
+ }
+ echo $jsObject."=";
+ }
+} else {
+ die('no XML input');
}
//print_r($xml);
$document = DOMDocument::loadXML($xml);
@@ -46,8 +63,5 @@
die ('/* invalid xml document:'.$xml.' */');
}
$root = $document->documentElement;
-
-header('Content-type: text/plain');
-header('X-JSON: true');
-echo '{"' . $root->tagName . '":' . xml2json($root) . '}';
+echo '{"' . $root->tagName . '":' . xml2json($root) . '};';
?>
\ No newline at end of file
Copied: sandbox/aboudreault/configHeader.json (from rev 1412, trunk/configHeader.json)
===================================================================
--- sandbox/aboudreault/configHeader.json (rev 0)
+++ sandbox/aboudreault/configHeader.json 2008-05-29 14:21:40 UTC (rev 1413)
@@ -0,0 +1 @@
+Fusion.configuration=
\ No newline at end of file
Modified: sandbox/aboudreault/fusion.cfg
===================================================================
--- sandbox/aboudreault/fusion.cfg 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/fusion.cfg 2008-05-29 14:21:40 UTC (rev 1413)
@@ -4,10 +4,11 @@
[first]
OpenLayers/SingleFile.js
OpenLayers.js
+OpenLayers/BaseTypes.js
+OpenLayers/BaseTypes/Class.js
OpenLayers/Util.js
+OpenLayers/Ajax.js
OpenLayers/Console.js
-OpenLayers/BaseTypes.js
-OpenLayers/BaseTypes/Class.js
OpenLayers/BaseTypes/Size.js
OpenLayers/BaseTypes/Bounds.js
OpenLayers/BaseTypes/Element.js
@@ -31,6 +32,12 @@
OpenLayers/Control/Navigation.js
OpenLayers/Control/PanZoom.js
OpenLayers/Control/ArgParser.js
+OpenLayers/Control/DragPan.js
+OpenLayers/Control/MousePosition.js
+OpenLayers/Control/ScaleLine.js
+OpenLayers/Handler/Box.js
+OpenLayers/Handler/Click.js
+OpenLayers/Handler/MouseWheel.js
OpenLayers/Projection.js
OpenLayers/Marker.js
OpenLayers/Icon.js
Modified: sandbox/aboudreault/jx/lib/jx_combined.js
===================================================================
--- sandbox/aboudreault/jx/lib/jx_combined.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/jx/lib/jx_combined.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -8253,7 +8253,9 @@
if (options.parentObj) {
$(options.parentObj).appendChild(this.blanket);
} else {
- document.body.appendChild(this.blanket);
+ document.body.appendChild(this.blanket);
+ var temp = new Jx.Layout(this.blanket);
+ temp.resize();
}
}
Modified: sandbox/aboudreault/lib/ApplicationDefinition.js
===================================================================
--- sandbox/aboudreault/lib/ApplicationDefinition.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/ApplicationDefinition.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,8 +30,7 @@
*
*/
-Fusion.Lib.ApplicationDefinition = Class.create();
-Fusion.Lib.ApplicationDefinition.prototype = {
+Fusion.Lib.ApplicationDefinition = OpenLayers.Class({
/**
* Property: mapGroups
*
@@ -85,7 +84,6 @@
initialize: function(sessionId) {
//console.log('ApplicationDefinition initialize');
- Fusion.Lib.EventMgr.initialize.apply(this, []);
this.sessionId = sessionId;
this.oBroker = Fusion.getBroker();
this.applicationDefinition = Fusion.getApplicationDefinitionURL();
@@ -97,11 +95,6 @@
this.parse();
},
- loadFailure: function() {
- Fusion.reportError(new Fusion.Error(Fusion.Error.FATAL,
- OpenLayers.String.translate('appDefLoadFailed',this.applicationDefinition)));
- },
-
/**
* Function: parse
*
@@ -123,16 +116,17 @@
if ( (this.applicationDefinition.match('Library://') == null) &&
(this.applicationDefinition.match('Session:') == null) ) {
- var options = {};
- options.method = 'get';
- options.onSuccess = this.convertXML.bind(this);
- options.onFailure = this.loadFailure.bind(this);
- new Ajax.Request( this.applicationDefinition, options);
+ if (Fusion.appDefJson) {
+ this.parseAppDef(Fusion.appDefJson);
+ } else {
+ Fusion.getXmlAsJson(this.applicationDefinition,
+ OpenLayers.Function.bind(this.getAppDefCB, this));
+ }
} else {
//TODO: request as JSON format
if (!this.sessionId) {
var r = new Fusion.Lib.MGRequest.MGCreateSession();
- this.oBroker.dispatchRequest(r, this.getAppDef.bind(this));
+ this.oBroker.dispatchRequest(r, OpenLayers.Function.bind(this.getAppDef, this));
} else {
this.getAppDef();
}
@@ -147,122 +141,88 @@
}
var r = new Fusion.Lib.MGRequest.MGGetResourceContent(this.applicationDefinition);
r.parameters.session = this.sessionId;
- this.oBroker.dispatchRequest(r, this.convertXML.bind(this));
+ this.oBroker.dispatchRequest(r,
+ OpenLayers.Function.bind(Fusion.xml2json, this,
+ OpenLayers.Function.bind(this.getAppDefCB, this)));
},
- /**
- * Function: convertXML
- *
- * Optionally convert XML to JSON using a server-side script
- * if the application definition wasn't available in JSON.
- *
- * Parameter: {XmlHttpRequest} r
- *
- * the XmlHttpRequest object
- *
- * Parameter: json
- *
- * boolean indicator if the content is JSON or not.
- */
- convertXML: function(r, json) {
- if (json) {
- this.parseJSON(r, json);
- } else {
- //this check only works on Firefox - it is safely ignored in IE and IE
- //will happily parse an invalid XML document
- if (r.responseXML.documentElement.nodeName == 'parsererror') {
- Fusion.reportError(new Fusion.Error(Fusion.Error.FATAL,
- 'invalid XML document: ' + this.applicationDefinition));
- }
-
- var options = {};
- options.onSuccess = this.parseJSON.bind(this);
- options.parameters = 'xml='+encodeURIComponent(r.responseText.replace(/\\/g, '\\\\\\\\'))+'&ts='+((new Date()).getTime());
- var sl = Fusion.getScriptLanguage();
- Fusion.ajaxRequest('common/'+sl+'/Xml2JSON.'+sl, options);
- }
+ getAppDefCB: function(xhr) {
+ var o;
+ eval("o="+xhr.responseText);
+ this.parseAppDef(o);
+ Fusion.setLoadState(Fusion.LOAD_WIDGETS);
},
-
+
/**
- * Function: parseJSON
+ * Function: parseAppDef
*
- * parse a JSON string into an ApplicationDefinition
+ * parse the ApplicationDefinition file into the appropriate Fusion objects
*
- * Parameter: {XmlHttpRequest} r
+ * Parameter: {XmlHttpRequest} xhr
*
* the XmlHttpRequest object
- *
- * Parameter: json
- *
- * boolean indicator if the content is JSON or not.
*/
- parseJSON: function(r, json) {
- if (json) {
- var mainNode;
- eval("mainNode="+r.responseText);
-
- var appDef = mainNode.ApplicationDefinition;
+ parseAppDef: function(json) {
+ var appDef = json.ApplicationDefinition;
- /* Set the application title */
- if (appDef.Title) {
- var title = appDef.Title[0];
- document.title = title;
- }
+ /* Set the application title */
+ if (appDef.Title) {
+ var title = appDef.Title[0];
+ document.title = title;
+ }
- /* process Map nodes */
- if (appDef.MapSet) {
- var mapSet = appDef.MapSet[0];
- if (mapSet.MapGroup instanceof Array) {
- for (var i=0; i<mapSet.MapGroup.length; i++) {
- var mapGroup = new Fusion.Lib.ApplicationDefinition.MapGroup(mapSet.MapGroup[i]);
- this.mapGroups.push(mapGroup);
- }
+ /* process Map nodes */
+ if (appDef.MapSet) {
+ var mapSet = appDef.MapSet[0];
+ if (mapSet.MapGroup instanceof Array) {
+ for (var i=0; i<mapSet.MapGroup.length; i++) {
+ var mapGroup = new Fusion.Lib.ApplicationDefinition.MapGroup(mapSet.MapGroup[i]);
+ this.mapGroups.push(mapGroup);
}
- } else {
- Fusion.reportError(new Fusion.Error(Fusion.Error.FATAL,
- OpenLayers.String.translate('appDefParseError')));
}
-
- /* process WIDGET sets */
- if (appDef.WidgetSet) {
- for (var i=0; i<appDef.WidgetSet.length; i++) {
- var widgetSet = new Fusion.Lib.ApplicationDefinition.WidgetSet(appDef.WidgetSet[i]);
- this.widgetSets.push(widgetSet);
- }
- } else {
- Fusion.reportError(new Fusion.Error(Fusion.Error.FATAL,
- OpenLayers.String.translate('widgetSetParseError')));
+ } else {
+ Fusion.reportError(new Fusion.Error(Fusion.Error.FATAL,
+ OpenLayers.i18n('appDefParseError')));
+ }
+
+ /* process WIDGET sets */
+ if (appDef.WidgetSet) {
+ for (var i=0; i<appDef.WidgetSet.length; i++) {
+ var widgetSet = new Fusion.Lib.ApplicationDefinition.WidgetSet(appDef.WidgetSet[i]);
+ this.widgetSets.push(widgetSet);
}
-
- /* process extensions */
- if (appDef.Extension) {
- var extension = appDef.Extension[0];
- /* process search definitions */
- if (extension.SearchDefinitions instanceof Array) {
- var categories = extension.SearchDefinitions[0];
- if (categories.SearchCategory instanceof Array) {
- for (var i=0; i<categories.SearchCategory.length; i++) {
- var oCategory = {};
- var category = categories.SearchCategory[i];
- oCategory.id = category['@id'];
- oCategory.name = category['@name'];
- oCategory.layer = category.Layer ? category.Layer[0] : '';
- oCategory.searchDefinitions = [];
- this.searchCategories[oCategory.id] = oCategory;
- var defns = category.SearchDefinition;
- for (var k=0; k<defns.length; k++) {
- var defn = new Fusion.Lib.ApplicationDefinition.SearchDefinition(defns[k]);
- defn.category = oCategory;
- oCategory.searchDefinitions[defn.id] = defn;
- this.searchDefinitions[defn.id] = defn;
- }
+ } else {
+ Fusion.reportError(new Fusion.Error(Fusion.Error.FATAL,
+ OpenLayers.i18n('widgetSetParseError')));
+ }
+
+ /* process extensions */
+ if (appDef.Extension) {
+ var extension = appDef.Extension[0];
+ /* process search definitions */
+ if (extension.SearchDefinitions instanceof Array) {
+ var categories = extension.SearchDefinitions[0];
+ if (categories.SearchCategory instanceof Array) {
+ for (var i=0; i<categories.SearchCategory.length; i++) {
+ var oCategory = {};
+ var category = categories.SearchCategory[i];
+ oCategory.id = category['@id'];
+ oCategory.name = category['@name'];
+ oCategory.layer = category.Layer ? category.Layer[0] : '';
+ oCategory.searchDefinitions = [];
+ this.searchCategories[oCategory.id] = oCategory;
+ var defns = category.SearchDefinition;
+ for (var k=0; k<defns.length; k++) {
+ var defn = new Fusion.Lib.ApplicationDefinition.SearchDefinition(defns[k]);
+ defn.category = oCategory;
+ oCategory.searchDefinitions[defn.id] = defn;
+ this.searchDefinitions[defn.id] = defn;
}
}
}
-
}
+
}
- Fusion.setLoadState(Fusion.LOAD_WIDGETS);
},
/**
@@ -381,7 +341,7 @@
}
return widgets;
}
-};
+});
/****************************************************************************
* Class: Fusion.Lib.ApplicationDefinition.MapGroup
@@ -390,8 +350,7 @@
*
*/
-Fusion.Lib.ApplicationDefinition.MapGroup = Class.create();
-Fusion.Lib.ApplicationDefinition.MapGroup.prototype = {
+Fusion.Lib.ApplicationDefinition.MapGroup = OpenLayers.Class({
initialView: null,
maps: null,
@@ -506,7 +465,7 @@
setInitialView: function(view) {
this.initialView = view;
}
-};
+});
/****************************************************************************
* Class: Fusion.Lib.ApplicationDefinition.Map
@@ -515,8 +474,7 @@
*
*/
-Fusion.Lib.ApplicationDefinition.Map = Class.create();
-Fusion.Lib.ApplicationDefinition.Map.prototype = {
+Fusion.Lib.ApplicationDefinition.Map = OpenLayers.Class({
type: null,
singleTile: false,
extension: null,
@@ -537,7 +495,7 @@
Fusion.require(this.type + '/' + this.type + '.js');
}
}
-};
+});
/****************************************************************************
* Class: Fusion.Lib.ApplicationDefinition.WidgetSet
@@ -546,8 +504,7 @@
*
*/
-Fusion.Lib.ApplicationDefinition.WidgetSet = Class.create();
-Fusion.Lib.ApplicationDefinition.WidgetSet.prototype = {
+Fusion.Lib.ApplicationDefinition.WidgetSet = OpenLayers.Class({
containers: null,
containersByName: null,
widgetTags: null,
@@ -707,7 +664,7 @@
getContainerByName: function(name) {
return this.containersByName[name];
}
-};
+});
/****************************************************************************
* Class: Fusion.Lib.ApplicationDefinition.Container
@@ -716,8 +673,7 @@
*
*/
-Fusion.Lib.ApplicationDefinition.Container = Class.create();
-Fusion.Lib.ApplicationDefinition.Container.prototype = {
+Fusion.Lib.ApplicationDefinition.Container = OpenLayers.Class({
name: null,
type: null,
validPositions: ['top', 'left', 'bottom', 'right'],
@@ -763,7 +719,7 @@
this.createWidgets(widgetSet, container);
}
if (container && container.domObj.jxLayout) {
- container.domObj.jxLayout.resize();
+ container.domObj.jxLayout.resize({forceResize: true});
}
},
@@ -773,7 +729,7 @@
}
}
-};
+});
/****************************************************************************
* Class: Fusion.Lib.ApplicationDefinition.Widget
@@ -782,8 +738,7 @@
*
*/
-Fusion.Lib.ApplicationDefinition.Widget = Class.create();
-Fusion.Lib.ApplicationDefinition.Widget.prototype = {
+Fusion.Lib.ApplicationDefinition.Widget = OpenLayers.Class({
name: null,
type: null,
statusText: null,
@@ -870,7 +825,7 @@
}
return widget;
}
-};
+});
/****************************************************************************
* Class: Fusion.Lib.ApplicationDefinition.Item
@@ -879,8 +834,7 @@
*
*/
-Fusion.Lib.ApplicationDefinition.Item = Class.create();
-Fusion.Lib.ApplicationDefinition.Item.prototype = {
+Fusion.Lib.ApplicationDefinition.Item = OpenLayers.Class({
uniqueId: [0],
type: null,
initialize: function(jsonNode) {
@@ -923,7 +877,7 @@
widget.oMenu.domObj.widget = widget;
container.add(widget.oMenu);
} else {
- var action = new Jx.Action(widget.activateTool.bind(widget));
+ var action = new Jx.Action(OpenLayers.Function.bind(widget.activateTool, widget));
var opt = {};
opt.label = widgetTag.label;
opt.image = widgetTag.imageUrl;
@@ -968,7 +922,7 @@
break;
}
}
-};
+});
/****************************************************************************
* Class: Fusion.Lib.ApplicationDefinition.Flyout
@@ -977,8 +931,7 @@
*
*/
-Fusion.Lib.ApplicationDefinition.Flyout = Class.create();
-Fusion.Lib.ApplicationDefinition.Flyout.prototype = {
+Fusion.Lib.ApplicationDefinition.Flyout = OpenLayers.Class({
label: null,
tooltip: null,
description: null,
@@ -1004,7 +957,7 @@
}
}
-};
+});
/****************************************************************************
* Class: Fusion.Lib.ApplicationDefinition.SearchDefinition
@@ -1013,8 +966,7 @@
*
*/
-Fusion.Lib.ApplicationDefinition.SearchDefinition = Class.create();
-Fusion.Lib.ApplicationDefinition.SearchDefinition.prototype = {
+Fusion.Lib.ApplicationDefinition.SearchDefinition = OpenLayers.Class({
id: null,
name: null,
category: null,
@@ -1060,7 +1012,7 @@
getFilterUrl: function(params) {
return '&filter='+encodeURIComponent(this.rule.toString(params));
}
-};
+});
/****************************************************************************
* Class: Fusion.Lib.ApplicationDefinition.SearchJoin
@@ -1069,8 +1021,7 @@
*
*/
-Fusion.Lib.ApplicationDefinition.SearchJoin = Class.create();
-Fusion.Lib.ApplicationDefinition.SearchJoin.prototype = {
+Fusion.Lib.ApplicationDefinition.SearchJoin = OpenLayers.Class({
layer: null,
primaryKey: null,
foreignKey: null,
@@ -1079,7 +1030,7 @@
this.primaryKey = json.PrimaryKey ? json.PrimaryKey[0] : '';
this.foreignKey = json.ForeignKey ? json.ForeignKey[0] : '';
}
-};
+});
/****************************************************************************
* Class: Fusion.Lib.ApplicationDefinition.SearchRule
@@ -1088,8 +1039,7 @@
*
*/
-Fusion.Lib.ApplicationDefinition.SearchRule = Class.create();
-Fusion.Lib.ApplicationDefinition.SearchRule.prototype = {
+Fusion.Lib.ApplicationDefinition.SearchRule = OpenLayers.Class({
type: null,
conditions: null,
initialize: function(type) {
@@ -1121,7 +1071,7 @@
}
return '(' + conditions.join(') ' + this.type + ' (') + ')';
}
-};
+});
/****************************************************************************
* Class: Fusion.Lib.ApplicationDefinition.SearchCondition
@@ -1130,8 +1080,7 @@
*
*/
-Fusion.Lib.ApplicationDefinition.SearchCondition = Class.create();
-Fusion.Lib.ApplicationDefinition.SearchCondition.prototype = {
+Fusion.Lib.ApplicationDefinition.SearchCondition = OpenLayers.Class({
column: null,
operator: null,
parameter: null,
@@ -1184,4 +1133,4 @@
var wildcard = this.operator == 'like' ? '*' : '';
return upper + '('+this.column + ') ' + this.operator + ' ' + this.quote + prewildcard + value + postwildcard + this.quote;
}
-};
+});
Modified: sandbox/aboudreault/lib/ButtonBase.js
===================================================================
--- sandbox/aboudreault/lib/ButtonBase.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/ButtonBase.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -44,8 +44,7 @@
* **********************************************************************/
-Fusion.Tool.ButtonBase = Class.create();
-Fusion.Tool.ButtonBase.prototype = {
+Fusion.Tool.ButtonBase = OpenLayers.Class({
/**
* constructor
*/
@@ -64,7 +63,7 @@
if (!this.isEnabled()) {
this._oButton.disableTool();
}
- this.clickWatcher = this.clickCB.bind(this);
+ this.clickWatcher = OpenLayers.Function.bind(this.clickCB, this);
this._oButton.observeEvent('click', this.clickWatcher);
},
@@ -107,6 +106,8 @@
disable: function() {
//console.log('button base disable');
Fusion.Widget.prototype.disable.apply(this,[]);
- this._oButton.disableTool();
+ if (this._oButton) {
+ this._oButton.disableTool();
+ }
}
-};
+});
Modified: sandbox/aboudreault/lib/ButtonTool.js
===================================================================
--- sandbox/aboudreault/lib/ButtonTool.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/ButtonTool.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -29,8 +29,7 @@
* Utility base class for the actual buttons used by widgets.
* **********************************************************************/
-Fusion.Tool.Button = Class.create();
-Fusion.Tool.Button.prototype = {
+Fusion.Tool.Button = OpenLayers.Class({
bActive: null,
sActiveClass: 'jxButtonActive',
sDisabledClass: 'jxButtonDisabled',
@@ -39,7 +38,7 @@
//console.log('Fusion.Tool.Button.initialize');
var json = widgetTag.extension;
- this.buttonAction = new Jx.Action(this.buttonClicked.bind(this));
+ this.buttonAction = new Jx.Action(OpenLayers.Function.bind(this.buttonClicked, this));
if (domObj) {
var options = {};
options.imgPath = widgetTag.imageUrl;
@@ -108,4 +107,4 @@
clickCB : function(e) { this.activateTool(); },
isActive: function() {return this.bActive;}
-};
+});
Modified: sandbox/aboudreault/lib/CanvasTool.js
===================================================================
--- sandbox/aboudreault/lib/CanvasTool.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/CanvasTool.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -29,9 +29,7 @@
* Utility base class for drawing features on the map.
* **********************************************************************/
-Fusion.Tool.Canvas = Class.create();
-Fusion.Tool.Canvas.prototype =
-{
+Fusion.Tool.Canvas = OpenLayers.Class({
context: null,
canvas: null,
width: null,
@@ -44,12 +42,12 @@
this.width = null;
this.height = null;
- this.mouseMoveCB = this.mouseMove.bindAsEventListener(this);
- this.mouseUpCB = this.mouseUp.bindAsEventListener(this);
- this.mouseDownCB = this.mouseDown.bindAsEventListener(this);
- this.dblClickCB = this.dblClick.bindAsEventListener(this);
+ this.mouseMoveCB = OpenLayers.Function.bindAsEventListener(this.mouseMove, this);
+ this.mouseUpCB = OpenLayers.Function.bindAsEventListener(this.mouseUp, this);
+ this.mouseDownCB = OpenLayers.Function.bindAsEventListener(this.mouseDown, this);
+ this.dblClickCB = OpenLayers.Function.bindAsEventListener(this.dblClick, this);
- this.resizeCanvasFn = this.resizeCanvas.bind(this);
+ this.resizeCanvasFn = OpenLayers.Function.bind(this.resizeCanvas, this);
},
/**
@@ -175,7 +173,7 @@
* @param e Event the event that happened on the mapObj
*/
dblClick: function(e) { }
-};
+});
/********************************************
* Class: Fusion.Tool.Canvas.Point
@@ -183,8 +181,7 @@
* Utility base class for drawing point features on the map.
* **********************************************************************/
-Fusion.Tool.Canvas.Point = Class.create();
-Fusion.Tool.Canvas.Point.prototype = {
+Fusion.Tool.Canvas.Point = OpenLayers.Class({
center: null,
radius: null,
lineStyle: null,
@@ -237,7 +234,7 @@
updatePx: function() {
this.center.updatePx();
}
-};
+});
/********************************************
* Class: Fusion.Tool.Canvas.Circle
@@ -245,8 +242,7 @@
* Utility base class for drawing circle features on the map.
* **********************************************************************/
-Fusion.Tool.Canvas.Circle = Class.create();
-Fusion.Tool.Canvas.Circle.prototype = {
+Fusion.Tool.Canvas.Circle = OpenLayers.Class({
map: null,
center: null,
radius: null,
@@ -319,7 +315,7 @@
this.center.updatePx();
this.radiusPx = this.map.geoToPixMeasure(this.radius);
}
-};
+});
/********************************************
* Class: Fusion.Tool.Canvas.Polygon
@@ -327,8 +323,7 @@
* Utility base class for drawing polygon features on the map.
* **********************************************************************/
-Fusion.Tool.Canvas.Polygon = Class.create();
-Fusion.Tool.Canvas.Polygon.prototype = {
+Fusion.Tool.Canvas.Polygon = OpenLayers.Class({
segments: null,
lineStyle: null,
fillStyle: null,
@@ -532,7 +527,7 @@
this.segments[i].updatePx();
}
}
-};
+});
/********************************************
* Class: Fusion.Tool.Canvas.line
@@ -540,8 +535,7 @@
* Utility base class for drawing line features on the map.
* **********************************************************************/
-Fusion.Tool.Canvas.Line = Class.create();
-Fusion.Tool.Canvas.Line.prototype = {
+Fusion.Tool.Canvas.Line = OpenLayers.Class({
segments: null,
lineStyle: null,
map: null,
@@ -694,7 +688,7 @@
this.segments[i].updatePx();
}
}
-};
+});
/********************************************
* Class: Fusion.Tool.Canvas.Segment
@@ -702,8 +696,7 @@
* Utility base class for drawing line segments on the map.
* **********************************************************************/
-Fusion.Tool.Canvas.Segment = Class.create();
-Fusion.Tool.Canvas.Segment.prototype = {
+Fusion.Tool.Canvas.Segment = OpenLayers.Class({
from: null,
to: null,
@@ -799,7 +792,7 @@
this.from.updatePx();
this.to.updatePx();
}
-};
+});
/********************************************
* Class: Fusion.Tool.Canvas.Node
@@ -807,8 +800,7 @@
* Utility base class to hold nodes that make up otherr features
* **********************************************************************/
-Fusion.Tool.Canvas.Node = Class.create();
-Fusion.Tool.Canvas.Node.prototype = {
+Fusion.Tool.Canvas.Node = OpenLayers.Class({
x: null,
y: null,
px: null,
@@ -911,7 +903,7 @@
toString: function() {
return '('+this.uid+') '+ this.x + ' ['+this.px+'px] '+ this.y+ ' ['+this.py+'px] ';
}
-};
+});
/* encapsulate a context style */
/********************************************
@@ -920,8 +912,7 @@
* Utility base class to encapsulate a context style.
* **********************************************************************/
-Fusion.Tool.Canvas.Style = Class.create();
-Fusion.Tool.Canvas.Style.prototype = {
+Fusion.Tool.Canvas.Style = OpenLayers.Class({
properties: ['fillStyle',
'globalAlpha',
'globalCompositeOperation',
@@ -954,4 +945,4 @@
}
}
}
-};
+});
Modified: sandbox/aboudreault/lib/ClickTool.js
===================================================================
--- sandbox/aboudreault/lib/ClickTool.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/ClickTool.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -31,16 +31,14 @@
* All classes using this should redefine the execute function
* **********************************************************************/
-Fusion.Tool.Click = Class.create();
-Fusion.Tool.Click.prototype =
-{
+Fusion.Tool.Click = OpenLayers.Class({
/**
* constructor
* @param oMap {Object} a map widget
*/
initialize : function()
{
- this.mouseUpCB = this.mouseUp.bindAsEventListener(this);
+ this.mouseUpCB = OpenLayers.Function.bindAsEventListener(this.mouseUp, this);
},
execute : function(x,y)
@@ -72,4 +70,4 @@
this.execute(sPixPoint.x, sPixPoint.y);
}
}
-};
+});
Modified: sandbox/aboudreault/lib/Error.js
===================================================================
--- sandbox/aboudreault/lib/Error.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/Error.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -29,13 +29,7 @@
* General purpose Error object
*/
-Fusion.Error = Class.create();
-
-Fusion.Error.FATAL = 0;
-Fusion.Error.WARNING = 1;
-Fusion.Error.NOTICE = 2;
-
-Fusion.Error.prototype = {
+Fusion.Error = OpenLayers.Class({
type: null,
message: null,
initialize: function(type, message) {
@@ -45,7 +39,7 @@
alert: function() {
var type = this.typeToString(this.type);
- alert(OpenLayers.String.translate('fusionError', type, this.message));
+ alert(OpenLayers.i18n('fusionError', {'type':type, 'message': this.message}));
},
toString: function() {
@@ -65,4 +59,10 @@
return 'UNKNOWN ('+type+')';
}
}
-};
\ No newline at end of file
+});
+
+Fusion.Error.FATAL = 0;
+Fusion.Error.WARNING = 1;
+Fusion.Error.NOTICE = 2;
+
+
Copied: sandbox/aboudreault/lib/EventMgr.js (from rev 1412, trunk/lib/EventMgr.js)
===================================================================
--- sandbox/aboudreault/lib/EventMgr.js (rev 0)
+++ sandbox/aboudreault/lib/EventMgr.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -0,0 +1,127 @@
+/**
+ * Class: Fusion.Lib.EventMgr
+ *
+ * an internal class for managing generic events. Classes that wish to
+ * publish and trigger events that other objects can listen for need to
+ * inherit from Fusion.Lib.EventMgr.
+ *
+ * To publish an event, call registerEventID with some unique numeric or
+ * string value. Other objects can then call registerForEvent with the
+ * eventID and a function to call when the event is triggered.
+ *
+ * To trigger an event, call triggerEvent with the eventID and any additional
+ * arguments that should be passed to listeners.
+ */
+Fusion.Lib.EventMgr = OpenLayers.Class({
+ /* an array of eventIDs and associated listener functions */
+ events : null,
+
+ initialize: function() { if (!this.events) {this.events = []; }},
+
+ /**
+ * Method: destroy
+ *
+ */
+ destroy: function() {
+ this.events = [];
+ },
+
+ /**
+ * register an event ID so that others can use it. This should really
+ * only be called by 'this' object.
+ *
+ * @param eventID the event ID to register
+ */
+ registerEventID : function( eventID ) {
+ if (!this.events) {this.events = []; }
+ if (!eventID) {
+ Fusion.reportError(new Fusion.Error(Fusion.Error.WARNING,
+ OpenLayers.i18n('regsiterEventError')));
+ }
+ var ev = new String(eventID);
+ if (!this.events[eventID]) {
+ this.events[eventID] = [];
+ }
+ },
+
+ /**
+ * register for receiving a callback when an event happens. If you
+ * want the callback to be a method on an instance of some object,
+ * use the OpenLayers.Function.bind() function as in:
+ *
+ * otherObj.registerForEvent(SOME_EVENT, OpenLayers.Function.bind(this.callback,this));
+ *
+ * @param eventID the event ID to register for
+ * @param f the function to call when the event happens.
+ */
+ registerForEvent : function(eventID, f) {
+ var ev = new String(eventID);
+ this.events[eventID].push(f);
+ },
+
+ /**
+ * deregister a callback function when you no longer want to
+ * recieve it. Note that if you used bind() when registering,
+ * you need to pass EXACTLY THE SAME FUNCTION when
+ * deregistering. Typically, this means you need to assign the
+ * result of bind() to an instance variable and pass that instance
+ * variable to both registerForEvent and deregisterForEvent.
+ *
+ * For instance:
+ *
+ * this.callbackFn = OpenLayers.Function.bind(this.callback, this);
+ * otherObj.registerForEvent(SOME_EVENT, this.callbackFn);
+ * otherObj.deregisterForEvent(SOME_EVENT, this.callbackFn);
+ *
+ * @param eventID the event ID to deregister
+ * @param f the function that used when registering.
+ */
+ deregisterForEvent : function( eventID, f ) {
+ var ev = new String(eventID);
+ var bResult = false;
+ if (!this.events[eventID]){
+ return false;
+ }
+
+ for (var i=0;i<this.events[eventID].length;i++) {
+ if (this.events[eventID][i]== f) {
+ this.events[eventID].splice(i,1);
+ bResult = true;
+ }
+ }
+ return bResult;
+ },
+
+ /**
+ * trigger an event and call all registered listener functions.
+ * This is intended to be called by 'this'. The eventID param
+ * is mandatory. Any additional arguments will be passed to the
+ * listener function.
+ *
+ * @param eventID the event ID to trigger
+ */
+ triggerEvent : function( eventID ) {
+ var ev = new String(eventID);
+ if (!this.events || !this.events[eventID]) {
+ return false;
+ }
+
+ for (var i=0; i<this.events[eventID].length; i++) {
+ this.events[eventID][i].apply(null, arguments);
+ }
+ return true;
+ }
+});
+
+//window.Fusion = OpenLayers.Class(Fusion.Lib.EventMgr, Fusion.prototype);
+//OpenLayers.Util.extend(Fusion, Fusion.Lib.EventMgr.prototype);
+Fusion.events = [];
+Fusion.registerEventID = Fusion.Lib.EventMgr.prototype.registerEventID;
+Fusion.registerForEvent = Fusion.Lib.EventMgr.prototype.registerForEvent;
+Fusion.triggerEvent = Fusion.Lib.EventMgr.prototype.triggerEvent;
+
+Fusion.Event.FUSION_INITIALIZED = Fusion.Event.lastEventId++;
+Fusion.Event.FUSION_ERROR = Fusion.Event.lastEventId++;
+Fusion.registerEventID(Fusion.Event.FUSION_INITIALIZED);
+Fusion.registerEventID(Fusion.Event.FUSION_ERROR);
+
Modified: sandbox/aboudreault/lib/MGBroker.js
===================================================================
--- sandbox/aboudreault/lib/MGBroker.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/MGBroker.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -32,8 +32,7 @@
* send requests to the server via the dispatchRequest method.
*/
-Fusion.Lib.MGBroker = Class.create();
-Fusion.Lib.MGBroker.prototype = {
+Fusion.Lib.MGBroker = OpenLayers.Class({
/**
* the URL to a MapGuide Open Source installation. Set this using
* setSiteURL
@@ -76,8 +75,8 @@
if (this.method) {
r.options.method = this.method;
}
- var a = new Ajax.Request( this.mapAgentURL,
- Object.extend({ parameters:r.parameters, onComplete:f }, r.options ) );
+ var a = new OpenLayers.Ajax.Request( this.mapAgentURL,
+ Object.extend({parameters:r.parameters, onComplete:f }, r.options));
a.originalRequest = r;
},
/**
@@ -118,7 +117,7 @@
this.mapGuideURL = '';
this.mapAgentURL = '';
}
-};
+});
/****************************************************************************
* Class: Fusion.Lib.MGRequest
@@ -126,8 +125,7 @@
* MGRequest is the base class for all broker-compatible requests. A request
* is a wrapper around an operation that is supported by the mapagent.
*/
-Fusion.Lib.MGRequest = Class.create();
-Fusion.Lib.MGRequest.prototype = {
+Fusion.Lib.MGRequest = OpenLayers.Class({
/**
* core options shared by all requests
*/
@@ -144,7 +142,7 @@
*/
initializeRequest : function() {
this.options = { method:'post' };
- this.parameters = { version : '1.0.0', locale : Fusion.locale };
+ this.parameters = { version : '1.0.0', locale : Fusion.locale, clientagent : 'Fusion Viewer' };
},
/**
@@ -180,16 +178,14 @@
}
return s;
}
-};
+});
-Fusion.Lib.MGRequest.MGEnumerateResources = Class.create();
-Object.extend(Fusion.Lib.MGRequest.MGEnumerateResources.prototype, Fusion.Lib.MGRequest.prototype);
/****************************************************************************
* Class: Fusion.Lib.MGRequest.MGEnumerateResources
*
* encapsulate a request to the server to enumerate resources in the library.
*/
-Object.extend( Fusion.Lib.MGRequest.MGEnumerateResources.prototype, {
+Fusion.Lib.MGRequest.MGEnumerateResources = OpenLayers.Class(Fusion.Lib.MGRequest, {
/**
* @constructor
* initialize a new instance of MGEnumerateResources
@@ -218,14 +214,12 @@
}
});
-Fusion.Lib.MGRequest.MGGetResourceContent = Class.create();
-Object.extend(Fusion.Lib.MGRequest.MGGetResourceContent.prototype, Fusion.Lib.MGRequest.prototype);
/****************************************************************************
* Class: Fusion.Lib.MGRequest.MGGetResourceContent
*
* encapsulate a request to the server to get resource contents from the library.
*/
-Object.extend( Fusion.Lib.MGRequest.MGGetResourceContent.prototype, {
+Fusion.Lib.MGRequest.MGGetResourceContent = OpenLayers.Class(Fusion.Lib.MGRequest, {
/**
* @constructor
* initialize a new instance of Fusion.Lib.MGRequest.MGGetResourceContent
@@ -245,14 +239,12 @@
}
});
-Fusion.Lib.MGRequest.MGGetResourceHeader = Class.create();
-Object.extend(Fusion.Lib.MGRequest.MGGetResourceHeader.prototype, Fusion.Lib.MGRequest.prototype);
/****************************************************************************
* Class: Fusion.Lib.MGRequest.MGGetResourceHeader
*
* encapsulate a request to the server to get resource header from the library.
*/
-Object.extend( Fusion.Lib.MGRequest.MGGetResourceHeader.prototype, {
+Fusion.Lib.MGRequest.MGGetResourceHeader = OpenLayers.Class(Fusion.Lib.MGRequest, {
/**
* @constructor
* initialize a new instance of Fusion.Lib.MGRequest.MGGetResourceHeader
@@ -272,15 +264,13 @@
}
});
-Fusion.Lib.MGRequest.MGCreateSession = Class.create();
-Object.extend(Fusion.Lib.MGRequest.MGCreateSession.prototype, Fusion.Lib.MGRequest.prototype);
/****************************************************************************
* Class: Fusion.Lib.MGRequest.MGCreateSession
*
* encapsulate a request to the server to create a new session on the server.
*
*/
-Object.extend( Fusion.Lib.MGRequest.MGCreateSession.prototype, {
+Fusion.Lib.MGRequest.MGCreateSession = OpenLayers.Class(Fusion.Lib.MGRequest, {
/**
* @constructor
* initialize a new instance of Fusion.Lib.MGRequest.MGCreateSession
@@ -295,15 +285,13 @@
}
});
-Fusion.Lib.MGRequest.MGCopyResource = Class.create();
-Object.extend(Fusion.Lib.MGRequest.MGCopyResource.prototype, Fusion.Lib.MGRequest.prototype);
/****************************************************************************
* Class: Fusion.Lib.MGRequest.MGCopyResource
*
* encapsulate a request to the server to copy a resource.
*
*/
-Object.extend( Fusion.Lib.MGRequest.MGCopyResource.prototype, {
+Fusion.Lib.MGRequest.MGCopyResource = OpenLayers.Class(Fusion.Lib.MGRequest, {
/**
* @constructor
* initialize a new instance of Fusion.Lib.MGRequest.MGCopyResource
@@ -325,15 +313,13 @@
}
});
-Fusion.Lib.MGRequest.MGDeleteResource = Class.create();
-Object.extend(Fusion.Lib.MGRequest.MGDeleteResource.prototype, Fusion.Lib.MGRequest.prototype);
/****************************************************************************
* Class: Fusion.Lib.MGRequest.MGDeleteResource
*
* encapsulate a request to the server to delete a resource.
*
*/
-Object.extend( Fusion.Lib.MGRequest.MGDeleteResource.prototype, {
+Fusion.Lib.MGRequest.MGDeleteResource = OpenLayers.Class(Fusion.Lib.MGRequest, {
/**
* @constructor
* initialize a new instance of Fusion.Lib.MGRequest.MGDeleteResource
@@ -351,15 +337,13 @@
}
});
-Fusion.Lib.MGRequest.MGMoveResource = Class.create();
-Object.extend(Fusion.Lib.MGRequest.MGMoveResource.prototype, Fusion.Lib.MGRequest.prototype);
/****************************************************************************
* Class: Fusion.Lib.MGRequest.MGMoveResource
*
* encapsulate a request to the server to move a resource in the repository.
*
*/
-Object.extend( Fusion.Lib.MGRequest.MGMoveResource.prototype, {
+Fusion.Lib.MGRequest.MGMoveResource = OpenLayers.Class(Fusion.Lib.MGRequest, {
/**
* @constructor
* initialize a new instance of Fusion.Lib.MGRequest.MGMoveResource
@@ -381,15 +365,13 @@
}
});
-Fusion.Lib.MGRequest.MGMoveResource = Class.create();
-Object.extend(Fusion.Lib.MGRequest.MGMoveResource.prototype, Fusion.Lib.MGRequest.prototype);
/****************************************************************************
* Class: Fusion.Lib.MGRequest.MGMoveResource
*
* encapsulate a request to the server to set the content XML of a resource.
*
*/
-Object.extend( Fusion.Lib.MGRequest.MGMoveResource.prototype, {
+Fusion.Lib.MGRequest.MGMoveResource = OpenLayers.Class(Fusion.Lib.MGRequest, {
/**
* @constructor
* initialize a new instance of Fusion.Lib.MGRequest.MGMoveResource
@@ -408,15 +390,13 @@
}
});
-Fusion.Lib.MGRequest.MGDescribeSchema = Class.create();
-Object.extend(Fusion.Lib.MGRequest.MGDescribeSchema.prototype, Fusion.Lib.MGRequest.prototype);
/****************************************************************************
* Class: Fusion.Lib.MGRequest.MGDescribeSchema
*
* encapsulate a request to the server to describe the schema of a FeatureSource.
*
*/
-Object.extend( Fusion.Lib.MGRequest.MGDescribeSchema.prototype, {
+Fusion.Lib.MGRequest.MGDescribeSchema = OpenLayers.Class(Fusion.Lib.MGRequest, {
/**
* @constructor
* initialize a new instance of Fusion.Lib.MGRequest.MGDescribeSchema
@@ -436,15 +416,13 @@
}
});
-Fusion.Lib.MGRequest.MGGetSpatialContexts = Class.create();
-Object.extend(Fusion.Lib.MGRequest.MGGetSpatialContexts.prototype, Fusion.Lib.MGRequest.prototype);
/****************************************************************************
* Class: Fusion.Lib.MGRequest.MGGetSpatialContexts
*
* encapsulate a request to the server to retrieve the spatial context of a resource.
*
*/
-Object.extend( Fusion.Lib.MGRequest.MGGetSpatialContexts.prototype, {
+Fusion.Lib.MGRequest.MGGetSpatialContexts = OpenLayers.Class(Fusion.Lib.MGRequest, {
/**
* @constructor
* initialize a new instance of Fusion.Lib.MGRequest.MGGetSpatialContexts
@@ -464,15 +442,13 @@
}
});
-Fusion.Lib.MGRequest.MGEnumerateResourceReferences = Class.create();
-Object.extend(Fusion.Lib.MGRequest.MGEnumerateResourceReferences.prototype, Fusion.Lib.MGRequest.prototype);
/****************************************************************************
* Class: Fusion.Lib.MGRequest.MGEnumerateResourceReferences
*
* encapsulate a request to the server to enumerate the references to a resource id.
*
*/
-Object.extend( Fusion.Lib.MGRequest.MGEnumerateResourceReferences.prototype, {
+Fusion.Lib.MGRequest.MGEnumerateResourceReferences = OpenLayers.Class(Fusion.Lib.MGRequest, {
/**
* @constructor
* initialize a new instance of Fusion.Lib.MGRequest.MGEnumerateResourceReferences
@@ -490,8 +466,6 @@
}
});
-Fusion.Lib.MGRequest.MGEnumerateResourceData = Class.create();
-Object.extend(Fusion.Lib.MGRequest.MGEnumerateResourceData.prototype, Fusion.Lib.MGRequest.prototype);
/****************************************************************************
* Class: Fusion.Lib.MGRequest.MGEnumerateResourceData
*
@@ -501,7 +475,7 @@
* (those referencing files or directories outside the respository)
* Fusion.Lib.MGRequest.MGDescribeSchema should be used for those sources.
*/
-Object.extend( Fusion.Lib.MGRequest.MGEnumerateResourceData.prototype, {
+Fusion.Lib.MGRequest.MGEnumerateResourceData = OpenLayers.Class(Fusion.Lib.MGRequest, {
/**
* @constructor
* initialize a new instance of Fusion.Lib.MGRequest.MGEnumerateResourceData
@@ -519,8 +493,6 @@
}
});
-Fusion.Lib.MGRequest.MGGetVisibleMapExtent = Class.create();
-Object.extend(Fusion.Lib.MGRequest.MGGetVisibleMapExtent.prototype, Fusion.Lib.MGRequest.prototype);
/****************************************************************************
* Class: Fusion.Lib.MGRequest.MGGetVisibleMapExtent
*
@@ -530,7 +502,7 @@
* (those referencing files or directories outside the respository)
* Fusion.Lib.MGRequest.MGDescribeSchema should be used for those sources.
*/
-Object.extend( Fusion.Lib.MGRequest.MGGetVisibleMapExtent.prototype, {
+Fusion.Lib.MGRequest.MGGetVisibleMapExtent = OpenLayers.Class(Fusion.Lib.MGRequest, {
/**
* @constructor
* initialize a new instance of Fusion.Lib.MGRequest.MGGetVisibleMapExtent
@@ -578,15 +550,13 @@
});
-Fusion.Lib.MGRequest.MGQueryMapFeatures = Class.create();
-Object.extend(Fusion.Lib.MGRequest.MGQueryMapFeatures.prototype, Fusion.Lib.MGRequest.prototype);
/****************************************************************************
* Class: Fusion.Lib.MGRequest.MGQueryMapFeatures
*
* encapsulate a request to the server to query map features on
* selectable layers
*/
-Object.extend( Fusion.Lib.MGRequest.MGQueryMapFeatures.prototype, {
+Fusion.Lib.MGRequest.MGQueryMapFeatures = OpenLayers.Class(Fusion.Lib.MGRequest, {
/**
* @constructor
* initialize a new instance of Fusion.Lib.MGRequest.MGQueryMapFeatures
@@ -597,11 +567,13 @@
* @param maxFeatures {integer} number of maximum results (-1 to indicate no maximum)
* @param selectionPersist {boolean} save the selection (valid values are 0 and 1)
* @param selectionVariant {String} indicates the spatial operation. Valid values are 'INTERSECTS', ...
- *@param layerNames {String} comma separated list of layer names to include in the query
+ * @param layerNames {String} comma separated list of layer names to include in the query
+ * @param layerAttributeFilter {integer} bitmask determining layer selection behaviour (1=visible layers,
+ * 2=selectable layers, 4=layers with tooltips)
*
* @return {Object} an instance of Fusion.Lib.MGRequest.MGQueryMapFeatures
*/
- initialize : function( sessionId, mapName, geometry, maxFeatures, persist, selectionVariant, layerNames )
+ initialize : function( sessionId, mapName, geometry, maxFeatures, persist, selectionVariant, layerNames, layerAttributeFilter )
{
this.initializeRequest();
this.setParams( {
@@ -612,20 +584,19 @@
maxFeatures: maxFeatures,
persist: persist,
selectionVariant: selectionVariant,
- layerNames: layerNames
+ layerNames: layerNames,
+ layerAttributeFilter: layerAttributeFilter
} );
}
});
-Fusion.Lib.MGRequest.MGGetFeatureSetEnvelope = Class.create();
-Object.extend(Fusion.Lib.MGRequest.MGGetFeatureSetEnvelope.prototype, Fusion.Lib.MGRequest.prototype);
/****************************************************************************
* Class: Fusion.Lib.MGRequest.MGGetFeatureSetEnvelope
*
* encapsulate a request to the server to query map features on
* selectable layers
*/
-Object.extend( Fusion.Lib.MGRequest.MGGetFeatureSetEnvelope.prototype, {
+Fusion.Lib.MGRequest.MGGetFeatureSetEnvelope = OpenLayers.Class(Fusion.Lib.MGRequest, {
/**
* @constructor
* initialize a new instance of Fusion.Lib.MGRequest.MGGetFeatureSetEnvelope
@@ -646,4 +617,4 @@
featureSet: features
} );
}
-});
\ No newline at end of file
+});
Modified: sandbox/aboudreault/lib/Map.js
===================================================================
--- sandbox/aboudreault/lib/Map.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/Map.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -49,10 +49,7 @@
Fusion.Constant.LAYER_RASTER_TYPE = 4;
Fusion.Constant.LAYER_DWF_TYPE = 5;
-Fusion.Widget.Map = Class.create();
-Fusion.Widget.Map.prototype =
-{
-
+Fusion.Widget.Map = OpenLayers.Class(Fusion.Lib.EventMgr, {
_oDomObj : null,
_sDomObj : '',
_sMapname : '',
@@ -70,12 +67,12 @@
aMaps: null,
layerRoot: null,
singleTile: true,
+ fractionalZoom: true, //TODO: set this in AppDef?
/**
* construct a new view Fusion.Widget.Map class.
*/
initialize : function(widgetTag, mapGroup, widgetSet) {
- Object.inheritFrom(this, Fusion.Lib.EventMgr, []);
this.widgetTag = widgetTag;
var name = widgetTag.name;
@@ -89,9 +86,24 @@
this._oDomObj.jxLayout.addSizeChangeListener(this);
}
+ if (widgetTag.extension.FractionalZoom) {
+ this.fractionalZoom = widgetTag.extension.FractionalZoom[0]=='false'?false:true;
+ }
+
+ var scalesArray = null;
+ if (widgetTag.extension.Scales) {
+ scalesArray = widgetTag.extension.Scales[0].split(',');
+ this.fractionalZoom = false;
+ }
+
OpenLayers.DOTS_PER_INCH = this._nDpi;
if (!this.oMapOL) {
- var options = {controls: [], fallThrough: true};
+ var options = {
+ controls: [],
+ fallThrough: true,
+ scales: scalesArray,
+ fractionalZoom: this.fractionalZoom
+ };
if (widgetTag.extension.ConstrainMapExtent) {
this.bRestrictExtent = widgetTag.extension.ConstrainMapExtent[0]=='true'?true:false;
}
@@ -144,7 +156,8 @@
this.oMapOL.events.register('moveend', this, this.mapExtentsChanged);
this._oDomObj.oncontextmenu = function() {return false;};
- OpenLayers.Event.observe(this._oDomObj, 'contextmenu', this.onContextMenu.bind(this));
+ OpenLayers.Event.observe(this._oDomObj, 'contextmenu',
+ OpenLayers.Function.bind(this.onContextMenu, this));
this.aSelectionCallbacks = [];
this.bFetchingSelection = false;
@@ -289,8 +302,10 @@
}
}
this.oMapOL.addLayer(map.oLayerOL);
- map.registerForEvent(Fusion.Event.MAP_SELECTION_OFF, this.selectionHandler.bind(this));
- map.registerForEvent(Fusion.Event.MAP_SELECTION_ON, this.selectionHandler.bind(this));
+ map.registerForEvent(Fusion.Event.MAP_SELECTION_OFF,
+ OpenLayers.Function.bind(this.selectionHandler, this));
+ map.registerForEvent(Fusion.Event.MAP_SELECTION_ON,
+ OpenLayers.Function.bind(this.selectionHandler, this));
},
getAllMaps: function() {
@@ -301,7 +316,7 @@
reloadMap: function() {
for (var i=0; i<this.aMaps.length; ++i) {
var map = this.aMaps[i];
- window.setTimeout(map.reloadMap.bind(map),1);
+ window.setTimeout(OpenLayers.Function.bind(map.reloadMap, map),1);
}
},
@@ -377,7 +392,9 @@
this.nSelectionMaps = 0;
for (var i=0; i<this.aMaps.length; i++ ) {
this.nSelectionMaps++;
- this.aMaps[i].getSelection(this.accumulateSelection.bind(this, this.aMaps[i]), layers, startcount);
+ this.aMaps[i].getSelection(
+ OpenLayers.Function.bind(this.accumulateSelection, this, this.aMaps[i]),
+ layers, startcount);
}
},
@@ -495,23 +512,12 @@
setExtents : function(oExtents) {
if (!oExtents) {
Fusion.reportError(new Fusion.Error(Fusion.Error.WARNING,
- OpenLayers.String.translate('nullExtents')));
+ OpenLayers.i18n('nullExtents')));
}
if (oExtents instanceof Array && oExtents.length == 4) {
oExtents = new OpenLayers.Bounds(oExtents[0], oExtents[1], oExtents[2], oExtents[3]);
}
- if (this.aMaps[0].bSingleTile) {
- var viewSize = this.oMapOL.getSize();
- var idealResolution = Math.max( oExtents.getWidth() / viewSize.w,
- oExtents.getHeight() / viewSize.h,
- this.oMapOL.baseLayer.minResolution);
- idealResolution = Math.min( idealResolution, this.oMapOL.baseLayer.maxResolution);
-
- this.oMapOL.baseLayer.resolutions = [idealResolution];
- this.oMapOL.zoom = 1;
- }
-
//update the timestamp param to prevent caching
for (var i=0; i<this.aMaps.length; i++ ) {
this.aMaps[i].oLayerOL.params.ts = (new Date()).getTime();
@@ -555,30 +561,38 @@
zoom : function(fX, fY, nFactor) {
//do this differntly with OL code??
- var extent = this.oMapOL.getExtent();
- var fDeltaX = extent.right - extent.left;
- var fDeltaY = extent.top - extent.bottom;
- var fMinX,fMaxX,fMinY,fMaxY;
if (nFactor == 1 || nFactor == 0) {
/*recenter*/
- fMinX = fX - (fDeltaX/2);
- fMaxX = fX + (fDeltaX/2);
- fMinY = fY - (fDeltaY/2);
- fMaxY = fY + (fDeltaY/2);
- } else if (nFactor > 0) {
- /*zoomin*/
- fMinX = fX - (fDeltaX/2 / nFactor);
- fMaxX = fX + (fDeltaX/2 / nFactor);
- fMinY = fY - (fDeltaY/2 / nFactor);
- fMaxY = fY + (fDeltaY/2 / nFactor);
- } else if (nFactor < 0) {
- /*zoomout*/
- fMinX = fX - ((fDeltaX/2) * Math.abs(nFactor));
- fMaxX = fX + ((fDeltaX/2) * Math.abs(nFactor));
- fMinY = fY - ((fDeltaY/2) * Math.abs(nFactor));
- fMaxY = fY + ((fDeltaY/2) * Math.abs(nFactor));
- }
- this.setExtents(new OpenLayers.Bounds(fMinX, fMinY, fMaxX, fMaxY));
+ this.oMapOL.panTo(new OpenLayers.LonLat(fX, fY));
+ } else {
+ var extent = this.oMapOL.getExtent();
+ if (this.fractionalZoom) {
+ var fDeltaX = extent.right - extent.left;
+ var fDeltaY = extent.top - extent.bottom;
+ var fMinX,fMaxX,fMinY,fMaxY;
+ if (nFactor > 0) {
+ /*zoomin*/
+ fMinX = fX - (fDeltaX/2 / nFactor);
+ fMaxX = fX + (fDeltaX/2 / nFactor);
+ fMinY = fY - (fDeltaY/2 / nFactor);
+ fMaxY = fY + (fDeltaY/2 / nFactor);
+ } else if (nFactor < 0) {
+ /*zoomout*/
+ fMinX = fX - ((fDeltaX/2) * Math.abs(nFactor));
+ fMaxX = fX + ((fDeltaX/2) * Math.abs(nFactor));
+ fMinY = fY - ((fDeltaY/2) * Math.abs(nFactor));
+ fMaxY = fY + ((fDeltaY/2) * Math.abs(nFactor));
+ }
+ this.setExtents(new OpenLayers.Bounds(fMinX, fMinY, fMaxX, fMaxY));
+ } else {
+ var currentZoomLevel = this.oMapOL.getZoom();
+ if (nFactor > 1) {
+ this.oMapOL.zoomTo(currentZoomLevel+1);
+ } else if (nFactor < 1) {
+ this.oMapOL.zoomTo(currentZoomLevel-1);
+ }
+ }
+ }
},
zoomToScale: function(fScale) {
@@ -640,8 +654,38 @@
return (nPixels*resolution);
},
+ /**
+ *
+ * initializes the meters per unit values when a new map is loaded. Some systems make different
+ * assumptions for the conversion of degrees to meters so this makes sure both Fusion and
+ * OpenLayers are using the same value.
+ *
+ * @param metersPerUnit the value returned by LoadMap.php for meters per unit
+ */
+ setMetersPerUnit: function(metersPerUnit) {
+ if (this._fMetersperunit < 0) {
+ Fusion.initUnits(metersPerUnit);
+ this._fMetersperunit = metersPerUnit;
+ } else {
+ if (metersPerUnit != this._fMetersperunit) {
+ Fusion.reportError(new Fusion.Error(Fusion.Error.WARNING,
+ 'meters per unit value already set'));
+ }
+ }
+ },
+
/**
*
+ * returns the meters per unit value
+ *
+ * @return metersPerUnit the value as set when the map initialized
+ */
+ getMetersPerUnit: function() {
+ return this._fMetersperunit;
+ },
+
+ /**
+ *
* convert geographic into pixels.
*
* @param fGeo float distance in geographic units
@@ -705,7 +749,7 @@
},
getScale : function() {
- return Math.round(this.oMapOL.getScale());
+ return this.oMapOL.getScale();
},
getResolution : function() {
@@ -833,7 +877,7 @@
//console.log('executefromcontextmenu');
widget.execute(this.contextMenuPosition.x, this.contextMenuPosition.y);
}
-};
+});
/****************************************************************************
* Class: Fusion.Widget.Map.Layer
@@ -841,11 +885,9 @@
* generic class for map layers. This class is primarily for legends.
* **********************************************************************/
Fusion.Event.LAYER_PROPERTY_CHANGED = Fusion.Event.lastEventId++;
-Fusion.Widget.Map.Layer = Class.create();
-Fusion.Widget.Map.Layer.prototype = {
+Fusion.Widget.Map.Layer = OpenLayers.Class(Fusion.Lib.EventMgr, {
name: null,
initialize: function(name) {
- Object.inheritFrom(this, Fusion.Lib.EventMgr, []);
this.name = name;
this.registerEventID(Fusion.Event.LAYER_PROPERTY_CHANGED);
},
@@ -854,7 +896,7 @@
this[property] = value;
this.triggerEvent(Fusion.Event.LAYER_PROPERTY_CHANGED, this);
}
-};
+});
/****************************************************************************
* Class: Fusion.Widget.Map.Group
@@ -862,13 +904,11 @@
* generic class for map layer groups. This class is primarily for legends.
* **********************************************************************/
Fusion.Event.GROUP_PROPERTY_CHANGED = Fusion.Event.lastEventId++;
-Fusion.Widget.Map.Group = Class.create();
-Fusion.Widget.Map.Group.prototype = {
+Fusion.Widget.Map.Group = OpenLayers.Class(Fusion.Lib.EventMgr, {
name: null,
groups: null,
layers: null,
initialize: function(name) {
- Object.inheritFrom(this, Fusion.Lib.EventMgr, []);
this.name = name;
this.groups = [];
this.layers = [];
@@ -936,7 +976,7 @@
}
return null;
}
-};
+});
/**
@@ -945,9 +985,7 @@
* Utility class to hold slection information
*
*/
-var GxSelectionObject = Class.create();
-GxSelectionObject.prototype =
-{
+Fusion.SelectionObject = OpenLayers.Class({
aLayers : null,
initialize: function(o)
@@ -966,7 +1004,7 @@
this.nLayers = o.layers.length;
for (var i=0; i<o.layers.length; i++)
{
- this.aLayers[i] = new GxSelectionObjectLayer(o, o.layers[i]);
+ this.aLayers[i] = new Fusion.SelectionObject.Layer(o, o.layers[i]);
}
}
},
@@ -1017,12 +1055,10 @@
}
}
-};
+});
-var GxSelectionObjectLayer = Class.create();
-GxSelectionObjectLayer.prototype = {
-
+Fusion.SelectionObject.Layer = OpenLayers.Class({
sName: null,
nElements: null,
aElements: null,
@@ -1140,4 +1176,4 @@
return null;
}
}
-};
+});
Modified: sandbox/aboudreault/lib/MenuBase.js
===================================================================
--- sandbox/aboudreault/lib/MenuBase.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/MenuBase.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -29,20 +29,11 @@
* generic base class for implementing widgets that incorporate a menu
* **********************************************************************/
-Fusion.Tool.MenuBase = Class.create();
-Fusion.Tool.MenuBase.prototype = {
+Fusion.Tool.MenuBase = OpenLayers.Class({
/**
* constructor
*/
initialize : function() {
- /* overload enable/disable. Normal inheritance should
- * work but because we use inheritFrom, it doesn't overload
- * Widget's enable/disable functions. We do it manually
- * here.
- */
- this.enable = Fusion.Tool.MenuBase.prototype.enable;
- this.disable = Fusion.Tool.MenuBase.prototype.disable;
-
//console.log('Fusion.Tool.MenuBase.initialize');
var options = {};
options.imgPath = this.widgetTag.imageUrl;
@@ -66,4 +57,4 @@
disable: function() {
Fusion.Widget.prototype.disable.apply(this,[]);
}
-};
+});
Copied: sandbox/aboudreault/lib/OpenLayers/Lang (from rev 1412, trunk/lib/OpenLayers/Lang)
Deleted: sandbox/aboudreault/lib/OpenLayers/Lang/de.js
===================================================================
--- trunk/lib/OpenLayers/Lang/de.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/OpenLayers/Lang/de.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -1,69 +0,0 @@
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Lang/en.js
- */
-
-/**
- * Namespace: OpenLayers.Lang["de"]
- * Dictionary for German. Keys for entries are used in calls to
- * <OpenLayers.Lang.translate>. Entry bodies are normal strings or
- * strings formatted for use with <OpenLayers.String.format> calls.
- */
-OpenLayers.Lang.de = OpenLayers.Util.applyDefaults({
-
- 'unhandledRequest': "Unbehandelte Anfragerückmeldung ${statusText}",
-
- 'permalink': "Permalink",
-
- 'overlays': "Overlays",
-
- 'baseLayer': "Grundkarte",
-
- 'sameProjection':
- "Die Ãbersichtskarte funktioniert nur, wenn sie dieselbe Projektion wie die Hauptkarte verwendet",
-
- 'readNotImplemented': "Lesen nicht implementiert.",
-
- 'writeNotImplemented': "Schreiben nicht implementiert.",
-
- 'noFID': "Ein Feature, für das keine FID existiert, kann nicht aktualisiert werden.",
-
- 'errorLoadingGML': "Fehler beim Laden der GML-Datei ${url}",
-
- 'browserNotSupported':
- "Ihr Browser unterstützt keine Vektordarstellung. Aktuell unterstützte Renderer:\n${renderers}",
-
- 'componentShouldBe': "addFeatures : Komponente sollte vom Typ ${geomType} sein",
-
- 'commitSuccess': "WFS-Transaktion: ERFOLGREICH ${response}",
-
- 'commitFailed': "WFS-Transaktion: FEHLGESCHLAGEN ${response}",
-
- 'googleWarning':
- "Der Google-Layer konnte nicht korrekt geladen werden.<br><br>" +
- "Um diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen " +
- "Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.<br><br>" +
- "Sehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der " +
- "Google-Maps-Bibliothek nicht eingebunden wurde oder keinen gültigen " +
- "API-Schlüssel für Ihre URL enthält.<br><br>" +
- "Entwickler: Für Hilfe zum korrekten Einbinden des Google-Layers " +
- "<a href='http://trac.openlayers.org/wiki/Google' " +
- "target='_blank'>hier klicken</a>",
-
- 'getLayerWarning':
- "Der ${layerType}-Layer konnte nicht korrekt geladen werden.<br><br>" +
- "Um diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen " +
- "Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.<br><br>" +
- "Sehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der " +
- '"${layerLib}"-Bibliothek nicht eingebunden wurde.<br><br>' +
- "Entwickler: Für Hilfe zum korrekten Einbinden von Layern " +
- "<a href='http://trac.openlayers.org/wiki/${layerLib}' " +
- "target='_blank'>hier klicken</a>",
-
- 'scale': "MaÃstab = 1 : ${scaleDenom}",
-
- 'end': ''
-}, OpenLayers.Lang["en"]);
Copied: sandbox/aboudreault/lib/OpenLayers/Lang/de.js (from rev 1412, trunk/lib/OpenLayers/Lang/de.js)
===================================================================
--- sandbox/aboudreault/lib/OpenLayers/Lang/de.js (rev 0)
+++ sandbox/aboudreault/lib/OpenLayers/Lang/de.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -0,0 +1,69 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Lang/en.js
+ */
+
+/**
+ * Namespace: OpenLayers.Lang["de"]
+ * Dictionary for German. Keys for entries are used in calls to
+ * <OpenLayers.Lang.translate>. Entry bodies are normal strings or
+ * strings formatted for use with <OpenLayers.String.format> calls.
+ */
+OpenLayers.Lang.de = OpenLayers.Util.applyDefaults({
+
+ 'unhandledRequest': "Unbehandelte Anfragerückmeldung ${statusText}",
+
+ 'permalink': "Permalink",
+
+ 'overlays': "Overlays",
+
+ 'baseLayer': "Grundkarte",
+
+ 'sameProjection':
+ "Die Ãbersichtskarte funktioniert nur, wenn sie dieselbe Projektion wie die Hauptkarte verwendet",
+
+ 'readNotImplemented': "Lesen nicht implementiert.",
+
+ 'writeNotImplemented': "Schreiben nicht implementiert.",
+
+ 'noFID': "Ein Feature, für das keine FID existiert, kann nicht aktualisiert werden.",
+
+ 'errorLoadingGML': "Fehler beim Laden der GML-Datei ${url}",
+
+ 'browserNotSupported':
+ "Ihr Browser unterstützt keine Vektordarstellung. Aktuell unterstützte Renderer:\n${renderers}",
+
+ 'componentShouldBe': "addFeatures : Komponente sollte vom Typ ${geomType} sein",
+
+ 'commitSuccess': "WFS-Transaktion: ERFOLGREICH ${response}",
+
+ 'commitFailed': "WFS-Transaktion: FEHLGESCHLAGEN ${response}",
+
+ 'googleWarning':
+ "Der Google-Layer konnte nicht korrekt geladen werden.<br><br>" +
+ "Um diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen " +
+ "Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.<br><br>" +
+ "Sehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der " +
+ "Google-Maps-Bibliothek nicht eingebunden wurde oder keinen gültigen " +
+ "API-Schlüssel für Ihre URL enthält.<br><br>" +
+ "Entwickler: Für Hilfe zum korrekten Einbinden des Google-Layers " +
+ "<a href='http://trac.openlayers.org/wiki/Google' " +
+ "target='_blank'>hier klicken</a>",
+
+ 'getLayerWarning':
+ "Der ${layerType}-Layer konnte nicht korrekt geladen werden.<br><br>" +
+ "Um diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen " +
+ "Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.<br><br>" +
+ "Sehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der " +
+ '"${layerLib}"-Bibliothek nicht eingebunden wurde.<br><br>' +
+ "Entwickler: Für Hilfe zum korrekten Einbinden von Layern " +
+ "<a href='http://trac.openlayers.org/wiki/${layerLib}' " +
+ "target='_blank'>hier klicken</a>",
+
+ 'scale': "MaÃstab = 1 : ${scaleDenom}",
+
+ 'end': ''
+}, OpenLayers.Lang["en"]);
Deleted: sandbox/aboudreault/lib/OpenLayers/Lang/en-CA.js
===================================================================
--- trunk/lib/OpenLayers/Lang/en-CA.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/OpenLayers/Lang/en-CA.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -1,25 +0,0 @@
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Lang/en.js
- */
-
-/**
- * Namespace: OpenLayers.Lang["en-CA"]
- * Dictionary for English-CA. This dictionary inherits from the standard
- * English dictionary. Override only those entries with language specific
- * to the CA region.
- *
- * Keys for entries are used in calls to <OpenLayers.Lang.translate>. Entry
- * bodies are normal strings or strings formatted for use with
- * <OpenLayers.String.format> calls.
- */
-OpenLayers.Lang['en-CA'] = OpenLayers.Util.applyDefaults({
-
- // add any entries specific for this region here
- // e.g.
- // "someKey": "Some regionally specific value"
-
-}, OpenLayers.Lang["en"]);
Copied: sandbox/aboudreault/lib/OpenLayers/Lang/en-CA.js (from rev 1412, trunk/lib/OpenLayers/Lang/en-CA.js)
===================================================================
--- sandbox/aboudreault/lib/OpenLayers/Lang/en-CA.js (rev 0)
+++ sandbox/aboudreault/lib/OpenLayers/Lang/en-CA.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -0,0 +1,25 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Lang/en.js
+ */
+
+/**
+ * Namespace: OpenLayers.Lang["en-CA"]
+ * Dictionary for English-CA. This dictionary inherits from the standard
+ * English dictionary. Override only those entries with language specific
+ * to the CA region.
+ *
+ * Keys for entries are used in calls to <OpenLayers.Lang.translate>. Entry
+ * bodies are normal strings or strings formatted for use with
+ * <OpenLayers.String.format> calls.
+ */
+OpenLayers.Lang['en-CA'] = OpenLayers.Util.applyDefaults({
+
+ // add any entries specific for this region here
+ // e.g.
+ // "someKey": "Some regionally specific value"
+
+}, OpenLayers.Lang["en"]);
Deleted: sandbox/aboudreault/lib/OpenLayers/Lang/en.js
===================================================================
--- trunk/lib/OpenLayers/Lang/en.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/OpenLayers/Lang/en.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -1,120 +0,0 @@
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Lang.js
- */
-
-/**
- * Namespace: OpenLayers.Lang["en"]
- * Dictionary for English. Keys for entries are used in calls to
- * <OpenLayers.Lang.translate>. Entry bodies are normal strings or
- * strings formatted for use with <OpenLayers.String.format> calls.
- */
-OpenLayers.Lang.en = {
-
- 'unhandledRequest': "Unhandled request return ${statusText}",
-
- 'permalink': "Permalink",
-
- 'overlays': "Overlays",
-
- 'baseLayer': "Base Layer",
-
- 'sameProjection':
- "The overview map only works when it is in the same projection as the main map",
-
- 'readNotImplemented': "Read not implemented.",
-
- 'writeNotImplemented': "Write not implemented.",
-
- 'noFID': "Can't update a feature for which there is no FID.",
-
- 'errorLoadingGML': "Error in loading GML file ${url}",
-
- 'browserNotSupported':
- "Your browser does not support vector rendering. Currently supported renderers are:\n${renderers}",
-
- 'componentShouldBe': "addFeatures : component should be an ${geomType}",
-
- // console message
- 'getFeatureError':
- "getFeatureFromEvent called on layer with no renderer. This usually means you " +
- "destroyed a layer, but not some handler which is associated with it.",
-
- // console message
- 'minZoomLevelError':
- "The minZoomLevel property is only intended for use " +
- "with the FixedZoomLevels-descendent layers. That this " +
- "wfs layer checks for minZoomLevel is a relic of the" +
- "past. We cannot, however, remove it without possibly " +
- "breaking OL based applications that may depend on it." +
- " Therefore we are deprecating it -- the minZoomLevel " +
- "check below will be removed at 3.0. Please instead " +
- "use min/max resolution setting as described here: " +
- "http://trac.openlayers.org/wiki/SettingZoomLevels",
-
- 'commitSuccess': "WFS Transaction: SUCCESS ${response}",
-
- 'commitFailed': "WFS Transaction: FAILED ${response}",
-
- 'googleWarning':
- "The Google Layer was unable to load correctly.<br><br>" +
- "To get rid of this message, select a new BaseLayer " +
- "in the layer switcher in the upper-right corner.<br><br>" +
- "Most likely, this is because the Google Maps library " +
- "script was either not included, or does not contain the " +
- "correct API key for your site.<br><br>" +
- "Developers: For help getting this working correctly, " +
- "<a href='http://trac.openlayers.org/wiki/Google' " +
- "target='_blank'>click here</a>",
-
- 'getLayerWarning':
- "The ${layerType} Layer was unable to load correctly.<br><br>" +
- "To get rid of this message, select a new BaseLayer " +
- "in the layer switcher in the upper-right corner.<br><br>" +
- "Most likely, this is because the ${layerLib} library " +
- "script was either not correctly included.<br><br>" +
- "Developers: For help getting this working correctly, " +
- "<a href='http://trac.openlayers.org/wiki/${layerLib}' " +
- "target='_blank'>click here</a>",
-
- 'scale': "Scale = 1 : ${scaleDenom}",
-
- // console message
- 'layerAlreadyAdded':
- "You tried to add the layer: ${layerName} to the map, but it has already been added",
-
- // console message
- 'reprojectDeprecated':
- "You are using the 'reproject' option " +
- "on the ${layerName} layer. This option is deprecated: " +
- "its use was designed to support displaying data over commercial " +
- "basemaps, but that functionality should now be achieved by using " +
- "Spherical Mercator support. More information is available from " +
- "http://trac.openlayers.org/wiki/SphericalMercator.",
-
- // console message
- 'methodDeprecated':
- "This method has been deprecated and will be removed in 3.0. " +
- "Please use ${newMethod} instead.",
-
- // console message
- 'boundsAddError': "You must pass both x and y values to the add function.",
-
- // console message
- 'lonlatAddError': "You must pass both lon and lat values to the add function.",
-
- // console message
- 'pixelAddError': "You must pass both x and y values to the add function.",
-
- // console message
- 'unsupportedGeometryType': "Unsupported geometry type: ${geomType}",
-
- // console message
- 'pagePositionFailed':
- "OpenLayers.Util.pagePosition failed: element with id ${elemId} may be misplaced.",
-
- 'end': ''
-};
Copied: sandbox/aboudreault/lib/OpenLayers/Lang/en.js (from rev 1412, trunk/lib/OpenLayers/Lang/en.js)
===================================================================
--- sandbox/aboudreault/lib/OpenLayers/Lang/en.js (rev 0)
+++ sandbox/aboudreault/lib/OpenLayers/Lang/en.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -0,0 +1,120 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Lang.js
+ */
+
+/**
+ * Namespace: OpenLayers.Lang["en"]
+ * Dictionary for English. Keys for entries are used in calls to
+ * <OpenLayers.Lang.translate>. Entry bodies are normal strings or
+ * strings formatted for use with <OpenLayers.String.format> calls.
+ */
+OpenLayers.Lang.en = {
+
+ 'unhandledRequest': "Unhandled request return ${statusText}",
+
+ 'permalink': "Permalink",
+
+ 'overlays': "Overlays",
+
+ 'baseLayer': "Base Layer",
+
+ 'sameProjection':
+ "The overview map only works when it is in the same projection as the main map",
+
+ 'readNotImplemented': "Read not implemented.",
+
+ 'writeNotImplemented': "Write not implemented.",
+
+ 'noFID': "Can't update a feature for which there is no FID.",
+
+ 'errorLoadingGML': "Error in loading GML file ${url}",
+
+ 'browserNotSupported':
+ "Your browser does not support vector rendering. Currently supported renderers are:\n${renderers}",
+
+ 'componentShouldBe': "addFeatures : component should be an ${geomType}",
+
+ // console message
+ 'getFeatureError':
+ "getFeatureFromEvent called on layer with no renderer. This usually means you " +
+ "destroyed a layer, but not some handler which is associated with it.",
+
+ // console message
+ 'minZoomLevelError':
+ "The minZoomLevel property is only intended for use " +
+ "with the FixedZoomLevels-descendent layers. That this " +
+ "wfs layer checks for minZoomLevel is a relic of the" +
+ "past. We cannot, however, remove it without possibly " +
+ "breaking OL based applications that may depend on it." +
+ " Therefore we are deprecating it -- the minZoomLevel " +
+ "check below will be removed at 3.0. Please instead " +
+ "use min/max resolution setting as described here: " +
+ "http://trac.openlayers.org/wiki/SettingZoomLevels",
+
+ 'commitSuccess': "WFS Transaction: SUCCESS ${response}",
+
+ 'commitFailed': "WFS Transaction: FAILED ${response}",
+
+ 'googleWarning':
+ "The Google Layer was unable to load correctly.<br><br>" +
+ "To get rid of this message, select a new BaseLayer " +
+ "in the layer switcher in the upper-right corner.<br><br>" +
+ "Most likely, this is because the Google Maps library " +
+ "script was either not included, or does not contain the " +
+ "correct API key for your site.<br><br>" +
+ "Developers: For help getting this working correctly, " +
+ "<a href='http://trac.openlayers.org/wiki/Google' " +
+ "target='_blank'>click here</a>",
+
+ 'getLayerWarning':
+ "The ${layerType} Layer was unable to load correctly.<br><br>" +
+ "To get rid of this message, select a new BaseLayer " +
+ "in the layer switcher in the upper-right corner.<br><br>" +
+ "Most likely, this is because the ${layerLib} library " +
+ "script was either not correctly included.<br><br>" +
+ "Developers: For help getting this working correctly, " +
+ "<a href='http://trac.openlayers.org/wiki/${layerLib}' " +
+ "target='_blank'>click here</a>",
+
+ 'scale': "Scale = 1 : ${scaleDenom}",
+
+ // console message
+ 'layerAlreadyAdded':
+ "You tried to add the layer: ${layerName} to the map, but it has already been added",
+
+ // console message
+ 'reprojectDeprecated':
+ "You are using the 'reproject' option " +
+ "on the ${layerName} layer. This option is deprecated: " +
+ "its use was designed to support displaying data over commercial " +
+ "basemaps, but that functionality should now be achieved by using " +
+ "Spherical Mercator support. More information is available from " +
+ "http://trac.openlayers.org/wiki/SphericalMercator.",
+
+ // console message
+ 'methodDeprecated':
+ "This method has been deprecated and will be removed in 3.0. " +
+ "Please use ${newMethod} instead.",
+
+ // console message
+ 'boundsAddError': "You must pass both x and y values to the add function.",
+
+ // console message
+ 'lonlatAddError': "You must pass both lon and lat values to the add function.",
+
+ // console message
+ 'pixelAddError': "You must pass both x and y values to the add function.",
+
+ // console message
+ 'unsupportedGeometryType': "Unsupported geometry type: ${geomType}",
+
+ // console message
+ 'pagePositionFailed':
+ "OpenLayers.Util.pagePosition failed: element with id ${elemId} may be misplaced.",
+
+ 'end': ''
+};
Deleted: sandbox/aboudreault/lib/OpenLayers/Lang/fr.js
===================================================================
--- trunk/lib/OpenLayers/Lang/fr.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/OpenLayers/Lang/fr.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -1,19 +0,0 @@
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
- * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Lang.js
- */
-
-/**
- * Namespace: OpenLayers.Lang["fr"]
- * Dictionary for French. Keys for entries are used in calls to
- * <OpenLayers.Lang.translate>. Entry bodies are normal strings or
- * strings formatted for use with <OpenLayers.String.format> calls.
- */
-OpenLayers.Lang.fr = {
-
- 'overlays': "Couches de superposition"
-
-};
Copied: sandbox/aboudreault/lib/OpenLayers/Lang/fr.js (from rev 1412, trunk/lib/OpenLayers/Lang/fr.js)
===================================================================
--- sandbox/aboudreault/lib/OpenLayers/Lang/fr.js (rev 0)
+++ sandbox/aboudreault/lib/OpenLayers/Lang/fr.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -0,0 +1,19 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Lang.js
+ */
+
+/**
+ * Namespace: OpenLayers.Lang["fr"]
+ * Dictionary for French. Keys for entries are used in calls to
+ * <OpenLayers.Lang.translate>. Entry bodies are normal strings or
+ * strings formatted for use with <OpenLayers.String.format> calls.
+ */
+OpenLayers.Lang.fr = {
+
+ 'overlays': "Couches de superposition"
+
+};
Modified: sandbox/aboudreault/lib/OpenLayers/OpenLayers.js
===================================================================
--- sandbox/aboudreault/lib/OpenLayers/OpenLayers.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/OpenLayers/OpenLayers.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -2,8 +2,8 @@
OpenLayers.js -- OpenLayers Map Viewer Library
- Copyright 2005-2007 MetaCarta, Inc., released under a modified BSD license.
- Please see http://svn.openlayers.org/trunk/openlayers/repository-license.txt
+ Copyright 2005-2008 MetaCarta, Inc., released under the Clear BSD 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:
@@ -21,7 +21,7 @@
* Prototype is freely distributable under the terms of an MIT-style license.
* For details, see the Prototype web site: http://prototype.conio.net/
*
-/*--------------------------------------------------------------------------*/
+ *--------------------------------------------------------------------------*/
/**
*
@@ -43,12913 +43,15613 @@
*
**/
-/* ======================================================================
- OpenLayers/SingleFile.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-OpenLayers = {
- singleFile: true
-};
-
-
-/* ======================================================================
- OpenLayers.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/*
- * @requires OpenLayers/BaseTypes.js
- */
-
-(function() {
- /**
- * Before creating the OpenLayers namespace, check to see if
- * OpenLayers.singleFile is true. This occurs if the
- * OpenLayers/SingleFile.js script is included before this one - as is the
- * case with single file builds.
- */
- var singleFile = (typeof OpenLayers == "object" && OpenLayers.singleFile);
-
- /**
- * Namespace: OpenLayers
- * The OpenLayers object provides a namespace for all things OpenLayers
- */
- OpenLayers = {
-
- /**
- * Property: _scriptName
- * {String} Relative path of this script.
- */
- _scriptName: (!singleFile) ? "lib/OpenLayers.js" : "OpenLayers.js",
-
- /**
- * Function: _getScriptLocation
- * Return the path to this script.
- *
- * Returns:
- * Path to this script
- */
- _getScriptLocation: function () {
- var scriptLocation = "";
- var scriptName = OpenLayers._scriptName;
-
- var scripts = document.getElementsByTagName('script');
- for (var i = 0; i < scripts.length; i++) {
- var src = scripts[i].getAttribute('src');
- if (src) {
- var index = src.lastIndexOf(scriptName);
- // is it found, at the end of the URL?
- if ((index > -1) && (index + scriptName.length == src.length)) {
- scriptLocation = src.slice(0, -scriptName.length);
- break;
- }
- }
- }
- return scriptLocation;
- }
- };
- /**
- * OpenLayers.singleFile is a flag indicating this file is being included
- * in a Single File Library build of the OpenLayers Library.
- *
- * When we are *not* part of a SFL build we dynamically include the
- * OpenLayers library code.
- *
- * When we *are* part of a SFL build we do not dynamically include the
- * OpenLayers library code as it will be appended at the end of this file.
- */
- if(!singleFile) {
- var jsfiles = new Array(
- "OpenLayers/Util.js",
- "OpenLayers/BaseTypes.js",
- "OpenLayers/BaseTypes/Class.js",
- "OpenLayers/BaseTypes/Bounds.js",
- "OpenLayers/BaseTypes/Element.js",
- "OpenLayers/BaseTypes/LonLat.js",
- "OpenLayers/BaseTypes/Pixel.js",
- "OpenLayers/BaseTypes/Size.js",
- "OpenLayers/Console.js",
- "Rico/Corner.js",
- "Rico/Color.js",
- "OpenLayers/Ajax.js",
- "OpenLayers/Events.js",
- "OpenLayers/Map.js",
- "OpenLayers/Layer.js",
- "OpenLayers/Icon.js",
- "OpenLayers/Marker.js",
- "OpenLayers/Marker/Box.js",
- "OpenLayers/Popup.js",
- "OpenLayers/Tile.js",
- "OpenLayers/Tile/Image.js",
- "OpenLayers/Tile/WFS.js",
- "OpenLayers/Layer/Image.js",
- "OpenLayers/Layer/SphericalMercator.js",
- "OpenLayers/Layer/EventPane.js",
- "OpenLayers/Layer/FixedZoomLevels.js",
- "OpenLayers/Layer/Google.js",
- "OpenLayers/Layer/VirtualEarth.js",
- "OpenLayers/Layer/Yahoo.js",
- "OpenLayers/Layer/HTTPRequest.js",
- "OpenLayers/Layer/Grid.js",
- "OpenLayers/Layer/MapServer.js",
- "OpenLayers/Layer/MapGuide.js",
- "OpenLayers/Layer/MapServer/Untiled.js",
- "OpenLayers/Layer/KaMap.js",
- "OpenLayers/Layer/MultiMap.js",
- "OpenLayers/Layer/Markers.js",
- "OpenLayers/Layer/Text.js",
- "OpenLayers/Layer/WorldWind.js",
- "OpenLayers/Layer/WMS.js",
- "OpenLayers/Layer/WMS/Untiled.js",
- "OpenLayers/Layer/GeoRSS.js",
- "OpenLayers/Layer/Boxes.js",
- "OpenLayers/Layer/TMS.js",
- "OpenLayers/Layer/TileCache.js",
- "OpenLayers/Popup/Anchored.js",
- "OpenLayers/Popup/AnchoredBubble.js",
- "OpenLayers/Feature.js",
- "OpenLayers/Feature/Vector.js",
- "OpenLayers/Feature/WFS.js",
- "OpenLayers/Handler.js",
- "OpenLayers/Handler/Point.js",
- "OpenLayers/Handler/Path.js",
- "OpenLayers/Handler/Polygon.js",
- "OpenLayers/Handler/Feature.js",
- "OpenLayers/Handler/Drag.js",
- "OpenLayers/Handler/RegularPolygon.js",
- "OpenLayers/Handler/Box.js",
- "OpenLayers/Handler/MouseWheel.js",
- "OpenLayers/Handler/Keyboard.js",
- "OpenLayers/Control.js",
- "OpenLayers/Control/Attribution.js",
- "OpenLayers/Control/ZoomBox.js",
- "OpenLayers/Control/ZoomToMaxExtent.js",
- "OpenLayers/Control/DragPan.js",
- "OpenLayers/Control/Navigation.js",
- "OpenLayers/Control/MouseDefaults.js",
- "OpenLayers/Control/MousePosition.js",
- "OpenLayers/Control/OverviewMap.js",
- "OpenLayers/Control/KeyboardDefaults.js",
- "OpenLayers/Control/PanZoom.js",
- "OpenLayers/Control/PanZoomBar.js",
- "OpenLayers/Control/ArgParser.js",
- "OpenLayers/Control/Permalink.js",
- "OpenLayers/Control/Scale.js",
- "OpenLayers/Control/LayerSwitcher.js",
- "OpenLayers/Control/DrawFeature.js",
- "OpenLayers/Control/DragFeature.js",
- "OpenLayers/Control/ModifyFeature.js",
- "OpenLayers/Control/Panel.js",
- "OpenLayers/Control/SelectFeature.js",
- "OpenLayers/Geometry.js",
- "OpenLayers/Geometry/Rectangle.js",
- "OpenLayers/Geometry/Collection.js",
- "OpenLayers/Geometry/Point.js",
- "OpenLayers/Geometry/MultiPoint.js",
- "OpenLayers/Geometry/Curve.js",
- "OpenLayers/Geometry/LineString.js",
- "OpenLayers/Geometry/LinearRing.js",
- "OpenLayers/Geometry/Polygon.js",
- "OpenLayers/Geometry/MultiLineString.js",
- "OpenLayers/Geometry/MultiPolygon.js",
- "OpenLayers/Geometry/Surface.js",
- "OpenLayers/Renderer.js",
- "OpenLayers/Renderer/Elements.js",
- "OpenLayers/Renderer/SVG.js",
- "OpenLayers/Renderer/VML.js",
- "OpenLayers/Layer/Vector.js",
- "OpenLayers/Layer/GML.js",
- "OpenLayers/Format.js",
- "OpenLayers/Format/XML.js",
- "OpenLayers/Format/GML.js",
- "OpenLayers/Format/KML.js",
- "OpenLayers/Format/GeoRSS.js",
- "OpenLayers/Format/WFS.js",
- "OpenLayers/Format/WKT.js",
- "OpenLayers/Format/JSON.js",
- "OpenLayers/Format/GeoJSON.js",
- "OpenLayers/Layer/WFS.js",
- "OpenLayers/Control/MouseToolbar.js",
- "OpenLayers/Control/NavToolbar.js",
- "OpenLayers/Control/EditingToolbar.js",
- "OpenLayers/Projection.js",
- "OpenLayers/Strings/en.js"
- ); // etc.
-
-
-
- var allScriptTags = "";
- var host = OpenLayers._getScriptLocation() + "lib/";
-
- for (var i = 0; i < jsfiles.length; i++) {
- if (/MSIE/.test(navigator.userAgent) || /Safari/.test(navigator.userAgent)) {
- var currentScriptTag = "<script src='" + host + jsfiles[i] + "'></script>";
- allScriptTags += currentScriptTag;
- } else {
- var s = document.createElement("script");
- s.src = host + jsfiles[i];
- var h = document.getElementsByTagName("head").length ?
- document.getElementsByTagName("head")[0] :
- document.body;
- h.appendChild(s);
- }
- }
- if (allScriptTags) document.write(allScriptTags);
- }
-})();
-
-/**
- * Constant: VERSION_NUMBER
- */
-OpenLayers.VERSION_NUMBER="$Revision$";
-/* ======================================================================
- OpenLayers/Util.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-
-/**
- * Namespace: Util
- */
-OpenLayers.Util = {};
-
-/**
- * Function: getElement
- * This is the old $() from prototype
- */
-OpenLayers.Util.getElement = function() {
- var elements = [];
-
- for (var i = 0; i < arguments.length; i++) {
- var element = arguments[i];
- if (typeof element == 'string') {
- element = document.getElementById(element);
- }
- if (arguments.length == 1) {
- return element;
- }
- elements.push(element);
- }
- return elements;
-};
-
-/**
- * Maintain $() from prototype
- */
-if ($ == null) {
- var $ = OpenLayers.Util.getElement;
-}
-
-/**
- * APIFunction: extend
- * Copy all properties of a source object to a destination object. Modifies
- * the passed in destination object.
- *
- * Parameters:
- * destination - {Object} The object that will be modified
- * source - {Object} The object with properties to be set on the destination
- *
- * Returns:
- * {Object} The destination object.
- */
-OpenLayers.Util.extend = function(destination, source) {
- if(destination && source) {
- for(var property in source) {
- destination[property] = source[property];
- }
- /**
- * 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(source.hasOwnProperty && source.hasOwnProperty('toString')) {
- destination.toString = source.toString;
- }
- }
- return destination;
-};
-
-
-/**
- * Function: removeItem
- * Remove an object from an array. Iterates through the array
- * to find the item, then removes it.
- *
- * Parameters:
- * array - {Array}
- * item - {Object}
- *
- * Return
- * {Array} A reference to the array
- */
-OpenLayers.Util.removeItem = function(array, item) {
- for(var i=0; i < array.length; i++) {
- if(array[i] == item) {
- array.splice(i,1);
- //break;more than once??
- }
- }
- return array;
-};
-
-/**
- * Function: clearArray
- * *Deprecated*. This function will disappear in 3.0.
- * Please use "array.length = 0" instead.
- *
- * Parameters:
- * array - {Array}
- */
-OpenLayers.Util.clearArray = function(array) {
- var msg = OpenLayers.String.translate("clearArrayDeprecated");
- OpenLayers.Console.warn(msg);
- array.length = 0;
-};
-
-/**
- * Function: indexOf
- * Seems to exist already in FF, but not in MOZ.
- *
- * Parameters:
- * array - {Array}
- * obj - {Object}
- *
- * Returns:
- * {Integer} The index at, which the object was found in the array.
- * If not found, returns -1.v
- */
-OpenLayers.Util.indexOf = function(array, obj) {
-
- for(var i=0; i < array.length; i++) {
- if (array[i] == obj) return i;
- }
- return -1;
-};
-
-
-
-/**
- * Function: modifyDOMElement
- *
- * Modifies many properties of a DOM element all at once. Passing in
- * null to an individual parameter will avoid setting the attribute.
- *
- * Parameters:
- * id - {String} The element id attribute to set.
- * px - {<OpenLayers.Pixel>} The left and top style position.
- * sz - {<OpenLayers.Size>} The width and height style attributes.
- * position - {String} The position attribute. eg: absolute,
- * relative, etc.
- * border - {String} The style.border attribute. eg:
- * solid black 2px
- * overflow - {String} The style.overview attribute.
- * opacity - {Float} Fractional value (0.0 - 1.0)
- */
-OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position,
- border, overflow, opacity) {
-
- if (id) {
- element.id = id;
- }
- if (px) {
- element.style.left = px.x + "px";
- element.style.top = px.y + "px";
- }
- if (sz) {
- element.style.width = sz.w + "px";
- element.style.height = sz.h + "px";
- }
- if (position) {
- element.style.position = position;
- }
- if (border) {
- element.style.border = border;
- }
- if (overflow) {
- element.style.overflow = overflow;
- }
- if (opacity) {
- element.style.opacity = opacity;
- element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
- }
-};
-
-/**
- * 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.d
- *
- * Note: zIndex is NOT set
- *
- * Parameters:
- * id - {String} An identifier for this element. If no id is
- * passed an identifier will be created
- * automatically.
- * px - {<OpenLayers.Pixel>} The element left and top position.
- * sz - {<OpenLayers.Size>} The element width and height.
- * imgURL - {String} A url pointing to an image to use as a
- * background image.
- * position - {String} The style.position value. eg: absolute,
- * relative etc.
- * border - {String} The the style.border value.
- * eg: 2px solid black
- * overflow - {String} The style.overflow value. Eg. hidden
- * opacity - {Float} Fractional value (0.0 - 1.0)
- *
- * Returns:
- * {DOMElement} A DOM Div created with the specified attributes.
- */
-OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position,
- border, overflow, opacity) {
-
- var dom = document.createElement('div');
-
- if (imgURL) {
- dom.style.backgroundImage = 'url(' + imgURL + ')';
- }
-
- //set generic properties
- if (!id) {
- id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
- }
- if (!position) {
- position = "absolute";
- }
- OpenLayers.Util.modifyDOMElement(dom, id, px, sz, position,
- border, overflow, opacity);
-
- return dom;
-};
-
-/**
- * Function: createImage
- * Creates an img element with specific attribute values.
- *
- * Parameters:
- * id - {String} The id field for the img. If none assigned one will be
- * automatically generated.
- * px - {<OpenLayers.Pixel>} The left and top positions.
- * sz - {<OpenLayers.Size>} The style.width and style.height values.
- * imgURL - {String} The url to use as the image source.
- * position - {String} The style.position value.
- * border - {String} The border to place around the image.
- * delayDisplay - {Boolean} If true waits until the image has been
- * loaded.
- * opacity - {Float} Fractional value (0.0 - 1.0)
- *
- * Returns:
- * {DOMElement} A DOM Image created with the specified attributes.
- */
-OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border,
- opacity, delayDisplay) {
-
- var image = document.createElement("img");
-
- //set generic properties
- if (!id) {
- id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
- }
- if (!position) {
- position = "relative";
- }
- OpenLayers.Util.modifyDOMElement(image, id, px, sz, position,
- border, null, opacity);
-
- if(delayDisplay) {
- image.style.display = "none";
- OpenLayers.Event.observe(image, "load",
- OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, image));
- OpenLayers.Event.observe(image, "error",
- OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, image));
-
- }
-
- //set special properties
- image.style.alt = id;
- image.galleryImg = "no";
- if (imgURL) {
- image.src = imgURL;
- }
-
-
-
- return image;
-};
-
-/**
- * Function: setOpacity
- * Deprecated.
- * This function has been deprecated. Instead, please use
- * OpenLayers.Util.modifyDOMElement()
- * or
- * OpenLayers.Util.modifyAlphaImageDiv()
- *
- * Set the opacity of a DOM Element
- * Note that for this function to work in IE, elements must "have layout"
- * according to:
- * http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp
- *
- * Parameters:
- * element - {DOMElement} Set the opacity on this DOM element
- * opacity - {Float} Opacity value (0.0 - 1.0)
- */
-OpenLayers.Util.setOpacity = function(element, opacity) {
- OpenLayers.Util.modifyDOMElement(element, null, null, null,
- null, null, null, opacity);
-}
-
-/**
- * Function: onImageLoad
- */
-OpenLayers.Util.onImageLoad = function() {
- // The complex check here is to solve issues described in #480.
- // Every time a map view changes, it increments the 'viewRequestID'
- // property. As the requests for the images for the new map view are sent
- // out, they are tagged with this unique viewRequestID.
- //
- // If an image has no viewRequestID property set, we display it regardless,
- // but if it does have a viewRequestID property, we check that it matches
- // the viewRequestID set on the map.
- //
- // If the viewRequestID on the map has changed, that means that the user
- // has changed the map view since this specific request was sent out, and
- // therefore this tile does not need to be displayed (so we do not execute
- // this code that turns its display on).
- //
- if (!this.viewRequestID ||
- (this.map && this.viewRequestID == this.map.viewRequestID)) {
- this.style.backgroundColor = null;
- this.style.display = "";
- }
-};
-
-/**
- * Property: onImageLoadErrorColor
- * {String} The color tiles with load errors will turn.
- * Default is "pink"
- */
-OpenLayers.Util.onImageLoadErrorColor = "pink";
-
-/**
- * Property: onImageLoadErrorColor
- * {Integer} How many times should we try to reload an image before giving up?
- * Default is 0
- */
-OpenLayers.IMAGE_RELOAD_ATTEMPTS = 0;
-
-/**
- * Function: onImageLoadError
- */
-OpenLayers.Util.onImageLoadError = function() {
- this._attempts = (this._attempts) ? (this._attempts + 1) : 1;
- if(this._attempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
- this.src = this.src;
- } else {
- this.style.backgroundColor = OpenLayers.Util.onImageLoadErrorColor;
- }
- this.style.display = "";
-};
-
-/**
- * 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 alpha has is necessary and possible, false otherwise.
- */
-OpenLayers.Util.alphaHack = function() {
- 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) {
- }
-
- return ( filter &&
- (version >= 5.5) && (version < 7) );
-}
-
-/**
- * Function: modifyAlphaImageDiv
- *
- * div - {DOMElement} Div containing Alpha-adjusted Image
- * id - {String}
- * px - {<OpenLayers.Pixel>}
- * sz - {<OpenLayers.Size>}
- * imgURL - {String}
- * position - {String}
- * border - {String}
- * sizing {String} 'crop', 'scale', or 'image'. Default is "scale"
- * opacity - {Float} Fractional value (0.0 - 1.0)
- */
-OpenLayers.Util.modifyAlphaImageDiv = function(div, id, px, sz, imgURL,
- position, border, sizing,
- opacity) {
-
- OpenLayers.Util.modifyDOMElement(div, id, px, sz);
-
- var img = div.childNodes[0];
-
- if (imgURL) {
- img.src = imgURL;
- }
- OpenLayers.Util.modifyDOMElement(img, div.id + "_innerImage", null, sz,
- "relative", border);
- if (opacity) {
- div.style.opacity = opacity;
- div.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
- }
-
- if (OpenLayers.Util.alphaHack()) {
-
- div.style.display = "inline-block";
- if (sizing == null) {
- sizing = "scale";
- }
-
- div.style.filter = "progid:DXImageTransform.Microsoft" +
- ".AlphaImageLoader(src='" + img.src + "', " +
- "sizingMethod='" + sizing + "')";
- if (div.style.opacity) {
- div.style.filter += " alpha(opacity=" + div.style.opacity * 100 + ")";
- }
-
- img.style.filter = "progid:DXImageTransform.Microsoft" +
- ".Alpha(opacity=0)";
- }
-};
-
-/**
- * Function: createAlphaImageDiv
- *
- * id - {String}
- * px - {<OpenLayers.Pixel>}
- * sz - {<OpenLayers.Size>}
- * imgURL - {String}
- * position - {String}
- * border - {String}
- * sizing {String} 'crop', 'scale', or 'image'. Default is "scale"
- * delayDisplay{Boolean}
- *
- * Returns:
- * {DOMElement} A DOM Div created with a DOM Image inside it. If the hack is
- * needed for transparency in IE, it is added.
- */
-OpenLayers.Util.createAlphaImageDiv = function(id, px, sz, imgURL,
- position, border, sizing,
- opacity, delayDisplay) {
-
- var div = OpenLayers.Util.createDiv();
- var img = OpenLayers.Util.createImage(null, null, null, null, null, null,
- null, false);
- div.appendChild(img);
-
- if (delayDisplay) {
- img.style.display = "none";
- OpenLayers.Event.observe(img, "load",
- OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, div));
- OpenLayers.Event.observe(img, "error",
- OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, div));
- }
-
- OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL, position,
- border, sizing, opacity);
-
- return div;
-};
-
-
-/**
- * Function: upperCaseObject
- * Creates a new hashtable and copies over all the keys from the
- * passed-in object, but storing them under an uppercased
- * version of the key at which they were stored.
- *
- * Parameters:
- * object - {Object}
- *
- * Returns:
- * {Object} A new Object with all the same keys but uppercased
- */
-OpenLayers.Util.upperCaseObject = function (object) {
- var uObject = {};
- for (var key in object) {
- uObject[key.toUpperCase()] = object[key];
- }
- return uObject;
-};
-
-/**
- * Function: applyDefaults
- * Takes a hashtable and copies any keys that don't exist from
- * another hashtable, by analogy with OpenLayers.Util.extend() from
- * Prototype.js.
- *
- * Parameters:
- * to - {Object}
- * from - {Object}
- */
-OpenLayers.Util.applyDefaults = function (to, from) {
- for (var key in from) {
- if (to[key] == null) {
- to[key] = from[key];
- }
- }
-};
-
-/**
- * Function: getParameterString
- *
- * Parameters:
- * params - {Object}
- *
- * Returns:
- * {String} A concatenation of the properties of an object in
- * http parameter notation.
- * (ex. <i>"key1=value1&key2=value2&key3=value3"</i>)
- * If a parameter is actually a list, that parameter will then
- * be set to a comma-seperated list of values (foo,bar) instead
- * of being URL escaped (foo%3Abar).
- */
-OpenLayers.Util.getParameterString = function(params) {
- 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 = [];
- for (var itemIndex=0; itemIndex<value.length; itemIndex++) {
- encodedItemArray.push(encodeURIComponent(value[itemIndex]));
- }
- encodedValue = encodedItemArray.join(",");
- }
- else {
- /* value is a string; simply encode */
- encodedValue = encodeURIComponent(value);
- }
- paramsArray.push(encodeURIComponent(key) + "=" + encodedValue);
- }
- }
-
- return paramsArray.join("&");
-};
-
-/**
- * Property: ImgPath
- * {String} Default is ''.
- */
-OpenLayers.ImgPath = '';
-
-/**
- * Function: getImagesLocation
- *
- * Returns:
- * {String} The fully formatted image location string
- */
-OpenLayers.Util.getImagesLocation = function() {
- return OpenLayers.ImgPath || (OpenLayers._getScriptLocation() + "img/");
-};
-
-
-/**
- * Function: Try
- * Execute functions until one of them doesn't throw an error.
- * Capitalized because "try" is a reserved word in JavaScript.
- * Taken directly from OpenLayers.Util.Try()
- *
- * Parameters:
- * [*] - {Function} Any number of parameters may be passed to Try()
- * It will attempt to execute each of them until one of them
- * successfully executes.
- * If none executes successfully, returns null.
- *
- * Returns:
- * {*} The value returned by the first successfully executed function.
- */
-OpenLayers.Util.Try = function() {
- var returnValue = null;
-
- for (var i = 0; i < arguments.length; i++) {
- var lambda = arguments[i];
- try {
- returnValue = lambda();
- break;
- } catch (e) {}
- }
-
- return returnValue;
-}
-
-
-/**
- * Function: getNodes
- *
- * These could/should be made namespace aware?
- *
- * Parameters:
- * p - {}
- * tagName - {String}
- *
- * Returns:
- * {Array}
- */
-OpenLayers.Util.getNodes=function(p, tagName) {
- var nodes = OpenLayers.Util.Try(
- function () {
- return OpenLayers.Util._getNodes(p.documentElement.childNodes,
- tagName);
- },
- function () {
- return OpenLayers.Util._getNodes(p.childNodes, tagName);
- }
- );
- return nodes;
-};
-
-/**
- * Function: _getNodes
- *
- * Parameters:
- * nodes - {Array}
- * tagName - {String}
- *
- * Returns:
- * {Array}
- */
-OpenLayers.Util._getNodes=function(nodes, tagName) {
- var retArray = [];
- for (var i=0;i<nodes.length;i++) {
- if (nodes[i].nodeName==tagName) {
- retArray.push(nodes[i]);
- }
- }
-
- return retArray;
-};
-
-
-
-/**
- * Function: getTagText
- *
- * Parameters:
- * parent - {}
- * item - {String}
- * index - {Integer}
- *
- * Returns:
- * {String}
- */
-OpenLayers.Util.getTagText = function (parent, item, index) {
- var result = OpenLayers.Util.getNodes(parent, item);
- if (result && (result.length > 0))
- {
- if (!index) {
- index=0;
- }
- if (result[index].childNodes.length > 1) {
- return result.childNodes[1].nodeValue;
- }
- else if (result[index].childNodes.length == 1) {
- return result[index].firstChild.nodeValue;
- }
- } else {
- return "";
- }
-};
-
-/**
- * Function: getXmlNodeValue
- *
- * Parameters:
- * node - {XMLNode}
- *
- * Returns:
- * {String} The text value of the given node, without breaking in firefox or IE
- */
-OpenLayers.Util.getXmlNodeValue = function(node) {
- var val = null;
- OpenLayers.Util.Try(
- function() {
- val = node.text;
- if (!val)
- val = node.textContent;
- if (!val)
- val = node.firstChild.nodeValue;
- },
- function() {
- val = node.textContent;
- });
- return val;
-};
-
-/**
- * Function: mouseLeft
- *
- * Parameters:
- * evt - {Event}
- * div - {HTMLDivElement}
- *
- * Returns:
- * {Boolean}
- */
-OpenLayers.Util.mouseLeft = function (evt, div) {
- // start with the element to which the mouse has moved
- var target = (evt.relatedTarget) ? evt.relatedTarget : evt.toElement;
- // walk up the DOM tree.
- while (target != div && target != null) {
- target = target.parentNode;
- }
- // if the target we stop at isn't the div, then we've left the div.
- return (target != div);
-};
-
-/**
- * Function: rad
- *
- * Parameters:
- * x - {Float}
- *
- * Returns:
- * {Float}
- */
-OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
-
-/**
- * Function: distVincenty
- *
- * Parameters:
- * p1 - {Float}
- * p2 - {Float}
- *
- * Returns:
- * {Float}
- */
-OpenLayers.Util.distVincenty=function(p1, p2) {
- var a = 6378137, b = 6356752.3142, f = 1/298.257223563;
- 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;
-};
-
-/**
- * Function: getParameters
- * Parse the parameters from a URL or from the current page itself into a
- * JavaScript Object. Note that parameter values with commas are separated
- * out into an Array.
- *
- * Parameters:
- * url - {String} Optional url used to extract the query string.
- * If null, query string is taken from page location.
- *
- * Returns:
- * {Object} An object of key/value pairs from the query string.
- */
-OpenLayers.Util.getParameters = function(url) {
- //if no url specified, take it from the location bar
- url = url || window.location.href
- if(url == null) {
- url = window.location.href;
- }
-
- //parse out parameters portion of url string
- var paramsString = "";
- if (OpenLayers.String.contains(url, '?')) {
- var start = url.indexOf('?') + 1;
- var end = OpenLayers.String.contains(url, "#") ?
- url.indexOf('#') : url.length;
- paramsString = url.substring(start, end);
- }
-
- var parameters = {};
- var pairs = paramsString.split(/[&;]/);
- for(var i = 0; i < pairs.length; ++i) {
- var keyValue = pairs[i].split('=');
- if (keyValue[0]) {
- var key = decodeURIComponent(keyValue[0]);
- var value = keyValue[1] || ''; //empty string if no value
-
- //decode individual values
- value = value.split(",");
- for(var j=0; j < value.length; j++) {
- value[j] = decodeURIComponent(value[j]);
- }
-
- //if there's only one value, do not return as array
- if (value.length == 1) {
- value = value[0];
- }
-
- parameters[key] = value;
- }
- }
- return parameters;
-};
-
-/**
- * Function: getArgs
- * Deprecated - Will be removed in 3.0.
- * Please use instead OpenLayers.Util.getParameters
- *
- * Parameters:
- * url - {String} Optional url used to extract the query string.
- * If null, query string is taken from page location.
- *
- * Returns:
- * {Object} An object of key/value pairs from the query string.
- */
-OpenLayers.Util.getArgs = function(url) {
- var err = OpenLayers.String.translate("getArgsDeprecated");
- OpenLayers.Console.warn(err);
- return OpenLayers.Util.getParameters(url);
-};
-
-/**
- * Property: lastSeqID
- * {Integer} The ever-incrementing count variable.
- * Used for generating unique ids.
- */
-OpenLayers.Util.lastSeqID = 0;
-
-/**
- * Function: createUniqueID
- *
- * Parameters:
- * prefix {String} String to prefix unique id.
- * If null, default is "id_"
- *
- * Returns:
- * {String} A unique id string, built on the passed in prefix
- */
-OpenLayers.Util.createUniqueID = function(prefix) {
- if (prefix == null) {
- prefix = "id_";
- }
- OpenLayers.Util.lastSeqID += 1;
- return prefix + OpenLayers.Util.lastSeqID;
-};
-
-/**
- * Constant: INCHES_PER_UNIT
- * {Object} Constant inches per unit -- borrowed from MapServer mapscale.c
- */
-OpenLayers.INCHES_PER_UNIT = {
- 'inches': 1.0,
- 'ft': 12.0,
- 'mi': 63360.0,
- 'm': 39.3701,
- 'km': 39370.1,
- 'dd': 4374754
-};
-OpenLayers.INCHES_PER_UNIT["in"]= OpenLayers.INCHES_PER_UNIT.inches;
-OpenLayers.INCHES_PER_UNIT["degrees"] = OpenLayers.INCHES_PER_UNIT.dd;
-
-/**
- * Constant: DOTS_PER_INCH
- * {Integer} 72 (A sensible default)
- */
-OpenLayers.DOTS_PER_INCH = 72;
-
-/**
- * Function: normalzeScale
- *
- * Parameters:
- * scale - {float}
- *
- * Returns:
- * {Float} A normalized scale value, in 1 / X format.
- * This means that if a value less than one ( already 1/x) is passed
- * in, it just returns scale directly. Otherwise, it returns
- * 1 / scale
- */
-OpenLayers.Util.normalizeScale = function (scale) {
- var normScale = (scale > 1.0) ? (1.0 / scale)
- : scale;
- return normScale;
-};
-
-/**
- * Function: getResolutionFromScale
- *
- * Parameters:
- * scale - {Float}
- * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
- * Default is degrees
- *
- * Returns:
- * {Float} The corresponding resolution given passed-in scale and unit
- * parameters.
- */
-OpenLayers.Util.getResolutionFromScale = function (scale, units) {
-
- if (units == null) {
- units = "degrees";
- }
-
- var normScale = OpenLayers.Util.normalizeScale(scale);
-
- var resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units]
- * OpenLayers.DOTS_PER_INCH);
- return resolution;
-};
-
-/**
- * Function: getScaleFromResolution
- *
- * Parameters:
- * resolution - {Float}
- * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
- * Default is degrees
- *
- * Returns:
- * {Float} The corresponding scale given passed-in resolution and unit
- * parameters.
- */
-OpenLayers.Util.getScaleFromResolution = function (resolution, units) {
-
- if (units == null) {
- units = "degrees";
- }
-
- var scale = resolution * OpenLayers.INCHES_PER_UNIT[units] *
- OpenLayers.DOTS_PER_INCH;
- return scale;
-};
-
-/**
- * Function: safeStopPropagation
- * Deprecated.
- *
- * This function has been deprecated. Please use directly
- * OpenLayers.Event.stop() passing 'true' as the 2nd
- * argument (preventDefault)
- *
- * Safely stop the propagation of an event *without* preventing
- * the default browser action from occurring.
- *
- * Parameter:
- * evt - {Event}
- */
-OpenLayers.Util.safeStopPropagation = function(evt) {
- OpenLayers.Event.stop(evt, true);
-};
-
-/**
- * Function: pagePositon
- * Calculates the position of an element on the page.
- *
- * Parameters:
- * forElement - {DOMElement}
- *
- * Returns:´
- * {Array} two item array, L value then T value.
- */
-OpenLayers.Util.pagePosition = function(forElement) {
- var valueT = 0, valueL = 0;
-
- var element = forElement;
- var child = forElement;
- while(element) {
-
- if(element == document.body) {
- if(OpenLayers.Element.getStyle(child, 'position') == 'absolute') {
- break;
- }
- }
-
- valueT += element.offsetTop || 0;
- valueL += element.offsetLeft || 0;
-
- child = element;
- try {
- // wrapping this in a try/catch because IE chokes on the offsetParent
- element = element.offsetParent;
- } catch(e) {
- OpenLayers.Console.error(OpenLayers.String.translate(
- "pagePositionFailed",element.id));
- break;
- }
- }
-
- element = forElement;
- while(element) {
- valueT -= element.scrollTop || 0;
- valueL -= element.scrollLeft || 0;
- element = element.parentNode;
- }
-
- return [valueL, valueT];
-};
-
-
-/**
- * Function: isEquivalentUrl
- * Test two URLs for equivalence.
- *
- * Setting 'ignoreCase' allows for case-independent comparison.
- *
- * Comparison is based on:
- * - Protocol
- * - Host (evaluated without the port)
- * - Port (set 'ignorePort80' to ignore "80" values)
- * - Hash ( set 'ignoreHash' to disable)
- * - Pathname (for relative <-> absolute comparison)
- * - Arguments (so they can be out of order)
- *
- * Parameters:
- * url1 - {String}
- * url2 - {String}
- * options - {Object} Allows for customization of comparison:
- * 'ignoreCase' - Default is True
- * 'ignorePort80' - Default is True
- * 'ignoreHash' - Default is True
- *
- * Returns:
- * {Boolean} Whether or not the two URLs are equivalent
- */
-OpenLayers.Util.isEquivalentUrl = function(url1, url2, options) {
- options = options || {};
-
- OpenLayers.Util.applyDefaults(options, {
- ignoreCase: true,
- ignorePort80: true,
- ignoreHash: true
- });
-
- urlObj1 = OpenLayers.Util.createUrlObject(url1, options);
- urlObj2 = OpenLayers.Util.createUrlObject(url2, options);
-
- //compare all keys (host, port, etc)
- for(var key in urlObj1) {
- if (options.test) {
- alert(key + "\n1:" + urlObj1[key] + "\n2:" + urlObj2[key]);
- }
- var val1 = urlObj1[key];
- var val2 = urlObj2[key];
-
- switch(key) {
- case "args":
- //do nothing, they'll be treated below
- break;
- case "host":
- case "port":
- case "protocol":
- if ((val1 == "") || (val2 == "")) {
- //these will be blank for relative urls, so no need to
- // compare them here -- call break.
- //
- break;
- }
- // otherwise continue with default compare
- //
- default:
- if ( (key != "args") && (urlObj1[key] != urlObj2[key]) ) {
- return false;
- }
- break;
- }
-
- }
-
- // compare search args - irrespective of order
- for(var key in urlObj1.args) {
- if(urlObj1.args[key] != urlObj2.args[key]) {
- return false;
- }
- delete urlObj2.args[key];
- }
- // urlObj2 shouldn't have any args left
- for(var key in urlObj2.args) {
- return false;
- }
-
- return true;
-};
-
-/**
- * Function: createUrlObject
- *
- * Parameters:
- * url - {String}
- * options - {Object} A hash of options. Can be one of:
- * ignoreCase: lowercase url,
- * ignorePort80: don't include explicit port if port is 80,
- * ignoreHash: Don't include part of url after the hash (#).
- *
- * Returns:
- * {Object} An object with separate url, a, port, host, and args parsed out
- * and ready for comparison
- */
-OpenLayers.Util.createUrlObject = function(url, options) {
- options = options || {};
-
- var urlObject = {};
-
- if (options.ignoreCase) {
- url = url.toLowerCase();
- }
-
- var a = document.createElement('a');
- a.href = url;
-
- //host (without port)
- urlObject.host = a.host;
- var port = a.port;
- if (port.length <= 0) {
- var newHostLength = urlObject.host.length - (port.length);
- urlObject.host = urlObject.host.substring(0, newHostLength);
- }
-
- //protocol
- urlObject.protocol = a.protocol;
-
- //port
- urlObject.port = ((port == "80") && (options.ignorePort80)) ? "" : port;
-
- //hash
- urlObject.hash = (options.ignoreHash) ? "" : 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 part allows for relative <-> absolute comparison)
- if ( ((urlObject.protocol == "file:") && (url.indexOf("file:") != -1)) ||
- ((urlObject.protocol != "file:") && (urlObject.host != "")) ) {
-
- urlObject.pathname = a.pathname;
-
- //Test to see if the pathname includes the arguments (Opera)
- var qIndex = urlObject.pathname.indexOf("?");
- if (qIndex != -1) {
- urlObject.pathname = urlObject.pathname.substring(0, qIndex);
- }
-
- } else {
- var relStr = OpenLayers.Util.removeTail(url);
-
- var backs = 0;
- do {
- var index = relStr.indexOf("../");
-
- if (index == 0) {
- backs++
- relStr = relStr.substr(3);
- } else if (index >= 0) {
- var prevChunk = relStr.substr(0,index - 1);
-
- var slash = prevChunk.indexOf("/");
- prevChunk = (slash != -1) ? prevChunk.substr(0, slash +1)
- : "";
-
- var postChunk = relStr.substr(index + 3);
- relStr = prevChunk + postChunk;
- }
- } while(index != -1)
-
- var windowAnchor = document.createElement("a");
- var windowUrl = window.location.href;
- if (options.ignoreCase) {
- windowUrl = windowUrl.toLowerCase();
- }
- windowAnchor.href = windowUrl;
-
- //set protocol of window
- urlObject.protocol = windowAnchor.protocol;
-
- var splitter = (windowAnchor.pathname.indexOf("/") != -1) ? "/" : "\\";
- var dirs = windowAnchor.pathname.split(splitter);
- dirs.pop(); //remove filename
- while ((backs > 0) && (dirs.length > 0)) {
- dirs.pop();
- backs--;
- }
- relStr = dirs.join("/") + "/"+ relStr;
- urlObject.pathname = relStr;
- }
-
- if ((urlObject.protocol == "file:") || (urlObject.protocol == "")) {
- urlObject.host = "localhost";
- }
-
- return urlObject;
-};
-
-/**
- * Function: removeTail
- * Takes a url and removes everything after the ? and #
- *
- * Parameters:
- * url - {String} The url to process
- *
- * Returns:
- * {String} The string with all queryString and Hash removed
- */
-OpenLayers.Util.removeTail = function(url) {
- var head = null;
-
- var qMark = url.indexOf("?");
- var hashMark = url.indexOf("#");
-
- if (qMark == -1) {
- head = (hashMark != -1) ? url.substr(0,hashMark) : url;
- } else {
- head = (hashMark != -1) ? url.substr(0,Math.min(qMark, hashMark))
- : url.substr(0, qMark);
- }
- return head;
-};
-
-
-/**
- * Function: getBrowserName
- *
- * Returns:
- * {String} A string which specifies which is the current
- * browser in which we are running.
- *
- * Currently-supported browser detection and codes:
- * * 'opera' -- Opera
- * * 'msie' -- Internet Explorer
- * * 'safari' -- Safari
- * * 'firefox' -- FireFox
- * * 'mozilla' -- Mozilla
- *
- * If we are unable to property identify the browser, we
- * return an empty string.
- */
-OpenLayers.Util.getBrowserName = function() {
- var browserName = "";
-
- var ua = navigator.userAgent.toLowerCase();
- if ( ua.indexOf( "opera" ) != -1 ) {
- browserName = "opera";
- } else if ( ua.indexOf( "msie" ) != -1 ) {
- browserName = "msie";
- } else if ( ua.indexOf( "safari" ) != -1 ) {
- browserName = "safari";
- } else if ( ua.indexOf( "mozilla" ) != -1 ) {
- if ( ua.indexOf( "firefox" ) != -1 ) {
- browserName = "firefox";
- } else {
- browserName = "mozilla";
- }
- }
-
- return browserName;
-};
-/* ======================================================================
- OpenLayers/Console.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * 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: 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.
- */
- if(window.console) {
- var scripts = document.getElementsByTagName("script");
- for(var i=0; i<scripts.length; ++i) {
- if(scripts[i].src.indexOf("firebug.js") != -1) {
- OpenLayers.Util.extend(OpenLayers.Console, console);
- break;
- }
- }
- }
-})();
-/* ======================================================================
- OpenLayers/BaseTypes.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/Class.js
- * @requires OpenLayers/BaseTypes/LonLat.js
- * @requires OpenLayers/BaseTypes/Size.js
- * @requires OpenLayers/BaseTypes/Pixel.js
- * @requires OpenLayers/BaseTypes/Bounds.js
- * @requires OpenLayers/BaseTypes/Element.js
- * @requires OpenLayers/Strings/en.js
- *
- * Header: OpenLayers Base Types
- * OpenLayers custom string, number and function functions are described here.
- */
-
-/*********************
- * *
- * STRING *
- * *
- *********************/
-
-OpenLayers.String = {
- /**
- * APIMethod: OpenLayers.String.startsWith
- * Test whether a string starts with another string.
- *
- * Parameters:
- * str - {String} The string to test.
- * sub - {Sring} The substring to look for.
- *
- * Returns:
- * {Boolean} The first string starts with the second.
- */
- startsWith: function(str, sub) {
- return (str.indexOf(sub) == 0);
- },
-
- /**
- * APIMethod: OpenLayers.String.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);
- },
-
- /**
- * APIMethod: OpenLayers.String.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*$/, "$1");
- },
-
- /**
- * APIMethod: OpenLayers.String.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; i < oStringList.length; i++) {
- var s = oStringList[i];
- camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
- }
- return camelizedString;
- },
-
- langCode: (OpenLayers.Util.getBrowserName() == "msie") ?
- navigator.userLanguage.substring(0,2)://only use the prefix part for now,
- navigator.language.substring(0,2), //e.g. en-CA becomes just en
- defaultLangCode: 'en',
-
- /**
- * APIMethod: OpenLayers.String.translate
- * uses the key into a dictionary of values based on the current language string.
- * any number of additional arguments. If additional arguments are passed,
- * they will be interpolated in the string in order.
- *
- * Parameters:
- * key - {String} The key for an i18n string value in the dictionary
- *
- * Returns:
- * {String} A internationalized string
- */
- translate: function(key) {
- var langCode = OpenLayers.String.langCode;
- if (!OpenLayers.Strings[langCode]) {
- var msg = 'failed to find ' +OpenLayers.String.langCode+ ' dictionary, falling back to default language';
- OpenLayers.Console.log(msg);
- OpenLayers.Strings[langCode] = OpenLayers.Strings[OpenLayers.String.defaultLangCode];
- langCode = OpenLayers.String.defaultLangCode;
- }
-
- var dictionary = OpenLayers.Strings[langCode];
- var message = "NoMsgsFound";
- var msgValue = dictionary[key];
- if (!msgValue) {
- // Message not found, fall back to message key
- message = key;
- } else {
- // Message found; pick last one so user can override messages
- message = msgValue;
- if (arguments[this.translate.length]) {
- // Extra arguments, format message
- var varArgs = [].slice.call(arguments, this.translate.length);
- varArgs.unshift(message);
- message = this.formatMessage.apply(this, varArgs);
- }
- }
- return message;
- },
-
- /**
- * APIMethod: OpenLayers.String.formatMessage
- * Formats a message template with the extra arguments.
- * E.g. if called as: <code>OpenLayers.String.formatMessage("{1} is {0} {2}, {1}", "a good", "this", "test")</code>
- * the formatted message returned is: <code>"this is a good test, this"</code>
- *
- * Parameters:
- * messageTemplate the message format string
- * args optional extra parameters for formatting the message
- *
- * Returns:
- * the formatted message
- */
- formatMessage: function(messageTemplate)
- {
- var message = messageTemplate;
- var varArgs = [].slice.call(arguments, this.formatMessage.length);
- for (var i in varArgs) {
- var parm = new RegExp("\\{" + i + "\\}", "g");
- message = message.replace(parm, varArgs[i]);
- }
- return message;
- }
-};
-
-/**
- * Header: OpenLayers Strings
- * OpenLayers I18n strings in various langauges. Default language is English, langcode='en'
- */
-OpenLayers.Strings = {};
-
-if (!String.prototype.startsWith) {
- /**
- * APIMethod: String.startsWith
- * *Deprecated*. Whether or not a string starts with another string.
- *
- * Parameters:
- * sStart - {Sring} The string we're testing for.
- *
- * Returns:
- * {Boolean} Whether or not this string starts with the string passed in.
- */
- String.prototype.startsWith = function(sStart) {
- OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
- "OpenLayers.String.startsWith"));
- return OpenLayers.String.startsWith(this, sStart);
- };
-}
-
-if (!String.prototype.contains) {
- /**
- * APIMethod: String.contains
- * *Deprecated*. Whether or not a string contains another string.
- *
- * Parameters:
- * str - {String} The string that we're testing for.
- *
- * Returns:
- * {Boolean} Whether or not this string contains with the string passed in.
- */
- String.prototype.contains = function(str) {
- OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
- "OpenLayers.String.contains"));
- return OpenLayers.String.contains(this, str);
- };
-}
-
-if (!String.prototype.trim) {
- /**
- * APIMethod: String.trim
- * *Deprecated*. Removes leading and trailing whitespace characters from a string.
- *
- * Returns:
- * {String} A trimmed version of the string - all leading and
- * trailing spaces removed
- */
- String.prototype.trim = function() {
- OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
- "OpenLayers.String.trim"));
- return OpenLayers.String.trim(this);
- };
-}
-
-if (!String.prototype.camelize) {
- /**
- * APIMethod: String.camelize
- * *Deprecated*. Camel-case a hyphenated string.
- * Ex. "chicken-head" becomes "chickenHead", and
- * "-chicken-head" becomes "ChickenHead".
- *
- * Returns:
- * {String} The string, camelized
- */
- String.prototype.camelize = function() {
- OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
- "OpenLayers.String.camelize"));
- return OpenLayers.String.camelize(this);
- };
-}
-
-/*********************
- * *
- * NUMBER *
- * *
- *********************/
-
-OpenLayers.Number = {
- /**
- * APIMethod: OpenLayers.Number.limitSigDigs
- * Limit the number of significant digits on an integer.
- *
- * Parameters:
- * num - {Integer}
- * sig - {Integer}
- *
- * Returns:
- * {Integer} The number, rounded to the specified number of significant
- * digits.
- */
- limitSigDigs: function(num, sig) {
- var fig;
- if(sig > 0) {
- fig = parseFloat(num.toPrecision(sig));
- } else {
- fig = 0;
- }
- return fig;
- }
-};
-
-if (!Number.prototype.limitSigDigs) {
- /**
- * APIMethod: Number.limitSigDigs
- * *Deprecated*. Limit the number of significant digits on an integer. Does *not*
- * work with floats!
- *
- * Parameters:
- * sig - {Integer}
- *
- * Returns:
- * {Integer} The number, rounded to the specified number of significant digits.
- * If null, 0, or negative value passed in, returns 0
- */
- Number.prototype.limitSigDigs = function(sig) {
- OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
- "OpenLayers.Number.limitSigDigs"));
- return OpenLayers.Number.limitSigDigs(this, sig);
- };
-}
-
-/*********************
- * *
- * FUNCTION *
- * *
- *********************/
-
-OpenLayers.Function = {
- /**
- * APIMethod: OpenLayers.Function.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);
- };
- },
-
- /**
- * APIMethod: OpenLayers.Function.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);
- };
- }
-};
-
-if (!Function.prototype.bind) {
- /**
- * APIMethod: Function.bind
- * *Deprecated*. Bind a function to an object.
- * Method to easily create closures with 'this' altered.
- *
- * Parameters:
- * object - {Object} the this parameter
- *
- * Returns:
- * {Function} A closure with 'this' altered to the first
- * argument.
- */
- Function.prototype.bind = function() {
- OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
- "OpenLayers.Function.bind"));
- // new function takes the same arguments with this function up front
- Array.prototype.unshift.apply(arguments, [this]);
- return OpenLayers.Function.bind.apply(null, arguments);
- };
-}
-
-if (!Function.prototype.bindAsEventListener) {
- /**
- * APIMethod: Function.bindAsEventListener
- * *Deprecated*. Bind a function to an object, and configure it to receive the
- * event object as first parameter when called.
- *
- * Parameters:
- * object - {Object} A reference to this.
- *
- * Returns:
- * {Function}
- */
- Function.prototype.bindAsEventListener = function(object) {
- OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated",
- "OpenLayers.Function.bindAsEventListener"));
- return OpenLayers.Function.bindAsEventListener(this, object);
- };
-}
-/* ======================================================================
- OpenLayers/BaseTypes/Class.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * Constructor: OpenLayers.Class
- * Base class used to construct all other classes. Includes support for
- * multiple inheritance.
- *
- * This constructor is new in OpenLayers 2.5. At OpenLayers 3.0, the old
- * syntax for creating classes and dealing with inheritance
- * will be removed.
- *
- * To create a new OpenLayers-style class, use the following syntax:
- * > var MyClass = OpenLayers.Class(prototype);
- *
- * To create a new OpenLayers-style class with multiple inheritance, use the
- * following syntax:
- * > var MyClass = OpenLayers.Class(Class1, Class2, prototype);
- *
- */
-OpenLayers.Class = function() {
- var Class = function() {
- /**
- * This following condition can be removed at 3.0 - this is only for
- * backwards compatibility while the Class.inherit method is still
- * in use. So at 3.0, the following three lines would be replaced with
- * simply:
- * this.initialize.apply(this, arguments);
- */
- if (arguments && arguments[0] != OpenLayers.Class.isPrototype) {
- this.initialize.apply(this, arguments);
- }
- }
- var extended = {};
- var parent;
- for(var i=0; i<arguments.length; ++i) {
- if(typeof arguments[i] == "function") {
- // get the prototype of the superclass
- parent = arguments[i].prototype;
- } else {
- // in this case we're extending with the prototype
- parent = arguments[i];
- }
- OpenLayers.Util.extend(extended, parent);
- }
- Class.prototype = extended;
- return Class;
-}
-
-/**
- * Property: isPrototype
- * *Deprecated*. This is no longer needed and will be removed at 3.0.
- */
-OpenLayers.Class.isPrototype = function () {};
-
-/**
- * APIFunction: OpenLayers.create
- * *Deprecated*. Old method to create an OpenLayers style class. Use the
- * <OpenLayers.Class> constructor instead.
- *
- * Returns:
- * An OpenLayers class
- */
-OpenLayers.Class.create = function() {
- return function() {
- if (arguments && arguments[0] != OpenLayers.Class.isPrototype)
- this.initialize.apply(this, arguments);
- }
-}
-
-
-/**
- * APIFunction: inherit
- * *Deprecated*. Old method to inherit from one or more OpenLayers style
- * classes. Use the <OpenLayers.Class> constructor instead.
- *
- * Parameters:
- * class - One or more classes can be provided as arguments
- *
- * Returns:
- * An object prototype
- */
-OpenLayers.Class.inherit = function () {
- var superClass = arguments[0];
- var proto = new superClass(OpenLayers.Class.isPrototype);
- for (var i = 1; i < arguments.length; i++) {
- if (typeof arguments[i] == "function") {
- var mixin = arguments[i];
- arguments[i] = new mixin(OpenLayers.Class.isPrototype);
- }
- OpenLayers.Util.extend(proto, arguments[i]);
- }
- return proto;
-}
-/* ======================================================================
- OpenLayers/BaseTypes/Size.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * Class: OpenLayers.Size
- * Instances of this class represent a width/height pair
- */
-OpenLayers.Size = OpenLayers.Class({
-
- /**
- * APIProperty: w
- * {Number} width
- */
- w: 0.0,
-
- /**
- * APIProperty: h
- * {Number} height
- */
- h: 0.0,
-
-
- /**
- * Constructor: OpenLayers.Size
- * Create an instance of OpenLayers.Size
- *
- * Parameters:
- * w - {Number} width
- * h - {Number} height
- */
- initialize: function(w, h) {
- this.w = parseFloat(w);
- this.h = parseFloat(h);
- },
-
- /**
- * Method: toString
- * Return the string representation of a size object
- *
- * Returns:
- * {String} The string representation of OpenLayers.Size object.
- * (ex. <i>"w=55,h=66"</i>)
- */
- toString:function() {
- return ("w=" + this.w + ",h=" + this.h);
- },
-
- /**
- * APIMethod: clone
- * Create a clone of this size object
- *
- * Returns:
- * {<OpenLayers.Size>} A new OpenLayers.Size object with the same w and h
- * values
- */
- clone:function() {
- return new OpenLayers.Size(this.w, this.h);
- },
-
- /**
- *
- * APIMethod: equals
- * Determine where this size is equal to another
- *
- * Parameters:
- * sz - {<OpenLayers.Size>}
- *
- * Returns:
- * {Boolean} The passed in size has the same h and w properties as this one.
- * Note that if sz passed in is null, returns false.
- *
- */
- equals:function(sz) {
- var equals = false;
- if (sz != null) {
- equals = ((this.w == sz.w && this.h == sz.h) ||
- (isNaN(this.w) && isNaN(this.h) && isNaN(sz.w) && isNaN(sz.h)));
- }
- return equals;
- },
-
- CLASS_NAME: "OpenLayers.Size"
-});
-/* ======================================================================
- OpenLayers/BaseTypes/Bounds.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * Class: OpenLayers.Bounds
- * Instances of this class represent bounding boxes. Data stored as left,
- * bottom, right, top floats. All values are initialized to null, however,
- * you should make sure you set them before using the bounds for anything.
- *
- * Possible use case:
- * > bounds = new OpenLayers.Bounds();
- * > bounds.extend(new OpenLayers.LonLat(4,5));
- * > bounds.extend(new OpenLayers.LonLat(5,6));
- * > bounds.toBBOX(); // returns 4,5,5,6
- */
-OpenLayers.Bounds = OpenLayers.Class({
-
- /**
- * Property: left
- * {Number}
- */
- left: null,
-
- /**
- * Property: bottom
- * {Number}
- */
- bottom: null,
-
- /**
- * Property: right
- * {Number}
- */
- right: null,
-
- /**
- * Property: top
- * {Number}
- */
- top: null,
-
- /**
- * Constructor: OpenLayers.Bounds
- * Construct a new bounds object.
- *
- * Parameters:
- * 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.
- */
- initialize: function(left, bottom, right, top) {
- if (left != null) {
- this.left = parseFloat(left);
- }
- if (bottom != null) {
- this.bottom = parseFloat(bottom);
- }
- if (right != null) {
- this.right = parseFloat(right);
- }
- if (top != null) {
- this.top = parseFloat(top);
- }
- },
-
- /**
- * Method: clone
- * Create a cloned instance of this bounds.
- *
- * Returns:
- * {<OpenLayers.Bounds>} 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 - {<OpenLayers.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:
- * {String} String representation of bounds object.
- * (ex.<i>"left-bottom=(5,42) right-top=(10,45)"</i>)
- */
- toString:function() {
- return ( "left-bottom=(" + this.left + "," + this.bottom + ")"
- + " right-top=(" + this.right + "," + this.top + ")" );
- },
-
- /**
- * APIMethod: toArray
- *
- * Returns:
- * {Array} array of left, bottom, right, top
- */
- toArray: function() {
- return [this.left, this.bottom, this.right, this.top];
- },
-
- /**
- * APIMethod: toBBOX
- *
- * Parameters:
- * decimal - {Integer} How many significant digits in the bbox coords?
- * Default is 6
- *
- * Returns:
- * {String} Simple String representation of bounds object.
- * (ex. <i>"5,42,10,45"</i>)
- */
- toBBOX:function(decimal) {
- if (decimal== null) {
- decimal = 6;
- }
- var mult = Math.pow(10, decimal);
- var bbox = Math.round(this.left * mult) / mult + "," +
- Math.round(this.bottom * mult) / mult + "," +
- Math.round(this.right * mult) / mult + "," +
- Math.round(this.top * mult) / mult;
-
- return bbox;
- },
-
- /**
- * APIMethod: getWidth
- *
- * Returns:
- * {Float} The width of the bounds
- */
- getWidth:function() {
- return (this.right - this.left);
- },
-
- /**
- * APIMethod: getHeight
- *
- * Returns:
- * {Float} The height of the bounds (top minus bottom).
- */
- getHeight:function() {
- return (this.top - this.bottom);
- },
-
- /**
- * APIMethod: getSize
- *
- * Returns:
- * {<OpenLayers.Size>} The size of the box.
- */
- getSize:function() {
- return new OpenLayers.Size(this.getWidth(), this.getHeight());
- },
-
- /**
- * APIMethod: getCenterPixel
- *
- * Returns:
- * {<OpenLayers.Pixel>} 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:
- * {<OpenLayers.LonLat>} The center of the bounds in map space.
- */
- getCenterLonLat:function() {
- return new OpenLayers.LonLat( (this.left + this.right) / 2,
- (this.bottom + this.top) / 2);
- },
-
- /**
- * APIMethod: add
- *
- * Parameters:
- * x - {Float}
- * y - {Float}
- *
- * Returns:
- * {<OpenLayers.Bounds>} 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) ) {
- var msg = OpenLayers.String.translate("boundsAddError");
- OpenLayers.Console.error(msg);
- return null;
- }
- return new OpenLayers.Bounds(this.left + x, this.bottom + y,
- this.right + x, this.top + y);
- },
-
- /**
- * APIMethod: extend
- * Extend the bounds to include the point, lonlat, or bounds specified.
- * Note, this function assumes that left < right and bottom < top.
- *
- * Parameters:
- * object - {Object} Can be LonLat, Point, or Bounds
- */
- extend:function(object) {
- var bounds = null;
- if (object) {
- 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) {
- 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
- *
- * Parameters:
- * ll - {<OpenLayers.LonLat>}
- * inclusive - {Boolean} Whether or not to include the border.
- * Default is true.
- *
- * Returns:
- * {Boolean} The passed-in lonlat is within this bounds.
- */
- containsLonLat:function(ll, inclusive) {
- return this.contains(ll.lon, ll.lat, inclusive);
- },
-
- /**
- * APIMethod: containsPixel
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- * 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
- *
- * 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;
- }
-
- 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
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * inclusive - {<Boolean>} Whether or not to include the border. Default
- * is true.
- *
- * Returns:
- * {Boolean} The passed-in OpenLayers.Bounds object intersects this bounds.
- * Simple math just check if either contains the other, allowing for
- * partial.
- */
- intersectsBounds:function(bounds, inclusive) {
-
- if (inclusive == null) {
- inclusive = true;
- }
- var inBottom = (bounds.bottom == this.bottom && bounds.top == this.top) ?
- true : (((bounds.bottom > this.bottom) && (bounds.bottom < this.top)) ||
- ((this.bottom > bounds.bottom) && (this.bottom < bounds.top)));
- var inTop = (bounds.bottom == this.bottom && bounds.top == this.top) ?
- true : (((bounds.top > this.bottom) && (bounds.top < this.top)) ||
- ((this.top > bounds.bottom) && (this.top < bounds.top)));
- var inRight = (bounds.right == this.right && bounds.left == this.left) ?
- true : (((bounds.right > this.left) && (bounds.right < this.right)) ||
- ((this.right > bounds.left) && (this.right < bounds.right)));
- var inLeft = (bounds.right == this.right && bounds.left == this.left) ?
- true : (((bounds.left > this.left) && (bounds.left < this.right)) ||
- ((this.left > bounds.left) && (this.left < bounds.right)));
-
- return (this.containsBounds(bounds, true, inclusive) ||
- bounds.containsBounds(this, true, inclusive) ||
- ((inTop || inBottom ) && (inLeft || inRight )));
- },
-
- /**
- * APIMethod: containsBounds
- *
- * bounds - {<OpenLayers.Bounds>}
- * partial - {<Boolean>} If true, only part of passed-in bounds needs be
- * within this bounds. If false, the entire passed-in bounds must be
- * within. Default is false
- * inclusive - {<Boolean>} Whether or not to include the border. Default is
- * true.
- *
- * Returns:
- * {Boolean} The passed-in bounds object is contained within this bounds.
- */
- containsBounds:function(bounds, partial, inclusive) {
-
- //set defaults
- if (partial == null) {
- partial = false;
- }
- if (inclusive == null) {
- inclusive = true;
- }
-
- var inLeft;
- var inTop;
- var inRight;
- var inBottom;
-
- if (inclusive) {
- inLeft = (bounds.left >= this.left) && (bounds.left <= this.right);
- inTop = (bounds.top >= this.bottom) && (bounds.top <= this.top);
- inRight= (bounds.right >= this.left) && (bounds.right <= this.right);
- inBottom = (bounds.bottom >= this.bottom) && (bounds.bottom <= this.top);
- } else {
- inLeft = (bounds.left > this.left) && (bounds.left < this.right);
- inTop = (bounds.top > this.bottom) && (bounds.top < this.top);
- inRight= (bounds.right > this.left) && (bounds.right < this.right);
- inBottom = (bounds.bottom > this.bottom) && (bounds.bottom < this.top);
- }
-
- return (partial) ? (inTop || inBottom ) && (inLeft || inRight )
- : (inTop && inLeft && inBottom && inRight);
- },
-
- /**
- * APIMethod: determineQuadrant
- *
- * Parameters:
- * lonlat - {<OpenLayers.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: wrapDateLine
- *
- * Parameters:
- * maxExtent - {<OpenLayers.Bounds>}
- * options - {Object} Some possible options are:
- * 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:
- * {<OpenLayers.Bounds>} 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 be
- * merely a copy of this one.
- */
- wrapDateLine: function(maxExtent, options) {
- options = options || {};
-
- var leftTolerance = options.leftTolerance || 0;
- var rightTolerance = options.rightTolerance || 0;
-
- var newBounds = this.clone();
-
- if (maxExtent) {
-
- //shift right?
- while ( newBounds.left < maxExtent.left &&
- (newBounds.right - rightTolerance) <= maxExtent.left ) {
- newBounds = newBounds.add(maxExtent.getWidth(), 0);
- }
-
- //shift left?
- while ( (newBounds.left + leftTolerance) >= maxExtent.right &&
- newBounds.right > maxExtent.right ) {
- newBounds = newBounds.add(-maxExtent.getWidth(), 0);
- }
- }
-
- return newBounds;
- },
-
- CLASS_NAME: "OpenLayers.Bounds"
-});
-
-/**
- * APIFunction: fromString
- * Alternative constructor that builds a new OpenLayers.Bounds from a
- * parameter string
- *
- * Parameters:
- * str - {String}Comma-separated bounds string. (ex. <i>"5,42,10,45"</i>)
- *
- * Returns:
- * {<OpenLayers.Bounds>} New bounds object built from the
- * passed-in String.
- */
-OpenLayers.Bounds.fromString = function(str) {
- var bounds = str.split(",");
- return OpenLayers.Bounds.fromArray(bounds);
-};
-
-/**
- * APIFunction: fromArray
- * Alternative constructor that builds a new OpenLayers.Bounds
- * from an array
- *
- * Parameters:
- * bbox - {Array(Float)} Array of bounds values (ex. <i>[5,42,10,45]</i>)
- *
- * Returns:
- * {<OpenLayers.Bounds>} New bounds object built from the passed-in Array.
- */
-OpenLayers.Bounds.fromArray = function(bbox) {
- return new OpenLayers.Bounds(parseFloat(bbox[0]),
- parseFloat(bbox[1]),
- parseFloat(bbox[2]),
- parseFloat(bbox[3]));
-};
-
-/**
- * APIFunction: fromSize
- * Alternative constructor that builds a new OpenLayers.Bounds
- * from a size
- *
- * Parameters:
- * size - {<OpenLayers.Size>}
- *
- * Returns:
- * {<OpenLayers.Bounds>} 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.
- *
- * 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-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * 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; i < arguments.length; i++) {
- var element = OpenLayers.Util.getElement(arguments[i]);
- var display = OpenLayers.Element.visible(element) ? 'hide'
- : 'show';
- OpenLayers.Element[display](element);
- }
- },
-
-
- /**
- * APIFunction: hide
- * Hide element(s) passed in
- *
- * Parameters:
- * element - {DOMElement} Actually user can pass any number of elements
- */
- hide: function() {
- for (var i = 0; i < arguments.length; i++) {
- var element = OpenLayers.Util.getElement(arguments[i]);
- element.style.display = 'none';
- }
- },
-
- /**
- * APIFunction: show
- * Show element(s) passed in
- *
- * Parameters:
- * element - {DOMElement} Actually user can pass any number of elements
- */
- show: function() {
- for (var i = 0; i < arguments.length; i++) {
- var element = OpenLayers.Util.getElement(arguments[i]);
- element.style.display = '';
- }
- },
-
- /**
- * APIFunction: remove
- * Remove the specified element from the DOM.
- *
- * Parameters:
- * element - {DOMElement}
- */
- remove: function(element) {
- element = OpenLayers.Util.getElement(element);
- element.parentNode.removeChild(element);
- },
-
- /**
- * APIFunction: getHeight
- *
- * Parameters:
- * element - {DOMElement}
- *
- * Returns:
- * {Integer} The offset height of the element passed in
- */
- getHeight: function(element) {
- element = OpenLayers.Util.getElement(element);
- return element.offsetHeight;
- },
-
- /**
- * APIFunction: getDimensions
- *
- * Parameters:
- * element - {DOMElement}
- *
- * Returns:
- * {Object} Object with 'width' and 'height' properties which are the
- * dimensions of the element passed in.
- */
- getDimensions: function(element) {
- element = OpenLayers.Util.getElement(element);
- if (OpenLayers.Element.getStyle(element, 'display') != 'none') {
- return {width: element.offsetWidth, height: element.offsetHeight};
- }
-
- // All *Width and *Height properties give 0 on elements with display none,
- // so enable the element temporarily
- var els = element.style;
- var originalVisibility = els.visibility;
- var originalPosition = els.position;
- els.visibility = 'hidden';
- els.position = 'absolute';
- els.display = '';
- var originalWidth = element.clientWidth;
- var originalHeight = element.clientHeight;
- els.display = 'none';
- els.position = originalPosition;
- els.visibility = originalVisibility;
- return {width: originalWidth, height: originalHeight};
- },
-
- /**
- * APIFunction: getStyle
- *
- * Parameters:
- * element - {DOMElement}
- * style - {?}
- *
- * Returns:
- * {?}
- */
- getStyle: function(element, style) {
- element = OpenLayers.Util.getElement(element);
- var value = element.style[OpenLayers.String.camelize(style)];
- if (!value) {
- if (document.defaultView &&
- document.defaultView.getComputedStyle) {
-
- var css = document.defaultView.getComputedStyle(element, null);
- value = css ? css.getPropertyValue(style) : null;
- } else if (element.currentStyle) {
- value = element.currentStyle[OpenLayers.String.camelize(style)];
- }
- }
-
- var positions = ['left', 'top', 'right', 'bottom'];
- if (window.opera &&
- (OpenLayers.Util.indexOf(positions,style) != -1) &&
- (OpenLayers.Element.getStyle(element, 'position') == 'static')) {
- value = 'auto';
- }
-
- return value == 'auto' ? null : value;
- }
-
-};
-/* ======================================================================
- OpenLayers/BaseTypes/LonLat.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * Class: OpenLayers.LonLat
- * This class represents a longitude and latitude pair
- */
-OpenLayers.LonLat = OpenLayers.Class({
-
- /**
- * APIProperty: lon
- * {Float} The x-axis coodinate in map units
- */
- lon: 0.0,
-
- /**
- * APIProperty: lat
- * {Float} The y-axis coordinate in map units
- */
- lat: 0.0,
-
- /**
- * Constructor: OpenLayers.LonLat
- * Create a new map location.
- *
- * Parameters:
- * lon - {Number} The x-axis coordinate in map units. If your map is in
- * a geographic projection, this will be the Longitude. Otherwise,
- * it will be the x coordinate of the map location in your map units.
- * lat - {Number} The y-axis coordinate in map units. If your map is in
- * a geographic projection, this will be the Latitude. Otherwise,
- * it will be the y coordinate of the map location in your map units.
- */
- initialize: function(lon, lat) {
- this.lon = parseFloat(lon);
- this.lat = parseFloat(lat);
- },
-
- /**
- * Method: toString
- * Return a readable string version of the lonlat
- *
- * Returns:
- * {String} String representation of OpenLayers.LonLat object.
- * (ex. <i>"lon=5,lat=42"</i>)
- */
- toString:function() {
- return ("lon=" + this.lon + ",lat=" + this.lat);
- },
-
- /**
- * APIMethod: toShortString
- *
- * Returns:
- * {String} Shortened String representation of OpenLayers.LonLat object.
- * (ex. <i>"5, 42"</i>)
- */
- toShortString:function() {
- return (this.lon + ", " + this.lat);
- },
-
- /**
- * APIMethod: clone
- *
- * Returns:
- * {<OpenLayers.LonLat>} 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:
- * {<OpenLayers.LonLat>} 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) ) {
- var msg = OpenLayers.String.translate("lonlatAddError");
- OpenLayers.Console.error(msg);
- return null;
- }
- return new OpenLayers.LonLat(this.lon + lon, this.lat + lat);
- },
-
- /**
- * APIMethod: equals
- *
- * Parameters:
- * ll - {<OpenLayers.LonLat>}
- *
- * Returns:
- * {Boolean} Boolean value indicating whether the passed-in
- * <OpenLayers.LonLat> 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: wrapDateLine
- *
- * Parameters:
- * maxExtent - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {<OpenLayers.LonLat>} 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 <OpenLayers.LonLat> from a
- * parameter string
- *
- * Parameters:
- * str - {String} Comma-separated Lon,Lat coordinate string.
- * (ex. <i>"5,40"</i>)
- *
- * Returns:
- * {<OpenLayers.LonLat>} New <OpenLayers.LonLat> object built from the
- * passed-in String.
- */
-OpenLayers.LonLat.fromString = function(str) {
- var pair = str.split(",");
- return new OpenLayers.LonLat(parseFloat(pair[0]),
- parseFloat(pair[1]));
-};
-/* ======================================================================
- OpenLayers/BaseTypes/Pixel.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * 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:
- * {<OpenLayers.Pixel>} 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 - {<OpenLayers.Pixel>}
- *
- * 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: add
- *
- * Parameters:
- * x - {Integer}
- * y - {Integer}
- *
- * Returns:
- * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the
- * values passed in.
- */
- add:function(x, y) {
- if ( (x == null) || (y == null) ) {
- var msg = OpenLayers.String.translate("pixelAddError");
- OpenLayers.Console.error(msg);
- return null;
- }
- return new OpenLayers.Pixel(this.x + x, this.y + y);
- },
-
- /**
- * APIMethod: offset
- *
- * Parameters
- * px - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.Pixel>} 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/Ajax.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-
-OpenLayers.ProxyHost = "";
-//OpenLayers.ProxyHost = "examples/proxy.cgi?url=";
-
-/**
- * Ajax reader for OpenLayers
- *
- * @uri url to do remote XML http get
- * @param {String} 'get' format params (x=y&a=b...)
- * @who object to handle callbacks for this request
- * @complete the function to be called on success
- * @failure the function to be called on failure
- *
- * example usage from a caller:
- *
- * caps: function(request) {
- * -blah-
- * },
- *
- * OpenLayers.loadURL(url,params,this,caps);
- *
- * Notice the above example does not provide an error handler; a default empty
- * handler is provided which merely logs the error if a failure handler is not
- * supplied
- *
- */
-
-
-/**
-* @param {} request
-*/
-OpenLayers.nullHandler = function(request) {
- alert(OpenLayers.String.translate("unhandledRequest", request.statusText));
-};
-
-/**
- * Function: loadURL
- * Background load a document.
- *
- * Parameters:
- * uri - {String} URI of source doc
- * params - {String} Params on get (doesnt seem to work)
- * caller - {Object} object which gets callbacks
- * onComplete - {Function} callback for success
- * onFailure - {Function} callback for failure
- *
- * Both callbacks optional (though silly)
- */
-OpenLayers.loadURL = function(uri, params, caller,
- onComplete, onFailure) {
-
- if (OpenLayers.ProxyHost && OpenLayers.String.startsWith(uri, "http")) {
- uri = OpenLayers.ProxyHost + escape(uri);
- }
-
- var success = (onComplete) ? OpenLayers.Function.bind(onComplete, caller)
- : OpenLayers.nullHandler;
-
- var failure = (onFailure) ? OpenLayers.Function.bind(onFailure, caller)
- : OpenLayers.nullHandler;
-
- // from prototype.js
- new OpenLayers.Ajax.Request(uri,
- { method: 'get',
- parameters: params,
- onComplete: success,
- onFailure: failure
- }
- );
-};
-
-/**
- * Function: parseXMLString
- * Parse XML into a doc structure
- *
- * Parameters:
- * text - {String}
- *
- * Returns:
- * {?} Parsed AJAX Responsev
- */
-OpenLayers.parseXMLString = function(text) {
-
- //MS sucks, if the server is bad it dies
- var index = text.indexOf('<');
- if (index > 0) {
- text = text.substring(index);
- }
-
- var ajaxResponse = OpenLayers.Util.Try(
- function() {
- var xmldom = new ActiveXObject('Microsoft.XMLDOM');
- xmldom.loadXML(text);
- return xmldom;
- },
- function() {
- return new DOMParser().parseFromString(text, 'text/xml');
- },
- function() {
- var req = new XMLHttpRequest();
- req.open("GET", "data:" + "text/xml" +
- ";charset=utf-8," + encodeURIComponent(text), false);
- if (req.overrideMimeType) {
- req.overrideMimeType("text/xml");
- }
- req.send(null);
- return req.responseXML;
- }
- );
-
- return ajaxResponse;
-};
-
-
-/**
- * Namespace: OpenLayers.Ajax
- */
-OpenLayers.Ajax = {
-
- /**
- * Method: emptyFunction
- */
- emptyFunction: function () {},
-
- /**
- * Method: getTransport
- *
- * Returns:
- * {Object} Transport mechanism for whichever browser we're in, or false if
- * none available.
- */
- getTransport: function() {
- return OpenLayers.Util.Try(
- function() {return new ActiveXObject('Msxml2.XMLHTTP')},
- function() {return new ActiveXObject('Microsoft.XMLHTTP')},
- function() {return new XMLHttpRequest()}
- ) || false;
- },
-
- /**
- * Property: activeRequestCount
- * {Integer}
- */
- activeRequestCount: 0
-};
-
-/**
- * Namespace: OpenLayers.Ajax.Responders
- * {Object}
- */
-OpenLayers.Ajax.Responders = {
-
- /**
- * Property: responders
- * {Array}
- */
- responders: [],
-
- /**
- * Method: register
- *
- * Parameters:
- * responderToAdd - {?}
- */
- register: function(responderToAdd) {
- for (var i = 0; i < this.responders.length; i++)
- if (responderToAdd == this.responders[i])
- return;
- this.responders.push(responderToAdd);
- },
-
- /**
- * Method: dispatch
- *
- * Parameters:
- * callback - {?}
- * request - {?}
- * transport - {?}
- * json - {?}
- */
- dispatch: function(callback, request, transport, json) {
- var responder;
- for (var i = 0; i < this.responders.length; i++) {
- responder = this.responders[i];
-
- if (responder[callback] &&
- typeof responder[callback] == 'function') {
- try {
- responder[callback].apply(responder,
- [request, transport, json]);
- } catch (e) {}
- }
- }
- }
-};
-
-OpenLayers.Ajax.Responders.register({
- /**
- * Function: onCreate
- */
- onCreate: function() {
- OpenLayers.Ajax.activeRequestCount++;
- },
-
- /**
- * Function: onComplete
- */
- onComplete: function() {
- OpenLayers.Ajax.activeRequestCount--;
- }
-});
-
-/**
- * Namespace: OpenLayers.Ajax.Base
- * {Object}
- */
-OpenLayers.Ajax.Base = function() {};
-OpenLayers.Ajax.Base.prototype = {
-
- /**
- * Function: setOptions
- *
- * Parameters:
- * options - {Object}
- */
- setOptions: function(options) {
- this.options = {
- 'method': 'post',
- 'asynchronous': true,
- 'parameters': ''
- };
- OpenLayers.Util.extend(this.options, options || {});
- },
-
- /**
- * Function: responseIsSuccess
- *
- * Returns:
- * {Boolean}
- */
- responseIsSuccess: function() {
- return this.transport.status == undefined ||
- this.transport.status == 0 ||
- (this.transport.status >= 200 && this.transport.status < 300);
- },
-
- /**
- * Function: responseIsFailure
- *
- * Returns:
- * {Boolean}
- */
- responseIsFailure: function() {
- return !this.responseIsSuccess();
- }
-};
-
-
-/**
- * Class: OpenLayers.Ajax.Request
- *
- * Inherit:
- * - <OpenLayers.Ajax.Base>
- */
-OpenLayers.Ajax.Request = OpenLayers.Class(OpenLayers.Ajax.Base, {
-
- /**
- * Constructor: OpenLayers.Ajax.Request
- *
- * Parameters:
- * url - {String}
- * options - {Object}
- */
- initialize: function(url, options) {
- this.transport = OpenLayers.Ajax.getTransport();
- this.setOptions(options);
- this.request(url);
- },
-
- /**
- * Method: request
- *
- * Parameters:
- * url - {String}
- */
- request: function(url) {
- var parameters = this.options.parameters || '';
- if (parameters.length > 0) parameters += '&_=';
-
- try {
- this.url = url;
- if (this.options.method == 'get' && parameters.length > 0) {
- this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
- }
-
- OpenLayers.Ajax.Responders.dispatch('onCreate',
- this,
- this.transport);
-
- this.transport.open(this.options.method,
- this.url,
- this.options.asynchronous);
-
- if (this.options.asynchronous) {
- this.transport.onreadystatechange =
- OpenLayers.Function.bind(this.onStateChange, this);
-
- setTimeout(OpenLayers.Function.bind(
- (function() {this.respondToReadyState(1)}),this), 10
- );
- }
-
- this.setRequestHeaders();
-
- var body = this.options.postBody ? this.options.postBody
- : parameters;
- this.transport.send(this.options.method == 'post' ? body : null);
-
- // Force Firefox to handle ready state 4 for synchronous requests
- if (!this.options.asynchronous &&
- this.transport.overrideMimeType) {
-
- this.onStateChange();
- }
-
- } catch (e) {
- this.dispatchException(e);
- }
- },
-
- /**
- * Method: setRequestHeaders
- */
- setRequestHeaders: function() {
- var requestHeaders = [
- 'X-Requested-With',
- 'XMLHttpRequest',
- 'X-Prototype-Version',
- 'OpenLayers'
- ];
-
- if (this.options.method == 'post' && !this.options.postBody) {
- requestHeaders.push('Content-type',
- 'application/x-www-form-urlencoded');
-
- // Force "Connection: close" for Mozilla browsers to work around
- // a bug where XMLHttpReqeuest sends an incorrect Content-length
- // header. See Mozilla Bugzilla #246651.
- if (this.transport.overrideMimeType) {
- requestHeaders.push('Connection', 'close');
- }
- }
-
- if (this.options.requestHeaders) {
- requestHeaders.push.apply(requestHeaders,
- this.options.requestHeaders);
- }
-
- for (var i = 0; i < requestHeaders.length; i += 2) {
- this.transport.setRequestHeader(requestHeaders[i],
- requestHeaders[i+1]);
- }
- },
-
- /**
- * Method: onStateChange
- */
- onStateChange: function() {
- var readyState = this.transport.readyState;
- if (readyState != 1) {
- this.respondToReadyState(this.transport.readyState);
- }
- },
-
- /**
- * Method: header
- *
- * Returns:
- * {?}
- */
- header: function(name) {
- try {
- return this.transport.getResponseHeader(name);
- } catch (e) {}
- },
-
- /**
- * Method: evalJSON
- *
- * Returns:
- * {?}
- */
- evalJSON: function() {
- try {
- return eval(this.header('X-JSON'));
- } catch (e) {}
- },
-
- /**
- * Method: evalResponse
- *
- * Returns:
- * {?}
- */
- evalResponse: function() {
- try {
- return eval(this.transport.responseText);
- } catch (e) {
- this.dispatchException(e);
- }
- },
-
- /**
- * Method: respondToReadyState
- *
- * Parameters:
- * readyState - {?}
- */
- respondToReadyState: function(readyState) {
- var event = OpenLayers.Ajax.Request.Events[readyState];
- var transport = this.transport, json = this.evalJSON();
-
- if (event == 'Complete') {
- try {
- var responseSuccess = this.responseIsSuccess() ? 'Success'
- : 'Failure';
-
- (this.options['on' + this.transport.status] ||
- this.options['on' + responseSuccess] ||
- OpenLayers.Ajax.emptyFunction)(transport, json);
- } catch (e) {
- this.dispatchException(e);
- }
-
- var contentType = this.header('Content-type') || '';
- if (contentType.match(/^text\/javascript/i)) {
- this.evalResponse();
- }
- }
-
- try {
- (this.options['on' + event] ||
- OpenLayers.Ajax.emptyFunction)(transport, json);
- OpenLayers.Ajax.Responders.dispatch('on' + event,
- this,
- transport,
- json);
- } catch (e) {
- this.dispatchException(e);
- }
-
- // Avoid memory leak in MSIE: clean up the oncomplete event handler
- if (event == 'Complete') {
- this.transport.onreadystatechange = OpenLayers.Ajax.emptyFunction;
- }
- },
-
- /**
- * Method: dispatchException
- *
- * Parameters:
- * exception - {?}
- */
- dispatchException: function(exception) {
- if (this.options.onException) {
- this.options.onException(this, exception);
- } else {
- // if we get here, Responders.dispatch('onException') will never
- // be called. too bad. we should probably take out the Responders
- // stuff anyway.
- throw exception;
- }
- OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
- }
-
-});
-
-/**
- * Property: Events
- * {Array(String)}
- */
-OpenLayers.Ajax.Request.Events =
- ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
-
-/**
- * Function: getElementsByTagNameNS
- *
- * Parameters:
- * parentnode - {?}
- * nsuri - {?}
- * nsprefix - {?}
- * tagname - {?}
- *
- * Returns:
- * {?}
- */
-OpenLayers.Ajax.getElementsByTagNameNS = function(parentnode, nsuri,
- nsprefix, tagname) {
- var elem = null;
- if (parentnode.getElementsByTagNameNS) {
- elem = parentnode.getElementsByTagNameNS(nsuri, tagname);
- } else {
- elem = parentnode.getElementsByTagName(nsprefix + ':' + tagname);
- }
- return elem;
-};
-
-
-/**
- * Function: serializeXMLToString
- * Wrapper function around XMLSerializer, which doesn't exist/work in
- * IE/Safari. We need to come up with a way to serialize in those browser:
- * for now, these browsers will just fail. #535, #536
- *
- * Parameters:
- * xmldom {XMLNode} xml dom to serialize
- *
- * Returns:
- * {?}
- */
-OpenLayers.Ajax.serializeXMLToString = function(xmldom) {
- var serializer = new XMLSerializer();
- data = serializer.serializeToString(xmldom);
- return data;
-}
-/* ======================================================================
- OpenLayers/Control.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * Class: OpenLayers.Control
- * Controls affect the display or behavior of the map. They allow everything
- * from panning and zooming to displaying a scale indicator. Controls by
- * default are added to the map they are contained within however it is
- * possible to add a control to an external div by passing the div in the
- * options parameter.
- *
- * Example:
- * The following example shows how to add many of the common controls
- * to a map.
- *
- * > var map = new OpenLayers.Map('map', { controls: [] });
- * >
- * > map.addControl(new OpenLayers.Control.PanZoomBar());
- * > map.addControl(new OpenLayers.Control.MouseToolbar());
- * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
- * > map.addControl(new OpenLayers.Control.Permalink());
- * > map.addControl(new OpenLayers.Control.Permalink('permalink'));
- * > map.addControl(new OpenLayers.Control.MousePosition());
- * > map.addControl(new OpenLayers.Control.OverviewMap());
- * > map.addControl(new OpenLayers.Control.KeyboardDefaults());
- *
- * The next code fragment is a quick example of how to intercept
- * shift-mouse click to display the extent of the bounding box
- * dragged out by the user. Usually controls are not created
- * in exactly this manner. See the source for a more complete
- * example:
- *
- * > var control = new OpenLayers.Control();
- * > OpenLayers.Util.extend(control, {
- * > draw: function () {
- * > // this Handler.Box will intercept the shift-mousedown
- * > // before Control.MouseDefault gets to see it
- * > this.box = new OpenLayers.Handler.Box( control,
- * > {"done": this.notice},
- * > {keyMask: OpenLayers.Handler.MOD_SHIFT});
- * > this.box.activate();
- * > },
- * >
- * > notice: function (bounds) {
- * > alert(bounds);
- * > }
- * > });
- * > map.addControl(control);
- *
- */
-OpenLayers.Control = OpenLayers.Class({
-
- /**
- * Property: id
- * {String}
- */
- id: null,
-
- /**
- * Property: map
- * {<OpenLayers.Map>} this gets set in the addControl() function in
- * OpenLayers.Map
- */
- map: null,
-
- /**
- * Property: div
- * {DOMElement}
- */
- div: null,
-
- /**
- * Property: type
- * {OpenLayers.Control.TYPES} Controls can have a 'type'. The type
- * determines the type of interactions which are possible with them when
- * they are placed into a toolbar.
- */
- type: null,
-
- /**
- * Property: displayClass
- * {string} This property is used for CSS related to the drawing of the
- * Control.
- */
- displayClass: "",
-
- /**
- * Property: active
- * {boolean} null
- */
- active: null,
-
- /**
- * Property: handler
- * {<OpenLayers.Handler>} null
- */
- handler: 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.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 () {
- // eliminate circular references
- if (this.handler) {
- this.handler.destroy();
- }
- this.map = null;
- },
-
- /**
- * Method: setMap
- * Set the map property for the control. This is done through an accessor
- * so that subclasses can override this and take special action once
- * they have their map variable set.
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- setMap: function(map) {
- this.map = map;
- if (this.handler) {
- this.handler.setMap(map);
- }
- },
-
- /**
- * Method: draw
- * The draw method is called when the control is ready to be displayed
- * on the page. If a div has not been created one is created. Controls
- * with a visual component will almost always want to override this method
- * to customize the look of control.
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>} The top-left pixel position of the control
- * or null.
- *
- * Returns:
- * {DOMElement} A reference to the DIV DOMElement containing the control
- */
- draw: function (px) {
- if (this.div == null) {
- this.div = OpenLayers.Util.createDiv();
- this.div.id = this.id;
- this.div.className = this.displayClass;
- }
- if (px != null) {
- this.position = px.clone();
- }
- this.moveTo(this.position);
- return this.div;
- },
-
- /**
- * Method: moveTo
- * Sets the left and top style attributes to the passed in pixel
- * coordinates.
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- */
- moveTo: function (px) {
- if ((px != null) && (this.div != null)) {
- this.div.style.left = px.x + "px";
- this.div.style.top = px.y + "px";
- }
- },
-
- /**
- * Method: activate
- * Explicitly activates a control and it's associated
- * handler if one has been set. Controls can be
- * deactivated by calling the deactivate() method.
- *
- * Returns:
- * {Boolean} True if the control was successfully activated or
- * false if the control was already active.
- */
- activate: function () {
- if (this.active) {
- return false;
- }
- if (this.handler) {
- this.handler.activate();
- }
- this.active = true;
- return true;
- },
-
- /**
- * Method: deactivate
- * Deactivates a control and it's associated handler if any. The exact
- * effect of this depends on the control itself.
- *
- * Returns:
- * {Boolean} True if the control was effectively deactivated or false
- * if the control was already inactive.
- */
- deactivate: function () {
- if (this.active) {
- if (this.handler) {
- this.handler.deactivate();
- }
- this.active = false;
- return true;
- }
- return false;
- },
-
- CLASS_NAME: "OpenLayers.Control"
-});
-
-OpenLayers.Control.TYPE_BUTTON = 1;
-OpenLayers.Control.TYPE_TOGGLE = 2;
-OpenLayers.Control.TYPE_TOOL = 3;
-/* ======================================================================
- OpenLayers/Icon.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-
-/**
- * Class: OpenLayers.Icon
- *
- * The icon represents a graphical icon on the screen. Typically used in
- * conjunction with a <OpenLayers.Marker> to represent markers on a screen.
- *
- * An icon has a url, size and position. It also contains an offset which
- * allows the center point to be represented correctly. This can be
- * provided either as a fixed offset or a function provided to calculate
- * the desired offset.
- *
- */
-OpenLayers.Icon = OpenLayers.Class({
-
- /**
- * Property: url
- * {String} image url
- */
- url: null,
-
- /**
- * Property: size
- * {<OpenLayers.Size>}
- */
- size: null,
-
- /**
- * Property: offset
- * {<OpenLayers.Pixel>} distance in pixels to offset the image when being rendered
- */
- offset: null,
-
- /**
- * Property: calculateOffset
- * {<OpenLayers.Pixel>} Function to calculate the offset (based on the size)
- */
- calculateOffset: null,
-
- /**
- * Property: imageDiv
- * {DOMElement}
- */
- imageDiv: null,
-
- /**
- * Property: px
- * {<OpenLayers.Pixel>}
- */
- px: null,
-
- /**
- * Constructor: OpenLayers.Icon
- * Creates an icon, which is an image tag in a div.
- *
- * url - {String}
- * size - {<OpenLayers.Size>}
- * calculateOffset - {Function}
- */
- initialize: function(url, size, offset, calculateOffset) {
- this.url = url;
- this.size = (size) ? size : new OpenLayers.Size(20,20);
- this.offset = offset ? offset : new OpenLayers.Pixel(-(this.size.w/2), -(this.size.h/2));
- this.calculateOffset = calculateOffset;
-
- var id = OpenLayers.Util.createUniqueID("OL_Icon_");
- this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);
- },
-
- /**
- * Method: destroy
- * Nullify references and remove event listeners to prevent circular
- * references and memory leaks
- */
- destroy: function() {
- OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);
- this.imageDiv.innerHTML = "";
- this.imageDiv = null;
- },
-
- /**
- * Method: clone
- *
- * Returns:
- * {<OpenLayers.Icon>} A fresh copy of the icon.
- */
- clone: function() {
- return new OpenLayers.Icon(this.url,
- this.size,
- this.offset,
- this.calculateOffset);
- },
-
- /**
- * Method: setSize
- *
- * size - {<OpenLayers.Size>}
- */
- setSize: function(size) {
- if (size != null) {
- this.size = size;
- }
- this.draw();
- },
-
- /**
- * Method: draw
- * Move the div to the given pixel.
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {DOMElement} A new DOM Image of this icon set at the location passed-in
- */
- draw: function(px) {
- OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,
- null,
- null,
- this.size,
- this.url,
- "absolute");
- this.moveTo(px);
- return this.imageDiv;
- },
-
-
- /**
- * Method: setOpacity
- * Change the icon's opacity
- *
- * Parameters:
- * opacity - {float}
- */
- setOpacity: function(opacity) {
- OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null,
- null, null, null, null, opacity);
-
- },
-
- /**
- * Method: moveTo
- * move icon to passed in px.
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- */
- moveTo: function (px) {
- //if no px passed in, use stored location
- if (px != null) {
- this.px = px;
- }
-
- if (this.imageDiv != null) {
- if (this.px == null) {
- this.display(false);
- } else {
- if (this.calculateOffset) {
- this.offset = this.calculateOffset(this.size);
- }
- var offsetPx = this.px.offset(this.offset);
- OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, offsetPx);
- }
- }
- },
-
- /**
- * Method: display
- * Hide or show the icon
- *
- * Parameters:
- * display - {Boolean}
- */
- display: function(display) {
- this.imageDiv.style.display = (display) ? "" : "none";
- },
-
- CLASS_NAME: "OpenLayers.Icon"
-});
-/* ======================================================================
- OpenLayers/Strings/en.js
- ====================================================================== */
-
-OpenLayers.Strings.en = {
-'test1': 'this is a test',
-'test2': 'and another test',
-'test3': 'arg one:{0} arg two: {1}',
-'unhandledRequest': "Unhandled request return {0}",
-'permalink': "Permalink",
-'overlays': "Overlays",
-'baseLayer': "Base Layer",
-'sameProjection': "The overview map only works when it is in the same projection as the main map",
-'readNotImplemented': "Read not implemented.",
-'writeNotImplemented': "Write not implemented.",
-'noFID': "Can't update a feature for which there is no FID.",
-'errorLoadingGML': "Error in loading GML file {0}",
-'browserNotSupported': "Your browser does not support vector rendering. Currently supported renderers are:\n{0}",
-'componentShouldBe': "addFeatures : component should be an {0}",
-'getFeatureError': "getFeatureFromEvent called on layer with no renderer. " +
- "This usually means you destroyed a layer, but not some handler which is associated with it.",
-'minZoomLevelError': "The minZoomLevel property is only intended for use " +
- "with the FixedZoomLevels-descendent layers. That this " +
- "wfs layer checks for minZoomLevel is a relic of the" +
- "past. We cannot, however, remove it without possibly " +
- "breaking OL based applications that may depend on it." +
- " Therefore we are deprecating it -- the minZoomLevel " +
- "check below will be removed at 3.0. Please instead " +
- "use min/max resolution setting as described here: " +
- "http://trac.openlayers.org/wiki/SettingZoomLevels",
-'commitSuccess': "WFS Transaction: SUCCESS {0}",
-'commitFailed': "WFS Transaction: FAILED {0}",
-'googleWarning': "The Google Layer was unable to load correctly.<br><br>" +
- "To get rid of this message, select a new BaseLayer " +
- "in the layer switcher in the upper-right corner.<br><br>" +
- "Most likely, this is because the Google Maps library " +
- "script was either not included, or does not contain the " +
- "correct API key for your site.<br><br>" +
- "Developers: For help getting this working correctly, " +
- "<a href='http://trac.openlayers.org/wiki/Google' " +
- "target='_blank'>click here</a>",
-'getLayerWarning': "The {0} Layer was unable to load correctly.<br><br>" +
- "To get rid of this message, select a new BaseLayer " +
- "in the layer switcher in the upper-right corner.<br><br>" +
- "Most likely, this is because the {0} library " +
- "script was either not correctly included.<br><br>" +
- "Developers: For help getting this working correctly, " +
- "<a href='http://trac.openlayers.org/wiki/{1}' " +
- "target='_blank'>click here</a>",
-'scale': "Scale = 1 : {0}",
-'layerAlreadyAdded': "You tried to add the layer: {0} to the map, but it has already been added",
-'reprojectDeprecated': "You are using the 'reproject' option " +
- "on the {0} layer. This option is deprecated: " +
- "its use was designed to support displaying data over commercial " +
- "basemaps, but that functionality should now be achieved by using " +
- "Spherical Mercator support. More information is available from " +
- "http://trac.openlayers.org/wiki/SphericalMercator.",
-'methodDeprecated': "This method has been deprecated and will be removed in 3.0. " +
- "Please use {0} instead.",
-'boundsAddError': "You must pass both x and y values to the add function.",
-'lonlatAddError': "You must pass both lon and lat values to the add function.",
-'pixelAddError': "You must pass both x and y values to the add function.",
-'unsupportedGeometryType': "Unsupported geometry type: {0}",
-'clearArrayDeprecated': "OpenLayers.Util.clearArray() is Deprecated." +
- " Please use 'array.length = 0' instead.",
-'getArgsDeprecated': "The getArgs() function is deprecated and will be removed " +
- "with the 3.0 version of OpenLayers. Please instead use " +
- "OpenLayers.Util.getParameters().",
-'pagePositionFailed': "OpenLayers.Util.pagePosition failed: element with id {0} may be misplaced.",
-
-'end': ''
-};
-/* ======================================================================
- OpenLayers/Control/ArgParser.js
- ====================================================================== */
-
-/* Cpyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Control.js
- *
- * Class: OpenLayers.Control.ArgParser
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * Parameter: center
- * {<OpenLayers.LonLat>}
- */
- center: null,
-
- /**
- * Parameter: zoom
- * {int}
- */
- zoom: null,
-
- /**
- * Parameter: layers
- * {Array(<OpenLayers.Layer>)}
- */
- layers: null,
-
- /**
- * Constructor: OpenLayers.Control.ArgParser
- *
- * Parameters:
- * options - {Object}
- */
- initialize: function(options) {
- OpenLayers.Control.prototype.initialize.apply(this, arguments);
- },
-
- /**
- * Method: setMap
- * Set the map property for the control.
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- setMap: function(map) {
- OpenLayers.Control.prototype.setMap.apply(this, arguments);
-
- //make sure we dont already have an arg parser attached
- for(var i=0; i< this.map.controls.length; i++) {
- var control = this.map.controls[i];
- if ( (control != this) &&
- (control.CLASS_NAME == "OpenLayers.Control.ArgParser") ) {
- break;
- }
- }
- if (i == this.map.controls.length) {
-
- var args = OpenLayers.Util.getParameters();
- if (args.lat && args.lon) {
- this.center = new OpenLayers.LonLat(parseFloat(args.lon),
- parseFloat(args.lat));
- if (args.zoom) {
- this.zoom = parseInt(args.zoom);
- }
-
- // when we add a new baselayer to see when we can set the center
- this.map.events.register('changebaselayer', this,
- this.setCenter);
- this.setCenter();
- }
-
- if (args.layers) {
- this.layers = args.layers;
-
- // when we add a new layer, set its visibility
- this.map.events.register('addlayer', this,
- this.configureLayers);
- this.configureLayers();
- }
- }
- },
-
- /**
- * Method: setCenter
- * As soon as a baseLayer has been loaded, we center and zoom
- * ...and remove the handler.
- */
- setCenter: function() {
-
- if (this.map.baseLayer) {
- //dont need to listen for this one anymore
- this.map.events.unregister('changebaselayer', this,
- this.setCenter);
-
- this.map.setCenter(this.center, this.zoom);
- }
- },
-
- /**
- * Method: configureLayers
- * As soon as all the layers are loaded, cycle through them and
- * hide or show them.
- */
- configureLayers: function() {
-
- if (this.layers.length == this.map.layers.length) {
- this.map.events.unregister('addlayer', this, this.configureLayers);
-
- for(var i=0; i < this.layers.length; i++) {
-
- var layer = this.map.layers[i];
- var c = this.layers.charAt(i);
-
- if (c == "B") {
- this.map.setBaseLayer(layer);
- } else if ( (c == "T") || (c == "F") ) {
- layer.setVisibility(c == "T");
- }
- }
- }
- },
-
- CLASS_NAME: "OpenLayers.Control.ArgParser"
-});
-/* ======================================================================
- OpenLayers/Control/PanZoom.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Control.js
- *
- * Class: OpenLayers.PanZoom
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * APIProperty: slideFactor
- * {Integer}
- */
- slideFactor: 50,
-
- /**
- * Property: buttons
- * {Array(DOMElement)} Array of Button Divs
- */
- buttons: null,
-
- /**
- * Property: position
- * {<OpenLayers.Pixel>}
- */
- position: null,
-
- /**
- * Constructor: OpenLayers.Control.PanZoom
- *
- * Parameters:
- * options - {Object}
- */
- initialize: function(options) {
- this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,
- OpenLayers.Control.PanZoom.Y);
- OpenLayers.Control.prototype.initialize.apply(this, arguments);
- },
-
- /**
- * APIMethod: destroy
- */
- destroy: function() {
- OpenLayers.Control.prototype.destroy.apply(this, arguments);
- while(this.buttons.length) {
- var btn = this.buttons.shift();
- btn.map = null;
- OpenLayers.Event.stopObservingElement(btn);
- }
- this.buttons = null;
- this.position = null;
- },
-
- /**
- * Method: draw
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {DOMElement} A reference to the container div for the PanZoom control.
- */
- draw: function(px) {
- // initialize our internal div
- OpenLayers.Control.prototype.draw.apply(this, arguments);
- px = this.position;
-
- // place the controls
- this.buttons = [];
-
- var sz = new OpenLayers.Size(18,18);
- var centered = new OpenLayers.Pixel(px.x+sz.w/2, px.y);
-
- this._addButton("panup", "north-mini.png", centered, sz);
- px.y = centered.y+sz.h;
- this._addButton("panleft", "west-mini.png", px, sz);
- this._addButton("panright", "east-mini.png", px.add(sz.w, 0), sz);
- this._addButton("pandown", "south-mini.png",
- centered.add(0, sz.h*2), sz);
- this._addButton("zoomin", "zoom-plus-mini.png",
- centered.add(0, sz.h*3+5), sz);
- this._addButton("zoomworld", "zoom-world-mini.png",
- centered.add(0, sz.h*4+5), sz);
- this._addButton("zoomout", "zoom-minus-mini.png",
- centered.add(0, sz.h*5+5), sz);
- return this.div;
- },
-
- /**
- * Method: _addButton
- *
- * Parameters:
- * id - {String}
- * img - {String}
- * xy - {<OpenLayers.Pixel>}
- * sz - {<OpenLayers.Size>}
- *
- * Returns:
- * {DOMElement} A Div (an alphaImageDiv, to be precise) that contains the
- * image of the button, and has all the proper event handlers set.
- */
- _addButton:function(id, img, xy, sz) {
- var imgLocation = OpenLayers.Util.getImagesLocation() + img;
- var btn = OpenLayers.Util.createAlphaImageDiv(
- "OpenLayers_Control_PanZoom_" + id,
- xy, sz, imgLocation, "absolute");
-
- //we want to add the outer div
- this.div.appendChild(btn);
-
- OpenLayers.Event.observe(btn, "mousedown",
- OpenLayers.Function.bindAsEventListener(this.buttonDown, btn));
- OpenLayers.Event.observe(btn, "dblclick",
- OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
- OpenLayers.Event.observe(btn, "click",
- OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
- btn.action = id;
- btn.map = this.map;
- btn.slideFactor = this.slideFactor;
-
- //we want to remember/reference the outer div
- this.buttons.push(btn);
- return btn;
- },
-
- /**
- * Method: doubleClick
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean}
- */
- doubleClick: function (evt) {
- OpenLayers.Event.stop(evt);
- return false;
- },
-
- /**
- * Method: buttonDown
- *
- * Parameters:
- * evt - {Event}
- */
- buttonDown: function (evt) {
- if (!OpenLayers.Event.isLeftClick(evt)) return;
-
- switch (this.action) {
- case "panup":
- this.map.pan(0, -50);
- break;
- case "pandown":
- this.map.pan(0, 50);
- break;
- case "panleft":
- this.map.pan(-50, 0);
- break;
- case "panright":
- this.map.pan(50, 0);
- break;
- case "zoomin":
- this.map.zoomIn();
- break;
- case "zoomout":
- this.map.zoomOut();
- break;
- case "zoomworld":
- this.map.zoomToMaxExtent();
- break;
- }
-
- OpenLayers.Event.stop(evt);
- },
-
- CLASS_NAME: "OpenLayers.Control.PanZoom"
-});
-
-/**
- * Constant: X
- * {Integer}
- */
-OpenLayers.Control.PanZoom.X = 4;
-
-/**
- * Constant: Y
- * {Integer}
- */
-OpenLayers.Control.PanZoom.Y = 4;
-/* ======================================================================
- OpenLayers/Events.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * 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_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: 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: 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 false
- */
- stop: function(event, allowDefault) {
-
- if (!allowDefault) {
- if (event.preventDefault) {
- event.preventDefault();
- } else {
- event.returnValue = false;
- }
- }
-
- if (event.stopPropagation) {
- event.stopPropagation();
- } else {
- event.cancelBubble = true;
- }
- },
-
- /**
- * 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];
- var args = new Array(entry.element,
- entry.name,
- entry.observer,
- entry.useCapture);
- var removed = OpenLayers.Event.stopObserving.apply(this, args);
- }
- }
- },
-
- /**
- * 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 (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() {
- if (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);
-
-// FIXME: Remove this in 3.0. In 3.0, Event.stop will no longer be provided
-// by OpenLayers.
-if (window.Event) {
- OpenLayers.Util.applyDefaults(window.Event, OpenLayers.Event);
-} else {
- var Event = OpenLayers.Event;
-}
-
-/**
- * Class: OpenLayers.Events
- */
-OpenLayers.Events = OpenLayers.Class({
-
- /**
- * Constant: BROWSER_EVENTS
- * {Array(String)} supported events
- */
- BROWSER_EVENTS: [
- "mouseover", "mouseout",
- "mousedown", "mouseup", "mousemove",
- "click", "dblclick",
- "resize", "focus", "blur"
- ],
-
- /**
- * 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: eventTypes
- * {Array(String)} list of support application events
- */
- eventTypes: null,
-
- /**
- * Property: eventHandler
- * {Function} bound event handler attached to elements
- */
- eventHandler: null,
-
- /**
- * APIProperty: fallThrough
- * {Boolean}
- */
- fallThrough: 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)} Array of custom application events
- * fallThrough - {Boolean} Allow events to fall through after these have
- * been handled?
- */
- initialize: function (object, element, eventTypes, fallThrough) {
- this.object = object;
- this.element = element;
- this.eventTypes = eventTypes;
- this.fallThrough = fallThrough;
- this.listeners = {};
-
- // 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
- );
-
- // if eventTypes is specified, create a listeners list for each
- // custom application event.
- if (this.eventTypes != null) {
- for (var i = 0; i < this.eventTypes.length; i++) {
- this.addEventType(this.eventTypes[i]);
- }
- }
-
- // if a dom element is specified, add a listeners list
- // for browser events on the element and register them
- if (this.element != null) {
- this.attachToElement(element);
- }
- },
-
- /**
- * APIMethod: destroy
- */
- destroy: function () {
- if (this.element) {
- OpenLayers.Event.stopObservingElement(this.element);
- }
- this.element = null;
-
- this.listeners = null;
- this.object = null;
- this.eventTypes = null;
- this.fallThrough = null;
- this.eventHandler = null;
- },
-
- /**
- * APIMethod: addEventType
- * Add a new event type to this events object.
- * If the event type has already been added, do nothing.
- *
- * Parameters:
- * eventName - {String}
- */
- addEventType: function(eventName) {
- if (!this.listeners[eventName]) {
- this.listeners[eventName] = [];
- }
- },
-
- /**
- * Method: attachToElement
- *
- * Parameters:
- * element - {HTMLDOMElement} a DOM element to attach browser events to
- */
- attachToElement: function (element) {
- for (var i = 0; i < this.BROWSER_EVENTS.length; i++) {
- var eventType = this.BROWSER_EVENTS[i];
-
- // every browser event has a corresponding application event
- // (whether it's listened for or not).
- this.addEventType(eventType);
-
- // use Prototype to register the event cross-browser
- OpenLayers.Event.observe(element, eventType, this.eventHandler);
- }
- // disable dragstart in IE so that mousedown/move/up works normally
- OpenLayers.Event.observe(element, "dragstart", OpenLayers.Event.stop);
- },
-
- /**
- * 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.
- *
- *
- */
- register: function (type, obj, func) {
-
- if (func != null) {
- if (obj == null) {
- obj = this.object;
- }
- var listeners = this.listeners[type];
- if (listeners != null) {
- listeners.push( {obj: obj, func: func} );
- }
- }
- },
-
- /**
- * 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) {
-
- if (func != null) {
- if (obj == null) {
- obj = this.object;
- }
- var listeners = this.listeners[type];
- if (listeners != null) {
- listeners.unshift( {obj: obj, func: func} );
- }
- }
- },
-
- /**
- * 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; i < listeners.length; i++) {
- if (listeners[i].obj == obj && listeners[i].func == func) {
- listeners.splice(i, 1);
- break;
- }
- }
- }
- },
-
- /**
- * Method: remove
- * Remove all listeners for a given event type. If type is not registered,
- * does nothing.
- *
- * Parameters:
- * type - {String}
- */
- remove: function(type) {
- if (this.listeners[type] != null) {
- this.listeners[type] = [];
- }
- },
-
- /**
- * APIMethod: triggerEvent
- * Trigger a specified registered event
- *
- * Parameters:
- * type - {String}
- * evt - {Event}
- */
- triggerEvent: function (type, evt) {
-
- // prep evt object with object & div references
- if (evt == null) {
- evt = {};
- }
- evt.object = this.object;
- evt.element = this.element;
-
- // execute all callbacks registered for specified type
- // get a clone of the listeners array to
- // allow for splicing during callbacks
- var listeners = (this.listeners[type]) ?
- this.listeners[type].slice() : null;
- if ((listeners != null) && (listeners.length > 0)) {
- for (var i = 0; i < listeners.length; i++) {
- var callback = listeners[i];
- var continueChain;
- if (callback.obj != null) {
- // use the 'call' method to bind the context to callback.obj
- continueChain = callback.func.call(callback.obj, evt);
- } else {
- continueChain = callback.func(evt);
- }
-
- if ((continueChain != null) && (continueChain == false)) {
- // if callback returns false, execute no more callbacks.
- break;
- }
- }
- // don't fall through to other DOM elements
- if (!this.fallThrough) {
- OpenLayers.Event.stop(evt, true);
- }
- }
- },
-
- /**
- * Method: handleBrowserEvent
- * Basically just a wrapper to the triggerEvent() function, but takes
- * care to set a property 'xy' on the event with the current mouse
- * position.
- *
- * Parameters:
- * evt - {Event}
- */
- handleBrowserEvent: function (evt) {
- evt.xy = this.getMousePosition(evt);
- this.triggerEvent(evt.type, evt)
- },
-
- /**
- * Method: getMousePosition
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns
- * {<OpenLayers.Pixel>} The current xy coordinate of the mouse, adjusted
- * for offsets
- */
- getMousePosition: function (evt) {
- if (!this.element.offsets) {
- this.element.offsets = OpenLayers.Util.pagePosition(this.element);
- this.element.offsets[0] += (document.documentElement.scrollLeft
- || document.body.scrollLeft);
- this.element.offsets[1] += (document.documentElement.scrollTop
- || document.body.scrollTop);
- }
- return new OpenLayers.Pixel(
- (evt.clientX + (document.documentElement.scrollLeft
- || document.body.scrollLeft)) - this.element.offsets[0]
- - (document.documentElement.clientLeft || 0),
- (evt.clientY + (document.documentElement.scrollTop
- || document.body.scrollTop)) - this.element.offsets[1]
- - (document.documentElement.clientTop || 0)
- );
- },
-
- CLASS_NAME: "OpenLayers.Events"
-});
-/* ======================================================================
- OpenLayers/Projection.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Util.js
- *
- * Class: OpenLayers.Projection
- * Class for coordinate transformations between coordinate systems.
- * Depends on the proj4js library. If proj4js is not available,
- * then this is just an empty stub.
- */
-OpenLayers.Projection = OpenLayers.Class({
-
- /**
- * Constructor: OpenLayers.Projection
- * This class offers several methods for interacting with a wrapped
- * pro4js projection object.
- *
- * Parameters:
- * options - {Object} An optional object with properties to set on the
- * format
- *
- * Returns:
- * An instance of OpenLayers.Projection
- */
- initialize: function(projCode, options) {
- OpenLayers.Util.extend(this, options);
- this.projCode = projCode;
- if (window.Proj4js) {
- this.proj = new Proj4js.Proj(projCode);
- }
-
- },
-
- /**
- * APIMethod: getCode
- * Get the string 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..
- */
- getUnits: function() {
- return this.proj ? this.proj.units : null;
- },
-
- CLASS_NAME: "OpenLayers.Projection"
-
-});
-
-/**
- * APIMethod: transform
- * Read data from a string, and return an object whose type depends on the
- * subclass.
- *
- * Parameters:
- * point - {object} input horizontal coodinate
- * sourceProj - {OpenLayers.Projection} source map coordinate system
- * destProj - {OpenLayers.Projection} destination map coordinate system
- *
- * Returns:
- * point - {object} trasnformed coordinate
- */
-OpenLayers.Projection.transform = function(point, source, dest) {
- if (source.proj && dest.proj) {
- point = Proj4js.transform(source.proj, dest.proj, point);
- }
- return point;
-};
-/* ======================================================================
- OpenLayers/Tile.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-
-/*
- * @requires OpenLayers/Util.js
- *
- * Class: OpenLayers.Tile
- * This is a class designed to designate a single tile, however
- * it is explicitly designed to do relatively little. Tiles store
- * information about themselves -- such as the URL that they are related
- * to, and their size - but do not add themselves to the layer div
- * automatically, for example. Create a new tile with the
- * <OpenLayers.Tile> constructor, or a subclass.
- *
- * TBD 3.0 - remove reference to url in above paragraph
- *
- */
-OpenLayers.Tile = OpenLayers.Class({
-
- /**
- * Constant: EVENT_TYPES
- * {Array(String)} Supported application event types
- */
- EVENT_TYPES: [ "loadstart", "loadend", "reload"],
-
- /**
- * APIProperty: events
- * {<OpenLayers.Events>} An events object that handles all
- * events on the tile.
- */
- events: null,
-
- /**
- * Property: id
- * {String} null
- */
- id: null,
-
- /**
- * Property: layer
- * {<OpenLayers.Layer>} layer the tile is attached to
- */
- layer: null,
-
- /**
- * Property: url
- * {String} url of the request.
- *
- * TBD 3.0
- * Deprecated. The base tile class does not need an url. This should be
- * handled in subclasses. Does not belong here.
- */
- url: null,
-
- /**
- * APIProperty: bounds
- * {<OpenLayers.Bounds>} null
- */
- bounds: null,
-
- /**
- * Property: size
- * {<OpenLayers.Size>} null
- */
- size: null,
-
- /**
- * Property: position
- * {<OpenLayers.Pixel>} Top Left pixel of the tile
- */
- position: null,
-
- /**
- * Property: isLoading
- * {Boolean} Is the tile loading?
- */
- isLoading: false,
-
- /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor.
- * there is no need for the base tile class to have a url.
- *
- * Constructor: OpenLayers.Tile
- * Constructor for a new <OpenLayers.Tile> instance.
- *
- * Parameters:
- * layer - {<OpenLayers.Layer>} layer that the tile will go in.
- * position - {<OpenLayers.Pixel>}
- * bounds - {<OpenLayers.Bounds>}
- * url - {<String>}
- * size - {<OpenLayers.Size>}
- */
- initialize: function(layer, position, bounds, url, size) {
- this.layer = layer;
- this.position = position.clone();
- this.bounds = bounds.clone();
- this.url = url;
- this.size = size.clone();
-
- //give the tile a unique id based on its BBOX.
- this.id = OpenLayers.Util.createUniqueID("Tile_");
-
- this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
- },
-
- /**
- * APIMethod: destroy
- * Nullify references to prevent circular references and memory leaks.
- */
- destroy:function() {
- this.layer = null;
- this.bounds = null;
- this.size = null;
- this.position = null;
-
- this.events.destroy();
- this.events = null;
- },
-
- /**
- * Method: draw
- * Clear whatever is currently in the tile, then return whether or not
- * it should actually be re-drawn.
- *
- * Returns:
- * {Boolean} Whether or not the tile should actually be drawn. Note that
- * this is not really the best way of doing things, but such is
- * the way the code has been developed. Subclasses call this and
- * depend on the return to know if they should draw or not.
- */
- draw: function() {
-
- //clear tile's contents and mark as not drawn
- this.clear();
-
- var maxExtent = this.layer.maxExtent;
- var withinMaxExtent = true;
- if (this.layer.restrictedExtent) {
- withinMaxExtent = (maxExtent &&
- this.bounds.intersectsBounds(maxExtent, false));
- }
-
- // The only case where we *wouldn't* want to draw the tile is if the
- // tile is outside its layer's maxExtent.
- return (withinMaxExtent || this.layer.displayOutsideMaxExtent);
- },
-
- /**
- * Method: moveTo
- * Reposition the tile.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * position - {<OpenLayers.Pixel>}
- * redraw - {Boolean} Call draw method on tile after moving.
- * Default is true
- */
- moveTo: function (bounds, position, redraw) {
- if (redraw == null) {
- redraw = true;
- }
-
- this.bounds = bounds.clone();
- this.position = position.clone();
- if (redraw) {
- this.draw();
- }
- },
-
- /**
- * Method: clear
- * Clear the tile of any bounds/position-related data so that it can
- * be reused in a new location. To be implemented by subclasses.
- */
- clear: function() {
- // to be implemented by subclasses
- },
-
- /**
- * Method: getBoundsFromBaseLayer
- * Take the pixel locations of the corner of the tile, and pass them to
- * the base layer and ask for the location of those pixels, so that
- * displaying tiles over Google works fine.
- *
- * Parameters:
- * position - {<OpenLayers.Pixel>}
- *
- * Returns:
- * bounds - {<OpenLayers.Bounds>}
- */
- getBoundsFromBaseLayer: function(position) {
- OpenLayers.Console.warn(OpenLayers.String.translate("layerAlreadyAdded",
- this.layer.name));
- var topLeft = this.layer.map.getLonLatFromLayerPx(position);
- var bottomRightPx = position.clone();
- bottomRightPx.x += this.size.w;
- bottomRightPx.y += this.size.h;
- var bottomRight = this.layer.map.getLonLatFromLayerPx(bottomRightPx);
- // Handle the case where the base layer wraps around the date line.
- // Google does this, and it breaks WMS servers to request bounds in
- // that fashion.
- if (topLeft.lon > bottomRight.lon) {
- if (topLeft.lon < 0) {
- topLeft.lon = -180 - (topLeft.lon+180);
- } else {
- bottomRight.lon = 180+bottomRight.lon+180;
- }
- }
- bounds = new OpenLayers.Bounds(topLeft.lon,
- bottomRight.lat,
- bottomRight.lon,
- topLeft.lat);
- return bounds;
- },
-
- CLASS_NAME: "OpenLayers.Tile"
-});
-/* ======================================================================
- OpenLayers/Control/OverviewMap.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/BaseTypes.js
- * @requires OpenLayers/Events.js
- *
- * Class: OpenLayers.Control.OverviewMap
- * Create an overview map to display the extent of your main map and provide
- * additional navigation control. Create a new overview map with the
- * <OpenLayers.Control.OverviewMap> constructor.
- *
- * Inerits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * Property: id
- * {String} For div.id
- */
- id: "OverviewMap",
-
- /**
- * Property: element
- * {DOMElement} The DOM element that contains the overview map
- */
- element: null,
-
- /**
- * APIProperty: ovmap
- * {<OpenLayers.Map>} A reference to the overvew map itself.
- */
- ovmap: null,
-
- /**
- * APIProperty: size
- * {<OpenLayers.Size>} The overvew map size in pixels. Note that this is
- * the size of the map itself - the element that contains the map (default
- * class name olControlOverviewMapElement) may have padding or other style
- * attributes added via CSS.
- */
- size: new OpenLayers.Size(180, 90),
-
- /**
- * APIProperty: layers
- * {Array(<OpenLayers.Layer>)} Ordered list of layers in the overview map.
- * If none are sent at construction, the base layer for the main map is used.
- */
- layers: null,
-
- /**
- * APIProperty: minRatio
- * {Float} The ratio of the overview map resolution to the main map
- * resolution at which to zoom farther out on the overview map.
- */
- minRatio: 8,
-
- /**
- * APIProperty: maxRatio
- * {Float} The ratio of the overview map resolution to the main map
- * resolution at which to zoom farther in on the overview map.
- */
- maxRatio: 32,
-
- /**
- * APIProperty: mapOptions
- * {Object} An object containing any non-default properties to be sent to
- * the overview map's map constructor. These should include any non-default
- * options that the main map was constructed with.
- */
- mapOptions: null,
-
- /**
- * Constructor: OpenLayers.Control.OverviewMap
- * Create a new overview map
- *
- * Parameters:
- * object - {Object} Properties of this object will be set on the overview
- * map object. Note, to set options on the map object contained in this
- * control, set <mapOptions> as one of the options properties.
- */
- initialize: function(options) {
- this.layers = [];
- OpenLayers.Control.prototype.initialize.apply(this, [options]);
- },
-
- /**
- * APIMethod: destroy
- * Deconstruct the control
- */
- destroy: function() {
- if (!this.mapDiv) { // we've already been destroyed
- return;
- }
- this.mapDiv.removeChild(this.extentRectangle);
- this.extentRectangle = null;
- this.rectEvents.destroy();
- this.rectEvents = null;
-
- this.ovmap.destroy();
- this.ovmap = null;
-
- this.element.removeChild(this.mapDiv);
- this.mapDiv = null;
- this.mapDivEvents.destroy();
- this.mapDivEvents = null;
-
- this.div.removeChild(this.element);
- this.element = null;
- this.elementEvents.destroy();
- this.elementEvents = null;
-
- if (this.maximizeDiv) {
- OpenLayers.Event.stopObservingElement(this.maximizeDiv);
- this.div.removeChild(this.maximizeDiv);
- this.maximizeDiv = null;
- }
-
- if (this.minimizeDiv) {
- OpenLayers.Event.stopObservingElement(this.minimizeDiv);
- this.div.removeChild(this.minimizeDiv);
- this.minimizeDiv = null;
- }
-
- this.map.events.unregister('moveend', this, this.update);
- this.map.events.unregister("changebaselayer", this,
- this.baseLayerDraw);
-
- OpenLayers.Control.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: draw
- * Render the control in the browser.
- */
- draw: function() {
- OpenLayers.Control.prototype.draw.apply(this, arguments);
- if(!(this.layers.length > 0)) {
- if (this.map.baseLayer) {
- var layer = this.map.baseLayer.clone();
- this.layers = [layer];
- } else {
- this.map.events.register("changebaselayer", this, this.baseLayerDraw);
- return this.div;
- }
- }
-
- // create overview map DOM elements
- this.element = document.createElement('div');
- this.element.className = this.displayClass + 'Element';
- this.element.style.display = 'none';
-
- this.mapDiv = document.createElement('div');
- this.mapDiv.style.width = this.size.w + 'px';
- this.mapDiv.style.height = this.size.h + 'px';
- this.mapDiv.style.position = 'relative';
- this.mapDiv.style.overflow = 'hidden';
- this.mapDiv.id = OpenLayers.Util.createUniqueID('overviewMap');
-
- this.extentRectangle = document.createElement('div');
- this.extentRectangle.style.position = 'absolute';
- this.extentRectangle.style.zIndex = 1000; //HACK
- this.extentRectangle.style.overflow = 'hidden';
- this.extentRectangle.style.backgroundImage = 'url(' +
- OpenLayers.Util.getImagesLocation() +
- 'blank.gif)';
- this.extentRectangle.className = this.displayClass+'ExtentRectangle';
- this.mapDiv.appendChild(this.extentRectangle);
-
- this.element.appendChild(this.mapDiv);
-
- this.div.appendChild(this.element);
-
- this.map.events.register('moveend', this, this.update);
-
- // Set up events. The image div recenters the map on click.
- // The extent rectangle can be dragged to recenter the map.
- // If the mousedown happened elsewhere, then mousemove and mouseup
- // should slip through.
- this.elementEvents = new OpenLayers.Events(this, this.element);
- this.elementEvents.register('mousedown', this, function(e) {
- OpenLayers.Event.stop(e);
- });
- this.elementEvents.register('click', this, function(e) {
- OpenLayers.Event.stop(e);
- });
- this.elementEvents.register('dblclick', this, function(e) {
- OpenLayers.Event.stop(e);
- });
- this.rectEvents = new OpenLayers.Events(this, this.extentRectangle,
- null, true);
- this.rectEvents.register('mouseout', this, this.rectMouseOut);
- this.rectEvents.register('mousedown', this, this.rectMouseDown);
- this.rectEvents.register('mousemove', this, this.rectMouseMove);
- this.rectEvents.register('mouseup', this, this.rectMouseUp);
- this.rectEvents.register('click', this, function(e) {
- OpenLayers.Event.stop(e);
- });
- this.rectEvents.register('dblclick', this, this.rectDblClick );
- this.mapDivEvents = new OpenLayers.Events(this, this.mapDiv);
- this.mapDivEvents.register('click', this, this.mapDivClick);
-
- // Optionally add min/max buttons if the control will go in the
- // map viewport.
- if(!this.outsideViewport) {
- this.div.className = this.displayClass + 'Container';
- var imgLocation = OpenLayers.Util.getImagesLocation();
- // maximize button div
- var img = imgLocation + 'layer-switcher-maximize.png';
- this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
- this.displayClass + 'MaximizeButton',
- null,
- new OpenLayers.Size(18,18),
- img,
- 'absolute');
- this.maximizeDiv.style.display = 'none';
- this.maximizeDiv.className = this.displayClass + 'MaximizeButton';
- OpenLayers.Event.observe(this.maximizeDiv, 'click',
- OpenLayers.Function.bindAsEventListener(this.maximizeControl,
- this)
- );
- this.div.appendChild(this.maximizeDiv);
-
- // minimize button div
- var img = imgLocation + 'layer-switcher-minimize.png';
- this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
- 'OpenLayers_Control_minimizeDiv',
- null,
- new OpenLayers.Size(18,18),
- img,
- 'absolute');
- this.minimizeDiv.style.display = 'none';
- this.minimizeDiv.className = this.displayClass + 'MinimizeButton';
- OpenLayers.Event.observe(this.minimizeDiv, 'click',
- OpenLayers.Function.bindAsEventListener(this.minimizeControl,
- this)
- );
- this.div.appendChild(this.minimizeDiv);
-
- var eventsToStop = ['dblclick','mousedown'];
-
- for (var i = 0; i < eventsToStop.length; i++) {
-
- OpenLayers.Event.observe(this.maximizeDiv,
- eventsToStop[i],
- OpenLayers.Event.stop);
-
- OpenLayers.Event.observe(this.minimizeDiv,
- eventsToStop[i],
- OpenLayers.Event.stop);
- }
-
- this.minimizeControl();
- } else {
- // show the overview map
- this.element.style.display = '';
- }
- if(this.map.getExtent()) {
- this.update();
- }
- return this.div;
- },
-
- /**
- * Method: baseLayerDraw
- * Draw the base layer - called if unable to complete in the initial draw
- */
- baseLayerDraw: function() {
- this.draw();
- this.map.events.unregister("changebaselayer", this, this.baseLayerDraw);
- },
-
- /**
- * Method: rectMouseOut
- * Handle browser events
- *
- * Parameters:
- * evt - {<OpenLayers.Event>} evt
- */
- rectMouseOut: function (evt) {
- if(this.rectDragStart != null) {
- if(this.performedRectDrag) {
- this.rectMouseMove(evt);
- var rectPxBounds = this.getRectPxBounds();
- // if we're off of the overview map, update the main map
- // otherwise, keep moving the rect
- if((rectPxBounds.top <= 0) || (rectPxBounds.left <= 0) ||
- (rectPxBounds.bottom >= this.size.h - this.hComp) ||
- (rectPxBounds.right >= this.size.w - this.wComp)) {
- this.updateMapToRect();
- } else {
- return;
- }
- }
- document.onselectstart = null;
- this.rectDragStart = null;
- }
- },
-
- /**
- * Method: rectMouseDown
- * Handle browser events
- *
- * Parameters:
- * evt - {<OpenLayers.Event>} evt
- */
- rectMouseDown: function (evt) {
- if(!OpenLayers.Event.isLeftClick(evt)) return;
- this.rectDragStart = evt.xy.clone();
- this.performedRectDrag = false;
- OpenLayers.Event.stop(evt);
- },
-
- /**
- * Method: rectMouseMove
- * Handle browser events
- *
- * Parameters:
- * evt - {<OpenLayers.Event>} evt
- */
- rectMouseMove: function(evt) {
- if(this.rectDragStart != null) {
- var deltaX = this.rectDragStart.x - evt.xy.x;
- var deltaY = this.rectDragStart.y - evt.xy.y;
- var rectPxBounds = this.getRectPxBounds();
- var rectTop = rectPxBounds.top;
- var rectLeft = rectPxBounds.left;
- var rectHeight = Math.abs(rectPxBounds.getHeight());
- var rectWidth = rectPxBounds.getWidth();
- // don't allow dragging off of parent element
- var newTop = Math.max(0, (rectTop - deltaY));
- newTop = Math.min(newTop,
- this.ovmap.size.h - this.hComp - rectHeight);
- var newLeft = Math.max(0, (rectLeft - deltaX));
- newLeft = Math.min(newLeft,
- this.ovmap.size.w - this.wComp - rectWidth);
- this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
- newTop + rectHeight,
- newLeft + rectWidth,
- newTop));
- this.rectDragStart = evt.xy.clone();
- this.performedRectDrag = true;
- OpenLayers.Event.stop(evt);
- }
- },
-
- /**
- * Method: rectMouseUp
- * Handle browser events
- *
- * Parameters:
- * evt - {<OpenLayers.Event>} evt
- */
- rectMouseUp: function(evt) {
- if(!OpenLayers.Event.isLeftClick(evt)) return;
- if(this.performedRectDrag) {
- this.updateMapToRect();
- OpenLayers.Event.stop(evt);
- }
- document.onselectstart = null;
- this.rectDragStart = null;
- },
-
- /**
- * Method: rectDblClick
- * Handle browser events
- *
- * Parameters:
- * evt - {<OpenLayers.Event>} evt
- */
- rectDblClick: function(evt) {
- this.performedRectDrag = false;
- OpenLayers.Event.stop(evt);
- this.updateOverview();
- },
-
- /**
- * Method: mapDivClick
- * Handle browser events
- *
- * Parameters:
- * evt - {<OpenLayers.Event>} evt
- */
- mapDivClick: function(evt) {
- var pxBounds = this.getRectPxBounds();
- var pxCenter = pxBounds.getCenterPixel();
- var deltaX = evt.xy.x - pxCenter.x;
- var deltaY = evt.xy.y - pxCenter.y;
- var top = pxBounds.top;
- var left = pxBounds.left;
- var height = Math.abs(pxBounds.getHeight());
- var width = pxBounds.getWidth();
- var newTop = Math.max(0, (top + deltaY));
- newTop = Math.min(newTop, this.ovmap.size.h - height);
- var newLeft = Math.max(0, (left + deltaX));
- newLeft = Math.min(newLeft, this.ovmap.size.w - width);
- this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
- newTop + height,
- newLeft + width,
- newTop));
- this.updateMapToRect();
- OpenLayers.Event.stop(evt);
- },
-
- /**
- * Method: maximizeControl
- * Unhide the control. Called when the control is in the map viewport.
- *
- * Parameters:
- * e - {<OpenLayers.Event>}
- */
- maximizeControl: function(e) {
- this.element.style.display = '';
- this.showToggle(false);
- if (e != null) {
- OpenLayers.Event.stop(e);
- }
- },
-
- /**
- * Method: minimizeControl
- * Hide all the contents of the control, shrink the size,
- * add the maximize icon
- *
- * Parameters:
- * e - {<OpenLayers.Event>}
- */
- minimizeControl: function(e) {
- this.element.style.display = 'none';
- this.showToggle(true);
- if (e != null) {
- OpenLayers.Event.stop(e);
- }
- },
-
- /**
- * Method: showToggle
- * Hide/Show the toggle depending on whether the control is minimized
- *
- * Parameters:
- * minimize - {Boolean}
- */
- showToggle: function(minimize) {
- this.maximizeDiv.style.display = minimize ? '' : 'none';
- this.minimizeDiv.style.display = minimize ? 'none' : '';
- },
-
- /**
- * Method: update
- * Update the overview map after layers move.
- */
- update: function() {
- if(this.ovmap == null) {
- this.createMap();
- }
-
- if(!this.isSuitableOverview()) {
- this.updateOverview();
- }
-
- // update extent rectangle
- this.updateRectToMap();
- },
-
- /**
- * Method: isSuitableOverview
- * Determines if the overview map is suitable given the extent and
- * resolution of the main map.
- */
- isSuitableOverview: function() {
- var mapExtent = this.map.getExtent();
- var maxExtent = this.map.maxExtent;
- var testExtent = new OpenLayers.Bounds(
- Math.max(mapExtent.left, maxExtent.left),
- Math.max(mapExtent.bottom, maxExtent.bottom),
- Math.min(mapExtent.right, maxExtent.right),
- Math.min(mapExtent.top, maxExtent.top));
- var resRatio = this.ovmap.getResolution() / this.map.getResolution();
- return ((resRatio > this.minRatio) &&
- (resRatio <= this.maxRatio) &&
- (this.ovmap.getExtent().containsBounds(testExtent)));
- },
-
- /**
- * Method updateOverview
- * Called by <update> if <isSuitableOverview> returns true
- */
- updateOverview: function() {
- var mapRes = this.map.getResolution();
- var targetRes = this.ovmap.getResolution();
- var resRatio = targetRes / mapRes;
- if(resRatio > this.maxRatio) {
- // zoom in overview map
- targetRes = this.minRatio * mapRes;
- } else if(resRatio <= this.minRatio) {
- // zoom out overview map
- targetRes = this.maxRatio * mapRes;
- }
- this.ovmap.setCenter(this.map.center,
- this.ovmap.getZoomForResolution(targetRes));
- this.updateRectToMap();
- },
-
- /**
- * Method: createMap
- * Construct the map that this control contains
- */
- createMap: function() {
- // create the overview map
- var options = OpenLayers.Util.extend(
- {controls: [], maxResolution: 'auto'}, this.mapOptions);
- this.ovmap = new OpenLayers.Map(this.mapDiv, options);
- this.ovmap.addLayers(this.layers);
- this.ovmap.zoomToMaxExtent();
- // check extent rectangle border width
- this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
- 'border-left-width')) +
- parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
- 'border-right-width'));
- this.wComp = (this.wComp) ? this.wComp : 2;
- this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
- 'border-top-width')) +
- parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
- 'border-bottom-width'));
- this.hComp = (this.hComp) ? this.hComp : 2;
- },
-
- /**
- * Method: updateRectToMap
- * Updates the extent rectangle position and size to match the map extent
- */
- updateRectToMap: function() {
- // The base layer for overview map needs to be in the same projection
- // as the base layer for the main map. This should be made more robust.
- /*if(this.map.units != 'degrees') {
- if(this.ovmap.getProjection() && (this.map.getProjection() != this.ovmap.getProjection())) {
- alert(OpenLayers.String.translate("sameProjection"));
- }
- }*/
- var pxBounds = this.getRectBoundsFromMapBounds(this.map.getExtent());
- if (pxBounds) {
- this.setRectPxBounds(pxBounds);
- }
- },
-
- /**
- * Method: updateMapToRect
- * Updates the map extent to match the extent rectangle position and size
- */
- updateMapToRect: function() {
- var pxBounds = this.getRectPxBounds();
- var lonLatBounds = this.getMapBoundsFromRectBounds(pxBounds);
- this.map.setCenter(lonLatBounds.getCenterLonLat(), this.map.zoom);
- },
-
- /**
- * Method: getRectPxBounds
- * Get extent rectangle pixel bounds
- *
- * Returns:
- * {<OpenLayers.Bounds>} A bounds which is the extent rectangle's pixel
- * bounds (relative to the parent element)
- */
- getRectPxBounds: function() {
- var top = parseInt(this.extentRectangle.style.top);
- var left = parseInt(this.extentRectangle.style.left);
- var height = parseInt(this.extentRectangle.style.height);
- var width = parseInt(this.extentRectangle.style.width);
- return new OpenLayers.Bounds(left, top + height, left + width, top);
- },
-
- /**
- * Method: setRectPxBounds
- * Set extent rectangle pixel bounds.
- *
- * Parameters:
- * pxBounds - {<OpenLayers.Bounds>}
- */
- setRectPxBounds: function(pxBounds) {
- var top = Math.max(pxBounds.top, 0);
- var left = Math.max(pxBounds.left, 0);
- var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()),
- this.ovmap.size.h - this.hComp);
- var right = Math.min(pxBounds.left + pxBounds.getWidth(),
- this.ovmap.size.w - this.wComp);
- this.extentRectangle.style.top = parseInt(top) + 'px';
- this.extentRectangle.style.left = parseInt(left) + 'px';
- this.extentRectangle.style.height = parseInt(Math.max(bottom - top, 0))+ 'px';
- this.extentRectangle.style.width = parseInt(Math.max(right - left, 0)) + 'px';
- },
-
- /**
- * Method: getRectBoundsFromMapBounds
- * Get the rect bounds from the map bounds.
- *
- * Parameters:
- * lonLatBounds - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {<OpenLayers.Bounds>}A bounds which is the passed-in map lon/lat extent
- * translated into pixel bounds for the overview map
- */
- getRectBoundsFromMapBounds: function(lonLatBounds) {
- var leftBottomLonLat = new OpenLayers.LonLat(lonLatBounds.left,
- lonLatBounds.bottom);
- var rightTopLonLat = new OpenLayers.LonLat(lonLatBounds.right,
- lonLatBounds.top);
- var leftBottomPx = this.getOverviewPxFromLonLat(leftBottomLonLat);
- var rightTopPx = this.getOverviewPxFromLonLat(rightTopLonLat);
- var bounds = null;
- if (leftBottomPx && rightTopPx) {
- bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y,
- rightTopPx.x, rightTopPx.y);
- }
- return bounds;
- },
-
- /**
- * Method: getMapBoundsFromRectBounds
- * Get the map bounds from the rect bounds.
- *
- * Parameters:
- * pxBounds - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {<OpenLayers.Bounds>} Bounds which is the passed-in overview rect bounds
- * translated into lon/lat bounds for the overview map
- */
- getMapBoundsFromRectBounds: function(pxBounds) {
- var leftBottomPx = new OpenLayers.Pixel(pxBounds.left,
- pxBounds.bottom);
- var rightTopPx = new OpenLayers.Pixel(pxBounds.right,
- pxBounds.top);
- var leftBottomLonLat = this.getLonLatFromOverviewPx(leftBottomPx);
- var rightTopLonLat = this.getLonLatFromOverviewPx(rightTopPx);
- return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat,
- rightTopLonLat.lon, rightTopLonLat.lat);
- },
-
- /**
- * Method: getLonLatFromOverviewPx
- * Get a map location from a pixel location
- *
- * Parameters:
- * overviewMapPx - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.LonLat>} Location which is the passed-in overview map
- * OpenLayers.Pixel, translated into lon/lat by the overview map
- */
- getLonLatFromOverviewPx: function(overviewMapPx) {
- var size = this.ovmap.size;
- var res = this.ovmap.getResolution();
- var center = this.ovmap.getExtent().getCenterLonLat();
-
- var delta_x = overviewMapPx.x - (size.w / 2);
- var delta_y = overviewMapPx.y - (size.h / 2);
-
- return new OpenLayers.LonLat(center.lon + delta_x * res ,
- center.lat - delta_y * res);
- },
-
- /**
- * Method: getOverviewPxFromLonLat
- * Get a pixel location from a map location
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>}
- *
- * Returns:
- * {<OpenLayers.Pixel>} Location which is the passed-in OpenLayers.LonLat,
- * translated into overview map pixels
- */
- getOverviewPxFromLonLat: function(lonlat) {
- var res = this.ovmap.getResolution();
- var extent = this.ovmap.getExtent();
- var px = null;
- if (extent) {
- px = new OpenLayers.Pixel(
- Math.round(1/res * (lonlat.lon - extent.left)),
- Math.round(1/res * (extent.top - lonlat.lat)));
- }
- return px;
- },
-
- CLASS_NAME: 'OpenLayers.Control.OverviewMap'
-});
-/* ======================================================================
- OpenLayers/Handler.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Events.js
- *
- * Class: OpenLayers.Handler
- * Base class to construct a higher-level handler for event sequences. All
- * handlers have activate and deactivate methods. In addition, they have
- * methods named like browser events. When a handler is activated, any
- * additional methods named like a browser event is registered as a
- * listener for the corresponding event. When a handler is deactivated,
- * those same methods are unregistered as event listeners.
- *
- * Handlers also typically have a callbacks object with keys named like
- * the abstracted events or event sequences that they are in charge of
- * handling. The controls that wrap handlers define the methods that
- * correspond to these abstract events - so instead of listening for
- * individual browser events, they only listen for the abstract events
- * defined by the handler.
- *
- * Handlers are created by controls, which ultimately have the responsibility
- * of making changes to the the state of the application. Handlers
- * themselves may make temporary changes, but in general are expected to
- * return the application in the same state that they found it.
- */
-OpenLayers.Handler = OpenLayers.Class({
-
- /**
- * Property: id
- * {String}
- */
- id: null,
-
- /**
- * APIProperty: control
- * {<OpenLayers.Control>}. The control that initialized this handler. The
- * control is assumed to have a valid map property - that map is used
- * in the handler's own setMap method.
- */
- control: null,
-
- /**
- * Property: map
- * {<OpenLayers.Map>}
- */
- map: null,
-
- /**
- * APIProperty: keyMask
- * {Integer} Use bitwise operators and one or more of the OpenLayers.Handler
- * constants to construct a keyMask. The keyMask is used by
- * <checkModifiers>. If the keyMask matches the combination of keys
- * down on an event, checkModifiers returns true.
- *
- * Example:
- * (code)
- * // handler only responds if the Shift key is down
- * handler.keyMask = OpenLayers.Handler.MOD_SHIFT;
- *
- * // handler only responds if Ctrl-Shift is down
- * handler.keyMask = OpenLayers.Handler.MOD_SHIFT |
- * OpenLayers.Handler.MOD_CTRL;
- * (end)
- */
- keyMask: null,
-
- /**
- * Property: active
- * {Boolean}
- */
- active: false,
-
- /**
- * Property: evt
- * {Event} This property references the last event handled by the handler.
- * Note that this property is not part of the stable API. Use of the
- * evt property should be restricted to controls in the library
- * or other applications that are willing to update with changes to
- * the OpenLayers code.
- */
- evt: null,
-
- /**
- * Constructor: OpenLayers.Handler
- * Construct a handler.
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that initialized this
- * handler. The control is assumed to have a valid map property; that
- * map is used in the handler's own setMap method.
- * 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;
- if (control.map) {
- this.setMap(control.map);
- }
-
- OpenLayers.Util.extend(this, options);
-
- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
- },
-
- /**
- * Method: setMap
- */
- setMap: function (map) {
- this.map = map;
- },
-
- /**
- * Method: checkModifiers
- * Check the keyMask on the handler. If no <keyMask> is set, this always
- * returns true. If a <keyMask> is set and it matches the combination
- * of keys down on an event, this returns true.
- *
- * Returns:
- * {Boolean} The keyMask matches the keys down on an event.
- */
- checkModifiers: function (evt) {
- if(this.keyMask == null) {
- return true;
- }
- /* calculate the keyboard modifier mask for this event */
- var keyModifiers =
- (evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) |
- (evt.ctrlKey ? OpenLayers.Handler.MOD_CTRL : 0) |
- (evt.altKey ? OpenLayers.Handler.MOD_ALT : 0);
-
- /* if it differs from the handler object's key mask,
- bail out of the event handler */
- return (keyModifiers == this.keyMask);
- },
-
- /**
- * APIMethod: activate
- * Turn on the handler. Returns false if the handler was already active.
- *
- * Returns:
- * {Boolean} The handler was activated.
- */
- activate: function() {
- if(this.active) {
- return false;
- }
- // register for event handlers defined on this class.
- var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
- for (var i = 0; i < events.length; i++) {
- if (this[events[i]]) {
- this.register(events[i], this[events[i]]);
- }
- }
- this.active = true;
- return true;
- },
-
- /**
- * APIMethod: deactivate
- * Turn off the handler. Returns false if the handler was already inactive.
- *
- * Returns:
- * {Boolean} The handler was deactivated.
- */
- deactivate: function() {
- if(!this.active) {
- return false;
- }
- // unregister event handlers defined on this class.
- var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
- for (var i = 0; i < events.length; i++) {
- if (this[events[i]]) {
- this.unregister(events[i], this[events[i]]);
- }
- }
- this.active = false;
- return true;
- },
-
- /**
- * Method: callback
- * Trigger the control's named callback with the given arguments
- *
- * Parameters:
- * name - {String} The key for the callback that is one of the properties
- * of the handler's callbacks object.
- * args - {Array(*)} An array of arguments (any type) with which to call
- * the callback (defined by the control).
- */
- callback: function (name, args) {
- if (this.callbacks[name]) {
- this.callbacks[name].apply(this.control, args);
- }
- },
-
- /**
- * Method: register
- * register an event on the map
- */
- register: function (name, method) {
- // TODO: deal with registerPriority in 3.0
- this.map.events.registerPriority(name, this, method);
- this.map.events.registerPriority(name, this, this.setEvent);
- },
-
- /**
- * Method: unregister
- * unregister an event from the map
- */
- unregister: function (name, method) {
- this.map.events.unregister(name, this, method);
- this.map.events.unregister(name, this, this.setEvent);
- },
-
- /**
- * Method: setEvent
- * With each registered browser event, the handler sets its own evt
- * property. This property can be accessed by controls if needed
- * to get more information about the event that the handler is
- * processing.
- *
- * This allows modifier keys on the event to be checked (alt, shift,
- * and ctrl cannot be checked with the keyboard handler). For a
- * control to determine which modifier keys are associated with the
- * event that a handler is currently processing, it should access
- * (code)handler.evt.altKey || handler.evt.shiftKey ||
- * handler.evt.ctrlKey(end).
- *
- * Parameters:
- * evt - {Event} The browser event.
- */
- setEvent: function(evt) {
- this.evt = evt;
- return true;
- },
-
- /**
- * Method: destroy
- * Deconstruct the handler.
- */
- destroy: function () {
- // unregister event listeners
- this.deactivate();
- // eliminate circular references
- this.control = this.map = null;
- },
-
- CLASS_NAME: "OpenLayers.Handler"
-});
-
-/**
- * Constant: OpenLayers.Handler.MOD_NONE
- * If set as the <keyMask>, <checkModifiers> returns false if any key is down.
- */
-OpenLayers.Handler.MOD_NONE = 0;
-
-/**
- * Constant: OpenLayers.Handler.MOD_SHIFT
- * If set as the <keyMask>, <checkModifiers> returns false if Shift is down.
- */
-OpenLayers.Handler.MOD_SHIFT = 1;
-
-/**
- * Constant: OpenLayers.Handler.MOD_CTRL
- * If set as the <keyMask>, <checkModifiers> returns false if Ctrl is down.
- */
-OpenLayers.Handler.MOD_CTRL = 2;
-
-/**
- * Constant: OpenLayers.Handler.MOD_ALT
- * If set as the <keyMask>, <checkModifiers> returns false if Alt is down.
- */
-OpenLayers.Handler.MOD_ALT = 4;
-
-
-/* ======================================================================
- OpenLayers/Map.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Util.js
- * @requires OpenLayers/Events.js
- *
- * Class: OpenLayers.Map
- * Instances of OpenLayers.Map are interactive maps embedded in a web page.
- * Create a new map with the <OpenLayers.Map> constructor.
- *
- * On their own maps do not provide much functionality. To extend a map
- * it's necessary to add controls (<OpenLayers.Control>) and
- * layers (<OpenLayers.Layer>) 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, Popup: 750, Control: 1000 },
-
- /**
- * Constant: EVENT_TYPES
- * {Array(String)} supported application event types
- */
- EVENT_TYPES: [
- "addlayer", "removelayer", "changelayer", "movestart", "move",
- "moveend", "zoomend", "popupopen", "popupclose",
- "addmarker", "removemarker", "clearmarkers", "mouseover",
- "mouseout", "mousemove", "dragstart", "drag", "dragend",
- "changebaselayer"],
-
- /**
- * Property: id
- * {String} Unique identifier for the map
- */
- id: null,
-
- /**
- * APIProperty: events
- * {<OpenLayers.Events>} An events object that handles all
- * events on the map
- */
- events: null,
-
- /**
- * APIProperty: div
- * {DOMElement} The element that contains the map
- */
- div: null,
-
- /**
- * Property: size
- * {<OpenLayers.Size>} Size of the main div (this.div)
- */
- size: null,
-
- /**
- * Property: viewPortDiv
- * {HTMLDivElement} The element that represents the map viewport
- */
- viewPortDiv: null,
-
- /**
- * Property: layerContainerOrigin
- * {<OpenLayers.LonLat>} 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,
-
- /**
- * Property: layers
- * {Array(<OpenLayers.Layer>)} Ordered list of layers in the map
- */
- layers: null,
-
- /**
- * Property: controls
- * {Array(<OpenLayers.Control>)} List of controls associated with the map
- */
- controls: null,
-
- /**
- * Property: popups
- * {Array(<OpenLayers.Popup>)} List of popups associated with the map
- */
- popups: null,
-
- /**
- * APIProperty: baseLayer
- * {<OpenLayers.Layer>} The currently selected base layer. This determines
- * min/max zoom level, projection, etc.
- */
- baseLayer: null,
-
- /**
- * Property: center
- * {<OpenLayers.LonLat>} The current center of the map
- */
- center: null,
-
- /**
- * Property: zoom
- * {Integer} The current zoom level of the map
- */
- zoom: 0,
-
- /**
- * Property: viewRequestID
- * {String} Used to store a unique identifier that changes when the map
- * view changes. viewRequestID should be used when adding data
- * asynchronously to the map: viewRequestID is incremented when
- * you initiate your request (right now during changing of
- * baselayers and changing of zooms). It is stored here in the
- * map and also in the data that will be coming back
- * asynchronously. Before displaying this data on request
- * completion, we check that the viewRequestID of the data is
- * still the same as that of the map. Fix for #480
- */
- viewRequestID: 0,
-
- // Options
-
- /**
- * APIProperty: tileSize
- * {<OpenLayers.Size>} 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 override the default projection
- * string this map - also set maxExtent, maxResolution, and
- * units if appropriate.
- */
- projection: "EPSG:4326",
-
- /**
- * APIProperty: units
- * {String} The map units. Defaults to 'degrees'. Possible values are
- * 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
- */
- units: 'degrees',
-
- /**
- * 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} Default max is 360 deg / 256 px, which corresponds to
- * zoom level 0 on gmaps. Specify a different value in the map
- * options if you are not using a geographic projection and
- * displaying the whole world.
- */
- maxResolution: 1.40625,
-
- /**
- * APIProperty: minResolution
- * {Float}
- */
- minResolution: null,
-
- /**
- * APIProperty: maxScale
- * {Float}
- */
- maxScale: null,
-
- /**
- * APIProperty: minScale
- * {Float}
- */
- minScale: null,
-
- /**
- * APIProperty: maxExtent
- * {<OpenLayers.Bounds>} 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.
- */
- maxExtent: null,
-
- /**
- * APIProperty: minExtent
- * {<OpenLayers.Bounds>}
- */
- minExtent: null,
-
- /**
- * APIProperty: restrictedExtent
- * {<OpenLayers.Bounds>} 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: 'auto',
-
- /**
- * 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: fallThrough
- * {Boolean} Should OpenLayers allow events on the map to fall through to
- * other elements on the page, or should it swallow them? (#457)
- * Default is to swallow them.
- */
- fallThrough: false,
-
- /**
- * Constructor: OpenLayers.Map
- * Constructor for a new OpenLayers.Map instance.
- *
- * Parameters:
- * div - {String} Id of an element in your page that will contain the map.
- * options - {Object} Optional object with properties to tag onto the map.
- *
- * 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 = {
- * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000),
- * maxResolution: 156543,
- * units: 'meters',
- * projection: "EPSG:41001"
- * };
- * var map = new OpenLayers.Map("map2", options);
- * (end)
- */
- initialize: function (div, options) {
-
- //set the default options
- this.setOptions(options);
-
- this.id = OpenLayers.Util.createUniqueID("OpenLayers.Map_");
-
- this.div = OpenLayers.Util.getElement(div);
-
- // the viewPortDiv is the outermost div we modify
- var id = this.div.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);
-
- // the layerContainerDiv is the one that holds all the layers
- id = this.div.id + "_OpenLayers_Container";
- this.layerContainerDiv = OpenLayers.Util.createDiv(id);
- this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;
-
- this.viewPortDiv.appendChild(this.layerContainerDiv);
-
- this.events = new OpenLayers.Events(this,
- this.div,
- this.EVENT_TYPES,
- this.fallThrough);
- this.updateSize();
-
- // update the map size and location before the map moves
- this.events.register("movestart", this, this.updateSize);
-
- // Because Mozilla does not support the "resize" event for elements
- // other than "window", we need to put a hack here.
- if (OpenLayers.String.contains(navigator.appName, "Microsoft")) {
- // If IE, register the resize on the div
- this.events.register("resize", this, this.updateSize);
- } else {
- // Else 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.
- OpenLayers.Event.observe(window, 'resize',
- OpenLayers.Function.bind(this.updateSize, this));
- }
-
- // 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; i<nodes.length; ++i) {
- if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,
- this.theme)) {
- addNode = false;
- break;
- }
- }
- // only add a new node if one with an equivalent url hasn't already
- // been added
- if(addNode) {
- var cssNode = document.createElement('link');
- cssNode.setAttribute('rel', 'stylesheet');
- cssNode.setAttribute('type', 'text/css');
- cssNode.setAttribute('href', this.theme);
- document.getElementsByTagName('head')[0].appendChild(cssNode);
- }
- }
-
- this.layers = [];
-
- if (this.controls == null) {
- if (OpenLayers.Control != null) { // running full or lite?
- this.controls = [ new OpenLayers.Control.Navigation(),
- new OpenLayers.Control.PanZoom(),
- new OpenLayers.Control.ArgParser(),
- new OpenLayers.Control.Attribution()
- ];
- } else {
- this.controls = [];
- }
- }
-
- for(var i=0; i < this.controls.length; i++) {
- this.addControlToMap(this.controls[i]);
- }
-
- this.popups = [];
-
- this.unloadDestroy = OpenLayers.Function.bind(this.destroy, this);
-
-
- // always call map.destroy()
- OpenLayers.Event.observe(window, 'unload', this.unloadDestroy);
-
- },
-
- /**
- * Method: unloadDestroy
- * Function that is called to destroy the map on page unload. stored here
- * so that if map is manually destroyed, we can unregister this.
- */
- unloadDestroy: null,
-
- /**
- * APIMethod: destroy
- * Destroy this map
- */
- destroy:function() {
- // if unloadDestroy is null, we've already been destroyed
- if (!this.unloadDestroy) {
- return false;
- }
-
- // map has been destroyed. dont do it again!
- OpenLayers.Event.stopObserving(window, 'unload', this.unloadDestroy);
- this.unloadDestroy = 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.controls != null) {
- for (var i = this.controls.length - 1; i>=0; --i) {
- this.controls[i].destroy();
- }
- this.controls = null;
- }
- if (this.viewPortDiv) {
- this.div.removeChild(this.viewPortDiv);
- }
- this.viewPortDiv = null;
-
- this.events.destroy();
- this.events = null;
-
- },
-
- /**
- * APIMethod: setOptions
- * Change the map options
- *
- * Parameters:
- * options - {Object} Hashtable of options to tag to the map
- */
- setOptions: function(options) {
-
- // 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.maxExtent = new OpenLayers.Bounds(-180, -90, 180, 90);
-
- this.theme = OpenLayers._getScriptLocation() +
- 'theme/default/style.css';
-
- // now add the options declared by the user
- // (these will override defaults)
- OpenLayers.Util.extend(this, options);
- },
-
- /**
- * APIMethod: getTileSize
- * Get the tile size for the map
- *
- * Returns:
- * {<OpenLayers.Size>}
- */
- getTileSize: function() {
- return this.tileSize;
- },
-
- /********************************************************/
- /* */
- /* 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
- *
- * Parameter:
- * id - {String} A layer id
- *
- * Returns:
- * {<OpenLayers.Layer>} 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; i < this.layers.length; i++) {
- var layer = this.layers[i];
- if (layer.id == id) {
- foundLayer = layer;
- }
- }
- return foundLayer;
- },
-
- /**
- * Method: setLayerZIndex
- *
- * Parameters:
- * layer - {<OpenLayers.Layer>}
- * zIdx - {int}
- */
- setLayerZIndex: function (layer, zIdx) {
- layer.setZIndex(
- this.Z_INDEX_BASE[layer.isBaseLayer ? 'BaseLayer' : 'Overlay']
- + zIdx * 5 );
- },
-
- /**
- * APIMethod: addLayer
- *
- * Parameters:
- * layer - {<OpenLayers.Layer>}
- */
- addLayer: function (layer) {
- for(var i=0; i < this.layers.length; i++) {
- if (this.layers[i] == layer) {
- OpenLayers.Console.warn(OpenLayers.String.translate("layerAlreadyAdded", layer.name));
- return false;
- }
- }
-
- 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) {
- 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");
- },
-
- /**
- * APIMethod: addLayers
- *
- * Parameters:
- * layers - Array({<OpenLayers.Layer>})
- */
- addLayers: function (layers) {
- for (var i = 0; i < layers.length; i++) {
- this.addLayer(layers[i]);
- }
- },
-
- /**
- * APIMethod: removeLayer
- * Removes a layer from the map by removing its visual element (the
- * layer.div property), then removing it from the map's internal list
- * of layers, setting the layer's map property to null.
- *
- * a "removelayer" event is triggered.
- *
- * very worthy of mention is that simply removing a layer from a map
- * will not cause the removal of any popups which may have been created
- * by the layer. this is due to the fact that it was decided at some
- * point that popups would not belong to layers. thus there is no way
- * for us to know here to which layer the popup belongs.
- *
- * A simple solution to this is simply to call destroy() on the layer.
- * the default OpenLayers.Layer class's destroy() function
- * automatically takes care to remove itself from whatever map it has
- * been attached to.
- *
- * The correct solution is for the layer itself to register an
- * event-handler on "removelayer" and when it is called, if it
- * recognizes itself as the layer being removed, then it cycles through
- * its own personal list of popups, removing them from the map.
- *
- * Parameters:
- * layer - {<OpenLayers.Layer>}
- * setNewBaseLayer - {Boolean} Default is true
- */
- removeLayer: function(layer, setNewBaseLayer) {
- 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 (setNewBaseLayer && (this.baseLayer == layer)) {
- this.baseLayer = null;
- for(i=0; i < this.layers.length; i++) {
- var iLayer = this.layers[i];
- if (iLayer.isBaseLayer) {
- this.setBaseLayer(iLayer);
- break;
- }
- }
- }
- this.events.triggerEvent("removelayer");
- },
-
- /**
- * APIMethod: getNumLayers
- *
- * Returns:
- * {Int} The number of layers attached to the map.
- */
- getNumLayers: function () {
- return this.layers.length;
- },
-
- /**
- * APIMethod: getLayerIndex
- *
- * Parameters:
- * layer - {<OpenLayers.Layer>}
- *
- * 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 - {<OpenLayers.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; i < this.layers.length; i++) {
- this.setLayerZIndex(this.layers[i], i);
- }
- this.events.triggerEvent("changelayer");
- }
- },
-
- /**
- * APIMethod: raiseLayer
- * Change the index of the given layer by delta. If delta is positive,
- * the layer is moved up the map's layer stack; if delta is negative,
- * the layer is moved down. Again, note that this cannot (or at least
- * should not) be effectively used to raise base layers above overlays.
- *
- * Paremeters:
- * layer - {<OpenLayers.Layer>}
- * idx - {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 - {<OpenLayers.Layer>}
- */
- setBaseLayer: function(newBaseLayer) {
- var oldExtent = null;
- if(this.baseLayer) {
- oldExtent = this.baseLayer.getExtent();
- }
-
- if (newBaseLayer != this.baseLayer) {
-
- // is newBaseLayer an already loaded layer?m
- if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) {
-
- // make the old base layer invisible
- if (this.baseLayer != null) {
- this.baseLayer.setVisibility(false);
- }
-
- // set new baselayer and make it visible
- this.baseLayer = newBaseLayer;
-
- //copy over projection and extent information
- this.maxExtent = newBaseLayer.maxExtent;
- this.minExtent = newBaseLayer.minExtent;
- this.maxScale = newBaseLayer.maxScale;
- this.minScale = newBaseLayer.minScale;
- this.maxResolution = newBaseLayer.maxResolution;
- this.minResolution = newBaseLayer.minResolution;
- this.units = newBaseLayer.units;
- this.projection = newBaseLayer.projection;
-
- // Increment viewRequestID since the baseLayer is
- // changing. This is used by tiles to check if they should
- // draw themselves.
- this.viewRequestID++;
- this.baseLayer.visibility = true;
-
- //redraw all layers
- var center = this.getCenter();
- if (center != null) {
- if (oldExtent == null) {
- // simply set center but force zoom change
- this.setCenter(center, this.getZoom(), false, true);
- } else {
- // zoom to oldExtent *and* force zoom change
- this.setCenter(oldExtent.getCenterLonLat(),
- this.getZoomForExtent(oldExtent),
- false, true);
- }
- }
-
- this.events.triggerEvent("changebaselayer");
- }
- }
- },
-
-
- /********************************************************/
- /* */
- /* Control Functions */
- /* */
- /* The following functions deal with adding and */
- /* removing Controls to and from the Map */
- /* */
- /********************************************************/
-
- /**
- * APIMethod: addControl
- *
- * Parameters:
- * control - {<OpenLayers.Control>}
- * px - {<OpenLayers.Pixel>}
- */
- addControl: function (control, px) {
- this.controls.push(control);
- this.addControlToMap(control, px);
- },
-
- /**
- * Method: addControlToMap
- *
- * Parameters:
- *
- * control - {<OpenLayers.Control>}
- * px - {<OpenLayers.Pixel>}
- */
- 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);
- 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 );
- }
- }
- },
-
- /**
- * APIMethod: getControl
- *
- * Parameters:
- * id - {String} ID of the control to return.
- *
- * Returns:
- * {<OpenLayers.Control>} 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; i < this.controls.length; i++) {
- var control = this.controls[i];
- if (control.id == id) {
- returnControl = control;
- break;
- }
- }
- return returnControl;
- },
-
- /**
- * APIMethod: removeControl
- * Remove a control from the map. Removes the control both from the map
- * object's internal array of controls, as well as from the map's
- * viewPort (assuming the control was not added outsideViewport)
- *
- * Parameters:
- * control - {<OpenLayers.Control>} 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.outsideViewport) {
- 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 - {<OpenLayers.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=0; i < this.popups.length; 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 - {<OpenLayers.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:
- * {<OpenLayers.Size>} An <OpenLayers.Size> 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
- this.events.element.offsets = null;
- var newSize = this.getCurrentSize();
- 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; i < this.layers.length; i++) {
- this.layers[i].onMapResize();
- }
-
- if (this.baseLayer != null) {
- var center = new OpenLayers.Pixel(newSize.w /2, newSize.h / 2);
- var centerLL = this.getLonLatFromViewPortPx(center);
- var zoom = this.getZoom();
- this.zoom = null;
- this.setCenter(this.getCenter(), zoom);
- }
-
- }
- },
-
- /**
- * Method: getCurrentSize
- *
- * Returns:
- * {<OpenLayers.Size>} A new <OpenLayers.Size> object with the dimensions
- * of the map div
- */
- getCurrentSize: function() {
-
- var size = new OpenLayers.Size(this.div.clientWidth,
- this.div.clientHeight);
-
- // Workaround for the fact that hidden elements return 0 for size.
- if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {
- var dim = OpenLayers.Element.getDimensions(this.div);
- size.w = dim.width;
- size.h = dim.height;
- }
- 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 - {<OpenLayers.LonLat>} Default is this.getCenter()
- * resolution - {float} Default is this.getResolution()
- *
- * Returns:
- * {<OpenLayers.Bounds>} A bounds based on resolution, center, and
- * current mapsize.
- */
- calculateBounds: function(center, resolution) {
-
- var extent = null;
-
- if (center == null) {
- center = this.getCenter();
- }
- if (resolution == null) {
- resolution = this.getResolution();
- }
-
- if ((center != null) && (resolution != null)) {
-
- var size = this.getSize();
- var w_deg = size.w * resolution;
- var h_deg = size.h * resolution;
-
- extent = new OpenLayers.Bounds(center.lon - w_deg / 2,
- center.lat - h_deg / 2,
- center.lon + w_deg / 2,
- center.lat + h_deg / 2);
-
- }
-
- 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:
- * {<OpenLayers.LonLat>}
- */
- getCenter: function () {
- 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}
- */
- pan: function(dx, dy) {
-
- // getCenter
- var centerPx = this.getViewPortPxFromLonLat(this.getCenter());
-
- // adjust
- var newCenterPx = centerPx.add(dx, dy);
-
- // only call setCenter if there has been a change
- if (!newCenterPx.equals(centerPx)) {
- var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx);
- this.setCenter(newCenterLonLat);
- }
-
- },
-
- /**
- * APIMethod: setCenter
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>}
- * zoom - {Integer}
- * 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) {
-
- if (!this.center && !this.isValidLonLat(lonlat)) {
- lonlat = this.maxExtent.getCenterLonLat();
- }
-
- if (this.restrictedExtent && this.restrictedExtent != 'auto') {
- // In 3.0, decide if we want to change interpretation of maxExtent.
- if(lonlat == null) {
- lonlat = this.getCenter();
- }
- if(zoom == null) {
- zoom = this.getZoom();
- }
- var resolution = null;
- if(this.baseLayer != null) {
- resolution = this.baseLayer.resolutions[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 = !lonlat.equals(this.center);
- if (this.restrictedExtent == 'auto') {
- centerChanged = this.isValidLonLat(lonlat) && centerChanged;
- }
-
- // if neither center nor zoom will change, no need to do anything
- if (zoomChanged || centerChanged || !dragging) {
-
- if (!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();
- }
-
- // (re)set the layerContainerDiv's location
- if ((zoomChanged) || (this.layerContainerOrigin == null)) {
- this.layerContainerOrigin = this.center.clone();
- this.layerContainerDiv.style.left = "0px";
- this.layerContainerDiv.style.top = "0px";
- }
-
- if (zoomChanged) {
- this.zoom = zoom;
- // zoom level has changed, increment viewRequestID.
- this.viewRequestID++;
- }
-
- var bounds = this.getExtent();
-
- //send the move call to the baselayer and all the overlays
- this.baseLayer.moveTo(bounds, zoomChanged, dragging);
-
- bounds = this.baseLayer.getExtent();
-
- for (var i = 0; i < this.layers.length; i++) {
- var layer = this.layers[i];
- if (!layer.isBaseLayer) {
-
- var moveLayer;
- var inRange = layer.calculateInRange();
- if (layer.inRange != inRange) {
- // Layer property has changed. We are going
- // to call moveLayer so that the layer can be turned
- // off or on.
- layer.inRange = inRange;
- moveLayer = true;
- this.events.triggerEvent("changelayer");
- } else {
- // If nothing has changed, then we only move the layer
- // if it is visible and inrange.
- moveLayer = (layer.visibility && layer.inRange);
- }
-
- if (moveLayer) {
- layer.moveTo(bounds, zoomChanged, dragging);
- }
- }
- }
-
- if (zoomChanged) {
- //redraw popups
- for (var i = 0; i < this.popups.length; i++) {
- this.popups[i].updatePosition();
- }
- }
-
- this.events.triggerEvent("move");
-
- if (zoomChanged) { this.events.triggerEvent("zoomend"); }
- }
-
- // even if nothing was done, we want to notify of this
- if (!dragging) { this.events.triggerEvent("moveend"); }
- },
-
- /**
- * Method: centerLayerContainer
- * This function takes care to recenter the layerContainerDiv.
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>}
- */
- centerLayerContainer: function (lonlat) {
-
- var originPx = this.getViewPortPxFromLonLat(this.layerContainerOrigin);
- var newPx = this.getViewPortPxFromLonLat(lonlat);
-
- if ((originPx != null) && (newPx != null)) {
- this.layerContainerDiv.style.left = (originPx.x - newPx.x) + "px";
- this.layerContainerDiv.style.top = (originPx.y - newPx.y) + "px";
- }
- },
-
- /**
- * 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 - {<OpenLayers.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();
- valid = maxExtent.containsLonLat(lonlat);
- }
- return valid;
- },
-
- /********************************************************/
- /* */
- /* Layer Options */
- /* */
- /* Accessor functions to Layer Options parameters */
- /* */
- /********************************************************/
-
- /**
- * APIMethod: getProjection
- *
- * Returns:
- * {String} The Projection of the base layer.
- */
- getProjection: 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
- *
- * Returns:
- * {<OpenLayers.Bounds>}
- */
- getMaxExtent: function () {
- var maxExtent = null;
- 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:
- * {<OpenLayers.Bounds>} 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();
- }
- return resolution;
- },
-
- /**
- * 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 - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {Integer} A suitable zoom level for the specified bounds.
- * If no baselayer is set, returns null.
- */
- getZoomForExtent: function (bounds) {
- var zoom = null;
- if (this.baseLayer != null) {
- zoom = this.baseLayer.getZoomForExtent(bounds);
- }
- return zoom;
- },
-
- /**
- * APIMethod: getZoomForResolution
- *
- * Parameter:
- * resolution - {Float}
- *
- * Returns:
- * {Integer} A suitable zoom level for the specified resolution.
- * If no baselayer is set, returns null.
- */
- getZoomForResolution: function(resolution) {
- var zoom = null;
- if (this.baseLayer != null) {
- zoom = this.baseLayer.getZoomForResolution(resolution);
- }
- 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
- *
- * Parameters:
- * zoom - {int}
- */
- zoomIn: function() {
- this.zoomTo(this.getZoom() + 1);
- },
-
- /**
- * APIMethod: zoomOut
- *
- * Parameters:
- * zoom - {int}
- */
- zoomOut: function() {
- this.zoomTo(this.getZoom() - 1);
- },
-
- /**
- * APIMethod: zoomToExtent
- * Zoom to the passed in bounds, recenter
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- */
- zoomToExtent: function(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. Because our new bounds is at least partially
- // outside the bounds of maxExtent, the new calculated center
- // might also be. We don't want to pass a bad center value to
- // setCenter, so we have it wrap itself across the date line.
- //
- center = bounds.getCenterLonLat().wrapDateLine(maxExtent);
- }
- this.setCenter(center, this.getZoomForExtent(bounds));
- },
-
- /**
- * APIMethod: zoomToMaxExtent
- * Zoom to the full extent and recenter.
- */
- zoomToMaxExtent: function() {
- this.zoomToExtent(this.getMaxExtent());
- },
-
- /**
- * APIMethod: zoomToScale
- * Zoom to a specified scale
- *
- * Parameters:
- * scale - {float}
- */
- zoomToScale: function(scale) {
- var res = OpenLayers.Util.getResolutionFromScale(scale,
- this.baseLayer.units);
- var size = this.getSize();
- var w_deg = size.w * res;
- var h_deg = size.h * res;
- var center = this.getCenter();
-
- var extent = new OpenLayers.Bounds(center.lon - w_deg / 2,
- center.lat - h_deg / 2,
- center.lon + w_deg / 2,
- center.lat + h_deg / 2);
- this.zoomToExtent(extent);
- },
-
- /********************************************************/
- /* */
- /* Translation Functions */
- /* */
- /* The following functions translate between */
- /* LonLat, LayerPx, and ViewPortPx */
- /* */
- /********************************************************/
-
- //
- // TRANSLATION: LonLat <-> ViewPortPx
- //
-
- /**
- * APIMethod: getLonLatFromViewPortPx
- *
- * Parameters:
- * viewPortPx - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view
- * port <OpenLayers.Pixel>, 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 - {<OpenLayers.LonLat>}
- *
- * Returns:
- * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
- * <OpenLayers.LonLat>, 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 - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.LonLat>} 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
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>}
- *
- * Returns:
- * {<OpenLayers.Pixel>} An OpenLayers.Pixel corresponding to the
- * <OpenLayers.LonLat> translated into view port
- * pixels by the current base layer.
- */
- getPixelFromLonLat: function (lonlat) {
- return this.getViewPortPxFromLonLat(lonlat);
- },
-
-
-
- //
- // TRANSLATION: ViewPortPx <-> LayerPx
- //
-
- /**
- * APIMethod: getViewPortPxFromLayerPx
- *
- * Parameters:
- * layerPx - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.Pixel>} Layer Pixel translated into ViewPort Pixel
- * coordinates
- */
- getViewPortPxFromLayerPx:function(layerPx) {
- var viewPortPx = null;
- if (layerPx != null) {
- var dX = parseInt(this.layerContainerDiv.style.left);
- var dY = parseInt(this.layerContainerDiv.style.top);
- viewPortPx = layerPx.add(dX, dY);
- }
- return viewPortPx;
- },
-
- /**
- * APIMethod: getLayerPxFromViewPortPx
- *
- * Parameters:
- * viewPortPx - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.Pixel>} ViewPort Pixel translated into Layer Pixel
- * coordinates
- */
- getLayerPxFromViewPortPx:function(viewPortPx) {
- var layerPx = null;
- if (viewPortPx != null) {
- var dX = -parseInt(this.layerContainerDiv.style.left);
- var dY = -parseInt(this.layerContainerDiv.style.top);
- layerPx = viewPortPx.add(dX, dY);
- if (isNaN(layerPx.x) || isNaN(layerPx.y)) {
- layerPx = null;
- }
- }
- return layerPx;
- },
-
- //
- // TRANSLATION: LonLat <-> LayerPx
- //
-
- /**
- * APIMethod: getLonLatFromLayerPx
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.LonLat>}
- */
- getLonLatFromLayerPx: function (px) {
- //adjust for displacement of layerContainerDiv
- px = this.getViewPortPxFromLayerPx(px);
- return this.getLonLatFromViewPortPx(px);
- },
-
- /**
- * APIMethod: getLayerPxFromLonLat
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>} lonlat
- *
- * Returns:
- * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
- * <OpenLayers.LonLat>, translated into layer pixels
- * by the current base layer
- */
- getLayerPxFromLonLat: function (lonlat) {
- //adjust for displacement of layerContainerDiv
- var px = this.getViewPortPxFromLonLat(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/Marker.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Events.js
- * @requires OpenLayers/Icon.js
- *
- * Class: OpenLayers.Marker
- * Instances of OpenLayers.Marker are a combination of a
- * <OpenLayers.LonLat> and an <OpenLayers.Icon>.
- *
- * Markers are generally added to a special layer called
- * <OpenLayers.Layer.Markers>.
- *
- * Example:
- * (code)
- * var markers = new OpenLayers.Layer.Markers( "Markers" );
- * map.addLayer(markers);
- *
- * var size = new OpenLayers.Size(10,17);
- * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
- * var icon = new OpenLayers.Icon('http://boston.openguides.org/markers/AQUA.png',size,offset);
- * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon));
- * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone()));
- *
- * (end)
- *
- * Note that if you pass an icon into the Marker constructor, it will take
- * that icon and use it. This means that you should not share icons between
- * markers -- you use them once, but you should clone() for any additional
- * markers using that same icon.
- */
-OpenLayers.Marker = OpenLayers.Class({
-
- /**
- * Property: icon
- * {<OpenLayers.Icon>} The icon used by this marker.
- */
- icon: null,
-
- /**
- * Property: lonlat
- * {<OpenLayers.LonLat>} location of object
- */
- lonlat: null,
-
- /**
- * Property: events
- * {<OpenLayers.Events>} the event handler.
- */
- events: null,
-
- /**
- * Property: map
- * {<OpenLayers.Map>} the map this marker is attached to
- */
- map: null,
-
- /**
- * Constructor: OpenLayers.Marker
- * Paraemeters:
- * icon - {<OpenLayers.Icon>} the icon for this marker
- * lonlat - {<OpenLayers.LonLat>} the position of this marker
- */
- initialize: function(lonlat, icon) {
- this.lonlat = lonlat;
-
- var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon();
- if (this.icon == null) {
- this.icon = newIcon;
- } else {
- this.icon.url = newIcon.url;
- this.icon.size = newIcon.size;
- this.icon.offset = newIcon.offset;
- this.icon.calculateOffset = newIcon.calculateOffset;
- }
- this.events = new OpenLayers.Events(this, this.icon.imageDiv, null);
- },
-
- /**
- * APIMethod: destroy
- * Destroy the marker. You must first remove the marker from any
- * layer which it has been added to, or you will get buggy behavior.
- * (This can not be done within the marker since the marker does not
- * know which layer it is attached to.)
- */
- destroy: function() {
- this.map = null;
-
- this.events.destroy();
- this.events = null;
-
- if (this.icon != null) {
- this.icon.destroy();
- this.icon = null;
- }
- },
-
- /**
- * Method: draw
- * Calls draw on the icon, and returns that output.
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {DOMElement} A new DOM Image with this marker's icon set at the
- * location passed-in
- */
- draw: function(px) {
- return this.icon.draw(px);
- },
-
- /**
- * Method: moveTo
- * Move the marker to the new location.
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>} the pixel position to move to
- */
- moveTo: function (px) {
- if ((px != null) && (this.icon != null)) {
- this.icon.moveTo(px);
- }
- this.lonlat = this.map.getLonLatFromLayerPx(px);
- },
-
- /**
- * Method: onScreen
- *
- * Returns:
- * {Boolean} Whether or not the marker is currently visible on screen.
- */
- onScreen:function() {
-
- var onScreen = false;
- if (this.map) {
- var screenBounds = this.map.getExtent();
- onScreen = screenBounds.containsLonLat(this.lonlat);
- }
- return onScreen;
- },
-
- /**
- * Method: inflate
- * Englarges the markers icon by the specified ratio.
- *
- * Parameters:
- * inflate - {float} the ratio to enlarge the marker by (passing 2
- * will double the size).
- */
- inflate: function(inflate) {
- if (this.icon) {
- var newSize = new OpenLayers.Size(this.icon.size.w * inflate,
- this.icon.size.h * inflate);
- this.icon.setSize(newSize);
- }
- },
-
- /**
- * Method: setOpacity
- * Change the opacity of the marker by changin the opacity of
- * its icon
- *
- * Parameters:
- * opacity - {float} Specified as fraction (0.4, etc)
- */
- setOpacity: function(opacity) {
- this.icon.setOpacity(opacity);
- },
-
- /**
- * Method: display
- * Hide or show the icon
- *
- * display - {Boolean}
- */
- display: function(display) {
- this.icon.display(display);
- },
-
- CLASS_NAME: "OpenLayers.Marker"
-});
-
-
-/**
- * Function: defaultIcon
- * Creates a default <OpenLayers.Icon>.
- *
- * Returns:
- * {<OpenLayers.Icon>} A default OpenLayers.Icon to use for a marker
- */
-OpenLayers.Marker.defaultIcon = function() {
- var url = OpenLayers.Util.getImagesLocation() + "marker.png";
- var size = new OpenLayers.Size(21, 25);
- var calculateOffset = function(size) {
- return new OpenLayers.Pixel(-(size.w/2), -size.h);
- };
-
- return new OpenLayers.Icon(url, size, null, calculateOffset);
-};
-
-
-/* ======================================================================
- OpenLayers/Tile/Image.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Tile.js
- *
- * Class: OpenLayers.Tile.Image
- * Instances of OpenLayers.Tile.Image are used to manage the image tiles
- * used by various layers. Create a new image tile with the
- * <OpenLayers.Tile.Image> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Tile>
- */
-OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
-
- /**
- * Property: url
- * {String} The URL of the image being requested. No default. Filled in by
- * layer.getURL() function.
- */
- url: null,
-
- /**
- * Property: imgDiv
- * {DOMElement} The div element which wraps the image.
- */
- imgDiv: null,
-
- /**
- * Property: frame
- * {DOMElement} The image element is appended to the frame. Any gutter on
- * the image will be hidden behind the frame.
- */
- frame: null,
-
- /** TBD 3.0 - reorder the parameters to the init function to remove
- * URL. the getUrl() function on the layer gets called on
- * each draw(), so no need to specify it here.
- *
- * Constructor: OpenLayers.Tile.Image
- * Constructor for a new <OpenLayers.Tile.Image> instance.
- *
- * Parameters:
- * layer - {<OpenLayers.Layer>} layer that the tile will go in.
- * position - {<OpenLayers.Pixel>}
- * bounds - {<OpenLayers.Bounds>}
- * url - {<String>} Deprecated. Remove me in 3.0.
- * size - {<OpenLayers.Size>}
- */
- initialize: function(layer, position, bounds, url, size) {
- OpenLayers.Tile.prototype.initialize.apply(this, arguments);
-
- this.url = url; //deprecated remove me
-
- this.frame = document.createElement('div');
- this.frame.style.overflow = 'hidden';
- this.frame.style.position = 'absolute';
- },
-
- /**
- * APIMethod: destroy
- * nullify references to prevent circular references and memory leaks
- */
- destroy: function() {
- if (this.imgDiv != null) {
- OpenLayers.Event.stopObservingElement(this.imgDiv.id);
- if (this.imgDiv.parentNode == this.frame) {
- this.frame.removeChild(this.imgDiv);
- this.imgDiv.map = null;
- }
- }
- this.imgDiv = null;
- if ((this.frame != null) && (this.frame.parentNode == this.layer.div)) {
- this.layer.div.removeChild(this.frame);
- }
- this.frame = null;
- OpenLayers.Tile.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: draw
- * Check that a tile should be drawn, and draw it.
- *
- * Returns:
- * {Boolean} Always returns true.
- */
- draw:function() {
- if (this.layer != this.layer.map.baseLayer && this.layer.reproject) {
- this.bounds = this.getBoundsFromBaseLayer(this.position);
- }
- if (!OpenLayers.Tile.prototype.draw.apply(this, arguments)) {
- return false;
- }
-
- if (this.isLoading) {
- //if we're already loading, send 'reload' instead of 'loadstart'.
- this.events.triggerEvent("reload");
- } else {
- this.isLoading = true;
- this.events.triggerEvent("loadstart");
- }
-
- if (this.imgDiv == null) {
- this.initImgDiv();
- }
-
- this.imgDiv.viewRequestID = this.layer.map.viewRequestID;
-
- this.url = this.layer.getURL(this.bounds);
- // position the frame
- OpenLayers.Util.modifyDOMElement(this.frame,
- null, this.position, this.size);
-
- var imageSize = this.layer.getImageSize();
- if (this.layer.alpha) {
- OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,
- null, null, imageSize, this.url);
- } else {
- this.imgDiv.src = this.url;
- OpenLayers.Util.modifyDOMElement(this.imgDiv,
- null, null, imageSize) ;
- }
- return true;
- },
-
- /**
- * Method: clear
- * Clear the tile of any bounds/position-related data so that it can
- * be reused in a new location.
- */
- clear: function() {
- if(this.imgDiv) {
- this.imgDiv.style.display = "none";
- }
- },
-
- /**
- * Method: initImgDiv
- * Creates the imgDiv property on the tile.
- */
- initImgDiv: function() {
-
- var offset = this.layer.imageOffset;
- var size = this.layer.getImageSize();
-
- if (this.layer.alpha) {
- this.imgDiv = OpenLayers.Util.createAlphaImageDiv(null,
- offset,
- size,
- null,
- "relative",
- null,
- null,
- null,
- true);
- } else {
- this.imgDiv = OpenLayers.Util.createImage(null,
- offset,
- size,
- null,
- "relative",
- null,
- null,
- true);
- }
-
- this.imgDiv.className = 'olTileImage';
-
- /* checkImgURL used to be used to called as a work around, but it
- ended up hiding problems instead of solving them and broke things
- like relative URLs. See discussion on the dev list:
- http://openlayers.org/pipermail/dev/2007-January/000205.html
-
- OpenLayers.Event.observe( this.imgDiv, "load",
- OpenLayers.Function.bind(this.checkImgURL, this) );
- */
- this.frame.appendChild(this.imgDiv);
- this.layer.div.appendChild(this.frame);
-
- if(this.layer.opacity != null) {
-
- OpenLayers.Util.modifyDOMElement(this.imgDiv, null, null, null,
- null, null, null,
- this.layer.opacity);
- }
-
- // we need this reference to check back the viewRequestID
- this.imgDiv.map = this.layer.map;
-
- //bind a listener to the onload of the image div so that we
- // can register when a tile has finished loading.
- var onload = function() {
-
- //normally isLoading should always be true here but there are some
- // right funky conditions where loading and then reloading a tile
- // with the same url *really*fast*. this check prevents sending
- // a 'loadend' if the msg has already been sent
- //
- if (this.isLoading) {
- this.isLoading = false;
- this.events.triggerEvent("loadend");
- }
- }
- OpenLayers.Event.observe(this.imgDiv, 'load',
- OpenLayers.Function.bind(onload, this));
-
- },
-
- /**
- * Method: checkImgURL
- * Make sure that the image that just loaded is the one this tile is meant
- * to display, since panning/zooming might have changed the tile's URL in
- * the meantime. If the tile URL did change before the image loaded, set
- * the imgDiv display to 'none', as either (a) it will be reset to visible
- * when the new URL loads in the image, or (b) we don't want to display
- * this tile after all because its new bounds are outside our maxExtent.
- *
- * This function should no longer be neccesary with the improvements to
- * Grid.js in OpenLayers 2.3. The lack of a good isEquivilantURL function
- * caused problems in 2.2, but it's possible that with the improved
- * isEquivilant URL function, this might be neccesary at some point.
- *
- * See discussion in the thread at
- * http://openlayers.org/pipermail/dev/2007-January/000205.html
- */
- checkImgURL: function () {
- // Sometimes our image will load after it has already been removed
- // from the map, in which case this check is not needed.
- if (this.layer) {
- var loaded = this.layer.alpha ? this.imgDiv.firstChild.src : this.imgDiv.src;
- if (!OpenLayers.Util.isEquivalentUrl(loaded, this.url)) {
- this.imgDiv.style.display = "none";
- }
- }
- },
-
- /** @final @type String */
- CLASS_NAME: "OpenLayers.Tile.Image"
- }
-);
-/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the clear BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/license.txt
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Handler.js
- */
-
-/**
- * Class: OpenLayers.Handler.Click
- * A handler for mouse clicks. The intention of this handler is to give
- * controls more flexibility with handling clicks. Browsers trigger
- * click events twice for a double-click. In addition, the mousedown,
- * mousemove, mouseup sequence fires a click event. With this handler,
- * controls can decide whether to ignore clicks associated with a double
- * click. By setting a <pixelTolerance>, controls can also ignore clicks
- * that include a drag. Create a new instance with the
- * <OpenLayers.Handler.Click> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Handler>
- */
-OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
-
- /**
- * APIProperty: delay
- * {Number} Number of milliseconds between clicks before the event is
- * considered a double-click.
- */
- delay: 300,
-
- /**
- * APIProperty: single
- * {Boolean} Handle single clicks. Default is true. If false, clicks
- * will not be reported. If true, single-clicks will be reported.
- */
- single: true,
-
- /**
- * APIProperty: double
- * {Boolean} Handle double-clicks. Default is false.
- */
- 'double': false,
-
- /**
- * APIProperty: pixelTolerance
- * {Number} Maximum number of pixels between mouseup and mousedown for an
- * event to be considered a click. Default is 0. If set to an
- * integer value, clicks with a drag greater than the value will be
- * ignored. This property can only be set when the handler is
- * constructed.
- */
- pixelTolerance: 0,
-
- /**
- * APIProperty: stopSingle
- * {Boolean} Stop other listeners from being notified of clicks. Default
- * is false. If true, any click listeners registered before this one
- * will not be notified of *any* click event (associated with double
- * or single clicks).
- */
- stopSingle: false,
-
- /**
- * APIProperty: stopDouble
- * {Boolean} Stop other listeners from being notified of double-clicks.
- * Default is false. If true, any click listeners registered before
- * this one will not be notified of *any* double-click events.
- *
- * The one caveat with stopDouble is that given a map with two click
- * handlers, one with stopDouble true and the other with stopSingle
- * true, the stopSingle handler should be activated last to get
- * uniform cross-browser performance. Since IE triggers one click
- * with a dblclick and FF triggers two, if a stopSingle handler is
- * activated first, all it gets in IE is a single click when the
- * second handler stops propagation on the dblclick.
- */
- stopDouble: false,
-
- /**
- * Property: timerId
- * {Number} The id of the timeout waiting to clear the <delayedEvent>.
- */
- timerId: null,
-
- /**
- * Property: down
- * {<OpenLayers.Pixel>} The pixel location of the last mousedown.
- */
- down: null,
-
- /**
- * Constructor: OpenLayers.Handler.Click
- * Create a new click handler.
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that is making use of
- * this handler. If a handler is being used without a control, the
- * handler's setMap method must be overridden to deal properly with
- * the map.
- * callbacks - {Object} An object with keys corresponding to callbacks
- * that will be called by the handler. The callbacks should
- * expect to recieve a single argument, the click event.
- * Callbacks for 'click' and 'dblclick' are supported.
- * options - {Object} Optional object whose properties will be set on the
- * handler.
- */
- initialize: function(control, callbacks, options) {
- OpenLayers.Handler.prototype.initialize.apply(this, arguments);
- // optionally register for mouseup and mousedown
- if(this.pixelTolerance != null) {
- this.mousedown = function(evt) {
- this.down = evt.xy;
- return true;
- };
- }
- },
-
- /**
- * Method: mousedown
- * Handle mousedown. Only registered as a listener if pixelTolerance is
- * a non-zero value at construction.
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- mousedown: null,
-
- /**
- * Method: dblclick
- * Handle dblclick. For a dblclick, we get two clicks in some browsers
- * (FF) and one in others (IE). So we need to always register for
- * dblclick to properly handle single clicks.
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- dblclick: function(evt) {
- if(this.passesTolerance(evt)) {
- if(this["double"]) {
- this.callback('dblclick', [evt]);
- }
- this.clearTimer();
- }
- return !this.stopDouble;
- },
-
- /**
- * Method: click
- * Handle click.
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- click: function(evt) {
- if(this.passesTolerance(evt)) {
- if(this.timerId != null) {
- // already received a click
- this.clearTimer();
- } else {
- // set the timer, send evt only if single is true
- var clickEvent = this.single ? OpenLayers.Util.extend({},evt):null;
- this.timerId = window.setTimeout(
- OpenLayers.Function.bind(this.delayedCall, this, clickEvent),
- this.delay
- );
- }
- }
- return !this.stopSingle;
- },
-
- /**
- * Method: passesTolerance
- * Determine whether the event is within the optional pixel tolerance. Note
- * that the pixel tolerance check only works if mousedown events get to
- * the listeners registered here. If they are stopped by other elements,
- * the <pixelTolerance> will have no effect here (this method will always
- * return true).
- *
- * Returns:
- * {Boolean} The click is within the pixel tolerance (if specified).
- */
- passesTolerance: function(evt) {
- var passes = true;
- if(this.pixelTolerance != null && this.down) {
- var dpx = Math.sqrt(
- Math.pow(this.down.x - evt.xy.x, 2) +
- Math.pow(this.down.y - evt.xy.y, 2)
- );
- if(dpx > this.pixelTolerance) {
- passes = false;
- }
- }
- return passes;
- },
-
- /**
- * Method: clearTimer
- * Clear the timer and set <timerId> to null.
- */
- clearTimer: function() {
- if(this.timerId != null) {
- window.clearTimeout(this.timerId);
- this.timerId = null;
- }
- },
-
- /**
- * Method: delayedCall
- * Sets <timerId> to null. And optionally triggers the click callback if
- * evt is set.
- */
- delayedCall: function(evt) {
- this.timerId = null;
- if(evt) {
- this.callback('click', [evt]);
- }
- },
-
- /**
- * APIMethod: deactivate
- * Deactivate the handler.
- *
- * Returns:
- * {Boolean} The handler was successfully deactivated.
- */
- deactivate: function() {
- var deactivated = false;
- if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
- this.clearTimer();
- this.down = null;
- deactivated = true;
- }
- return deactivated;
- },
-
- CLASS_NAME: "OpenLayers.Handler.Click"
-});
-/* ======================================================================
- OpenLayers/Handler/Drag.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Handler.js
- *
- * Class: OpenLayers.Handler.Drag
- * The drag handler is used to deal with sequences of browser events related
- * to dragging. The handler is used by controls that want to know when
- * a drag sequence begins, when a drag is happening, and when it has
- * finished.
- *
- * Controls that use the drag handler typically construct it with callbacks
- * for 'down', 'move', and 'done'. Callbacks for these keys are called
- * when the drag begins, with each move, and when the drag is done. In
- * addition, controls can have callbacks keyed to 'up' and 'out' if they
- * care to differentiate between the types of events that correspond with
- * the end of a drag sequence.
- *
- * Create a new drag handler with the <OpenLayers.Handler.Drag> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Handler>
- */
-OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, {
-
- /**
- * Property: started
- * {Boolean} When a mousedown event is received, we want to record it, but
- * not set 'dragging' until the mouse moves after starting.
- */
- started: false,
-
- /**
- * Property: dragging
- * {Boolean}
- */
- dragging: false,
-
- /**
- * Property: last
- * {<OpenLayers.Pixel>} The last pixel location of the drag.
- */
- last: null,
-
- /**
- * Property: start
- * {<OpenLayers.Pixel>} The first pixel location of the drag.
- */
- start: null,
-
- /**
- * Property: oldOnselectstart
- * {Function}
- */
- oldOnselectstart: null,
-
- /**
- * Constructor: OpenLayers.Handler.Drag
- * Returns OpenLayers.Handler.Drag
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that is making use of
- * this handler. If a handler is being used without a control, the
- * handlers setMap method must be overridden to deal properly with
- * the map.
- * callbacks - {Object} An object containing a single function to be
- * called when the drag operation is finished. The callback should
- * expect to recieve a single argument, the pixel location of the event.
- * Callbacks for 'move' and 'done' are supported. You can also speficy
- * callbacks for 'down', 'up', and 'out' to respond to those events.
- * options - {Object}
- */
- initialize: function(control, callbacks, options) {
- OpenLayers.Handler.prototype.initialize.apply(this, arguments);
- },
-
- /**
- * The four methods below (down, move, up, and out) are used by subclasses
- * to do their own processing related to these mouse events.
- */
-
- /**
- * Method: down
- * This method is called during the handling of the mouse down event.
- * Subclasses can do their own processing here.
- *
- * Parameters:
- * evt - {Event} The mouse down event
- */
- down: function(evt) {
- },
-
- /**
- * Method: move
- * This method is called during the handling of the mouse move event.
- * Subclasses can do their own processing here.
- *
- * Parameters:
- * evt - {Event} The mouse move event
- *
- */
- move: function(evt) {
- },
-
- /**
- * Method: up
- * This method is called during the handling of the mouse up event.
- * Subclasses can do their own processing here.
- *
- * Parameters:
- * evt - {Event} The mouse up event
- */
- up: function(evt) {
- },
-
- /**
- * Method: out
- * This method is called during the handling of the mouse out event.
- * Subclasses can do their own processing here.
- *
- * Parameters:
- * evt - {Event} The mouse out event
- */
- out: function(evt) {
- },
-
- /**
- * The methods below are part of the magic of event handling. Because
- * they are named like browser events, they are registered as listeners
- * for the events they represent.
- */
-
- /**
- * Method: mousedown
- * Handle mousedown events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- mousedown: function (evt) {
- var propagate = true;
- this.dragging = false;
- if (this.checkModifiers(evt) && OpenLayers.Event.isLeftClick(evt)) {
- this.started = true;
- this.start = evt.xy;
- this.last = evt.xy;
- // TBD replace with CSS classes
- this.map.div.style.cursor = "move";
- this.down(evt);
- this.callback("down", [evt.xy]);
- OpenLayers.Event.stop(evt);
-
- if(!this.oldOnselectstart) {
- this.oldOnselectstart = document.onselectstart;
- document.onselectstart = function() {return false;}
- }
-
- propagate = false;
- } else {
- this.started = false;
- this.start = null;
- this.last = null;
- }
- return propagate;
- },
-
- /**
- * Method: mousemove
- * Handle mousemove events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- mousemove: function (evt) {
- if (this.started) {
- if(evt.xy.x != this.last.x || evt.xy.y != this.last.y) {
- this.dragging = true;
- this.move(evt);
- this.callback("move", [evt.xy]);
- if(!this.oldOnselectstart) {
- this.oldOnselectstart = document.onselectstart;
- document.onselectstart = function() {return false;}
- }
- this.last = evt.xy;
- }
- }
- return true;
- },
-
- /**
- * Method: mouseup
- * Handle mouseup events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- mouseup: function (evt) {
- if (this.started) {
- this.started = false;
- this.dragging = false;
- // TBD replace with CSS classes
- this.map.div.style.cursor = "";
- this.up(evt);
- this.callback("up", [evt.xy]);
- this.callback("done", [evt.xy]);
- document.onselectstart = this.oldOnselectstart;
- }
- return true;
- },
-
- /**
- * Method: mouseout
- * Handle mouseout events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- mouseout: function (evt) {
- if (this.started && OpenLayers.Util.mouseLeft(evt, this.map.div)) {
- this.started = false;
- this.dragging = false;
- // TBD replace with CSS classes
- this.map.div.style.cursor = "";
- this.out(evt);
- this.callback("out", []);
- if(document.onselectstart) {
- document.onselectstart = this.oldOnselectstart;
- }
- this.callback("done", [evt.xy])
- }
- return true;
- },
-
- /**
- * Method: click
- * The drag handler captures the click event. If something else registers
- * for clicks on the same element, its listener will not be called
- * after a drag.
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- click: function (evt) {
- // let the click event propagate only if the mouse moved
- return (this.start == this.last);
- },
-
- /**
- * Method: activate
- * Activate the handler.
- *
- * Returns:
- * {Boolean} The handler was successfully activated.
- */
- activate: function() {
- var activated = false;
- if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
- this.dragging = false;
- activated = true;
- }
- return activated;
- },
-
- /**
- * Method: deactivate
- * Deactivate the handler.
- *
- * Returns:
- * {Boolean} The handler was successfully deactivated.
- */
- deactivate: function() {
- var deactivated = false;
- if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
- this.started = false;
- this.dragging = false;
- this.start = null;
- this.last = null;
- deactivated = true;
- }
- return deactivated;
- },
-
- CLASS_NAME: "OpenLayers.Handler.Drag"
-});
-/* ======================================================================
- OpenLayers/Handler/MouseWheel.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Handler.js
- *
- * Class: OpenLayers.Handler.MouseWheel
- * Handler for wheel up/down events.
- *
- * Inherits from:
- * - <OpenLayers.Handler>
- */
-OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, {
- /**
- * Property: wheelListener
- * {function}
- */
- wheelListener: null,
-
- /**
- * Property: mousePosition
- * {<OpenLayers.Pixel>} mousePosition is necessary because
- * evt.clientX/Y is buggy in Moz on wheel events, so we cache and use the
- * value from the last mousemove.
- */
- mousePosition: null,
-
- /**
- * Constructor: OpenLayers.Handler.MouseWheel
- *
- * Parameters:
- * control - {<OpenLayers.Control>}
- * callbacks - {Object} An object containing a single function to be
- * called when the drag operation is finished.
- * The callback should expect to recieve a single
- * argument, the point geometry.
- * options - {Object}
- */
- initialize: function(control, callbacks, options) {
- OpenLayers.Handler.prototype.initialize.apply(this, arguments);
- this.wheelListener = OpenLayers.Function.bindAsEventListener(
- this.onWheelEvent, this
- );
- },
-
- /**
- * Method: destroy
- */
- destroy: function() {
- OpenLayers.Handler.prototype.destroy.apply(this, arguments);
- this.wheelListener = null;
- },
-
- /**
- * Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/
- */
-
- /**
- * Method: onWheelEvent
- * Catch the wheel event and handle it xbrowserly
- *
- * Parameters:
- * e - {Event}
- */
- onWheelEvent: function(e){
- // first check keyboard modifiers
- if (!this.checkModifiers(e)) return;
-
- // first determine whether or not the wheeling was inside the map
- var inMap = false;
- var elem = OpenLayers.Event.element(e);
- while(elem != null) {
- if (this.map && elem == this.map.div) {
- inMap = true;
- break;
- }
- elem = elem.parentNode;
- }
-
- if (inMap) {
- var delta = 0;
- if (!e) {
- e = window.event;
- }
- if (e.wheelDelta) {
- delta = e.wheelDelta/120;
- if (window.opera) {
- delta = -delta;
- }
- } else if (e.detail) {
- delta = -e.detail / 3;
- }
- if (delta) {
- // add the mouse position to the event because mozilla has a bug
- // with clientX and clientY (see https://bugzilla.mozilla.org/show_bug.cgi?id=352179)
- // getLonLatFromViewPortPx(e) returns wrong values
- if (this.mousePosition) {
- e.xy = this.mousePosition;
- }
- if (!e.xy) {
- // If the mouse hasn't moved over the map yet, then
- // we don't have a mouse position (in FF), so we just
- // act as if the mouse was at the center of the map.
- // Note that we can tell we are in the map -- and
- // this.map is ensured to be true above.
- e.xy = this.map.getPixelFromLonLat(this.map.getCenter());
- }
- if (delta < 0) {
- this.callback("down", [e, delta]);
- } else {
- this.callback("up", [e, delta]);
- }
- }
-
- //only wheel the map, not the window
- OpenLayers.Event.stop(e);
- }
- },
-
- /**
- * Method: mousemove
- * Update the stored mousePosition on every move.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- mousemove: function (evt) {
- this.mousePosition = evt.xy;
- },
-
- /**
- * Method: activate
- */
- activate: function (evt) {
- if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
- //register mousewheel events specifically on the window and document
- var wheelListener = this.wheelListener;
- OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener);
- OpenLayers.Event.observe(window, "mousewheel", wheelListener);
- OpenLayers.Event.observe(document, "mousewheel", wheelListener);
- return true;
- } else {
- return false;
- }
- },
-
- /**
- * Method: deactivate
- */
- deactivate: function (evt) {
- if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
- // unregister mousewheel events specifically on the window and document
- var wheelListener = this.wheelListener;
- OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener);
- OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener);
- OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener);
- return true;
- } else {
- return false;
- }
- },
-
- CLASS_NAME: "OpenLayers.Handler.MouseWheel"
-});
-/* ======================================================================
- OpenLayers/Layer.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Map.js
- *
- * Class: OpenLayers.Layer
- */
-OpenLayers.Layer = OpenLayers.Class({
-
- /**
- * APIProperty: id
- * {String}
- */
- id: null,
-
- /**
- * APIProperty: name
- * {String}
- */
- name: null,
-
- /**
- * APIProperty: div
- * {DOMElement}
- */
- div: null,
-
- /**
- * Constant: EVENT_TYPES
- * {Array(String)} Supported application event types
- */
- EVENT_TYPES: [ "loadstart", "loadend", "loadcancel", "visibilitychanged"],
-
- /**
- * APIProperty: events``
- * {<OpenLayers.Events>}
- */
- events: null,
-
- /**
- * APIProperty: map
- * {<OpenLayers.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
- * <OpenLayers.Control.Attribution> 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 <OpenLayers.Map.setCenter> whenever the zoom
- * changes.
- */
- inRange: false,
-
- /**
- * Propery: imageSize
- * {<OpenLayers.Size>} For layers with a gutter, the image is larger than
- * the tile by twice the gutter in each dimension.
- */
- imageSize: null,
-
- /**
- * Property: imageOffset
- * {<OpenLayers.Pixel>} For layers with a gutter, the image offset
- * represents displacement due to the gutter.
- */
- imageOffset: 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: 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
- * {String} Set in the layer options to override the default projection
- * string this layer - also set maxExtent, maxResolution, and units if
- * appropriate.
- */
- projection: null,
-
- /**
- * APIProperty: units
- * {String} The layer map units. Defaults to 'degrees'. Possible values
- * are 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
- */
- 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 <resolutions> 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
- * {<OpenLayers.Bounds>} The center of these bounds will not stray outside
- * of the viewport extent during panning. In addition, if
- * <displayOutsideMaxExtent> is set to false, data will not be
- * requested that falls completely outside of these bounds.
- */
- maxExtent: null,
-
- /**
- * APIProperty: minExtent
- * {<OpenLayers.Bounds>}
- */
- 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 a geographic projection 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} #487 for more info.
- */
- wrapDateLine: false,
-
-
- /**
- * 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.addOptions(options);
-
- this.name = name;
-
- if (this.id == null) {
-
- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
-
- this.div = OpenLayers.Util.createDiv();
- this.div.style.width = "100%";
- this.div.style.height = "100%";
- this.div.id = this.id;
-
- this.events = new OpenLayers.Events(this, this.div,
- this.EVENT_TYPES);
- }
-
- if (this.wrapDateLine) {
- this.displayOutsideMaxExtent = true;
- }
- },
-
- /**
- * 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.map = null;
- this.name = null;
- this.div = null;
- this.options = null;
-
- if (this.events) {
- this.events.destroy();
- }
- this.events = null;
- },
-
- /**
- * Method: clone
- *
- * Parameters:
- * obj - {<OpenLayers.Layer>} The layer to be cloned
- *
- * Returns:
- * {<OpenLayers.Layer>} An exact clone of this <OpenLayers.Layer>
- */
- clone: function (obj) {
-
- if (obj == null) {
- obj = new OpenLayers.Layer(this.name, this.options);
- }
-
- // 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;
- },
-
- /**
- * 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");
- }
- }
- },
-
- /**
- * APIMethod: addOptions
- *
- * Parameters:
- * newOptions - {Object}
- */
- addOptions: function (newOptions) {
-
- if (this.options == null) {
- this.options = {};
- }
-
- // update our copy for clone
- OpenLayers.Util.extend(this.options, newOptions);
-
- // add new options to this
- OpenLayers.Util.extend(this, newOptions);
- },
-
- /**
- * 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) {
- this.moveTo(extent, true, false);
- redrawn = true;
- }
- }
- return redrawn;
- },
-
- /**
- * Method: moveTo
- *
- * Parameters:
- * bound - {<OpenLayers.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: 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 - {<OpenLayers.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.projection = this.projection || this.map.projection;
-
- if (this.projection && 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();
- }
- },
-
- /**
- * 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 - {<OpenLayers.Map>}
- */
- removeMap: function(map) {
- //to be overridden by subclasses
- },
-
- /**
- * APIMethod: getImageSize
- *
- * Returns:
- * {<OpenLayers.Size>} The size that the image should be, taking into
- * account gutters.
- */
- getImageSize: function() {
- return (this.imageSize || this.tileSize);
- },
-
- /**
- * APIMethod: setTileSize
- * Set the tile size based on the map size. This also sets layer.imageSize
- * and layer.imageOffset for use by Tile.Image.
- *
- * Parameters:
- * size - {<OpenLayers.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.imageOffset = new OpenLayers.Pixel(-this.gutter,
- -this.gutter);
- 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:
- * visible - {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");
- }
- this.events.triggerEvent("visibilitychanged");
- }
- },
-
- /**
- * APIMethod: display
- * Hide or show the Layer
- *
- * Parameters:
- * display - {Boolean}
- */
- display: function(display) {
- if (display != (this.div.style.display != "none")) {
- this.div.style.display = (display) ? "block" : "none";
- }
- },
-
- /**
- * Method: calculateInRange
- *
- * Returns:
- * {Boolean} The layer is displayable at the current map's current
- * resolution.
- */
- calculateInRange: function() {
- var inRange = false;
- 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("changelayer");
- }
- }
- },
-
- /********************************************************/
- /* */
- /* 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() {
-
- // These are the relevant options which are used for calculating
- // resolutions information.
- //
- var props = new Array(
- 'projection', 'units',
- 'scales', 'resolutions',
- 'maxScale', 'minScale',
- 'maxResolution', 'minResolution',
- 'minExtent', 'maxExtent',
- 'numZoomLevels', 'maxZoomLevel'
- );
-
- // First we create a new object where we will store all of the
- // resolution-related properties that we find in either the layer's
- // 'options' array or from the map.
- //
- var confProps = {};
- for(var i=0; i < props.length; i++) {
- var property = props[i];
- confProps[property] = this.options[property] || this.map[property];
- }
-
- // If numZoomLevels hasn't been set and the maxZoomLevel *has*,
- // then use maxZoomLevel to calculate numZoomLevels
- //
- if ( (!confProps.numZoomLevels) && (confProps.maxZoomLevel) ) {
- confProps.numZoomLevels = confProps.maxZoomLevel + 1;
- }
-
- // First off, we take whatever hodge-podge of values we have and
- // calculate/distill them down into a resolutions[] array
- //
- if ((confProps.scales != null) || (confProps.resolutions != null)) {
- //preset levels
- if (confProps.scales != null) {
- confProps.resolutions = [];
- for(var i = 0; i < confProps.scales.length; i++) {
- var scale = confProps.scales[i];
- confProps.resolutions[i] =
- OpenLayers.Util.getResolutionFromScale(scale,
- confProps.units);
- }
- }
- confProps.numZoomLevels = confProps.resolutions.length;
-
- } else {
- //maxResolution and numZoomLevels based calculation
-
- confProps.resolutions = [];
-
- // determine maxResolution
- if (confProps.minScale) {
- confProps.maxResolution =
- OpenLayers.Util.getResolutionFromScale(confProps.minScale,
- confProps.units);
- } else if (confProps.maxResolution == "auto") {
- var viewSize = this.map.getSize();
- var wRes = confProps.maxExtent.getWidth() / viewSize.w;
- var hRes = confProps.maxExtent.getHeight()/ viewSize.h;
- confProps.maxResolution = Math.max(wRes, hRes);
- }
-
- // determine minResolution
- if (confProps.maxScale != null) {
- confProps.minResolution =
- OpenLayers.Util.getResolutionFromScale(confProps.maxScale);
- } else if ( (confProps.minResolution == "auto") &&
- (confProps.minExtent != null) ) {
- var viewSize = this.map.getSize();
- var wRes = confProps.minExtent.getWidth() / viewSize.w;
- var hRes = confProps.minExtent.getHeight()/ viewSize.h;
- confProps.minResolution = Math.max(wRes, hRes);
- }
-
- // determine numZoomLevels
- if (confProps.minResolution != null) {
- var ratio = confProps.maxResolution / confProps.minResolution;
- confProps.numZoomLevels =
- Math.floor(Math.log(ratio) / Math.log(2)) + 1;
- }
-
- // now we have numZoomLevels and maxResolution,
- // we can populate the resolutions array
- for (var i=0; i < confProps.numZoomLevels; i++) {
- var res = confProps.maxResolution / Math.pow(2, i)
- confProps.resolutions.push(res);
- }
- }
-
- //sort resolutions array ascendingly
- //
- confProps.resolutions.sort( function(a, b) { return(b-a); } );
-
- // now set our newly calculated values back to the layer
- // Note: We specifically do *not* set them to layer.options, which we
- // will preserve as it was when we added this layer to the map.
- // this way cloned layers reset themselves to new map div
- // dimensions)
- //
-
- this.resolutions = confProps.resolutions;
- this.maxResolution = confProps.resolutions[0];
- var lastIndex = confProps.resolutions.length - 1;
- this.minResolution = confProps.resolutions[lastIndex];
-
- this.scales = [];
- for(var i = 0; i < confProps.resolutions.length; i++) {
- this.scales[i] =
- OpenLayers.Util.getScaleFromResolution(confProps.resolutions[i],
- confProps.units);
- }
- this.minScale = this.scales[0];
- this.maxScale = this.scales[this.scales.length - 1];
-
- this.numZoomLevels = confProps.numZoomLevels;
- },
-
- /**
- * APIMethod: getResolution
- *
- * Returns:
- * {Float} The currently selected resolution of the map, taken from the
- * resolutions array, indexed by current zoom level.
- */
- getResolution: function() {
- var zoom = this.map.getZoom();
- return this.resolutions[zoom];
- },
-
- /**
- * APIMethod: getExtent
- *
- * Returns:
- * {<OpenLayers.Bounds>} 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:
- * bounds - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {Integer} The index of the zoomLevel (entry in the resolutions array)
- * that still contains the passed-in extent. We do this by calculating
- * the ideal resolution for the given exteng (based on the map size)
- * and then find the closest resolution to this ideal resolution.
- */
- getZoomForExtent: function(extent) {
- var viewSize = this.map.getSize();
- var idealResolution = Math.max( extent.getWidth() / viewSize.w,
- extent.getHeight() / viewSize.h );
-
- return this.getZoomForResolution(idealResolution);
- },
-
- /**
- * Method: getDataExtent
- * Calculates the max extent which includes all of the data for the layer.
- * This function is to be implemented by subclasses.
- *
- * Returns:
- * {<OpenLayers.Bounds>}
- */
- getDataExtent: function () {
- //to be implemented by subclasses
- },
-
- /**
- * APIMethod: getZoomForResolution
- * Get the index for the closest resolution in the layers resolutions array.
- *
- * Parameters:
- * resolution - {Float} Map units per pixel.
- *
- * Returns:
- * {Integer} The index of the zoomLevel (entry in the resolutions array)
- * that is the closest to the passed-in resolution.
- */
- getZoomForResolution: function(resolution) {
- var zoom, diff;
- var minDiff = Number.POSITIVE_INFINITY;
- for(var i=0; i < this.resolutions.length; i++) {
- diff = Math.abs(this.resolutions[i] - resolution);
- if(diff < minDiff) {
- zoom = i;
- minDiff = diff;
- } else if(diff > minDiff) {
- break;
- }
- }
- return zoom;
- },
-
- /**
- * APIMethod: getLonLatFromViewPortPx
- *
- * Parameters:
- * viewPortPx - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in
- * view port <OpenLayers.Pixel>, translated into lon/lat by the layer.
- */
- getLonLatFromViewPortPx: function (viewPortPx) {
- var lonlat = null;
- if (viewPortPx != null) {
- var size = this.map.getSize();
- var center = this.map.getCenter();
- if (center) {
- var res = this.map.getResolution();
-
- var delta_x = viewPortPx.x - (size.w / 2);
- var delta_y = viewPortPx.y - (size.h / 2);
-
- lonlat = new OpenLayers.LonLat(center.lon + delta_x * res ,
- center.lat - delta_y * res);
-
- if (this.wrapDateLine) {
- lonlat = lonlat.wrapDateLine(this.maxExtent);
- }
- } // else { DEBUG STATEMENT }
- }
- return lonlat;
- },
-
- /**
- * APIMethod: getViewPortPxFromLonLat
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>}
- *
- * Returns:
- * {<OpenLayers.Pixel>} An <OpenLayers.Pixel> which is the passed-in
- * <OpenLayers.LonLat>,translated into view port pixels.
- */
- getViewPortPxFromLonLat: function (lonlat) {
- var px = null;
- if (lonlat != null) {
- var resolution = this.map.getResolution();
- var extent = this.map.getExtent();
- px = new OpenLayers.Pixel(
- Math.round(1/resolution * (lonlat.lon - extent.left)),
- Math.round(1/resolution * (extent.top - lonlat.lat))
- );
- }
- return px;
- },
-
- /**
- * APIMethod: setOpacity
- * Sets the opacity for the entire layer (all images)
- *
- * Parameter:
- * opacity - {Float}
- */
- setOpacity: function(opacity) {
- if (opacity != this.opacity) {
- this.opacity = opacity;
- for(var i=0; i<this.div.childNodes.length; ++i) {
- var element = this.div.childNodes[i].firstChild;
- OpenLayers.Util.modifyDOMElement(element, null, null, null,
- null, null, null, opacity);
- }
- }
- },
-
- /**
- * 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 - {<OpenLayers.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()
- };
- bounds = bounds.wrapDateLine(this.maxExtent, wrappingOptions);
-
- }
- return bounds;
- },
-
- CLASS_NAME: "OpenLayers.Layer"
-});
-/* ======================================================================
- OpenLayers/Marker/Box.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Marker.js
- *
- * Class: OpenLayers.Marker.Box
- *
- * Inherits from:
- * - <OpenLayers.Marker>
- */
-OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, {
-
- /**
- * Property: bounds
- * {<OpenLayers.Bounds>}
- */
- bounds: null,
-
- /**
- * Property: div
- * {DOMElement}
- */
- div: null,
-
- /**
- * Constructor: OpenLayers.Marker.Box
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * borderColor - {String}
- * borderWidth - {int}
- */
- initialize: function(bounds, borderColor, borderWidth) {
- this.bounds = bounds;
- this.div = OpenLayers.Util.createDiv();
- this.div.style.overflow = 'hidden';
- this.events = new OpenLayers.Events(this, this.div, null);
- this.setBorder(borderColor, borderWidth);
- },
-
- /**
- * Method: destroy
- */
- destroy: function() {
-
- this.bounds = null;
- this.div = null;
-
- OpenLayers.Marker.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: setBorder
- * Allow the user to change the box's color and border width
- *
- * Parameters:
- * color - {String} Default is "red"
- * width - {int} Default is 2
- */
- setBorder: function (color, width) {
- if (!color) {
- color = "red";
- }
- if (!width) {
- width = 2;
- }
- this.div.style.border = width + "px solid " + color;
- },
-
- /**
- * Method: draw
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- * sz - {<OpenLayers.Size>}
- *
- * Returns:
- * {DOMElement} A new DOM Image with this marker´s icon set at the
- * location passed-in
- */
- draw: function(px, sz) {
- OpenLayers.Util.modifyDOMElement(this.div, null, px, sz);
- return this.div;
- },
-
- /**
- * Method: onScreen
- *
- * Rreturn:
- * {Boolean} Whether or not the marker is currently visible on screen.
- */
- onScreen:function() {
- var onScreen = false;
- if (this.map) {
- var screenBounds = this.map.getExtent();
- onScreen = screenBounds.containsBounds(this.bounds, true, true);
- }
- return onScreen;
- },
-
- /**
- * Method: display
- * Hide or show the icon
- *
- * Parameters:
- * display - {Boolean}
- */
- display: function(display) {
- this.div.style.display = (display) ? "" : "none";
- },
-
- CLASS_NAME: "OpenLayers.Marker.Box"
-});
-
-/* ======================================================================
- OpenLayers/Control/DragPan.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/Handler/Drag.js
- *
- * Class: OpenLayers.Control.DragPan
- * DragPan control.
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * Property: type
- * {OpenLayers.Control.TYPES}
- */
- type: OpenLayers.Control.TYPE_TOOL,
-
- /**
- * Property: panned
- * {Boolean} The map moved.
- */
- panned: false,
-
- /**
- * Method: draw
- * Creates a Drag handler, using <OpenLayers.Control.PanMap.panMap> and
- * <OpenLayers.Control.PanMap.panMapDone> as callbacks.
- */
- draw: function() {
- this.handler = new OpenLayers.Handler.Drag(this,
- {"move": this.panMap, "done": this.panMapDone});
- },
-
- /**
- * Method: panMap
- *
- * Parameters:
- * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
- */
- panMap: function(xy) {
- this.panned = true;
- var deltaX = this.handler.last.x - xy.x;
- var deltaY = this.handler.last.y - xy.y;
- var size = this.map.getSize();
- var newXY = new OpenLayers.Pixel(size.w / 2 + deltaX,
- size.h / 2 + deltaY);
- var newCenter = this.map.getLonLatFromViewPortPx( newXY );
- this.map.setCenter(newCenter, null, this.handler.dragging);
- },
-
- /**
- * Method: panMapDone
- * Finish the panning operation. Only call setCenter (through <panMap>)
- * if the map has actually been moved.
- *
- * Parameters:
- * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
- */
- panMapDone: function(xy) {
- if(this.panned) {
- this.panMap(xy);
- this.panned = false;
- }
- },
-
- CLASS_NAME: "OpenLayers.Control.DragPan"
-});
-/* ======================================================================
- OpenLayers/Handler/Box.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Handler.js
- * @requires OpenLayers/Handler/Drag.js
- *
- * Class: OpenLayers.Handler.Box
- * Handler for dragging a rectangle across the map. Box is displayed
- * on mouse down, moves on mouse move, and is finished on mouse up.
- *
- * Inherits from:
- * - <OpenLayers.Handler>
- */
-OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, {
-
- /**
- * Property: dragHandler
- * {<OpenLayers.Handler.Drag>}
- */
- dragHandler: null,
-
- /**
- * Constructor: OpenLayers.Handler.Box
- *
- * Parameters:
- * control - {<OpenLayers.Control>}
- * callbacks - {Object} An object containing a single function to be
- * called when the drag operation is finished.
- * The callback should expect to recieve a single
- * argument, the point geometry.
- * options - {Object}
- */
- initialize: function(control, callbacks, options) {
- OpenLayers.Handler.prototype.initialize.apply(this, arguments);
- var callbacks = {
- "down": this.startBox,
- "move": this.moveBox,
- "out": this.removeBox,
- "up": this.endBox
- };
- this.dragHandler = new OpenLayers.Handler.Drag(
- this, callbacks, {keyMask: this.keyMask});
- },
-
- /**
- * Method: setMap
- */
- setMap: function (map) {
- OpenLayers.Handler.prototype.setMap.apply(this, arguments);
- if (this.dragHandler) {
- this.dragHandler.setMap(map);
- }
- },
-
- /**
- * Method: startBox
- *
- * Parameters:
- * evt - {Event}
- */
- startBox: function (xy) {
- this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
- this.dragHandler.start,
- null,
- null,
- "absolute",
- "2px solid red");
- this.zoomBox.style.backgroundColor = "white";
- this.zoomBox.style.filter = "alpha(opacity=50)"; // IE
- this.zoomBox.style.opacity = "0.50";
- this.zoomBox.style.fontSize = "1px";
- this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
- this.map.viewPortDiv.appendChild(this.zoomBox);
-
- // TBD: use CSS classes instead
- this.map.div.style.cursor = "crosshair";
- },
-
- /**
- * Method: moveBox
- */
- moveBox: function (xy) {
- var deltaX = Math.abs(this.dragHandler.start.x - xy.x);
- var deltaY = Math.abs(this.dragHandler.start.y - xy.y);
- this.zoomBox.style.width = Math.max(1, deltaX) + "px";
- this.zoomBox.style.height = Math.max(1, deltaY) + "px";
- if (xy.x < this.dragHandler.start.x) {
- this.zoomBox.style.left = xy.x+"px";
- }
- if (xy.y < this.dragHandler.start.y) {
- this.zoomBox.style.top = xy.y+"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();
-
- // TBD: use CSS classes instead
- this.map.div.style.cursor = "";
-
- 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;
- },
-
- /**
- * Method: activate
- */
- activate: function () {
- if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
- this.dragHandler.activate();
- return true;
- } else {
- return false;
- }
- },
-
- /**
- * Method: deactivate
- */
- deactivate: function () {
- if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
- this.dragHandler.deactivate();
- return true;
- } else {
- return false;
- }
- },
-
- CLASS_NAME: "OpenLayers.Handler.Box"
-});
-/* ======================================================================
- OpenLayers/Layer/HTTPRequest.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Layer.js
- *
- * Class: OpenLayers.Layer.HTTPRequest
- *
- * Inherits from:
- * - <OpenLayers.Layer>
- */
-OpenLayers.Layer.HTTPRequest = OpenLayers.Class(OpenLayers.Layer, {
-
- /**
- * Constant: URL_HASH_FACTOR
- * {Float} Used to hash URL param strings for multi-WMS server selection.
- * Set to the Golden Ratio per Knuth's recommendation.
- */
- URL_HASH_FACTOR: (Math.sqrt(5) - 1) / 2,
-
- /**
- * Property: url
- * {Array(String) or String} This is either an array of url strings or
- * a single url string.
- */
- url: null,
-
- /**
- * Property: params
- * {Object} Hashtable of key/value parameters
- */
- params: null,
-
- /**
- * APIProperty: reproject
- * *Deprecated*. See http://trac.openlayers.org/wiki/SpatialMercator
- * for information on the replacement for this functionality.
- * {Boolean} Whether layer should reproject itself based on base layer
- * locations. This allows reprojection onto commercial layers.
- * Default is false: Most layers can't reproject, but layers
- * which can create non-square geographic pixels can, like WMS.
- *
- */
- reproject: false,
-
- /**
- * Constructor: OpenLayers.Layer.HTTPRequest
- *
- * Parameters:
- * name - {String}
- * url - {Array(String) or String}
- * params - {Object}
- * options - {Object} Hashtable of extra options to tag onto the layer
- */
- initialize: function(name, url, params, options) {
- var newArguments = arguments;
- newArguments = [name, options];
- OpenLayers.Layer.prototype.initialize.apply(this, newArguments);
- this.url = url;
- this.params = OpenLayers.Util.extend( {}, params);
- },
-
- /**
- * APIMethod: destroy
- */
- destroy: function() {
- this.url = null;
- this.params = null;
- OpenLayers.Layer.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * APIMethod: clone
- *
- * Parameters:
- * obj - {Object}
- *
- * Returns:
- * {<OpenLayers.Layer.HTTPRequest>} An exact clone of this
- * <OpenLayers.Layer.HTTPRequest>
- */
- clone: function (obj) {
-
- if (obj == null) {
- obj = new OpenLayers.Layer.HTTPRequest(this.name,
- this.url,
- this.params,
- this.options);
- }
-
- //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}
- */
- mergeNewParams:function(newParams) {
- this.params = OpenLayers.Util.extend(this.params, newParams);
- this.redraw();
- },
-
- /**
- * 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; i < paramString.length; i++) {
- product *= paramString.charCodeAt(i) * this.URL_HASH_FACTOR;
- product -= Math.floor(product);
- }
- return urls[Math.floor(product * urls.length)];
- },
-
- /**
- * Method: getFullRequestString
- * Combine url with layer's params and these newParams.
- *
- * does checking on the serverPath variable, allowing for cases when it
- * is supplied with trailing ? or &, as well as cases where not.
- *
- * return in formatted string like this:
- * "server?key1=value1&key2=value2&key3=value3"
- *
- * WARNING: The altUrl parameter is deprecated and will be removed in 3.0.
- *
- * Parameters:
- * newParams - {Object}
- * altUrl - {String} Use this as the url instead of the layer's url
- *
- * Returns:
- * {String}
- */
- getFullRequestString:function(newParams, altUrl) {
-
- // if not altUrl passed in, use layer's url
- var url = altUrl || this.url;
-
- // create a new params hashtable with all the layer params and the
- // new params together. then convert to string
- var allParams = OpenLayers.Util.extend({}, this.params);
- allParams = OpenLayers.Util.extend(allParams, newParams);
- var paramsString = OpenLayers.Util.getParameterString(allParams);
-
- // if url is not a string, it should be an array of strings,
- // in which case we will deterministically select one of them in
- // order to evenly distribute requests to different urls.
- //
- if (url instanceof Array) {
- url = this.selectUrl(paramsString, url);
- }
-
- // ignore parameters that are already in the url search string
- var urlParams =
- OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));
- for(var key in allParams) {
- if(key.toUpperCase() in urlParams) {
- delete allParams[key];
- }
- }
- paramsString = OpenLayers.Util.getParameterString(allParams);
-
- // requestString always starts with url
- var requestString = url;
-
- if (paramsString != "") {
- var lastServerChar = url.charAt(url.length - 1);
- if ((lastServerChar == "&") || (lastServerChar == "?")) {
- requestString += paramsString;
- } else {
- if (url.indexOf('?') == -1) {
- //serverPath has no ? -- add one
- requestString += '?' + paramsString;
- } else {
- //serverPath contains ?, so must already have
- // paramsString at the end
- requestString += '&' + paramsString;
- }
- }
- }
- return requestString;
- },
-
- CLASS_NAME: "OpenLayers.Layer.HTTPRequest"
-});
-/* ======================================================================
- OpenLayers/Layer/Markers.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Layer.js
- *
- * Class: OpenLayers.Layer.Markers
- *
- * Inherits from:
- * - <OpenLayers.Layer>
- */
-OpenLayers.Layer.Markers = OpenLayers.Class(OpenLayers.Layer, {
-
- /**
- * APIProperty: isBaseLayer
- * {Boolean} Markers layer is never a base layer.
- */
- isBaseLayer: false,
-
- /**
- * Property: markers
- * Array({<OpenLayers.Marker>}) internal marker list
- */
- markers: null,
-
-
- /**
- * Property: drawn
- * {Boolean} internal state of drawing. This is a workaround for the fact
- * that the map does not call moveTo with a zoomChanged when the map is
- * first starting up. This lets us catch the case where we have *never*
- * drawn the layer, and draw it even if the zoom hasn't changed.
- */
- drawn: false,
-
- /**
- * Constructor: OpenLayers.Layer.Markers
- * Create a Markers layer.
- *
- * Parameters:
- * name - {String}
- * options - {Object} Hashtable of extra options to tag onto the layer
- */
- initialize: function(name, options) {
- OpenLayers.Layer.prototype.initialize.apply(this, arguments);
- this.markers = [];
- },
-
- /**
- * APIMethod: destroy
- */
- destroy: function() {
- this.clearMarkers();
- this.markers = null;
- OpenLayers.Layer.prototype.destroy.apply(this, arguments);
- },
-
-
- /**
- * Method: moveTo
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * zoomChanged - {Boolean}
- * dragging - {Boolean}
- */
- moveTo:function(bounds, zoomChanged, dragging) {
- OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
-
- if (zoomChanged || !this.drawn) {
- for(i=0; i < this.markers.length; i++) {
- this.drawMarker(this.markers[i]);
- }
- this.drawn = true;
- }
- },
-
- /**
- * APIMethod: addMarker
- *
- * Parameters:
- * marker - {<OpenLayers.Marker>}
- */
- addMarker: function(marker) {
- this.markers.push(marker);
- if (this.map && this.map.getExtent()) {
- marker.map = this.map;
- this.drawMarker(marker);
- }
- },
-
- /**
- * APIMethod: removeMarker
- *
- * Parameters:
- * marker - {<OpenLayers.Marker>}
- */
- removeMarker: function(marker) {
- OpenLayers.Util.removeItem(this.markers, marker);
- if ((marker.icon != null) && (marker.icon.imageDiv != null) &&
- (marker.icon.imageDiv.parentNode == this.div) ) {
- this.div.removeChild(marker.icon.imageDiv);
- marker.drawn = false;
- }
- },
-
- /**
- * Method: clearMarkers
- * This method removes all markers from a layer. The markers are not
- * destroyed by this function, but are removed from the list of markers.
- */
- clearMarkers: function() {
- if (this.markers != null) {
- while(this.markers.length > 0) {
- this.removeMarker(this.markers[0]);
- }
- }
- },
-
- /**
- * Method: drawMarker
- * Calculate the pixel location for the marker, create it, and
- * add it to the layer's div
- *
- * Parameters:
- * marker - {<OpenLayers.Marker>}
- */
- drawMarker: function(marker) {
- var px = this.map.getLayerPxFromLonLat(marker.lonlat);
- if (px == null) {
- marker.display(false);
- } else {
- var markerImg = marker.draw(px);
- if (!marker.drawn) {
- this.div.appendChild(markerImg);
- marker.drawn = true;
- }
- }
- },
-
- /**
- * APIMethod: getDataExtent
- * Calculates the max extent which includes all of the markers.
- *
- * Returns:
- * {<OpenLayers.Bounds>}
- */
- getDataExtent: function () {
- var maxExtent = null;
-
- if ( this.markers && (this.markers.length > 0)) {
- var maxExtent = new OpenLayers.Bounds();
- for(var i=0; i < this.markers.length; i++) {
- var marker = this.markers[i];
- maxExtent.extend(marker.lonlat);
- }
- }
-
- return maxExtent;
- },
-
- CLASS_NAME: "OpenLayers.Layer.Markers"
-});
-/* ======================================================================
- OpenLayers/Control/ZoomBox.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/Handler/Box.js
- *
- * Class: OpenLayers.Control.ZoomBox
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, {
- /**
- * Property: type
- * {OpenLayers.Control.TYPE}
- */
- type: OpenLayers.Control.TYPE_TOOL,
-
- /**
- * Method: draw
- */
- draw: function() {
- this.handler = new OpenLayers.Handler.Box( this,
- {done: this.zoomBox}, {keyMask: this.keyMask} );
- },
-
- /**
- * Method: zoomBox
- *
- * Parameters:
- * position - {<OpenLayers.Bounds>} or {<OpenLayers.Pixel>}
- */
- zoomBox: function (position) {
- if (position instanceof OpenLayers.Bounds) {
- var minXY = this.map.getLonLatFromPixel(
- new OpenLayers.Pixel(position.left, position.bottom));
- var maxXY = this.map.getLonLatFromPixel(
- new OpenLayers.Pixel(position.right, position.top));
- var bounds = new OpenLayers.Bounds(minXY.lon, minXY.lat,
- maxXY.lon, maxXY.lat);
- this.map.zoomToExtent(bounds);
- } else { // it's a pixel
- this.map.setCenter(this.map.getLonLatFromPixel(position),
- this.map.getZoom() + 1);
- }
- },
-
- CLASS_NAME: "OpenLayers.Control.ZoomBox"
-});
-/* ======================================================================
- OpenLayers/Layer/Grid.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Layer/HTTPRequest.js
- *
- * Class: OpenLayers.Layer.Grid
- * Base class for layers that use a lattice of tiles. Create a new grid
- * layer with the <OpenLayers.Layer.Grid> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Layer.HTTPRequest>
- */
-OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
-
- /**
- * APIProperty: tileSize
- * {<OpenLayers.Size>}
- */
- tileSize: null,
-
- /**
- * Property: grid
- * {Array(Array(<OpenLayers.Tile>))} This is an array of rows, each row is
- * an array of tiles.
- */
- grid: null,
-
- /**
- * APIProperty: singleTile
- * {Boolean} Moves the layer into single-tile mode, meaning that one tile
- * will be loaded. The tile's size will be determined by the 'ratio'
- * property. When the tile is dragged such that it does not cover the
- * entire viewport, it is reloaded.
- */
- singleTile: false,
-
- /** APIProperty: ratio
- * {Float} Used only when in single-tile mode, this specifies the
- * ratio of the size of the single tile to the size of the map.
- */
- ratio: 1.5,
-
- /**
- * APIProperty: buffer
- * {Integer} Used only when in gridded mode, this specifies the number of
- * extra rows and colums of tiles on each side which will
- * surround the minimum grid tiles to cover the map.
- */
- buffer: 2,
-
- /**
- * APIProperty: numLoadingTiles
- * {Integer} How many tiles are still loading?
- */
- numLoadingTiles: 0,
-
- /**
- * Constructor: OpenLayers.Layer.Grid
- * Create a new grid layer
- *
- * Parameters:
- * name - {String}
- * url - {String}
- * params - {Object}
- * options - {Object} Hashtable of extra options to tag onto the layer
- */
- initialize: function(name, url, params, options) {
- OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,
- arguments);
-
- //grid layers will trigger 'tileloaded' when each new tile is
- // loaded, as a means of progress update to listeners.
- // listeners can access 'numLoadingTiles' if they wish to keep track
- // of the loading progress
- //
- this.events.addEventType("tileloaded");
-
- this.grid = [];
- },
-
- /**
- * APIMethod: destroy
- * Deconstruct the layer and clear the grid.
- */
- destroy: function() {
- this.clearGrid();
- this.grid = null;
- this.tileSize = null;
- OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: clearGrid
- * Go through and remove all tiles from the grid, calling
- * destroy() on each of them to kill circular references
- */
- clearGrid:function() {
- if (this.grid) {
- for(var iRow=0; iRow < this.grid.length; iRow++) {
- var row = this.grid[iRow];
- for(var iCol=0; iCol < row.length; iCol++) {
- var tile = row[iCol];
- this.removeTileMonitoringHooks(tile);
- tile.destroy();
- }
- }
- this.grid = [];
- }
- },
-
- /**
- * APIMethod: clone
- * Create a clone of this layer
- *
- * Parameters:
- * obj - {Object} Is this ever used?
- *
- * Returns:
- * {<OpenLayers.Layer.Grid>} An exact clone of this OpenLayers.Layer.Grid
- */
- clone: function (obj) {
-
- if (obj == null) {
- obj = new OpenLayers.Layer.Grid(this.name,
- this.url,
- this.params,
- this.options);
- }
-
- //get all additions from superclasses
- obj = OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this, [obj]);
-
- // copy/set any non-init, non-simple values here
- if (this.tileSize != null) {
- obj.tileSize = this.tileSize.clone();
- }
-
- // we do not want to copy reference to grid, so we make a new array
- obj.grid = [];
-
- return obj;
- },
-
- /**
- * Method: moveTo
- * This function is called whenever the map is moved. All the moving
- * of actual 'tiles' is done by the map, but moveTo's role is to accept
- * a bounds and make sure the data that that bounds requires is pre-loaded.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * zoomChanged - {Boolean}
- * dragging - {Boolean}
- */
- moveTo:function(bounds, zoomChanged, dragging) {
- OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this, arguments);
-
- bounds = bounds || this.map.getExtent();
-
- if (bounds != null) {
-
- // if grid is empty or zoom has changed, we *must* re-tile
- var forceReTile = !this.grid.length || zoomChanged;
-
- // total bounds of the tiles
- var tilesBounds = this.getTilesBounds();
-
- if (this.singleTile) {
-
- // We want to redraw whenever even the slightest part of the
- // current bounds is not contained by our tile.
- // (thus, we do not specify partial -- its default is false)
- if ( forceReTile ||
- (!dragging && !tilesBounds.containsBounds(bounds))) {
- this.initSingleTile(bounds);
- }
- } else {
-
- // if the bounds have changed such that they are not even
- // *partially* contained by our tiles (IE user has
- // programmatically panned to the other side of the earth)
- // then we want to reTile (thus, partial true).
- //
- if (forceReTile || !tilesBounds.containsBounds(bounds, true)) {
- this.initGriddedTiles(bounds);
- } else {
- //we might have to shift our buffer tiles
- this.moveGriddedTiles(bounds);
- }
- }
- }
- },
-
- /**
- * APIMethod: setTileSize
- * Check if we are in singleTile mode and if so, set the size as a ratio
- * of the map size (as specified by the layer's 'ratio' property).
- *
- * Parameters:
- * size - {<OpenLayers.Size>}
- */
- setTileSize: function(size) {
- if (this.singleTile) {
- var size = this.map.getSize().clone();
- size.h = parseInt(size.h * this.ratio);
- size.w = parseInt(size.w * this.ratio);
- }
- OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this, [size]);
- },
-
- /**
- * Method: getGridBounds
- * Deprecated. This function will be removed in 3.0. Please use
- * getTilesBounds() instead.
- *
- * Returns:
- * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
- * currently loaded tiles (including those partially or not at all seen
- * onscreen)
- */
- getGridBounds: function() {
- var msg = "The getGridBounds() function is deprecated. It will be " +
- "removed in 3.0. Please use getTilesBounds() instead.";
- OpenLayers.Console.warn(msg);
- return this.getTilesBounds();
- },
-
- /**
- * APIMethod: getTilesBounds
- * Return the bounds of the tile grid.
- *
- * Returns:
- * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
- * currently loaded tiles (including those partially or not at all seen
- * onscreen).
- */
- getTilesBounds: function() {
- var bounds = null;
-
- if (this.grid.length) {
- var bottom = this.grid.length - 1;
- var bottomLeftTile = this.grid[bottom][0];
-
- var right = this.grid[0].length - 1;
- var topRightTile = this.grid[0][right];
-
- bounds = new OpenLayers.Bounds(bottomLeftTile.bounds.left,
- bottomLeftTile.bounds.bottom,
- topRightTile.bounds.right,
- topRightTile.bounds.top);
-
- }
- return bounds;
- },
-
- /**
- * Method: initSingleTile
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- */
- initSingleTile: function(bounds) {
-
- //determine new tile bounds
- var center = bounds.getCenterLonLat();
- var tileWidth = bounds.getWidth() * this.ratio;
- var tileHeight = bounds.getHeight() * this.ratio;
-
- var tileBounds =
- new OpenLayers.Bounds(center.lon - (tileWidth/2),
- center.lat - (tileHeight/2),
- center.lon + (tileWidth/2),
- center.lat + (tileHeight/2));
-
- var ul = new OpenLayers.LonLat(tileBounds.left, tileBounds.top);
- var px = this.map.getLayerPxFromLonLat(ul);
-
- if (!this.grid.length) {
- this.grid[0] = [];
- }
-
- var tile = this.grid[0][0];
- if (!tile) {
- tile = this.addTile(tileBounds, px);
-
- this.addTileMonitoringHooks(tile);
- tile.draw();
- this.grid[0][0] = tile;
- } else {
- tile.moveTo(tileBounds, px);
- }
-
- //remove all but our single tile
- this.removeExcessTiles(1,1);
- },
-
- /**
- * Method: initGriddedTiles
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- */
- initGriddedTiles:function(bounds) {
-
- // work out mininum number of rows and columns; this is the number of
- // tiles required to cover the viewport plus at least one for panning
-
- var viewSize = this.map.getSize();
- var minRows = Math.ceil(viewSize.h/this.tileSize.h) +
- Math.max(1, 2 * this.buffer);
- var minCols = Math.ceil(viewSize.w/this.tileSize.w) +
- Math.max(1, 2 * this.buffer);
-
- var extent = this.map.getMaxExtent();
- var resolution = this.map.getResolution();
- var tilelon = resolution * this.tileSize.w;
- var tilelat = resolution * this.tileSize.h;
-
- var offsetlon = bounds.left - extent.left;
- var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
- var tilecolremain = offsetlon/tilelon - tilecol;
- var tileoffsetx = -tilecolremain * this.tileSize.w;
- var tileoffsetlon = extent.left + tilecol * tilelon;
-
- var offsetlat = bounds.top - (extent.bottom + tilelat);
- var tilerow = Math.ceil(offsetlat/tilelat) + this.buffer;
- var tilerowremain = tilerow - offsetlat/tilelat;
- var tileoffsety = -tilerowremain * this.tileSize.h;
- var tileoffsetlat = extent.bottom + tilerow * tilelat;
-
- tileoffsetx = Math.round(tileoffsetx); // heaven help us
- tileoffsety = Math.round(tileoffsety);
-
- this.origin = new OpenLayers.Pixel(tileoffsetx, tileoffsety);
-
- var startX = tileoffsetx;
- var startLon = tileoffsetlon;
-
- var rowidx = 0;
-
- 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 -= parseInt(this.map.layerContainerDiv.style.left);
-
- var y = tileoffsety;
- y -= parseInt(this.map.layerContainerDiv.style.top);
-
- var px = new OpenLayers.Pixel(x, y);
- var tile = row[colidx++];
- if (!tile) {
- tile = this.addTile(tileBounds, px);
- this.addTileMonitoringHooks(tile);
- row.push(tile);
- } else {
- tile.moveTo(tileBounds, px, false);
- }
-
- tileoffsetlon += tilelon;
- tileoffsetx += this.tileSize.w;
- } while ((tileoffsetlon <= bounds.right + tilelon * this.buffer)
- || colidx < minCols)
-
- tileoffsetlat -= tilelat;
- tileoffsety += this.tileSize.h;
- } while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer)
- || rowidx < minRows)
-
- //shave off exceess rows and colums
- this.removeExcessTiles(rowidx, colidx);
-
- //now actually draw the tiles
- this.spiralTileLoad();
- },
-
- /**
- * Method: spiralTileLoad
- * Starts at the top right corner of the grid and proceeds in a spiral
- * towards the center, adding tiles one at a time to the beginning of a
- * queue.
- *
- * Once all the grid's tiles have been added to the queue, we go back
- * and iterate through the queue (thus reversing the spiral order from
- * outside-in to inside-out), calling draw() on each tile.
- */
- spiralTileLoad: function() {
- var tileQueue = [];
-
- var directions = ["right", "down", "left", "up"];
-
- var iRow = 0;
- var iCell = -1;
- var direction = OpenLayers.Util.indexOf(directions, "right");
- var directionsTried = 0;
-
- while( directionsTried < directions.length) {
-
- var testRow = iRow;
- var testCell = iCell;
-
- switch (directions[direction]) {
- case "right":
- testCell++;
- break;
- case "down":
- testRow++;
- break;
- case "left":
- testCell--;
- break;
- case "up":
- testRow--;
- break;
- }
-
- // if the test grid coordinates are within the bounds of the
- // grid, get a reference to the tile.
- var tile = null;
- if ((testRow < this.grid.length) && (testRow >= 0) &&
- (testCell < this.grid[0].length) && (testCell >= 0)) {
- tile = this.grid[testRow][testCell];
- }
-
- if ((tile != null) && (!tile.queued)) {
- //add tile to beginning of queue, mark it as queued.
- tileQueue.unshift(tile);
- tile.queued = true;
-
- //restart the directions counter and take on the new coords
- directionsTried = 0;
- iRow = testRow;
- iCell = testCell;
- } else {
- //need to try to load a tile in a different direction
- direction = (direction + 1) % 4;
- directionsTried++;
- }
- }
-
- // now we go through and draw the tiles in forward order
- for(var i=0; i < tileQueue.length; i++) {
- var tile = tileQueue[i];
- tile.draw();
- //mark tile as unqueued for the next time (since tiles are reused)
- tile.queued = false;
- }
- },
-
- /**
- * APIMethod: addTile
- * Gives subclasses of Grid the opportunity to create an
- * OpenLayer.Tile of their choosing. The implementer should initialize
- * the new tile and take whatever steps necessary to display it.
- *
- * Parameters
- * bounds - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {<OpenLayers.Tile>} The added OpenLayers.Tile
- */
- addTile:function(bounds, position) {
- // Should be implemented by subclasses
- },
-
- /**
- * Method: addTileMonitoringHooks
- * This function takes a tile as input and adds the appropriate hooks to
- * the tile so that the layer can keep track of the loading tiles.
- *
- * Parameters:
- * tile - {<OpenLayers.Tile>}
- */
- addTileMonitoringHooks: function(tile) {
-
- tile.onLoadStart = function() {
- //if that was first tile then trigger a 'loadstart' on the layer
- if (this.numLoadingTiles == 0) {
- this.events.triggerEvent("loadstart");
- }
- this.numLoadingTiles++;
- };
- tile.events.register("loadstart", this, tile.onLoadStart);
-
- tile.onLoadEnd = function() {
- this.numLoadingTiles--;
- this.events.triggerEvent("tileloaded");
- //if that was the last tile, then trigger a 'loadend' on the layer
- if (this.numLoadingTiles == 0) {
- this.events.triggerEvent("loadend");
- }
- };
- tile.events.register("loadend", this, tile.onLoadEnd);
- },
-
- /**
- * Method: removeTileMonitoringHooks
- * This function takes a tile as input and removes the tile hooks
- * that were added in addTileMonitoringHooks()
- *
- * Parameters:
- * tile - {<OpenLayers.Tile>}
- */
- removeTileMonitoringHooks: function(tile) {
- tile.events.unregister("loadstart", this, tile.onLoadStart);
- tile.events.unregister("loadend", this, tile.onLoadEnd);
- },
-
- /**
- * Method: moveGriddedTiles
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- */
- moveGriddedTiles: function(bounds) {
- var buffer = this.buffer || 1;
- while (true) {
- var tlLayer = this.grid[0][0].position;
- var tlViewPort =
- this.map.getViewPortPxFromLayerPx(tlLayer);
- if (tlViewPort.x > -this.tileSize.w * (buffer - 1)) {
- this.shiftColumn(true);
- } else if (tlViewPort.x < -this.tileSize.w * buffer) {
- this.shiftColumn(false);
- } else if (tlViewPort.y > -this.tileSize.h * (buffer - 1)) {
- this.shiftRow(true);
- } else if (tlViewPort.y < -this.tileSize.h * buffer) {
- this.shiftRow(false);
- } else {
- break;
- }
- };
- },
-
- /**
- * Method: shiftRow
- * Shifty grid work
- *
- * Parameters:
- * prepend - {Boolean} if true, prepend to beginning.
- * if false, then append to end
- */
- shiftRow:function(prepend) {
- var modelRowIndex = (prepend) ? 0 : (this.grid.length - 1);
- var modelRow = this.grid[modelRowIndex];
-
- var resolution = this.map.getResolution();
- var deltaY = (prepend) ? -this.tileSize.h : this.tileSize.h;
- var deltaLat = resolution * -deltaY;
-
- var row = (prepend) ? this.grid.pop() : this.grid.shift();
-
- for (var i=0; i < modelRow.length; i++) {
- var modelTile = modelRow[i];
- var bounds = modelTile.bounds.clone();
- var position = modelTile.position.clone();
- bounds.bottom = bounds.bottom + deltaLat;
- bounds.top = bounds.top + deltaLat;
- position.y = position.y + deltaY;
- row[i].moveTo(bounds, position);
- }
-
- if (prepend) {
- this.grid.unshift(row);
- } else {
- this.grid.push(row);
- }
- },
-
- /**
- * Method: shiftColumn
- * Shift grid work in the other dimension
- *
- * Parameters:
- * prepend - {Boolean} if true, prepend to beginning.
- * if false, then append to end
- */
- shiftColumn: function(prepend) {
- var deltaX = (prepend) ? -this.tileSize.w : this.tileSize.w;
- var resolution = this.map.getResolution();
- var deltaLon = resolution * deltaX;
-
- for (var i=0; i<this.grid.length; i++) {
- var row = this.grid[i];
- var modelTileIndex = (prepend) ? 0 : (row.length - 1);
- var modelTile = row[modelTileIndex];
-
- var bounds = modelTile.bounds.clone();
- var position = modelTile.position.clone();
- bounds.left = bounds.left + deltaLon;
- bounds.right = bounds.right + deltaLon;
- position.x = position.x + deltaX;
-
- var tile = prepend ? this.grid[i].pop() : this.grid[i].shift();
- tile.moveTo(bounds, position);
- if (prepend) {
- this.grid[i].unshift(tile);
- } else {
- this.grid[i].push(tile);
- }
- }
- },
-
- /**
- * Method: removeExcessTiles
- * When the size of the map or the buffer changes, we may need to
- * remove some excess rows and columns.
- *
- * Parameters:
- * rows - {Integer} Maximum number of rows we want our grid to have.
- * colums - {Integer} Maximum number of columns we want our grid to have.
- */
- removeExcessTiles: function(rows, columns) {
-
- // remove extra rows
- while (this.grid.length > rows) {
- var row = this.grid.pop();
- for (var i=0, l=row.length; i<l; i++) {
- var tile = row[i];
- this.removeTileMonitoringHooks(tile);
- tile.destroy();
- }
- }
-
- // remove extra columns
- while (this.grid[0].length > columns) {
- for (var i=0, l=this.grid.length; i<l; i++) {
- var row = this.grid[i];
- var tile = row.pop();
- this.removeTileMonitoringHooks(tile);
- tile.destroy();
- }
- }
- },
-
- /**
- * Method: onMapResize
- * For singleTile layers, this will replace the tile with the
- * a new one with updated tileSize and extent.
- */
- onMapResize: function() {
- if (this.singleTile) {
- this.clearGrid();
- this.setTileSize();
- this.initSingleTile(this.map.getExtent());
- }
- },
-
- /**
- * APIMethod: getTileBounds
- * Returns The tile bounds for a layer given a pixel location.
- *
- * Parameters:
- * viewPortPx - {<OpenLayers.Pixel>} The location in the viewport.
- *
- * Returns:
- * {<OpenLayers.Bounds>} Bounds of the tile at the given pixel location.
- */
- getTileBounds: function(viewPortPx) {
- var maxExtent = this.map.getMaxExtent();
- 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/Control/Navigation.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Control/ZoomBox.js
- * @requires OpenLayers/Control/DragPan.js
- * @requires OpenLayers/Handler/MouseWheel.js
- *
- * Class: OpenLayers.Control.Navigation
- * The navigation control handles map browsing with mouse events (dragging,
- * double-clicking, and scrolling the wheel). Create a new navigation
- * control with the <OpenLayers.Control.Navigation> control.
- *
- * Note that this control is added to the map by default (if no controls
- * array is sent in the options object to the <OpenLayers.Map>
- * constructor).
- *
- * Inherits:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * Property: dragPan
- * {<OpenLayers.Control.DragPan>}
- */
- dragPan: null,
-
- /**
- * Property: zoomBox
- * {<OpenLayers.Control.ZoomBox>}
- */
- zoomBox: null,
-
- /**
- * Property: wheelHandler
- * {<OpenLayers.Handler.MouseWheel>}
- */
- wheelHandler: null,
-
- /**
- * 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) {
- OpenLayers.Control.prototype.initialize.apply(this, arguments);
- },
-
- /**
- * Method: activate
- */
- activate: function() {
- this.dragPan.activate();
- this.wheelHandler.activate();
- this.zoomBox.activate();
- return OpenLayers.Control.prototype.activate.apply(this,arguments);
- },
-
- /**
- * Method: deactivate
- */
- deactivate: function() {
- this.zoomBox.deactivate();
- this.dragPan.deactivate();
- this.wheelHandler.deactivate();
- return OpenLayers.Control.prototype.deactivate.apply(this,arguments);
- },
-
- /**
- * Method: draw
- */
- draw: function() {
- this.map.events.register( "dblclick", this, this.defaultDblClick );
- this.dragPan = new OpenLayers.Control.DragPan({map: this.map});
- this.zoomBox = new OpenLayers.Control.ZoomBox(
- {map: this.map, keyMask: OpenLayers.Handler.MOD_SHIFT});
- this.dragPan.draw();
- this.zoomBox.draw();
- this.wheelHandler = new OpenLayers.Handler.MouseWheel(
- this, {"up" : this.wheelUp,
- "down": this.wheelDown} );
- this.activate();
- },
-
- /**
- * Method: defaultDblClick
- *
- * Parameters:
- * evt - {Event}
- */
- defaultDblClick: function (evt) {
- var newCenter = this.map.getLonLatFromViewPortPx( evt.xy );
- this.map.setCenter(newCenter, this.map.zoom + 1);
- OpenLayers.Event.stop(evt);
- return false;
- },
-
- /**
- * Method: wheelChange
- *
- * Parameters:
- * evt - {Event}
- */
- wheelChange: function(evt, deltaZ) {
- var newZoom = this.map.getZoom() + deltaZ;
- if (!this.map.isValidZoomLevel(newZoom)) 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.resolutions[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}
- */
- wheelUp: function(evt) {
- this.wheelChange(evt, 1);
- },
-
- /**
- * Method: wheelDown
- * User spun scroll wheel down
- *
- * Parameters:
- * evt - {Event}
- */
- wheelDown: function(evt) {
- this.wheelChange(evt, -1);
- },
-
- CLASS_NAME: "OpenLayers.Control.Navigation"
-});
-/* ======================================================================
- OpenLayers/Layer/MapGuide.js
- ====================================================================== */
-
-/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Ajax.js
- * @requires OpenLayers/Layer/Grid.js
- *
- * Class: OpenLayers.Layer.MapGuide
- * Instances of OpenLayers.Layer.MapGuide are used to display
- * data from a MapGuide OS instance.
- *
- * Inherits from:
- * - <OpenLayers.Layer.Grid>
- */
-OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, {
-
- /**
- * APIProperty: reproject
- * {Boolean} Try to reproject this layer if it is used as an overlay.
- * Default is false.
- **/
- reproject: false,
-
- /**
- * APIProperty: isBaseLayer
- * {Boolean} Treat this layer as a base layer. Default is true.
- **/
- isBaseLayer: true,
-
- /**
- * Constant: DEFAULT_PARAMS
- * {Object} Hashtable of default parameter key/value pairs
- */
- TILE_PARAMS: {
- operation: 'GETTILEIMAGE',
- version: '1.2.0'
- },
-
- SINGLE_TILE_PARAMS: {
- operation: 'GETMAPIMAGE',
- format: 'PNG',
- version: '1.0.0'
- },
-
- session: null,
- mapName: null,
- groupName: null,
-
- /**
- * @constructor
- *
- * @param {str} name
- * @param {str} url
- * @param {hash} params
- * @param {Object} options
- */
- initialize: function(name, url, params, options) {
-
- var newArguments = new Array();
- newArguments.push(name, url, params, options);
- OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
-
- // unless explicitly set in options, if the layer is transparent,
- // it will be an overlay
- if (options == null || options.isBaseLayer == null) {
- this.isBaseLayer = ((this.params.transparent != "true") &&
- (this.params.transparent != true));
- }
-
- if (arguments.length > 0) {
- if (this.options.singleTile) {
- this.session = params.session;
- this.mapName = params.mapname;
- OpenLayers.Util.applyDefaults(
- this.params,
- this.SINGLE_TILE_PARAMS
- );
- if (!this.isBaseLayer) {
- this.params.operation = "GETDYNAMICMAPOVERLAYIMAGE";
- }
- } else {
- this.groupName = params.groupname;
- OpenLayers.Util.applyDefaults(
- this.params,
- this.TILE_PARAMS
- );
- this.setTileSize(new OpenLayers.Size(300,300)); //TBD: set this by options?
- }
- }
- },
-
- updateExtents: function(a) {
- var center = this.map.getExtent().getCenterLonLat();
- var mapSize = this.map.getCurrentSize();
- var sParams = "operation=GETVISIBLEMAPEXTENT&version=1.0.0";
- sParams += "&session="+this.session;
- sParams += "&mapname="+this.mapName;
- sParams += "&setdisplaydpi="+OpenLayers.DOTS_PER_INCH;
- sParams += "&setdisplayheight="+mapSize.h*this.ratio;
- sParams += "&setdisplaywidth="+mapSize.w*this.ratio;
- sParams += "&setviewcenterx="+center.lon;
- sParams += "&setviewcentery="+center.lat;
- sParams += "&setviewscale="+this.map.getScale();
- if (this.options.showLayers) sParams += "&showlayers="+this.options.showLayers;
- if (this.options.hideLayers) sParams += "&hidelayers="+this.options.hideLayers;
- if (this.options.showGroups) sParams += "&showgroups="+this.options.showGroups;
- if (this.options.hideGroups) sParams += "&hidegroups="+this.options.hideGroups;
- if (this.options.refreshLayers) sParams += "&refreshlayers="+this.options.refreshLayers;
- sParams += "&ts="+(new Date()).getTime();
- // add in hidden/visible layers here?
- new OpenLayers.Ajax.Request(this.url,
- { parameters: sParams,
- onSuccess: this._getExtentSuccess,
- onFailure: this._getExtentFailure,
- //requestHeaders: ['Authorization', 'Basic QW5vbnltb3VzOg=='], //TBD anon user base64 encoded
- asynchronous: false //must be synchronous call to return control here
- });
-
- },
-
- _getExtentSuccess: function(transport) {
- //really this is a no-op, result is thrown away
- var temp = transport.responseXML;
- },
-
- _getExtentFailure: function(r) {
- //no-op
- },
-
-
- /**
- * @param {Object} obj
- *
- * @returns A clone of this OpenLayers.Layer.MapGuide
- * @type OpenLayers.Layer.MapGuide
- */
- clone: function (obj) {
- if (obj == null) {
- obj = new OpenLayers.Layer.MapGuide(this.name,
- this.url,
- this.params,
- this.options);
- }
- //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;
- },
-
- /**
- * addTile creates a tile, initializes it (via 'draw' in this case), and
- * adds it to the layer div.
- *
- * @param {OpenLayers.Bounds} bounds
- *
- * @returns The added OpenLayers.Tile.Image
- * @type OpenLayers.Tile.Image
- */
- addTile:function(bounds,position) {
- return new OpenLayers.Tile.Image(this, position, bounds, url, this.tileSize);
- },
-
- /**
- * @param {OpenLayers.Bounds} bounds
- *
- * @returns A string with the layer's url and parameters and also the
- * passed-in bounds and appropriate tile size specified as
- * parameters
- * @type String
- */
- getURL: function (bounds) {
-
- var center = bounds.getCenterLonLat();
- var mapSize = this.map.getCurrentSize();
-
- if (this.options.singleTile) {
- //set up the call for GETMAPIMAGE or GETDYNAMICMAPOVERLAY
- var params = {};
-
- params.session = this.session;
- params.mapname = this.mapName;
- if (this.isBaseLayer) {
- params.locale = "en";
- params.setdisplaydpi = OpenLayers.DOTS_PER_INCH;
- params.setdisplayheight = mapSize.h*this.ratio;
- params.setdisplaywidth = mapSize.w*this.ratio;
- params.setviewcenterx = center.lon;
- params.setviewcentery = center.lat;
- params.setviewscale = this.map.getScale();
- params.clip = "1";
- if (this.options.showLayers) params.showlayers = this.options.showLayers;
- if (this.options.hideLayers) params.hidelayers = this.options.hideLayers;
- if (this.options.showGroups) params.showgroups = this.options.showGroups;
- if (this.options.hideGroups) params.hidegroups = this.options.hideGroups;
- if (this.options.refreshLayers) params.refreshlayers = this.options.refreshLayers;
- } else {
- this.updateExtents();
- }
- params.ts = (new Date()).getTime();
-
- var url = this.getFullRequestString( params );
-
- } else {
-
- //tiled version
- var currentRes = this.map.getResolution();
- var colidx = Math.floor((bounds.left-this.maxExtent.left)/currentRes);
- colidx = Math.round(colidx/this.tileSize.w);
- var rowidx = Math.floor((this.maxExtent.top-bounds.top)/currentRes);
- rowidx = Math.round(rowidx/this.tileSize.h);
-
- var url = this.getFullRequestString(
- {
- tilecol: colidx,
- tilerow: rowidx,
- scaleindex: this.resolutions.length-this.map.zoom-1
- });
- }
-
- return url;
- },
-
- /**
- * getFullRequestString on MapGuide layers is special, because we
- * do a regular expression replace on ',' in parameters to '+'.
- * This is why it is subclassed here.
- *
- * @param {Object} newParams Parameters to add to the default parameters
- * for the layer.
- * @param {String} altUrl Alternative base URL to use.
- */
- getFullRequestString:function(newParams, altUrl) {
-
-
- // use layer's url unless altUrl passed in
- var url = (altUrl == null) ? this.url : altUrl;
-
- // if url is not a string, it should be an array of strings,
- // in which case we will randomly select one of them in order
- // to evenly distribute requests to different urls.
- if (typeof url == "object") {
- url = url[Math.floor(Math.random()*url.length)];
- }
- // requestString always starts with url
- var requestString = url;
-
- // create a new params hashtable with all the layer params and the
- // new params together. then convert to string
- var allParams = OpenLayers.Util.extend({}, this.params);
- allParams = OpenLayers.Util.extend(allParams, newParams);
- // ignore parameters that are already in the url search string
- var urlParams = OpenLayers.Util.upperCaseObject(
- OpenLayers.Util.getArgs(url));
- for(var key in allParams) {
- if(key.toUpperCase() in urlParams) {
- delete allParams[key];
- }
- }
- var paramsString = OpenLayers.Util.getParameterString(allParams);
-
- /* MapGuide needs '+' seperating things like bounds/height/width.
- Since typically this is URL encoded, we use a slight hack: we
- depend on the list-like functionality of getParameterString to
- leave ',' only in the case of list items (since otherwise it is
- encoded) then do a regular expression replace on the , characters
- to '+' */
- paramsString = paramsString.replace(/,/g, "+");
-
- if (paramsString != "") {
- var lastServerChar = url.charAt(url.length - 1);
- if ((lastServerChar == "&") || (lastServerChar == "?")) {
- requestString += paramsString;
- } else {
- if (url.indexOf('?') == -1) {
- //serverPath has no ? -- add one
- requestString += '?' + paramsString;
- } else {
- //serverPath contains ?, so must already have paramsString at the end
- requestString += '&' + paramsString;
- }
- }
- }
- return requestString;
- },
-
- /**
- * Method: initGriddedTiles
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- */
- initGriddedTiles:function(bounds) {
-
- // work out mininum number of rows and columns; this is the number of
- // tiles required to cover the viewport plus one for panning
- var viewSize = this.map.getSize();
- var minRows = Math.ceil(viewSize.h/this.tileSize.h) + 1;
- var minCols = Math.ceil(viewSize.w/this.tileSize.w) + 1;
-
- var extent = this.map.getMaxExtent();
- var resolution = this.map.getResolution();
- var tilelon = resolution * this.tileSize.w;
- var tilelat = resolution * this.tileSize.h;
-
- var offsetlon = bounds.left - extent.left;
- var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
- var tilecolremain = offsetlon/tilelon - tilecol;
- var tileoffsetx = -tilecolremain * this.tileSize.w;
- var tileoffsetlon = extent.left + tilecol * tilelon;
-
- //Original OL code
- //var offsetlat = bounds.top - (extent.bottom + tilelat);
- //var tilerow = Math.ceil(offsetlat/tilelat) + this.buffer;
- //var tilerowremain = tilerow - offsetlat/tilelat;
- //var tileoffsety = -tilerowremain * this.tileSize.h;
- //var tileoffsetlat = extent.bottom + tilerow * tilelat;
-
- var offsetlat = extent.top - bounds.top + tilelat;
- var tilerow = Math.floor(offsetlat/tilelat) - this.buffer;
- var tilerowremain = tilerow - offsetlat/tilelat;
- var tileoffsety = tilerowremain * this.tileSize.h;
- var tileoffsetlat = extent.top - tilelat*tilerow;
-
-
- tileoffsetx = Math.round(tileoffsetx); // heaven help us
- tileoffsety = Math.round(tileoffsety);
-
- this.origin = new OpenLayers.Pixel(tileoffsetx, tileoffsety);
-
- var startX = tileoffsetx;
- var startLon = tileoffsetlon;
-
- var rowidx = 0;
-
- 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 -= parseInt(this.map.layerContainerDiv.style.left);
-
- var y = tileoffsety;
- //y -= parseInt(this.map.layerContainerDiv.style.top);
-
- var px = new OpenLayers.Pixel(x, y);
- var tile = row[colidx++];
- if (!tile) {
- tile = this.addTile(tileBounds, px);
- this.addTileMonitoringHooks(tile);
- row.push(tile);
- } else {
- tile.moveTo(tileBounds, px, false);
- }
-
- tileoffsetlon += tilelon;
- tileoffsetx += this.tileSize.w;
- } while ((tileoffsetlon <= bounds.right + tilelon * this.buffer)
- || colidx < minCols)
-
- tileoffsetlat -= tilelat;
- tileoffsety += this.tileSize.h;
- } while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer)
- || rowidx < minRows)
-
- //shave off exceess rows and colums
- this.removeExcessTiles(rowidx, colidx);
-
- //now actually draw the tiles
- this.spiralTileLoad();
- },
-
-
- /** @final @type String */
- CLASS_NAME: "OpenLayers.Layer.MapGuide"
-});
-/* ======================================================================
- OpenLayers/Layer/MapServer.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-/**
- * @requires OpenLayers/Layer/Grid.js
- *
- * Class: OpenLayers.Layer.MapServer
- * Instances of OpenLayers.Layer.MapServer are used to display
- * data from a MapServer CGI instance.
- *
- * Inherits from:
- * - <OpenLayers.Layer.Grid>
- */
-OpenLayers.Layer.MapServer = OpenLayers.Class(OpenLayers.Layer.Grid, {
-
- /**
- * Constant: DEFAULT_PARAMS
- * {Object} Hashtable of default parameter key/value pairs
- */
- DEFAULT_PARAMS: {
- mode: "map",
- map_imagetype: "png"
- },
-
- /**
- * Constructor: OpenLayers.Layer.MapServer
- * Create a new MapServer layer object
- *
- * Parameters:
- * name - {String} A name for the layer
- * url - {String} Base url for the MapServer CGI
- * (e.g. http://www2.dmsolutions.ca/cgi-bin/mapserv)
- * params - {Object} An object with key/value pairs representing the
- * GetMap query string parameters and parameter values.
- * options - {Ojbect} Hashtable of extra options to tag onto the layer
- */
- initialize: function(name, url, params, options) {
- var newArguments = [];
- newArguments.push(name, url, params, options);
- OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
-
- if (arguments.length > 0) {
- OpenLayers.Util.applyDefaults(
- this.params,
- this.DEFAULT_PARAMS
- );
- }
-
- // unless explicitly set in options, if the layer is transparent,
- // it will be an overlay
- if (options == null || options.isBaseLayer == null) {
- this.isBaseLayer = ((this.params.transparent != "true") &&
- (this.params.transparent != true));
- }
- },
-
- /**
- * Method: clone
- * Create a clone of this layer
- *
- * Returns:
- * {<OpenLayers.Layer.MapServer>} An exact clone of this layer
- */
- clone: function (obj) {
- if (obj == null) {
- obj = new OpenLayers.Layer.MapServer(this.name,
- this.url,
- this.params,
- this.options);
- }
- //get all additions from superclasses
- obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
-
- // copy/set any non-init, non-simple values here
-
- return obj;
- },
-
- /**
- * Method: addTile
- * Creates a tile, initializes it, and adds it to the layer div.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
- */
- addTile:function(bounds,position) {
- return new OpenLayers.Tile.Image(this, position, bounds,
- null, this.tileSize);
- },
-
- /**
- * Method: getURL
- * Return a query string for this layer
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox
- * for the request
- *
- * Returns:
- * {String} A string with the layer's url and parameters and also
- * the passed-in bounds and appropriate tile size specified
- * as parameters.
- */
- getURL: function (bounds) {
- bounds = this.adjustBounds(bounds);
- // Make a list, so that getFullRequestString uses literal ","
- var extent = [bounds.left, bounds. bottom, bounds.right, bounds.top];
-
- var imageSize = this.getImageSize();
-
- // make lists, so that literal ','s are used
- var url = this.getFullRequestString(
- {mapext: extent,
- imgext: extent,
- map_size: [imageSize.w, imageSize.h],
- imgx: imageSize.w / 2,
- imgy: imageSize.h / 2,
- imgxy: [imageSize.w, imageSize.h]
- });
-
- return url;
- },
-
- /**
- * Method: getFullRequestString
- * combine the layer's url with its params and these newParams.
- *
- * Parameter:
- * newParams - {Object} New parameters that should be added to the
- * request string.
- * altUrl - {String} (optional) Replace the URL in the full request
- * string with the provided URL.
- *
- * Returns:
- * {String} A string with the layer's url and parameters embedded in it.
- */
- getFullRequestString:function(newParams, altUrl) {
- // use layer's url unless altUrl passed in
- var url = (altUrl == null) ? this.url : altUrl;
-
- // if url is not a string, it should be an array of strings,
- // in which case we will randomly select one of them in order
- // to evenly distribute requests to different urls.
- if (typeof url == "object") {
- url = url[Math.floor(Math.random()*url.length)];
- }
- // requestString always starts with url
- var requestString = url;
-
- // create a new params hashtable with all the layer params and the
- // new params together. then convert to string
- var allParams = OpenLayers.Util.extend({}, this.params);
- allParams = OpenLayers.Util.extend(allParams, newParams);
- // ignore parameters that are already in the url search string
- var urlParams = OpenLayers.Util.upperCaseObject(
- OpenLayers.Util.getParameters(url));
- for(var key in allParams) {
- if(key.toUpperCase() in urlParams) {
- delete allParams[key];
- }
- }
- var paramsString = OpenLayers.Util.getParameterString(allParams);
-
- // MapServer needs '+' seperating things like bounds/height/width.
- // Since typically this is URL encoded, we use a slight hack: we
- // depend on the list-like functionality of getParameterString to
- // leave ',' only in the case of list items (since otherwise it is
- // encoded) then do a regular expression replace on the , characters
- // to '+'
- //
- paramsString = paramsString.replace(/,/g, "+");
-
- if (paramsString != "") {
- var lastServerChar = url.charAt(url.length - 1);
- if ((lastServerChar == "&") || (lastServerChar == "?")) {
- requestString += paramsString;
- } else {
- if (url.indexOf('?') == -1) {
- //serverPath has no ? -- add one
- requestString += '?' + paramsString;
- } else {
- //serverPath contains ?, so must already have paramsString at the end
- requestString += '&' + paramsString;
- }
- }
- }
- return requestString;
- },
-
- CLASS_NAME: "OpenLayers.Layer.MapServer"
-});
-/* ======================================================================
- OpenLayers/Layer/WMS.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
- * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
- * for the full text of the license. */
-
-
-/**
- * @requires OpenLayers/Layer/Grid.js
- * @requires OpenLayers/Tile/Image.js
- *
- * Class: OpenLayers.Layer.WMS
- * Instances of OpenLayers.Layer.WMS are used to display data from OGC Web
- * Mapping Services. Create a new WMS layer with the <OpenLayers.Layer.WMS>
- * constructor.
- *
- * Inherits from:
- * - <OpenLayers.Layer.Grid>
- */
-OpenLayers.Layer.WMS = OpenLayers.Class(OpenLayers.Layer.Grid, {
-
- /**
- * Constant: DEFAULT_PARAMS
- * {Object} Hashtable of default parameter key/value pairs
- */
- DEFAULT_PARAMS: { service: "WMS",
- version: "1.1.1",
- request: "GetMap",
- styles: "",
- exceptions: "application/vnd.ogc.se_inimage",
- format: "image/jpeg"
- },
-
- /**
- * Property: reproject
- * *Deprecated*. See http://trac.openlayers.org/wiki/SpatialMercator
- * for information on the replacement for this functionality.
- * {Boolean} Try to reproject this layer if its coordinate reference system
- * is different than that of the base layer. Default is true.
- * Set this in the layer options. Should be set to false in
- * most cases.
- */
- reproject: false,
-
- /**
- * APIProperty: isBaseLayer
- * {Boolean} Default is true for WMS layer
- */
- isBaseLayer: true,
-
- /**
- * APIProperty: encodeBBOX
- * {Boolean} Should the BBOX commas be encoded? The WMS spec says 'no',
- * but some services want it that way. Default false.
- */
- encodeBBOX: false,
-
- /**
- * Constructor: OpenLayers.Layer.WMS
- * Create a new WMS layer object
- *
- * Example:
- * (code)
- * var wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
- * "http://wms.jpl.nasa.gov/wms.cgi",
- * {layers: "modis,global_mosaic"});
- * (end)
- *
- * Parameters:
- * name - {String} A name for the layer
- * url - {String} Base url for the WMS
- * (e.g. http://wms.jpl.nasa.gov/wms.cgi)
- * params - {Object} An object with key/value pairs representing the
- * GetMap query string parameters and parameter values.
- * options - {Ojbect} Hashtable of extra options to tag onto the layer
- */
- initialize: function(name, url, params, options) {
- var newArguments = [];
- //uppercase params
- params = OpenLayers.Util.upperCaseObject(params);
- 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.params.TRANSPARENT &&
- this.params.TRANSPARENT.toString().toLowerCase() == "true") {
-
- // unless explicitly set in options, make layer an overlay
- if ( (options == null) || (!options.isBaseLayer) ) {
- this.isBaseLayer = false;
- }
-
- // jpegs can never be transparent, so intelligently switch the
- // format, depending on teh browser's capabilities
- if (this.params.FORMAT == "image/jpeg") {
- this.params.FORMAT = OpenLayers.Util.alphaHack() ? "image/gif"
- : "image/png";
- }
- }
-
- },
-
- /**
- * Method: destroy
- * Destroy this layer
- */
- destroy: function() {
- // for now, nothing special to do here.
- OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);
- },
-
-
- /**
- * Method: clone
- * Create a clone of this layer
- *
- * Returns:
- * {<OpenLayers.Layer.WMS>} An exact clone of this layer
- */
- clone: function (obj) {
-
- if (obj == null) {
- obj = new OpenLayers.Layer.WMS(this.name,
- this.url,
- this.params,
- this.options);
- }
-
- //get all additions from superclasses
- obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
-
- // copy/set any non-init, non-simple values here
-
- return obj;
- },
-
- /**
- * Method: getURL
- * Return a GetMap query string for this layer
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the
- * request.
- *
- * Returns:
- * {String} A string with the layer's url and parameters and also the
- * passed-in bounds and appropriate tile size specified as
- * parameters.
- */
- getURL: function (bounds) {
- bounds = this.adjustBounds(bounds);
-
- var imageSize = this.getImageSize();
- return this.getFullRequestString(
- {BBOX: this.encodeBBOX ? bounds.toBBOX() : bounds.toArray(),
- WIDTH:imageSize.w,
- HEIGHT:imageSize.h});
- },
-
- /**
- * Method: addTile
- * addTile creates a tile, initializes it, and adds it to the layer div.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
- */
- addTile:function(bounds,position) {
- return new OpenLayers.Tile.Image(this, position, bounds,
- null, this.tileSize);
- },
-
- /**
- * APIMethod: mergeNewParams
- * Catch changeParams and uppercase the new params to be merged in
- * before calling changeParams on the super class.
- *
- * Once params have been changed, we will need to re-init our tiles.
- *
- * Parameters:
- * newParams - {Object} Hashtable of new params to use
- */
- mergeNewParams:function(newParams) {
- var upperParams = OpenLayers.Util.upperCaseObject(newParams);
- var newArguments = [upperParams];
- OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,
- newArguments);
- },
-
- /**
- * Method: 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}
- *
- * Returns:
- * {String}
- */
- getFullRequestString:function(newParams) {
- var projection = this.map.getProjection();
- this.params.SRS = (projection == "none") ? null : projection.getCode();
-
- return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(
- this, arguments);
- },
-
- CLASS_NAME: "OpenLayers.Layer.WMS"
-});
+/* ======================================================================
+ OpenLayers/SingleFile.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+var OpenLayers = {
+ singleFile: true
+};
+
+
+/* ======================================================================
+ OpenLayers.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/*
+ * @requires OpenLayers/BaseTypes.js
+ * @requires OpenLayers/Lang/en.js
+ */
+
+(function() {
+ /**
+ * Before creating the OpenLayers namespace, check to see if
+ * OpenLayers.singleFile is true. This occurs if the
+ * OpenLayers/SingleFile.js script is included before this one - as is the
+ * case with single file builds.
+ */
+ var singleFile = (typeof OpenLayers == "object" && OpenLayers.singleFile);
+
+ /**
+ * Namespace: OpenLayers
+ * The OpenLayers object provides a namespace for all things OpenLayers
+ */
+ window.OpenLayers = {
+
+ /**
+ * Property: _scriptName
+ * {String} Relative path of this script.
+ */
+ _scriptName: (!singleFile) ? "lib/OpenLayers.js" : "OpenLayers.js",
+
+ /**
+ * Function: _getScriptLocation
+ * Return the path to this script.
+ *
+ * Returns:
+ * {String} Path to this script
+ */
+ _getScriptLocation: function () {
+ var scriptLocation = "";
+ var scriptName = OpenLayers._scriptName;
+
+ var scripts = document.getElementsByTagName('script');
+ for (var i = 0; i < scripts.length; i++) {
+ var src = scripts[i].getAttribute('src');
+ if (src) {
+ var index = src.lastIndexOf(scriptName);
+ // set path length for src up to a query string
+ var pathLength = src.lastIndexOf('?');
+ if (pathLength < 0) {
+ pathLength = src.length;
+ }
+ // is it found, at the end of the URL?
+ if ((index > -1) && (index + scriptName.length == pathLength)) {
+ scriptLocation = src.slice(0, pathLength - scriptName.length);
+ break;
+ }
+ }
+ }
+ return scriptLocation;
+ }
+ };
+ /**
+ * OpenLayers.singleFile is a flag indicating this file is being included
+ * in a Single File Library build of the OpenLayers Library.
+ *
+ * When we are *not* part of a SFL build we dynamically include the
+ * OpenLayers library code.
+ *
+ * When we *are* part of a SFL build we do not dynamically include the
+ * OpenLayers library code as it will be appended at the end of this file.
+ */
+ if(!singleFile) {
+ var jsfiles = new Array(
+ "OpenLayers/Util.js",
+ "OpenLayers/BaseTypes.js",
+ "OpenLayers/BaseTypes/Class.js",
+ "OpenLayers/BaseTypes/Bounds.js",
+ "OpenLayers/BaseTypes/Element.js",
+ "OpenLayers/BaseTypes/LonLat.js",
+ "OpenLayers/BaseTypes/Pixel.js",
+ "OpenLayers/BaseTypes/Size.js",
+ "OpenLayers/Console.js",
+ "OpenLayers/Tween.js",
+ "Rico/Corner.js",
+ "Rico/Color.js",
+ "OpenLayers/Ajax.js",
+ "OpenLayers/Events.js",
+ "OpenLayers/Projection.js",
+ "OpenLayers/Map.js",
+ "OpenLayers/Layer.js",
+ "OpenLayers/Icon.js",
+ "OpenLayers/Marker.js",
+ "OpenLayers/Marker/Box.js",
+ "OpenLayers/Popup.js",
+ "OpenLayers/Tile.js",
+ "OpenLayers/Tile/Image.js",
+ "OpenLayers/Tile/WFS.js",
+ "OpenLayers/Layer/Image.js",
+ "OpenLayers/Layer/SphericalMercator.js",
+ "OpenLayers/Layer/EventPane.js",
+ "OpenLayers/Layer/FixedZoomLevels.js",
+ "OpenLayers/Layer/Google.js",
+ "OpenLayers/Layer/VirtualEarth.js",
+ "OpenLayers/Layer/Yahoo.js",
+ "OpenLayers/Layer/HTTPRequest.js",
+ "OpenLayers/Layer/Grid.js",
+ "OpenLayers/Layer/MapGuide.js",
+ "OpenLayers/Layer/MapServer.js",
+ "OpenLayers/Layer/MapServer/Untiled.js",
+ "OpenLayers/Layer/KaMap.js",
+ "OpenLayers/Layer/MultiMap.js",
+ "OpenLayers/Layer/Markers.js",
+ "OpenLayers/Layer/Text.js",
+ "OpenLayers/Layer/WorldWind.js",
+ "OpenLayers/Layer/WMS.js",
+ "OpenLayers/Layer/WMS/Untiled.js",
+ "OpenLayers/Layer/GeoRSS.js",
+ "OpenLayers/Layer/Boxes.js",
+ "OpenLayers/Layer/TMS.js",
+ "OpenLayers/Layer/TileCache.js",
+ "OpenLayers/Popup/Anchored.js",
+ "OpenLayers/Popup/AnchoredBubble.js",
+ "OpenLayers/Popup/Framed.js",
+ "OpenLayers/Popup/FramedCloud.js",
+ "OpenLayers/Feature.js",
+ "OpenLayers/Feature/Vector.js",
+ "OpenLayers/Feature/WFS.js",
+ "OpenLayers/Handler.js",
+ "OpenLayers/Handler/Click.js",
+ "OpenLayers/Handler/Hover.js",
+ "OpenLayers/Handler/Point.js",
+ "OpenLayers/Handler/Path.js",
+ "OpenLayers/Handler/Polygon.js",
+ "OpenLayers/Handler/Feature.js",
+ "OpenLayers/Handler/Drag.js",
+ "OpenLayers/Handler/RegularPolygon.js",
+ "OpenLayers/Handler/Box.js",
+ "OpenLayers/Handler/MouseWheel.js",
+ "OpenLayers/Handler/Keyboard.js",
+ "OpenLayers/Control.js",
+ "OpenLayers/Control/Attribution.js",
+ "OpenLayers/Control/Button.js",
+ "OpenLayers/Control/ZoomBox.js",
+ "OpenLayers/Control/ZoomToMaxExtent.js",
+ "OpenLayers/Control/DragPan.js",
+ "OpenLayers/Control/Navigation.js",
+ "OpenLayers/Control/MouseDefaults.js",
+ "OpenLayers/Control/MousePosition.js",
+ "OpenLayers/Control/OverviewMap.js",
+ "OpenLayers/Control/KeyboardDefaults.js",
+ "OpenLayers/Control/PanZoom.js",
+ "OpenLayers/Control/PanZoomBar.js",
+ "OpenLayers/Control/ArgParser.js",
+ "OpenLayers/Control/Permalink.js",
+ "OpenLayers/Control/Scale.js",
+ "OpenLayers/Control/ScaleLine.js",
+ "OpenLayers/Control/LayerSwitcher.js",
+ "OpenLayers/Control/DrawFeature.js",
+ "OpenLayers/Control/DragFeature.js",
+ "OpenLayers/Control/ModifyFeature.js",
+ "OpenLayers/Control/Panel.js",
+ "OpenLayers/Control/SelectFeature.js",
+ "OpenLayers/Control/NavigationHistory.js",
+ "OpenLayers/Geometry.js",
+ "OpenLayers/Geometry/Rectangle.js",
+ "OpenLayers/Geometry/Collection.js",
+ "OpenLayers/Geometry/Point.js",
+ "OpenLayers/Geometry/MultiPoint.js",
+ "OpenLayers/Geometry/Curve.js",
+ "OpenLayers/Geometry/LineString.js",
+ "OpenLayers/Geometry/LinearRing.js",
+ "OpenLayers/Geometry/Polygon.js",
+ "OpenLayers/Geometry/MultiLineString.js",
+ "OpenLayers/Geometry/MultiPolygon.js",
+ "OpenLayers/Geometry/Surface.js",
+ "OpenLayers/Renderer.js",
+ "OpenLayers/Renderer/Elements.js",
+ "OpenLayers/Renderer/SVG.js",
+ "OpenLayers/Renderer/VML.js",
+ "OpenLayers/Layer/Vector.js",
+ "OpenLayers/Layer/PointTrack.js",
+ "OpenLayers/Layer/GML.js",
+ "OpenLayers/Style.js",
+ "OpenLayers/StyleMap.js",
+ "OpenLayers/Rule.js",
+ "OpenLayers/Filter.js",
+ "OpenLayers/Filter/FeatureId.js",
+ "OpenLayers/Filter/Logical.js",
+ "OpenLayers/Filter/Comparison.js",
+ "OpenLayers/Format.js",
+ "OpenLayers/Format/XML.js",
+ "OpenLayers/Format/GML.js",
+ "OpenLayers/Format/KML.js",
+ "OpenLayers/Format/GeoRSS.js",
+ "OpenLayers/Format/WFS.js",
+ "OpenLayers/Format/WKT.js",
+ "OpenLayers/Format/OSM.js",
+ "OpenLayers/Format/SLD.js",
+ "OpenLayers/Format/SLD/v1.js",
+ "OpenLayers/Format/SLD/v1_0_0.js",
+ "OpenLayers/Format/Text.js",
+ "OpenLayers/Format/JSON.js",
+ "OpenLayers/Format/GeoJSON.js",
+ "OpenLayers/Format/WMC.js",
+ "OpenLayers/Format/WMC/v1.js",
+ "OpenLayers/Format/WMC/v1_0_0.js",
+ "OpenLayers/Format/WMC/v1_1_0.js",
+ "OpenLayers/Layer/WFS.js",
+ "OpenLayers/Control/MouseToolbar.js",
+ "OpenLayers/Control/NavToolbar.js",
+ "OpenLayers/Control/EditingToolbar.js",
+ "OpenLayers/Lang.js",
+ "OpenLayers/Lang/en.js"
+ ); // etc.
+
+ var agent = navigator.userAgent;
+ var docWrite = (agent.match("MSIE") || agent.match("Safari"));
+ if(docWrite) {
+ var allScriptTags = new Array(jsfiles.length);
+ }
+ var host = OpenLayers._getScriptLocation() + "lib/";
+ for (var i = 0; i < jsfiles.length; i++) {
+ if (docWrite) {
+ allScriptTags[i] = "<script src='" + host + jsfiles[i] +
+ "'></script>";
+ } else {
+ var s = document.createElement("script");
+ s.src = host + jsfiles[i];
+ var h = document.getElementsByTagName("head").length ?
+ document.getElementsByTagName("head")[0] :
+ document.body;
+ h.appendChild(s);
+ }
+ }
+ if (docWrite) {
+ document.write(allScriptTags.join(""));
+ }
+ }
+})();
+
+/**
+ * Constant: VERSION_NUMBER
+ */
+OpenLayers.VERSION_NUMBER="$Revision$";
+/* ======================================================================
+ OpenLayers/BaseTypes.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/BaseTypes/LonLat.js
+ * @requires OpenLayers/BaseTypes/Size.js
+ * @requires OpenLayers/BaseTypes/Pixel.js
+ * @requires OpenLayers/BaseTypes/Bounds.js
+ * @requires OpenLayers/BaseTypes/Element.js
+ * @requires OpenLayers/Lang/en.js
+ */
+
+/**
+ * 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 - {Sring} 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*$/, "$1");
+ },
+
+ /**
+ * 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; i < oStringList.length; i++) {
+ var s = oStringList[i];
+ camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
+ }
+ return camelizedString;
+ },
+
+ /**
+ * APIFunction: format
+ * Given a string with tokens in the form ${token}, return a string
+ * with tokens replaced with properties from the given context
+ * object. Represent a literal "${" by doubling it, e.g. "${${".
+ *
+ * Parameters:
+ * template - {String} A string with tokens to be replaced. A template
+ * has the form "literal ${token}" where the token will be replaced
+ * by the value of context["token"].
+ * context - {Object} An optional object with properties corresponding
+ * to the tokens in the format string. If no context is sent, the
+ * window object will be used.
+ * args - {Array} Optional arguments to pass to any functions found in
+ * the context. If a context property is a function, the token
+ * will be replaced by the return from the function called with
+ * these arguments.
+ *
+ * Returns:
+ * {String} A string with tokens replaced from the context object.
+ */
+ format: function(template, context, args) {
+ if(!context) {
+ context = window;
+ }
+ var tokens = template.split("${");
+ var item, last, replacement;
+ for(var i=1; i<tokens.length; i++) {
+ item = tokens[i];
+ last = item.indexOf("}");
+ if(last > 0) {
+ replacement = context[item.substring(0, last)];
+ if(typeof replacement == "function") {
+ replacement = args ?
+ replacement.apply(null, args) :
+ replacement();
+ }
+ tokens[i] = replacement + item.substring(++last);
+ } else {
+ tokens[i] = "${" + item;
+ }
+ }
+ return tokens.join("");
+ }
+
+};
+
+if (!String.prototype.startsWith) {
+ /**
+ * APIMethod: String.startsWith
+ * *Deprecated*. Whether or not a string starts with another string.
+ *
+ * Parameters:
+ * sStart - {Sring} The string we're testing for.
+ *
+ * Returns:
+ * {Boolean} Whether or not this string starts with the string passed in.
+ */
+ String.prototype.startsWith = function(sStart) {
+ OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+ {'newMethod':'OpenLayers.String.startsWith'}));
+ return OpenLayers.String.startsWith(this, sStart);
+ };
+}
+
+if (!String.prototype.contains) {
+ /**
+ * APIMethod: String.contains
+ * *Deprecated*. Whether or not a string contains another string.
+ *
+ * Parameters:
+ * str - {String} The string that we're testing for.
+ *
+ * Returns:
+ * {Boolean} Whether or not this string contains with the string passed in.
+ */
+ String.prototype.contains = function(str) {
+ OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+ {'newMethod':'OpenLayers.String.contains'}));
+ return OpenLayers.String.contains(this, str);
+ };
+}
+
+if (!String.prototype.trim) {
+ /**
+ * APIMethod: String.trim
+ * *Deprecated*. Removes leading and trailing whitespace characters from a string.
+ *
+ * Returns:
+ * {String} A trimmed version of the string - all leading and
+ * trailing spaces removed
+ */
+ String.prototype.trim = function() {
+ OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+ {'newMethod':'OpenLayers.String.trim'}));
+ return OpenLayers.String.trim(this);
+ };
+}
+
+if (!String.prototype.camelize) {
+ /**
+ * APIMethod: String.camelize
+ * *Deprecated*. Camel-case a hyphenated string.
+ * Ex. "chicken-head" becomes "chickenHead", and
+ * "-chicken-head" becomes "ChickenHead".
+ *
+ * Returns:
+ * {String} The string, camelized
+ */
+ String.prototype.camelize = function() {
+ OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+ {'newMethod':'OpenLayers.String.camelize'}));
+ return OpenLayers.String.camelize(this);
+ };
+}
+
+/**
+ * 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;
+ }
+};
+
+if (!Number.prototype.limitSigDigs) {
+ /**
+ * APIMethod: Number.limitSigDigs
+ * *Deprecated*. Limit the number of significant digits on an integer. Does *not*
+ * work with floats!
+ *
+ * Parameters:
+ * sig - {Integer}
+ *
+ * Returns:
+ * {Integer} The number, rounded to the specified number of significant digits.
+ * If null, 0, or negative value passed in, returns 0
+ */
+ Number.prototype.limitSigDigs = function(sig) {
+ OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+ {'newMethod':'OpenLayers.String.limitSigDigs'}));
+ return OpenLayers.Number.limitSigDigs(this, sig);
+ };
+}
+
+/**
+ * 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);
+ };
+ }
+};
+
+if (!Function.prototype.bind) {
+ /**
+ * APIMethod: Function.bind
+ * *Deprecated*. Bind a function to an object.
+ * Method to easily create closures with 'this' altered.
+ *
+ * Parameters:
+ * object - {Object} the this parameter
+ *
+ * Returns:
+ * {Function} A closure with 'this' altered to the first
+ * argument.
+ */
+ Function.prototype.bind = function() {
+ OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+ {'newMethod':'OpenLayers.String.bind'}));
+ // new function takes the same arguments with this function up front
+ Array.prototype.unshift.apply(arguments, [this]);
+ return OpenLayers.Function.bind.apply(null, arguments);
+ };
+}
+
+if (!Function.prototype.bindAsEventListener) {
+ /**
+ * APIMethod: Function.bindAsEventListener
+ * *Deprecated*. Bind a function to an object, and configure it to receive the
+ * event object as first parameter when called.
+ *
+ * Parameters:
+ * object - {Object} A reference to this.
+ *
+ * Returns:
+ * {Function}
+ */
+ Function.prototype.bindAsEventListener = function(object) {
+ OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+ {'newMethod':'OpenLayers.String.bindAsEventListener'}));
+ return OpenLayers.Function.bindAsEventListener(this, object);
+ };
+}
+
+/**
+ * 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/docs/Core_JavaScript_1.5_Reference: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<len; i++) {
+ if (i in array) {
+ var val = array[i];
+ if (callback.call(caller, val, i, array)) {
+ selected.push(val);
+ }
+ }
+ }
+ }
+ return selected;
+ }
+
+};
+/* ======================================================================
+ OpenLayers/BaseTypes/Class.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Constructor: OpenLayers.Class
+ * Base class used to construct all other classes. Includes support for
+ * multiple inheritance.
+ *
+ * This constructor is new in OpenLayers 2.5. At OpenLayers 3.0, the old
+ * syntax for creating classes and dealing with inheritance
+ * will be removed.
+ *
+ * To create a new OpenLayers-style class, use the following syntax:
+ * > var MyClass = OpenLayers.Class(prototype);
+ *
+ * To create a new OpenLayers-style class with multiple inheritance, use the
+ * following syntax:
+ * > var MyClass = OpenLayers.Class(Class1, Class2, prototype);
+ *
+ */
+OpenLayers.Class = function() {
+ var Class = function() {
+ /**
+ * This following condition can be removed at 3.0 - this is only for
+ * backwards compatibility while the Class.inherit method is still
+ * in use. So at 3.0, the following three lines would be replaced with
+ * simply:
+ * this.initialize.apply(this, arguments);
+ */
+ if (arguments && arguments[0] != OpenLayers.Class.isPrototype) {
+ this.initialize.apply(this, arguments);
+ }
+ };
+ var extended = {};
+ var parent;
+ for(var i=0; i<arguments.length; ++i) {
+ if(typeof arguments[i] == "function") {
+ // get the prototype of the superclass
+ parent = arguments[i].prototype;
+ } else {
+ // in this case we're extending with the prototype
+ parent = arguments[i];
+ }
+ OpenLayers.Util.extend(extended, parent);
+ }
+ Class.prototype = extended;
+ return Class;
+};
+
+/**
+ * Property: isPrototype
+ * *Deprecated*. This is no longer needed and will be removed at 3.0.
+ */
+OpenLayers.Class.isPrototype = function () {};
+
+/**
+ * APIFunction: OpenLayers.create
+ * *Deprecated*. Old method to create an OpenLayers style class. Use the
+ * <OpenLayers.Class> constructor instead.
+ *
+ * Returns:
+ * An OpenLayers class
+ */
+OpenLayers.Class.create = function() {
+ return function() {
+ if (arguments && arguments[0] != OpenLayers.Class.isPrototype) {
+ this.initialize.apply(this, arguments);
+ }
+ };
+};
+
+
+/**
+ * APIFunction: inherit
+ * *Deprecated*. Old method to inherit from one or more OpenLayers style
+ * classes. Use the <OpenLayers.Class> constructor instead.
+ *
+ * Parameters:
+ * class - One or more classes can be provided as arguments
+ *
+ * Returns:
+ * An object prototype
+ */
+OpenLayers.Class.inherit = function () {
+ var superClass = arguments[0];
+ var proto = new superClass(OpenLayers.Class.isPrototype);
+ for (var i = 1; i < arguments.length; i++) {
+ if (typeof arguments[i] == "function") {
+ var mixin = arguments[i];
+ arguments[i] = new mixin(OpenLayers.Class.isPrototype);
+ }
+ OpenLayers.Util.extend(proto, arguments[i]);
+ }
+ return proto;
+};
+/* ======================================================================
+ OpenLayers/Util.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * Namespace: Util
+ */
+OpenLayers.Util = {};
+
+/**
+ * Function: getElement
+ * This is the old $() from prototype
+ */
+OpenLayers.Util.getElement = function() {
+ var elements = [];
+
+ for (var i = 0; i < arguments.length; i++) {
+ var element = arguments[i];
+ if (typeof element == 'string') {
+ element = document.getElementById(element);
+ }
+ if (arguments.length == 1) {
+ return element;
+ }
+ elements.push(element);
+ }
+ return elements;
+};
+
+/**
+ * Maintain $() from prototype
+ */
+if ($ == null) {
+ var $ = OpenLayers.Util.getElement;
+}
+
+/**
+ * APIFunction: extend
+ * Copy all properties of a source object to a destination object. Modifies
+ * the passed in destination object. Any properties on the source object
+ * that are set to undefined will not be (re)set on the destination object.
+ *
+ * Parameters:
+ * destination - {Object} The object that will be modified
+ * source - {Object} The object with properties to be set on the destination
+ *
+ * Returns:
+ * {Object} The destination object.
+ */
+OpenLayers.Util.extend = function(destination, source) {
+ if(destination && source) {
+ for(var property in source) {
+ var value = source[property];
+ if(value !== undefined) {
+ destination[property] = value;
+ }
+ }
+
+ /**
+ * IE doesn't include the toString property when iterating over an object's
+ * properties with the for(property in object) syntax. Explicitly check if
+ * the source has its own toString property.
+ */
+
+ /*
+ * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative
+ * prototype object" when calling hawOwnProperty if the source object
+ * is an instance of window.Event.
+ */
+
+ var sourceIsEvt = typeof window.Event == "function"
+ && source instanceof window.Event;
+
+ if(!sourceIsEvt
+ && source.hasOwnProperty && source.hasOwnProperty('toString')) {
+ destination.toString = source.toString;
+ }
+ }
+ return destination;
+};
+
+
+/**
+ * Function: removeItem
+ * Remove an object from an array. Iterates through the array
+ * to find the item, then removes it.
+ *
+ * Parameters:
+ * array - {Array}
+ * item - {Object}
+ *
+ * Return
+ * {Array} A reference to the array
+ */
+OpenLayers.Util.removeItem = function(array, item) {
+ for(var i = array.length - 1; i >= 0; i--) {
+ if(array[i] == item) {
+ array.splice(i,1);
+ //break;more than once??
+ }
+ }
+ return array;
+};
+
+/**
+ * Function: clearArray
+ * *Deprecated*. This function will disappear in 3.0.
+ * Please use "array.length = 0" instead.
+ *
+ * Parameters:
+ * array - {Array}
+ */
+OpenLayers.Util.clearArray = function(array) {
+ OpenLayers.Console.warn(
+ OpenLayers.i18n(
+ "methodDeprecated", {'newMethod': 'array = []'}
+ )
+ );
+ array.length = 0;
+};
+
+/**
+ * Function: indexOf
+ * Seems to exist already in FF, but not in MOZ.
+ *
+ * Parameters:
+ * array - {Array}
+ * obj - {Object}
+ *
+ * Returns:
+ * {Integer} The index at, which the object was found in the array.
+ * If not found, returns -1.
+ */
+OpenLayers.Util.indexOf = function(array, obj) {
+
+ for(var i=0; i < array.length; i++) {
+ if (array[i] == obj) {
+ return i;
+ }
+ }
+ return -1;
+};
+
+
+
+/**
+ * Function: modifyDOMElement
+ *
+ * Modifies many properties of a DOM element all at once. Passing in
+ * null to an individual parameter will avoid setting the attribute.
+ *
+ * Parameters:
+ * id - {String} The element id attribute to set.
+ * px - {<OpenLayers.Pixel>} The left and top style position.
+ * sz - {<OpenLayers.Size>} The width and height style attributes.
+ * position - {String} The position attribute. eg: absolute,
+ * relative, etc.
+ * border - {String} The style.border attribute. eg:
+ * solid black 2px
+ * overflow - {String} The style.overview attribute.
+ * opacity - {Float} Fractional value (0.0 - 1.0)
+ */
+OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position,
+ border, overflow, opacity) {
+
+ if (id) {
+ element.id = id;
+ }
+ if (px) {
+ element.style.left = px.x + "px";
+ element.style.top = px.y + "px";
+ }
+ if (sz) {
+ element.style.width = sz.w + "px";
+ element.style.height = sz.h + "px";
+ }
+ if (position) {
+ element.style.position = position;
+ }
+ if (border) {
+ element.style.border = border;
+ }
+ if (overflow) {
+ element.style.overflow = overflow;
+ }
+ if (parseFloat(opacity) >= 0.0 && parseFloat(opacity) < 1.0) {
+ element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
+ element.style.opacity = opacity;
+ } else if (parseFloat(opacity) == 1.0) {
+ element.style.filter = '';
+ element.style.opacity = '';
+ }
+};
+
+/**
+ * Function: createDiv
+ * Creates a new div and optionally set some standard attributes.
+ * Null may be passed to each parameter if you do not wish to
+ * set a particular attribute.
+ * Note - zIndex is NOT set on the resulting div.
+ *
+ * Parameters:
+ * id - {String} An identifier for this element. If no id is
+ * passed an identifier will be created
+ * automatically.
+ * px - {<OpenLayers.Pixel>} The element left and top position.
+ * sz - {<OpenLayers.Size>} The element width and height.
+ * imgURL - {String} A url pointing to an image to use as a
+ * background image.
+ * position - {String} The style.position value. eg: absolute,
+ * relative etc.
+ * border - {String} The the style.border value.
+ * eg: 2px solid black
+ * overflow - {String} The style.overflow value. Eg. hidden
+ * opacity - {Float} Fractional value (0.0 - 1.0)
+ *
+ * Returns:
+ * {DOMElement} A DOM Div created with the specified attributes.
+ */
+OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position,
+ border, overflow, opacity) {
+
+ var dom = document.createElement('div');
+
+ if (imgURL) {
+ dom.style.backgroundImage = 'url(' + imgURL + ')';
+ }
+
+ //set generic properties
+ if (!id) {
+ id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
+ }
+ if (!position) {
+ position = "absolute";
+ }
+ OpenLayers.Util.modifyDOMElement(dom, id, px, sz, position,
+ border, overflow, opacity);
+
+ return dom;
+};
+
+/**
+ * Function: createImage
+ * Creates an img element with specific attribute values.
+ *
+ * Parameters:
+ * id - {String} The id field for the img. If none assigned one will be
+ * automatically generated.
+ * px - {<OpenLayers.Pixel>} The left and top positions.
+ * sz - {<OpenLayers.Size>} The style.width and style.height values.
+ * imgURL - {String} The url to use as the image source.
+ * position - {String} The style.position value.
+ * border - {String} The border to place around the image.
+ * delayDisplay - {Boolean} If true waits until the image has been
+ * loaded.
+ * opacity - {Float} Fractional value (0.0 - 1.0)
+ *
+ * Returns:
+ * {DOMElement} A DOM Image created with the specified attributes.
+ */
+OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border,
+ opacity, delayDisplay) {
+
+ var image = document.createElement("img");
+
+ //set generic properties
+ if (!id) {
+ id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
+ }
+ if (!position) {
+ position = "relative";
+ }
+ OpenLayers.Util.modifyDOMElement(image, id, px, sz, position,
+ border, null, opacity);
+
+ if(delayDisplay) {
+ image.style.display = "none";
+ OpenLayers.Event.observe(image, "load",
+ OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, image));
+ OpenLayers.Event.observe(image, "error",
+ OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, image));
+
+ }
+
+ //set special properties
+ image.style.alt = id;
+ image.galleryImg = "no";
+ if (imgURL) {
+ image.src = imgURL;
+ }
+
+
+
+ return image;
+};
+
+/**
+ * Function: setOpacity
+ * *Deprecated*. This function has been deprecated. Instead, please use
+ * <OpenLayers.Util.modifyDOMElement>
+ * or
+ * <OpenLayers.Util.modifyAlphaImageDiv>
+ *
+ * Set the opacity of a DOM Element
+ * Note that for this function to work in IE, elements must "have layout"
+ * according to:
+ * http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp
+ *
+ * Parameters:
+ * element - {DOMElement} Set the opacity on this DOM element
+ * opacity - {Float} Opacity value (0.0 - 1.0)
+ */
+OpenLayers.Util.setOpacity = function(element, opacity) {
+ OpenLayers.Util.modifyDOMElement(element, null, null, null,
+ null, null, null, opacity);
+};
+
+/**
+ * Function: onImageLoad
+ * Bound to image load events. For all images created with <createImage> or
+ * <createAlphaImageDiv>, this function will be bound to the load event.
+ */
+OpenLayers.Util.onImageLoad = function() {
+ // The complex check here is to solve issues described in #480.
+ // Every time a map view changes, it increments the 'viewRequestID'
+ // property. As the requests for the images for the new map view are sent
+ // out, they are tagged with this unique viewRequestID.
+ //
+ // If an image has no viewRequestID property set, we display it regardless,
+ // but if it does have a viewRequestID property, we check that it matches
+ // the viewRequestID set on the map.
+ //
+ // If the viewRequestID on the map has changed, that means that the user
+ // has changed the map view since this specific request was sent out, and
+ // therefore this tile does not need to be displayed (so we do not execute
+ // this code that turns its display on).
+ //
+ if (!this.viewRequestID ||
+ (this.map && this.viewRequestID == this.map.viewRequestID)) {
+ this.style.backgroundColor = null;
+ this.style.display = "";
+ }
+};
+
+/**
+ * Property: onImageLoadErrorColor
+ * {String} The color tiles with load errors will turn.
+ * Default is "pink"
+ */
+OpenLayers.Util.onImageLoadErrorColor = "pink";
+
+/**
+ * Property: IMAGE_RELOAD_ATTEMPTS
+ * {Integer} How many times should we try to reload an image before giving up?
+ * Default is 0
+ */
+OpenLayers.IMAGE_RELOAD_ATTEMPTS = 0;
+
+/**
+ * Function: onImageLoadError
+ */
+OpenLayers.Util.onImageLoadError = function() {
+ this._attempts = (this._attempts) ? (this._attempts + 1) : 1;
+ if(this._attempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
+ this.src = this.src;
+ } else {
+ this.style.backgroundColor = OpenLayers.Util.onImageLoadErrorColor;
+ }
+ this.style.display = "";
+};
+
+/**
+ * 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 alpha has is necessary and possible, false otherwise.
+ */
+OpenLayers.Util.alphaHack = function() {
+ 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) {
+ }
+
+ return ( filter &&
+ (version >= 5.5) && (version < 7) );
+};
+
+/**
+ * Function: modifyAlphaImageDiv
+ *
+ * div - {DOMElement} Div containing Alpha-adjusted Image
+ * id - {String}
+ * px - {<OpenLayers.Pixel>}
+ * sz - {<OpenLayers.Size>}
+ * imgURL - {String}
+ * position - {String}
+ * border - {String}
+ * sizing {String} 'crop', 'scale', or 'image'. Default is "scale"
+ * opacity - {Float} Fractional value (0.0 - 1.0)
+ */
+OpenLayers.Util.modifyAlphaImageDiv = function(div, id, px, sz, imgURL,
+ position, border, sizing,
+ opacity) {
+
+ OpenLayers.Util.modifyDOMElement(div, id, px, sz,
+ null, 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()) {
+
+ div.style.display = "inline-block";
+ if (sizing == null) {
+ sizing = "scale";
+ }
+
+ div.style.filter = "progid:DXImageTransform.Microsoft" +
+ ".AlphaImageLoader(src='" + img.src + "', " +
+ "sizingMethod='" + sizing + "')";
+ if (parseFloat(div.style.opacity) >= 0.0 &&
+ parseFloat(div.style.opacity) < 1.0) {
+ div.style.filter += " alpha(opacity=" + div.style.opacity * 100 + ")";
+ }
+
+ img.style.filter = "alpha(opacity=0)";
+ }
+};
+
+/**
+ * Function: createAlphaImageDiv
+ *
+ * id - {String}
+ * px - {<OpenLayers.Pixel>}
+ * sz - {<OpenLayers.Size>}
+ * imgURL - {String}
+ * position - {String}
+ * border - {String}
+ * sizing {String} 'crop', 'scale', or 'image'. Default is "scale"
+ * delayDisplay{Boolean}
+ *
+ * Returns:
+ * {DOMElement} A DOM Div created with a DOM Image inside it. If the hack is
+ * needed for transparency in IE, it is added.
+ */
+OpenLayers.Util.createAlphaImageDiv = function(id, px, sz, imgURL,
+ position, border, sizing,
+ opacity, delayDisplay) {
+
+ var div = OpenLayers.Util.createDiv();
+ var img = OpenLayers.Util.createImage(null, null, null, null, null, null,
+ null, false);
+ div.appendChild(img);
+
+ if (delayDisplay) {
+ img.style.display = "none";
+ OpenLayers.Event.observe(img, "load",
+ OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, div));
+ OpenLayers.Event.observe(img, "error",
+ OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, div));
+ }
+
+ OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL, position,
+ border, sizing, opacity);
+
+ return div;
+};
+
+
+/**
+ * Function: upperCaseObject
+ * Creates a new hashtable and copies over all the keys from the
+ * passed-in object, but storing them under an uppercased
+ * version of the key at which they were stored.
+ *
+ * Parameters:
+ * object - {Object}
+ *
+ * Returns:
+ * {Object} A new Object with all the same keys but uppercased
+ */
+OpenLayers.Util.upperCaseObject = function (object) {
+ var uObject = {};
+ for (var key in object) {
+ uObject[key.toUpperCase()] = object[key];
+ }
+ return uObject;
+};
+
+/**
+ * Function: applyDefaults
+ * Takes an object and copies any properties that don't exist from
+ * another properties, by analogy with OpenLayers.Util.extend() from
+ * Prototype.js.
+ *
+ * Parameters:
+ * to - {Object} The destination object.
+ * from - {Object} The source object. Any properties of this object that
+ * are undefined in the to object will be set on the to object.
+ *
+ * Returns:
+ * {Object} A reference to the to object. Note that the to argument is modified
+ * in place and returned by this function.
+ */
+OpenLayers.Util.applyDefaults = function (to, from) {
+
+ /*
+ * 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.hasOwnProperty
+ && from.hasOwnProperty('toString') && !to.hasOwnProperty('toString')) {
+ to.toString = from.toString;
+ }
+
+ return to;
+};
+
+/**
+ * Function: getParameterString
+ *
+ * Parameters:
+ * params - {Object}
+ *
+ * Returns:
+ * {String} A concatenation of the properties of an object in
+ * http parameter notation.
+ * (ex. <i>"key1=value1&key2=value2&key3=value3"</i>)
+ * If a parameter is actually a list, that parameter will then
+ * be set to a comma-seperated list of values (foo,bar) instead
+ * of being URL escaped (foo%3Abar).
+ */
+OpenLayers.Util.getParameterString = function(params) {
+ var paramsArray = [];
+
+ for (var key in params) {
+ var value = params[key];
+ if ((value != null) && (typeof value != 'function')) {
+ var encodedValue;
+ if (typeof value == 'object' && value.constructor == Array) {
+ /* value is an array; encode items and separate with "," */
+ var encodedItemArray = [];
+ for (var itemIndex=0; itemIndex<value.length; itemIndex++) {
+ encodedItemArray.push(encodeURIComponent(value[itemIndex]));
+ }
+ encodedValue = encodedItemArray.join(",");
+ }
+ else {
+ /* value is a string; simply encode */
+ encodedValue = encodeURIComponent(value);
+ }
+ paramsArray.push(encodeURIComponent(key) + "=" + encodedValue);
+ }
+ }
+
+ return paramsArray.join("&");
+};
+
+/**
+ * Property: ImgPath
+ * {String} Default is ''.
+ */
+OpenLayers.ImgPath = '';
+
+/**
+ * Function: getImagesLocation
+ *
+ * Returns:
+ * {String} The fully formatted image location string
+ */
+OpenLayers.Util.getImagesLocation = function() {
+ return OpenLayers.ImgPath || (OpenLayers._getScriptLocation() + "img/");
+};
+
+
+/**
+ * Function: Try
+ * Execute functions until one of them doesn't throw an error.
+ * Capitalized because "try" is a reserved word in JavaScript.
+ * Taken directly from OpenLayers.Util.Try()
+ *
+ * Parameters:
+ * [*] - {Function} Any number of parameters may be passed to Try()
+ * It will attempt to execute each of them until one of them
+ * successfully executes.
+ * If none executes successfully, returns null.
+ *
+ * Returns:
+ * {*} The value returned by the first successfully executed function.
+ */
+OpenLayers.Util.Try = function() {
+ var returnValue = null;
+
+ for (var i = 0; i < arguments.length; i++) {
+ var lambda = arguments[i];
+ try {
+ returnValue = lambda();
+ break;
+ } catch (e) {}
+ }
+
+ return returnValue;
+};
+
+
+/**
+ * Function: getNodes
+ *
+ * These could/should be made namespace aware?
+ *
+ * Parameters:
+ * p - {}
+ * tagName - {String}
+ *
+ * Returns:
+ * {Array}
+ */
+OpenLayers.Util.getNodes=function(p, tagName) {
+ var nodes = OpenLayers.Util.Try(
+ function () {
+ return OpenLayers.Util._getNodes(p.documentElement.childNodes,
+ tagName);
+ },
+ function () {
+ return OpenLayers.Util._getNodes(p.childNodes, tagName);
+ }
+ );
+ return nodes;
+};
+
+/**
+ * Function: _getNodes
+ *
+ * Parameters:
+ * nodes - {Array}
+ * tagName - {String}
+ *
+ * Returns:
+ * {Array}
+ */
+OpenLayers.Util._getNodes=function(nodes, tagName) {
+ var retArray = [];
+ for (var i=0;i<nodes.length;i++) {
+ if (nodes[i].nodeName==tagName) {
+ retArray.push(nodes[i]);
+ }
+ }
+
+ return retArray;
+};
+
+
+
+/**
+ * Function: getTagText
+ *
+ * Parameters:
+ * parent - {}
+ * item - {String}
+ * index - {Integer}
+ *
+ * Returns:
+ * {String}
+ */
+OpenLayers.Util.getTagText = function (parent, item, index) {
+ var result = OpenLayers.Util.getNodes(parent, item);
+ if (result && (result.length > 0))
+ {
+ if (!index) {
+ index=0;
+ }
+ if (result[index].childNodes.length > 1) {
+ return result.childNodes[1].nodeValue;
+ }
+ else if (result[index].childNodes.length == 1) {
+ return result[index].firstChild.nodeValue;
+ }
+ } else {
+ return "";
+ }
+};
+
+/**
+ * Function: getXmlNodeValue
+ *
+ * Parameters:
+ * node - {XMLNode}
+ *
+ * Returns:
+ * {String} The text value of the given node, without breaking in firefox or IE
+ */
+OpenLayers.Util.getXmlNodeValue = function(node) {
+ var val = null;
+ OpenLayers.Util.Try(
+ function() {
+ val = node.text;
+ if (!val) {
+ val = node.textContent;
+ }
+ if (!val) {
+ val = node.firstChild.nodeValue;
+ }
+ },
+ function() {
+ val = node.textContent;
+ });
+ return val;
+};
+
+/**
+ * Function: mouseLeft
+ *
+ * Parameters:
+ * evt - {Event}
+ * div - {HTMLDivElement}
+ *
+ * Returns:
+ * {Boolean}
+ */
+OpenLayers.Util.mouseLeft = function (evt, div) {
+ // start with the element to which the mouse has moved
+ var target = (evt.relatedTarget) ? evt.relatedTarget : evt.toElement;
+ // walk up the DOM tree.
+ while (target != div && target != null) {
+ target = target.parentNode;
+ }
+ // if the target we stop at isn't the div, then we've left the div.
+ return (target != div);
+};
+
+/**
+ * Function: rad
+ *
+ * Parameters:
+ * x - {Float}
+ *
+ * Returns:
+ * {Float}
+ */
+OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
+
+/**
+ * Function: distVincenty
+ *
+ * Parameters:
+ * p1 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
+ * p2 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
+ *
+ * Returns:
+ * {Float}
+ */
+OpenLayers.Util.distVincenty=function(p1, p2) {
+ var a = 6378137, b = 6356752.3142, f = 1/298.257223563;
+ 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;
+};
+
+/**
+ * Function: getParameters
+ * Parse the parameters from a URL or from the current page itself into a
+ * JavaScript Object. Note that parameter values with commas are separated
+ * out into an Array.
+ *
+ * Parameters:
+ * url - {String} Optional url used to extract the query string.
+ * If null, query string is taken from page location.
+ *
+ * Returns:
+ * {Object} An object of key/value pairs from the query string.
+ */
+OpenLayers.Util.getParameters = function(url) {
+ // if no url specified, take it from the location bar
+ url = url || window.location.href;
+
+ //parse out parameters portion of url string
+ var paramsString = "";
+ if (OpenLayers.String.contains(url, '?')) {
+ var start = url.indexOf('?') + 1;
+ var end = OpenLayers.String.contains(url, "#") ?
+ url.indexOf('#') : url.length;
+ paramsString = url.substring(start, end);
+ }
+
+ var parameters = {};
+ var pairs = paramsString.split(/[&;]/);
+ for(var i = 0; i < pairs.length; ++i) {
+ var keyValue = pairs[i].split('=');
+ if (keyValue[0]) {
+ var key = decodeURIComponent(keyValue[0]);
+ var value = keyValue[1] || ''; //empty string if no value
+
+ //decode individual values
+ value = value.split(",");
+ for(var j=0; j < value.length; j++) {
+ value[j] = decodeURIComponent(value[j]);
+ }
+
+ //if there's only one value, do not return as array
+ if (value.length == 1) {
+ value = value[0];
+ }
+
+ parameters[key] = value;
+ }
+ }
+ return parameters;
+};
+
+/**
+ * Function: getArgs
+ * *Deprecated*. Will be removed in 3.0. Please use instead
+ * <OpenLayers.Util.getParameters>
+ *
+ * Parameters:
+ * url - {String} Optional url used to extract the query string.
+ * If null, query string is taken from page location.
+ *
+ * Returns:
+ * {Object} An object of key/value pairs from the query string.
+ */
+OpenLayers.Util.getArgs = function(url) {
+ OpenLayers.Console.warn(
+ OpenLayers.i18n(
+ "methodDeprecated", {'newMethod': 'OpenLayers.Util.getParameters'}
+ )
+ );
+ return OpenLayers.Util.getParameters(url);
+};
+
+/**
+ * Property: lastSeqID
+ * {Integer} The ever-incrementing count variable.
+ * Used for generating unique ids.
+ */
+OpenLayers.Util.lastSeqID = 0;
+
+/**
+ * Function: createUniqueID
+ * Create a unique identifier for this session. Each time this function
+ * is called, a counter is incremented. The return will be the optional
+ * prefix (defaults to "id_") appended with the counter value.
+ *
+ * Parameters:
+ * prefix {String} Optionsal string to prefix unique id. Default is "id_".
+ *
+ * Returns:
+ * {String} A unique id string, built on the passed in prefix.
+ */
+OpenLayers.Util.createUniqueID = function(prefix) {
+ if (prefix == null) {
+ prefix = "id_";
+ }
+ OpenLayers.Util.lastSeqID += 1;
+ return prefix + OpenLayers.Util.lastSeqID;
+};
+
+/**
+ * Constant: INCHES_PER_UNIT
+ * {Object} Constant inches per unit -- borrowed from MapServer mapscale.c
+ * derivation of nautical miles from http://en.wikipedia.org/wiki/Nautical_mile
+ */
+OpenLayers.INCHES_PER_UNIT = {
+ 'inches': 1.0,
+ 'ft': 12.0,
+ 'mi': 63360.0,
+ 'm': 39.3701,
+ 'km': 39370.1,
+ 'dd': 4374754,
+ 'yd': 36
+};
+OpenLayers.INCHES_PER_UNIT["in"]= OpenLayers.INCHES_PER_UNIT.inches;
+OpenLayers.INCHES_PER_UNIT["degrees"] = OpenLayers.INCHES_PER_UNIT.dd;
+OpenLayers.INCHES_PER_UNIT["nmi"] = 1852 * OpenLayers.INCHES_PER_UNIT.m;
+
+/**
+ * Constant: DOTS_PER_INCH
+ * {Integer} 72 (A sensible default)
+ */
+OpenLayers.DOTS_PER_INCH = 72;
+
+/**
+ * Function: normalzeScale
+ *
+ * Parameters:
+ * scale - {float}
+ *
+ * Returns:
+ * {Float} A normalized scale value, in 1 / X format.
+ * This means that if a value less than one ( already 1/x) is passed
+ * in, it just returns scale directly. Otherwise, it returns
+ * 1 / scale
+ */
+OpenLayers.Util.normalizeScale = function (scale) {
+ var normScale = (scale > 1.0) ? (1.0 / scale)
+ : scale;
+ return normScale;
+};
+
+/**
+ * Function: getResolutionFromScale
+ *
+ * Parameters:
+ * scale - {Float}
+ * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
+ * Default is degrees
+ *
+ * Returns:
+ * {Float} The corresponding resolution given passed-in scale and unit
+ * parameters.
+ */
+OpenLayers.Util.getResolutionFromScale = function (scale, units) {
+
+ if (units == null) {
+ units = "degrees";
+ }
+
+ var normScale = OpenLayers.Util.normalizeScale(scale);
+
+ var resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units]
+ * OpenLayers.DOTS_PER_INCH);
+ return resolution;
+};
+
+/**
+ * Function: getScaleFromResolution
+ *
+ * Parameters:
+ * resolution - {Float}
+ * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
+ * Default is degrees
+ *
+ * Returns:
+ * {Float} The corresponding scale given passed-in resolution and unit
+ * parameters.
+ */
+OpenLayers.Util.getScaleFromResolution = function (resolution, units) {
+
+ if (units == null) {
+ units = "degrees";
+ }
+
+ var scale = resolution * OpenLayers.INCHES_PER_UNIT[units] *
+ OpenLayers.DOTS_PER_INCH;
+ return scale;
+};
+
+/**
+ * Function: safeStopPropagation
+ * *Deprecated*. This function has been deprecated. Please use directly
+ * <OpenLayers.Event.stop> passing 'true' as the 2nd
+ * argument (preventDefault)
+ *
+ * Safely stop the propagation of an event *without* preventing
+ * the default browser action from occurring.
+ *
+ * Parameter:
+ * evt - {Event}
+ */
+OpenLayers.Util.safeStopPropagation = function(evt) {
+ OpenLayers.Event.stop(evt, true);
+};
+
+/**
+ * Function: pagePositon
+ * Calculates the position of an element on the page.
+ *
+ * Parameters:
+ * forElement - {DOMElement}
+ *
+ * Returns:
+ * {Array} two item array, L value then T value.
+ */
+OpenLayers.Util.pagePosition = function(forElement) {
+ var valueT = 0, valueL = 0;
+
+ var element = forElement;
+ var child = forElement;
+ while(element) {
+
+ if(element == document.body) {
+ // FIXME: IE, when passed 'window' as the forElement, treats it as
+ // equal to document.body, but window.style fails, so getStyle
+ // fails, so we are paranoid and check this here. This check should
+ // probably move into element.getStyle in 2.6.
+ if(child && child.style &&
+ OpenLayers.Element.getStyle(child, 'position') == 'absolute') {
+ break;
+ }
+ }
+
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+
+ child = element;
+ try {
+ // wrapping this in a try/catch because IE chokes on the offsetParent
+ element = element.offsetParent;
+ } catch(e) {
+ OpenLayers.Console.error(OpenLayers.i18n(
+ "pagePositionFailed",{'elemId':element.id}));
+ break;
+ }
+ }
+
+ element = forElement;
+ while(element) {
+ valueT -= element.scrollTop || 0;
+ valueL -= element.scrollLeft || 0;
+ element = element.parentNode;
+ }
+
+ return [valueL, valueT];
+};
+
+
+/**
+ * Function: isEquivalentUrl
+ * Test two URLs for equivalence.
+ *
+ * Setting 'ignoreCase' allows for case-independent comparison.
+ *
+ * Comparison is based on:
+ * - Protocol
+ * - Host (evaluated without the port)
+ * - Port (set 'ignorePort80' to ignore "80" values)
+ * - Hash ( set 'ignoreHash' to disable)
+ * - Pathname (for relative <-> absolute comparison)
+ * - Arguments (so they can be out of order)
+ *
+ * Parameters:
+ * url1 - {String}
+ * url2 - {String}
+ * options - {Object} Allows for customization of comparison:
+ * 'ignoreCase' - Default is True
+ * 'ignorePort80' - Default is True
+ * 'ignoreHash' - Default is True
+ *
+ * Returns:
+ * {Boolean} Whether or not the two URLs are equivalent
+ */
+OpenLayers.Util.isEquivalentUrl = function(url1, url2, options) {
+ options = options || {};
+
+ OpenLayers.Util.applyDefaults(options, {
+ ignoreCase: true,
+ ignorePort80: true,
+ ignoreHash: true
+ });
+
+ var urlObj1 = OpenLayers.Util.createUrlObject(url1, options);
+ var urlObj2 = OpenLayers.Util.createUrlObject(url2, options);
+
+ //compare all keys (host, port, etc)
+ for(var key in urlObj1) {
+ if (options.test) {
+ alert(key + "\n1:" + urlObj1[key] + "\n2:" + urlObj2[key]);
+ }
+ var val1 = urlObj1[key];
+ var val2 = urlObj2[key];
+
+ switch(key) {
+ case "args":
+ //do nothing, they'll be treated below
+ break;
+ case "host":
+ case "port":
+ case "protocol":
+ if ((val1 == "") || (val2 == "")) {
+ //these will be blank for relative urls, so no need to
+ // compare them here -- call break.
+ //
+ break;
+ }
+ // otherwise continue with default compare
+ //
+ default:
+ if ( (key != "args") && (urlObj1[key] != urlObj2[key]) ) {
+ return false;
+ }
+ break;
+ }
+
+ }
+
+ // compare search args - irrespective of order
+ for(var key in urlObj1.args) {
+ if(urlObj1.args[key] != urlObj2.args[key]) {
+ return false;
+ }
+ delete urlObj2.args[key];
+ }
+ // urlObj2 shouldn't have any args left
+ for(var key in urlObj2.args) {
+ return false;
+ }
+
+ return true;
+};
+
+/**
+ * Function: createUrlObject
+ *
+ * Parameters:
+ * url - {String}
+ * options - {Object} A hash of options. Can be one of:
+ * ignoreCase: lowercase url,
+ * ignorePort80: don't include explicit port if port is 80,
+ * ignoreHash: Don't include part of url after the hash (#).
+ *
+ * Returns:
+ * {Object} An object with separate url, a, port, host, and args parsed out
+ * and ready for comparison
+ */
+OpenLayers.Util.createUrlObject = function(url, options) {
+ options = options || {};
+
+ var urlObject = {};
+
+ if (options.ignoreCase) {
+ url = url.toLowerCase();
+ }
+
+ var a = document.createElement('a');
+ a.href = url;
+
+ //host (without port)
+ urlObject.host = a.host;
+ var port = a.port;
+ if (port.length <= 0) {
+ var newHostLength = urlObject.host.length - (port.length);
+ urlObject.host = urlObject.host.substring(0, newHostLength);
+ }
+
+ //protocol
+ urlObject.protocol = a.protocol;
+
+ //port
+ urlObject.port = ((port == "80") && (options.ignorePort80)) ? "" : port;
+
+ //hash
+ urlObject.hash = (options.ignoreHash) ? "" : 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 part allows for relative <-> absolute comparison)
+ if ( ((urlObject.protocol == "file:") && (url.indexOf("file:") != -1)) ||
+ ((urlObject.protocol != "file:") && (urlObject.host != "")) ) {
+
+ urlObject.pathname = a.pathname;
+
+ //Test to see if the pathname includes the arguments (Opera)
+ var qIndex = urlObject.pathname.indexOf("?");
+ if (qIndex != -1) {
+ urlObject.pathname = urlObject.pathname.substring(0, qIndex);
+ }
+
+ } else {
+ var relStr = OpenLayers.Util.removeTail(url);
+
+ var backs = 0;
+ do {
+ var index = relStr.indexOf("../");
+
+ if (index == 0) {
+ backs++;
+ relStr = relStr.substr(3);
+ } else if (index >= 0) {
+ var prevChunk = relStr.substr(0,index - 1);
+
+ var slash = prevChunk.indexOf("/");
+ prevChunk = (slash != -1) ? prevChunk.substr(0, slash +1)
+ : "";
+
+ var postChunk = relStr.substr(index + 3);
+ relStr = prevChunk + postChunk;
+ }
+ } while(index != -1)
+
+ var windowAnchor = document.createElement("a");
+ var windowUrl = window.location.href;
+ if (options.ignoreCase) {
+ windowUrl = windowUrl.toLowerCase();
+ }
+ windowAnchor.href = windowUrl;
+
+ //set protocol of window
+ urlObject.protocol = windowAnchor.protocol;
+
+ var splitter = (windowAnchor.pathname.indexOf("/") != -1) ? "/" : "\\";
+ var dirs = windowAnchor.pathname.split(splitter);
+ dirs.pop(); //remove filename
+ while ((backs > 0) && (dirs.length > 0)) {
+ dirs.pop();
+ backs--;
+ }
+ relStr = dirs.join("/") + "/"+ relStr;
+ urlObject.pathname = relStr;
+ }
+
+ if ((urlObject.protocol == "file:") || (urlObject.protocol == "")) {
+ urlObject.host = "localhost";
+ }
+
+ return urlObject;
+};
+
+/**
+ * Function: removeTail
+ * Takes a url and removes everything after the ? and #
+ *
+ * Parameters:
+ * url - {String} The url to process
+ *
+ * Returns:
+ * {String} The string with all queryString and Hash removed
+ */
+OpenLayers.Util.removeTail = function(url) {
+ var head = null;
+
+ var qMark = url.indexOf("?");
+ var hashMark = url.indexOf("#");
+
+ if (qMark == -1) {
+ head = (hashMark != -1) ? url.substr(0,hashMark) : url;
+ } else {
+ head = (hashMark != -1) ? url.substr(0,Math.min(qMark, hashMark))
+ : url.substr(0, qMark);
+ }
+ return head;
+};
+
+
+/**
+ * Function: getBrowserName
+ *
+ * Returns:
+ * {String} A string which specifies which is the current
+ * browser in which we are running.
+ *
+ * Currently-supported browser detection and codes:
+ * * 'opera' -- Opera
+ * * 'msie' -- Internet Explorer
+ * * 'safari' -- Safari
+ * * 'firefox' -- FireFox
+ * * 'mozilla' -- Mozilla
+ *
+ * If we are unable to property identify the browser, we
+ * return an empty string.
+ */
+OpenLayers.Util.getBrowserName = function() {
+ var browserName = "";
+
+ var ua = navigator.userAgent.toLowerCase();
+ if ( ua.indexOf( "opera" ) != -1 ) {
+ browserName = "opera";
+ } else if ( ua.indexOf( "msie" ) != -1 ) {
+ browserName = "msie";
+ } else if ( ua.indexOf( "safari" ) != -1 ) {
+ browserName = "safari";
+ } else if ( ua.indexOf( "mozilla" ) != -1 ) {
+ if ( ua.indexOf( "firefox" ) != -1 ) {
+ browserName = "firefox";
+ } else {
+ browserName = "mozilla";
+ }
+ }
+
+ return browserName;
+};
+
+
+
+
+/**
+ * Method: getRenderedDimensions
+ * Renders the contentHTML offscreen to determine actual dimensions for
+ * popup sizing. As we need layout to determine dimensions the content
+ * is rendered -9999px to the left and absolute to ensure the
+ * scrollbars do not flicker
+ *
+ * Parameters:
+ * size - {<OpenLayers.Size>} If either the 'w' or 'h' properties is
+ * specified, we fix that dimension of the div to be measured. This is
+ * useful in the case where we have a limit in one dimension and must
+ * therefore meaure the flow in the other dimension.
+ *
+ * Returns:
+ * {OpenLayers.Size}
+ */
+OpenLayers.Util.getRenderedDimensions = function(contentHTML, size) {
+
+ var w = h = null;
+
+ // create temp container div with restricted size
+ var container = document.createElement("div");
+ container.style.overflow= "";
+ container.style.position = "absolute";
+ container.style.left = "-9999px";
+
+ //fix a dimension, if specified.
+ if (size) {
+ if (size.w) {
+ w = container.style.width = size.w;
+ } else if (size.h) {
+ h = container.style.height = size.h;
+ }
+ }
+
+ // create temp content div and assign content
+ var content = document.createElement("div");
+ content.innerHTML = contentHTML;
+
+ // add content to restricted container
+ container.appendChild(content);
+
+ // append container to body for rendering
+ document.body.appendChild(container);
+
+ // calculate scroll width of content and add corners and shadow width
+ if (!w) {
+ w = parseInt(content.scrollWidth);
+
+ // update container width to allow height to adjust
+ container.style.width = w + "px";
+ }
+ // capture height and add shadow and corner image widths
+ if (!h) {
+ h = parseInt(content.scrollHeight);
+ }
+
+ // remove elements
+ container.removeChild(content);
+ document.body.removeChild(container);
+
+ return new OpenLayers.Size(w, h);
+};
+
+/**
+ * APIFunction: getScrollbarWidth
+ * This function has been modified by the OpenLayers from the original version,
+ * written by Matthew Eernisse and released under the Apache 2
+ * license here:
+ *
+ * http://www.fleegix.org/articles/2006/05/30/getting-the-scrollbar-width-in-pixels
+ *
+ * It has been modified simply to cache its value, since it is physically
+ * impossible that this code could ever run in more than one browser at
+ * once.
+ *
+ * Returns:
+ * {Integer}
+ */
+OpenLayers.Util.getScrollbarWidth = function() {
+
+ var scrollbarWidth = OpenLayers.Util._scrollbarWidth;
+
+ if (scrollbarWidth == null) {
+ var scr = null;
+ var inn = null;
+ var wNoScroll = 0;
+ var wScroll = 0;
+
+ // Outer scrolling div
+ scr = document.createElement('div');
+ scr.style.position = 'absolute';
+ scr.style.top = '-1000px';
+ scr.style.left = '-1000px';
+ scr.style.width = '100px';
+ scr.style.height = '50px';
+ // Start with no scrollbar
+ scr.style.overflow = 'hidden';
+
+ // Inner content div
+ inn = document.createElement('div');
+ inn.style.width = '100%';
+ inn.style.height = '200px';
+
+ // Put the inner div in the scrolling div
+ scr.appendChild(inn);
+ // Append the scrolling div to the doc
+ document.body.appendChild(scr);
+
+ // Width of the inner div sans scrollbar
+ wNoScroll = inn.offsetWidth;
+
+ // Add the scrollbar
+ scr.style.overflow = 'scroll';
+ // Width of the inner div width scrollbar
+ wScroll = inn.offsetWidth;
+
+ // Remove the scrolling div from the doc
+ document.body.removeChild(document.body.lastChild);
+
+ // Pixel width of the scroller
+ OpenLayers.Util._scrollbarWidth = (wNoScroll - wScroll);
+ scrollbarWidth = OpenLayers.Util._scrollbarWidth;
+ }
+
+ return scrollbarWidth;
+};
+/* ======================================================================
+ OpenLayers/Ajax.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+OpenLayers.ProxyHost = "";
+//OpenLayers.ProxyHost = "examples/proxy.cgi?url=";
+
+/**
+ * Ajax reader for OpenLayers
+ *
+ * @uri url to do remote XML http get
+ * @param {String} 'get' format params (x=y&a=b...)
+ * @who object to handle callbacks for this request
+ * @complete the function to be called on success
+ * @failure the function to be called on failure
+ *
+ * example usage from a caller:
+ *
+ * caps: function(request) {
+ * -blah-
+ * },
+ *
+ * OpenLayers.loadURL(url,params,this,caps);
+ *
+ * Notice the above example does not provide an error handler; a default empty
+ * handler is provided which merely logs the error if a failure handler is not
+ * supplied
+ *
+ */
+
+
+/**
+* @param {} request
+*/
+OpenLayers.nullHandler = function(request) {
+ alert(OpenLayers.i18n("unhandledRequest", {'statusText':request.statusText}));
+};
+
+/**
+ * Function: loadURL
+ * Background load a document.
+ *
+ * Parameters:
+ * uri - {String} URI of source doc
+ * params - {String} Params on get (doesnt seem to work)
+ * caller - {Object} object which gets callbacks
+ * onComplete - {Function} Optional callback for success. The callback
+ * will be called with this set to caller and will receive the request
+ * object as an argument.
+ * onFailure - {Function} Optional callback for failure. In the event of
+ * a failure, the callback will be called with this set to caller and will
+ * receive the request object as an argument.
+ *
+ * Returns:
+ * {XMLHttpRequest} The request object. To abort loading, call
+ * request.abort().
+ */
+OpenLayers.loadURL = function(uri, params, caller,
+ onComplete, onFailure) {
+
+ var success = (onComplete) ? OpenLayers.Function.bind(onComplete, caller)
+ : OpenLayers.nullHandler;
+
+ var failure = (onFailure) ? OpenLayers.Function.bind(onFailure, caller)
+ : OpenLayers.nullHandler;
+
+ // from prototype.js
+ var request = new OpenLayers.Ajax.Request(
+ uri,
+ {
+ method: 'get',
+ parameters: params,
+ onComplete: success,
+ onFailure: failure
+ }
+ );
+ return request.transport;
+};
+
+/**
+ * Function: parseXMLString
+ * Parse XML into a doc structure
+ *
+ * Parameters:
+ * text - {String}
+ *
+ * Returns:
+ * {?} Parsed AJAX Responsev
+ */
+OpenLayers.parseXMLString = function(text) {
+
+ //MS sucks, if the server is bad it dies
+ var index = text.indexOf('<');
+ if (index > 0) {
+ text = text.substring(index);
+ }
+
+ var ajaxResponse = OpenLayers.Util.Try(
+ function() {
+ var xmldom = new ActiveXObject('Microsoft.XMLDOM');
+ xmldom.loadXML(text);
+ return xmldom;
+ },
+ function() {
+ return new DOMParser().parseFromString(text, 'text/xml');
+ },
+ function() {
+ var req = new XMLHttpRequest();
+ req.open("GET", "data:" + "text/xml" +
+ ";charset=utf-8," + encodeURIComponent(text), false);
+ if (req.overrideMimeType) {
+ req.overrideMimeType("text/xml");
+ }
+ req.send(null);
+ return req.responseXML;
+ }
+ );
+
+ return ajaxResponse;
+};
+
+
+/**
+ * Namespace: OpenLayers.Ajax
+ */
+OpenLayers.Ajax = {
+
+ /**
+ * Method: emptyFunction
+ */
+ emptyFunction: function () {},
+
+ /**
+ * Method: getTransport
+ *
+ * Returns:
+ * {Object} Transport mechanism for whichever browser we're in, or false if
+ * none available.
+ */
+ getTransport: function() {
+ return OpenLayers.Util.Try(
+ function() {return new XMLHttpRequest();},
+ function() {return new ActiveXObject('Msxml2.XMLHTTP');},
+ function() {return new ActiveXObject('Microsoft.XMLHTTP');}
+ ) || false;
+ },
+
+ /**
+ * Property: activeRequestCount
+ * {Integer}
+ */
+ activeRequestCount: 0
+};
+
+/**
+ * Namespace: OpenLayers.Ajax.Responders
+ * {Object}
+ */
+OpenLayers.Ajax.Responders = {
+
+ /**
+ * Property: responders
+ * {Array}
+ */
+ responders: [],
+
+ /**
+ * Method: register
+ *
+ * Parameters:
+ * responderToAdd - {?}
+ */
+ register: function(responderToAdd) {
+ for (var i = 0; i < this.responders.length; i++){
+ if (responderToAdd == this.responders[i]){
+ return;
+ }
+ }
+ this.responders.push(responderToAdd);
+ },
+
+ /**
+ * Method: unregister
+ *
+ * Parameters:
+ * responderToRemove - {?}
+ */
+ unregister: function(responderToRemove) {
+ OpenLayers.Util.removeItem(this.reponders, responderToRemove);
+ },
+
+ /**
+ * Method: dispatch
+ *
+ * Parameters:
+ * callback - {?}
+ * request - {?}
+ * transport - {?}
+ */
+ dispatch: function(callback, request, transport) {
+ var responder;
+ for (var i = 0; i < this.responders.length; i++) {
+ responder = this.responders[i];
+
+ if (responder[callback] &&
+ typeof responder[callback] == 'function') {
+ try {
+ responder[callback].apply(responder,
+ [request, transport]);
+ } catch (e) {}
+ }
+ }
+ }
+};
+
+OpenLayers.Ajax.Responders.register({
+ /**
+ * Function: onCreate
+ */
+ onCreate: function() {
+ OpenLayers.Ajax.activeRequestCount++;
+ },
+
+ /**
+ * Function: onComplete
+ */
+ onComplete: function() {
+ OpenLayers.Ajax.activeRequestCount--;
+ }
+});
+
+/**
+ * Class: OpenLayers.Ajax.Base
+ */
+OpenLayers.Ajax.Base = OpenLayers.Class({
+
+ /**
+ * Constructor: OpenLayers.Ajax.Base
+ *
+ * Parameters:
+ * options - {Object}
+ */
+ initialize: function(options) {
+ this.options = {
+ method: 'post',
+ asynchronous: true,
+ contentType: 'application/xml',
+ parameters: ''
+ };
+ OpenLayers.Util.extend(this.options, options || {});
+
+ this.options.method = this.options.method.toLowerCase();
+
+ if (typeof this.options.parameters == 'string') {
+ this.options.parameters =
+ OpenLayers.Util.getParameters(this.options.parameters);
+ }
+ }
+});
+
+/**
+ * Class: OpenLayers.Ajax.Request
+ *
+ * Inherit:
+ * - <OpenLayers.Ajax.Base>
+ */
+OpenLayers.Ajax.Request = OpenLayers.Class(OpenLayers.Ajax.Base, {
+
+ /**
+ * Property: _complete
+ *
+ * {Boolean}
+ */
+ _complete: false,
+
+ /**
+ * Constructor: OpenLayers.Ajax.Request
+ *
+ * Parameters:
+ * url - {String}
+ * options - {Object}
+ */
+ initialize: function(url, options) {
+ OpenLayers.Ajax.Base.prototype.initialize.apply(this, [options]);
+
+ if (OpenLayers.ProxyHost && OpenLayers.String.startsWith(url, "http")) {
+ url = OpenLayers.ProxyHost + encodeURIComponent(url);
+ }
+
+ this.transport = OpenLayers.Ajax.getTransport();
+ this.request(url);
+ },
+
+ /**
+ * Method: request
+ *
+ * Parameters:
+ * url - {String}
+ */
+ request: function(url) {
+ this.url = url;
+ this.method = this.options.method;
+ var params = OpenLayers.Util.extend({}, this.options.parameters);
+
+ if (this.method != 'get' && this.method != 'post') {
+ // simulate other verbs over post
+ params['_method'] = this.method;
+ this.method = 'post';
+ }
+
+ this.parameters = params;
+
+ if (params = OpenLayers.Util.getParameterString(params)) {
+ // when GET, append parameters to URL
+ if (this.method == 'get') {
+ this.url += ((this.url.indexOf('?') > -1) ? '&' : '?') + params;
+ } else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+ params += '&_=';
+ }
+ }
+ try {
+ var response = new OpenLayers.Ajax.Response(this);
+ if (this.options.onCreate) {
+ this.options.onCreate(response);
+ }
+
+ OpenLayers.Ajax.Responders.dispatch('onCreate',
+ this,
+ response);
+
+ this.transport.open(this.method.toUpperCase(),
+ this.url,
+ this.options.asynchronous);
+
+ if (this.options.asynchronous) {
+ window.setTimeout(
+ OpenLayers.Function.bind(this.respondToReadyState, this, 1),
+ 10);
+ }
+
+ this.transport.onreadystatechange =
+ OpenLayers.Function.bind(this.onStateChange, this);
+ this.setRequestHeaders();
+
+ this.body = this.method == 'post' ?
+ (this.options.postBody || params) : null;
+ this.transport.send(this.body);
+
+ // Force Firefox to handle ready state 4 for synchronous requests
+ if (!this.options.asynchronous &&
+ this.transport.overrideMimeType) {
+ this.onStateChange();
+ }
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ /**
+ * Method: onStateChange
+ */
+ onStateChange: function() {
+ var readyState = this.transport.readyState;
+ if (readyState > 1 && !((readyState == 4) && this._complete)) {
+ this.respondToReadyState(this.transport.readyState);
+ }
+ },
+
+ /**
+ * Method: setRequestHeaders
+ */
+ setRequestHeaders: function() {
+ var headers = {
+ 'X-Requested-With': 'XMLHttpRequest',
+ 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*',
+ 'OpenLayers': true
+ };
+
+ if (this.method == 'post') {
+ headers['Content-type'] = this.options.contentType +
+ (this.options.encoding ? '; charset=' + this.options.encoding : '');
+
+ /* Force "Connection: close" for older Mozilla browsers to work
+ * around a bug where XMLHttpRequest sends an incorrect
+ * Content-length header. See Mozilla Bugzilla #246651.
+ */
+ if (this.transport.overrideMimeType &&
+ (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) {
+ headers['Connection'] = 'close';
+ }
+ }
+ // user-defined headers
+ if (typeof this.options.requestHeaders == 'object') {
+ var extras = this.options.requestHeaders;
+
+ if (typeof extras.push == 'function') {
+ for (var i = 0, length = extras.length; i < length; i += 2) {
+ headers[extras[i]] = extras[i+1];
+ }
+ } else {
+ for (var i in extras) {
+ headers[i] = pair[i];
+ }
+ }
+ }
+
+ for (var name in headers) {
+ this.transport.setRequestHeader(name, headers[name]);
+ }
+ },
+
+ /**
+ * Method: success
+ *
+ * Returns:
+ * {Boolean} -
+ */
+ success: function() {
+ var status = this.getStatus();
+ return !status || (status >=200 && status < 300);
+ },
+
+ /**
+ * Method: getStatus
+ *
+ * Returns:
+ * {Integer} - Status
+ */
+ getStatus: function() {
+ try {
+ return this.transport.status || 0;
+ } catch (e) {
+ return 0;
+ }
+ },
+
+ /**
+ * Method: respondToReadyState
+ *
+ * Parameters:
+ * readyState - {?}
+ */
+ respondToReadyState: function(readyState) {
+ var state = OpenLayers.Ajax.Request.Events[readyState];
+ var response = new OpenLayers.Ajax.Response(this);
+
+ if (state == 'Complete') {
+ try {
+ this._complete = true;
+ (this.options['on' + response.status] ||
+ this.options['on' + (this.success() ? 'Success' : 'Failure')] ||
+ OpenLayers.Ajax.emptyFunction)(response);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ var contentType = response.getHeader('Content-type');
+ }
+
+ try {
+ (this.options['on' + state] ||
+ OpenLayers.Ajax.emptyFunction)(response);
+ OpenLayers.Ajax.Responders.dispatch('on' + state,
+ this,
+ response);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ if (state == 'Complete') {
+ // avoid memory leak in MSIE: clean up
+ this.transport.onreadystatechange = OpenLayers.Ajax.emptyFunction;
+ }
+ },
+
+ /**
+ * Method: getHeader
+ *
+ * Parameters:
+ * name - {String} Header name
+ *
+ * Returns:
+ * {?} - response header for the given name
+ */
+ getHeader: function(name) {
+ try {
+ return this.transport.getResponseHeader(name);
+ } catch (e) {
+ return null;
+ }
+ },
+
+ /**
+ * Method: dispatchException
+ * If the optional onException function is set, execute it
+ * and then dispatch the call to any other listener registered
+ * for onException.
+ *
+ * If no optional onException function is set, we suspect that
+ * the user may have also not used
+ * OpenLayers.Ajax.Responders.register to register a listener
+ * for the onException call. To make sure that something
+ * gets done with this exception, only dispatch the call if there
+ * are listeners.
+ *
+ * If you explicitly want to swallow exceptions, set
+ * request.options.onException to an empty function (function(){})
+ * or register an empty function with <OpenLayers.Ajax.Responders>
+ * for onException.
+ *
+ * Parameters:
+ * exception - {?}
+ */
+ dispatchException: function(exception) {
+ var handler = this.options.onException;
+ if(handler) {
+ // call options.onException and alert any other listeners
+ handler(this, exception);
+ OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
+ } else {
+ // check if there are any other listeners
+ var listener = false;
+ var responders = OpenLayers.Ajax.Responders.responders;
+ for (var i = 0; i < responders.length; i++) {
+ if(responders[i].onException) {
+ listener = true;
+ break;
+ }
+ }
+ if(listener) {
+ // call all listeners
+ OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
+ } else {
+ // let the exception through
+ throw exception;
+ }
+ }
+ }
+});
+
+/**
+ * Property: Events
+ * {Array(String)}
+ */
+OpenLayers.Ajax.Request.Events =
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+/**
+ * Class: OpenLayers.Ajax.Response
+ */
+OpenLayers.Ajax.Response = OpenLayers.Class({
+
+ /**
+ * Property: status
+ *
+ * {Integer}
+ */
+ status: 0,
+
+
+ /**
+ * Property: statusText
+ *
+ * {String}
+ */
+ statusText: '',
+
+ /**
+ * Constructor: OpenLayers.Ajax.Response
+ *
+ * Parameters:
+ * request - {Object}
+ */
+ initialize: function(request) {
+ this.request = request;
+ var transport = this.transport = request.transport,
+ readyState = this.readyState = transport.readyState;
+
+ if ((readyState > 2 &&
+ !(!!(window.attachEvent && !window.opera))) ||
+ readyState == 4) {
+ this.status = this.getStatus();
+ this.statusText = this.getStatusText();
+ this.responseText = transport.responseText == null ?
+ '' : String(transport.responseText);
+ }
+
+ if(readyState == 4) {
+ var xml = transport.responseXML;
+ this.responseXML = xml === undefined ? null : xml;
+ }
+ },
+
+ /**
+ * Method: getStatus
+ */
+ getStatus: OpenLayers.Ajax.Request.prototype.getStatus,
+
+ /**
+ * Method: getStatustext
+ *
+ * Returns:
+ * {String} - statusText
+ */
+ getStatusText: function() {
+ try {
+ return this.transport.statusText || '';
+ } catch (e) {
+ return '';
+ }
+ },
+
+ /**
+ * Method: getHeader
+ */
+ getHeader: OpenLayers.Ajax.Request.prototype.getHeader,
+
+ /**
+ * Method: getResponseHeader
+ *
+ * Returns:
+ * {?} - response header for given name
+ */
+ getResponseHeader: function(name) {
+ return this.transport.getResponseHeader(name);
+ }
+});
+
+
+/**
+ * Function: getElementsByTagNameNS
+ *
+ * Parameters:
+ * parentnode - {?}
+ * nsuri - {?}
+ * nsprefix - {?}
+ * tagname - {?}
+ *
+ * Returns:
+ * {?}
+ */
+OpenLayers.Ajax.getElementsByTagNameNS = function(parentnode, nsuri,
+ nsprefix, tagname) {
+ var elem = null;
+ if (parentnode.getElementsByTagNameNS) {
+ elem = parentnode.getElementsByTagNameNS(nsuri, tagname);
+ } else {
+ elem = parentnode.getElementsByTagName(nsprefix + ':' + tagname);
+ }
+ return elem;
+};
+
+
+/**
+ * Function: serializeXMLToString
+ * Wrapper function around XMLSerializer, which doesn't exist/work in
+ * IE/Safari. We need to come up with a way to serialize in those browser:
+ * for now, these browsers will just fail. #535, #536
+ *
+ * Parameters:
+ * xmldom {XMLNode} xml dom to serialize
+ *
+ * Returns:
+ * {?}
+ */
+OpenLayers.Ajax.serializeXMLToString = function(xmldom) {
+ var serializer = new XMLSerializer();
+ var data = serializer.serializeToString(xmldom);
+ return data;
+};
+/* ======================================================================
+ OpenLayers/Console.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * 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: 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.
+ */
+ if(window.console) {
+ var scripts = document.getElementsByTagName("script");
+ for(var i=0; i<scripts.length; ++i) {
+ if(scripts[i].src.indexOf("firebug.js") != -1) {
+ OpenLayers.Util.extend(OpenLayers.Console, console);
+ break;
+ }
+ }
+ }
+})();
+/* ======================================================================
+ OpenLayers/BaseTypes/Size.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Class: OpenLayers.Size
+ * Instances of this class represent a width/height pair
+ */
+OpenLayers.Size = OpenLayers.Class({
+
+ /**
+ * APIProperty: w
+ * {Number} width
+ */
+ w: 0.0,
+
+ /**
+ * APIProperty: h
+ * {Number} height
+ */
+ h: 0.0,
+
+
+ /**
+ * Constructor: OpenLayers.Size
+ * Create an instance of OpenLayers.Size
+ *
+ * Parameters:
+ * w - {Number} width
+ * h - {Number} height
+ */
+ initialize: function(w, h) {
+ this.w = parseFloat(w);
+ this.h = parseFloat(h);
+ },
+
+ /**
+ * Method: toString
+ * Return the string representation of a size object
+ *
+ * Returns:
+ * {String} The string representation of OpenLayers.Size object.
+ * (ex. <i>"w=55,h=66"</i>)
+ */
+ toString:function() {
+ return ("w=" + this.w + ",h=" + this.h);
+ },
+
+ /**
+ * APIMethod: clone
+ * Create a clone of this size object
+ *
+ * Returns:
+ * {<OpenLayers.Size>} A new OpenLayers.Size object with the same w and h
+ * values
+ */
+ clone:function() {
+ return new OpenLayers.Size(this.w, this.h);
+ },
+
+ /**
+ *
+ * APIMethod: equals
+ * Determine where this size is equal to another
+ *
+ * Parameters:
+ * sz - {<OpenLayers.Size>}
+ *
+ * Returns:
+ * {Boolean} The passed in size has the same h and w properties as this one.
+ * Note that if sz passed in is null, returns false.
+ *
+ */
+ equals:function(sz) {
+ var equals = false;
+ if (sz != null) {
+ equals = ((this.w == sz.w && this.h == sz.h) ||
+ (isNaN(this.w) && isNaN(this.h) && isNaN(sz.w) && isNaN(sz.h)));
+ }
+ return equals;
+ },
+
+ CLASS_NAME: "OpenLayers.Size"
+});
+/* ======================================================================
+ OpenLayers/BaseTypes/Bounds.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Class: OpenLayers.Bounds
+ * Instances of this class represent bounding boxes. Data stored as left,
+ * bottom, right, top floats. All values are initialized to null, however,
+ * you should make sure you set them before using the bounds for anything.
+ *
+ * Possible use case:
+ * > bounds = new OpenLayers.Bounds();
+ * > bounds.extend(new OpenLayers.LonLat(4,5));
+ * > bounds.extend(new OpenLayers.LonLat(5,6));
+ * > bounds.toBBOX(); // returns 4,5,5,6
+ */
+OpenLayers.Bounds = OpenLayers.Class({
+
+ /**
+ * Property: left
+ * {Number} Minimum horizontal coordinate.
+ */
+ left: null,
+
+ /**
+ * Property: bottom
+ * {Number} Minimum vertical coordinate.
+ */
+ bottom: null,
+
+ /**
+ * Property: right
+ * {Number} Maximum horizontal coordinate.
+ */
+ right: null,
+
+ /**
+ * Property: top
+ * {Number} Maximum vertical coordinate.
+ */
+ top: null,
+
+ /**
+ * Constructor: OpenLayers.Bounds
+ * Construct a new bounds object.
+ *
+ * Parameters:
+ * 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.
+ */
+ initialize: function(left, bottom, right, top) {
+ if (left != null) {
+ this.left = parseFloat(left);
+ }
+ if (bottom != null) {
+ this.bottom = parseFloat(bottom);
+ }
+ if (right != null) {
+ this.right = parseFloat(right);
+ }
+ if (top != null) {
+ this.top = parseFloat(top);
+ }
+ },
+
+ /**
+ * Method: clone
+ * Create a cloned instance of this bounds.
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} 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 - {<OpenLayers.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:
+ * {String} String representation of bounds object.
+ * (ex.<i>"left-bottom=(5,42) right-top=(10,45)"</i>)
+ */
+ toString:function() {
+ return ( "left-bottom=(" + this.left + "," + this.bottom + ")"
+ + " right-top=(" + this.right + "," + this.top + ")" );
+ },
+
+ /**
+ * APIMethod: toArray
+ *
+ * Returns:
+ * {Array} array of left, bottom, right, top
+ */
+ toArray: function() {
+ return [this.left, this.bottom, this.right, this.top];
+ },
+
+ /**
+ * APIMethod: toBBOX
+ *
+ * Parameters:
+ * decimal - {Integer} How many significant digits in the bbox coords?
+ * Default is 6
+ *
+ * Returns:
+ * {String} Simple String representation of bounds object.
+ * (ex. <i>"5,42,10,45"</i>)
+ */
+ toBBOX:function(decimal) {
+ if (decimal== null) {
+ decimal = 6;
+ }
+ var mult = Math.pow(10, decimal);
+ var bbox = Math.round(this.left * mult) / mult + "," +
+ Math.round(this.bottom * mult) / mult + "," +
+ Math.round(this.right * mult) / mult + "," +
+ Math.round(this.top * mult) / mult;
+
+ return bbox;
+ },
+
+ /**
+ * APIMethod: toGeometry
+ * Create a new polygon geometry based on this bounds.
+ *
+ * Returns:
+ * {<OpenLayers.Geometry.Polygon>} 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:
+ * {Float} The width of the bounds
+ */
+ getWidth:function() {
+ return (this.right - this.left);
+ },
+
+ /**
+ * APIMethod: getHeight
+ *
+ * Returns:
+ * {Float} The height of the bounds (top minus bottom).
+ */
+ getHeight:function() {
+ return (this.top - this.bottom);
+ },
+
+ /**
+ * APIMethod: getSize
+ *
+ * Returns:
+ * {<OpenLayers.Size>} The size of the box.
+ */
+ getSize:function() {
+ return new OpenLayers.Size(this.getWidth(), this.getHeight());
+ },
+
+ /**
+ * APIMethod: getCenterPixel
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} 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:
+ * {<OpenLayers.LonLat>} The center of the bounds in map space.
+ */
+ getCenterLonLat:function() {
+ return new OpenLayers.LonLat( (this.left + this.right) / 2,
+ (this.bottom + this.top) / 2);
+ },
+
+ /**
+ * APIMethod: add
+ *
+ * Parameters:
+ * x - {Float}
+ * y - {Float}
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} 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) ) {
+ var msg = OpenLayers.i18n("boundsAddError");
+ OpenLayers.Console.error(msg);
+ return null;
+ }
+ return new OpenLayers.Bounds(this.left + x, this.bottom + y,
+ this.right + x, this.top + y);
+ },
+
+ /**
+ * APIMethod: extend
+ * Extend the bounds to include the point, lonlat, or bounds specified.
+ * Note, this function assumes that left < right and bottom < top.
+ *
+ * Parameters:
+ * object - {Object} Can be LonLat, Point, or Bounds
+ */
+ extend:function(object) {
+ var bounds = null;
+ if (object) {
+ 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) {
+ 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
+ *
+ * Parameters:
+ * ll - {<OpenLayers.LonLat>}
+ * inclusive - {Boolean} Whether or not to include the border.
+ * Default is true.
+ *
+ * Returns:
+ * {Boolean} The passed-in lonlat is within this bounds.
+ */
+ containsLonLat:function(ll, inclusive) {
+ return this.contains(ll.lon, ll.lat, inclusive);
+ },
+
+ /**
+ * APIMethod: containsPixel
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ * 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
+ *
+ * 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;
+ }
+
+ 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
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * inclusive - {Boolean} Whether or not to include the border. Default
+ * is true.
+ *
+ * Returns:
+ * {Boolean} The passed-in OpenLayers.Bounds object intersects this bounds.
+ * Simple math just check if either contains the other, allowing for
+ * partial.
+ */
+ intersectsBounds:function(bounds, inclusive) {
+
+ if (inclusive == null) {
+ inclusive = true;
+ }
+ var inBottom = (bounds.bottom == this.bottom && bounds.top == this.top) ?
+ true : (((bounds.bottom > this.bottom) && (bounds.bottom < this.top)) ||
+ ((this.bottom > bounds.bottom) && (this.bottom < bounds.top)));
+ var inTop = (bounds.bottom == this.bottom && bounds.top == this.top) ?
+ true : (((bounds.top > this.bottom) && (bounds.top < this.top)) ||
+ ((this.top > bounds.bottom) && (this.top < bounds.top)));
+ var inRight = (bounds.right == this.right && bounds.left == this.left) ?
+ true : (((bounds.right > this.left) && (bounds.right < this.right)) ||
+ ((this.right > bounds.left) && (this.right < bounds.right)));
+ var inLeft = (bounds.right == this.right && bounds.left == this.left) ?
+ true : (((bounds.left > this.left) && (bounds.left < this.right)) ||
+ ((this.left > bounds.left) && (this.left < bounds.right)));
+
+ return (this.containsBounds(bounds, true, inclusive) ||
+ bounds.containsBounds(this, true, inclusive) ||
+ ((inTop || inBottom ) && (inLeft || inRight )));
+ },
+
+ /**
+ * APIMethod: containsBounds
+ *
+ * bounds - {<OpenLayers.Bounds>}
+ * partial - {Boolean} If true, only part of passed-in bounds needs be
+ * within this bounds. If false, the entire passed-in bounds must be
+ * within. Default is false
+ * inclusive - {Boolean} Whether or not to include the border. Default is
+ * true.
+ *
+ * Returns:
+ * {Boolean} The passed-in bounds object is contained within this bounds.
+ */
+ containsBounds:function(bounds, partial, inclusive) {
+
+ //set defaults
+ if (partial == null) {
+ partial = false;
+ }
+ if (inclusive == null) {
+ inclusive = true;
+ }
+
+ var inLeft;
+ var inTop;
+ var inRight;
+ var inBottom;
+
+ if (inclusive) {
+ inLeft = (bounds.left >= this.left) && (bounds.left <= this.right);
+ inTop = (bounds.top >= this.bottom) && (bounds.top <= this.top);
+ inRight= (bounds.right >= this.left) && (bounds.right <= this.right);
+ inBottom = (bounds.bottom >= this.bottom) && (bounds.bottom <= this.top);
+ } else {
+ inLeft = (bounds.left > this.left) && (bounds.left < this.right);
+ inTop = (bounds.top > this.bottom) && (bounds.top < this.top);
+ inRight= (bounds.right > this.left) && (bounds.right < this.right);
+ inBottom = (bounds.bottom > this.bottom) && (bounds.bottom < this.top);
+ }
+
+ return (partial) ? (inTop || inBottom ) && (inLeft || inRight )
+ : (inTop && inLeft && inBottom && inRight);
+ },
+
+ /**
+ * APIMethod: determineQuadrant
+ *
+ * Parameters:
+ * lonlat - {<OpenLayers.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 - {<OpenLayers.Projection>} Source projection.
+ * dest - {<OpenLayers.Projection>} Destination projection.
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} Itself, for use in chaining operations.
+ */
+ transform: function(source, dest) {
+ 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
+ *
+ * Parameters:
+ * maxExtent - {<OpenLayers.Bounds>}
+ * options - {Object} Some possible options are:
+ * 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:
+ * {<OpenLayers.Bounds>} 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 be
+ * merely a copy of this one.
+ */
+ wrapDateLine: function(maxExtent, options) {
+ options = options || {};
+
+ var leftTolerance = options.leftTolerance || 0;
+ var rightTolerance = options.rightTolerance || 0;
+
+ var newBounds = this.clone();
+
+ if (maxExtent) {
+
+ //shift right?
+ while ( newBounds.left < maxExtent.left &&
+ (newBounds.right - rightTolerance) <= maxExtent.left ) {
+ newBounds = newBounds.add(maxExtent.getWidth(), 0);
+ }
+
+ //shift left?
+ while ( (newBounds.left + leftTolerance) >= maxExtent.right &&
+ newBounds.right > maxExtent.right ) {
+ newBounds = newBounds.add(-maxExtent.getWidth(), 0);
+ }
+ }
+
+ return newBounds;
+ },
+
+ CLASS_NAME: "OpenLayers.Bounds"
+});
+
+/**
+ * APIFunction: fromString
+ * Alternative constructor that builds a new OpenLayers.Bounds from a
+ * parameter string
+ *
+ * Parameters:
+ * str - {String}Comma-separated bounds string. (ex. <i>"5,42,10,45"</i>)
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} New bounds object built from the
+ * passed-in String.
+ */
+OpenLayers.Bounds.fromString = function(str) {
+ var bounds = str.split(",");
+ return OpenLayers.Bounds.fromArray(bounds);
+};
+
+/**
+ * APIFunction: fromArray
+ * Alternative constructor that builds a new OpenLayers.Bounds
+ * from an array
+ *
+ * Parameters:
+ * bbox - {Array(Float)} Array of bounds values (ex. <i>[5,42,10,45]</i>)
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} New bounds object built from the passed-in Array.
+ */
+OpenLayers.Bounds.fromArray = function(bbox) {
+ return new OpenLayers.Bounds(parseFloat(bbox[0]),
+ parseFloat(bbox[1]),
+ parseFloat(bbox[2]),
+ parseFloat(bbox[3]));
+};
+
+/**
+ * APIFunction: fromSize
+ * Alternative constructor that builds a new OpenLayers.Bounds
+ * from a size
+ *
+ * Parameters:
+ * size - {<OpenLayers.Size>}
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} 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.
+ *
+ * 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-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * 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; i < arguments.length; i++) {
+ var element = OpenLayers.Util.getElement(arguments[i]);
+ var display = OpenLayers.Element.visible(element) ? 'hide'
+ : 'show';
+ OpenLayers.Element[display](element);
+ }
+ },
+
+
+ /**
+ * APIFunction: hide
+ * Hide element(s) passed in
+ *
+ * Parameters:
+ * element - {DOMElement} Actually user can pass any number of elements
+ */
+ hide: function() {
+ for (var i = 0; i < arguments.length; i++) {
+ var element = OpenLayers.Util.getElement(arguments[i]);
+ element.style.display = 'none';
+ }
+ },
+
+ /**
+ * APIFunction: show
+ * Show element(s) passed in
+ *
+ * Parameters:
+ * element - {DOMElement} Actually user can pass any number of elements
+ */
+ show: function() {
+ for (var i = 0; i < arguments.length; i++) {
+ var element = OpenLayers.Util.getElement(arguments[i]);
+ element.style.display = '';
+ }
+ },
+
+ /**
+ * APIFunction: remove
+ * Remove the specified element from the DOM.
+ *
+ * Parameters:
+ * element - {DOMElement}
+ */
+ remove: function(element) {
+ element = OpenLayers.Util.getElement(element);
+ element.parentNode.removeChild(element);
+ },
+
+ /**
+ * APIFunction: getHeight
+ *
+ * Parameters:
+ * element - {DOMElement}
+ *
+ * Returns:
+ * {Integer} The offset height of the element passed in
+ */
+ getHeight: function(element) {
+ element = OpenLayers.Util.getElement(element);
+ return element.offsetHeight;
+ },
+
+ /**
+ * APIFunction: getDimensions
+ *
+ * Parameters:
+ * element - {DOMElement}
+ *
+ * Returns:
+ * {Object} Object with 'width' and 'height' properties which are the
+ * dimensions of the element passed in.
+ */
+ getDimensions: function(element) {
+ element = OpenLayers.Util.getElement(element);
+ if (OpenLayers.Element.getStyle(element, 'display') != 'none') {
+ return {width: element.offsetWidth, height: element.offsetHeight};
+ }
+
+ // All *Width and *Height properties give 0 on elements with display none,
+ // so enable the element temporarily
+ var els = element.style;
+ var originalVisibility = els.visibility;
+ var originalPosition = els.position;
+ els.visibility = 'hidden';
+ els.position = 'absolute';
+ els.display = '';
+ var originalWidth = element.clientWidth;
+ var originalHeight = element.clientHeight;
+ els.display = 'none';
+ els.position = originalPosition;
+ els.visibility = originalVisibility;
+ return {width: originalWidth, height: originalHeight};
+ },
+
+ /**
+ * APIFunction: getStyle
+ *
+ * Parameters:
+ * element - {DOMElement}
+ * style - {?}
+ *
+ * Returns:
+ * {?}
+ */
+ getStyle: function(element, style) {
+ element = OpenLayers.Util.getElement(element);
+ var value = element.style[OpenLayers.String.camelize(style)];
+ if (!value) {
+ if (document.defaultView &&
+ document.defaultView.getComputedStyle) {
+
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css.getPropertyValue(style) : null;
+ } else if (element.currentStyle) {
+ value = element.currentStyle[OpenLayers.String.camelize(style)];
+ }
+ }
+
+ var positions = ['left', 'top', 'right', 'bottom'];
+ if (window.opera &&
+ (OpenLayers.Util.indexOf(positions,style) != -1) &&
+ (OpenLayers.Element.getStyle(element, 'position') == 'static')) {
+ value = 'auto';
+ }
+
+ return value == 'auto' ? null : value;
+ }
+
+};
+/* ======================================================================
+ OpenLayers/BaseTypes/LonLat.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Class: OpenLayers.LonLat
+ * This class represents a longitude and latitude pair
+ */
+OpenLayers.LonLat = OpenLayers.Class({
+
+ /**
+ * APIProperty: lon
+ * {Float} The x-axis coodinate in map units
+ */
+ lon: 0.0,
+
+ /**
+ * APIProperty: lat
+ * {Float} The y-axis coordinate in map units
+ */
+ lat: 0.0,
+
+ /**
+ * Constructor: OpenLayers.LonLat
+ * Create a new map location.
+ *
+ * Parameters:
+ * lon - {Number} The x-axis coordinate in map units. If your map is in
+ * a geographic projection, this will be the Longitude. Otherwise,
+ * it will be the x coordinate of the map location in your map units.
+ * lat - {Number} The y-axis coordinate in map units. If your map is in
+ * a geographic projection, this will be the Latitude. Otherwise,
+ * it will be the y coordinate of the map location in your map units.
+ */
+ initialize: function(lon, lat) {
+ this.lon = parseFloat(lon);
+ this.lat = parseFloat(lat);
+ },
+
+ /**
+ * Method: toString
+ * Return a readable string version of the lonlat
+ *
+ * Returns:
+ * {String} String representation of OpenLayers.LonLat object.
+ * (ex. <i>"lon=5,lat=42"</i>)
+ */
+ toString:function() {
+ return ("lon=" + this.lon + ",lat=" + this.lat);
+ },
+
+ /**
+ * APIMethod: toShortString
+ *
+ * Returns:
+ * {String} Shortened String representation of OpenLayers.LonLat object.
+ * (ex. <i>"5, 42"</i>)
+ */
+ toShortString:function() {
+ return (this.lon + ", " + this.lat);
+ },
+
+ /**
+ * APIMethod: clone
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} 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:
+ * {<OpenLayers.LonLat>} 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) ) {
+ var msg = OpenLayers.i18n("lonlatAddError");
+ OpenLayers.Console.error(msg);
+ return null;
+ }
+ return new OpenLayers.LonLat(this.lon + lon, this.lat + lat);
+ },
+
+ /**
+ * APIMethod: equals
+ *
+ * Parameters:
+ * ll - {<OpenLayers.LonLat>}
+ *
+ * Returns:
+ * {Boolean} Boolean value indicating whether the passed-in
+ * <OpenLayers.LonLat> 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.
+ *
+ * Parameters:
+ * source - {<OpenLayers.Projection>} Source projection.
+ * dest - {<OpenLayers.Projection>} Destination projection.
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} 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 - {<OpenLayers.Bounds>}
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} 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 <OpenLayers.LonLat> from a
+ * parameter string
+ *
+ * Parameters:
+ * str - {String} Comma-separated Lon,Lat coordinate string.
+ * (ex. <i>"5,40"</i>)
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} New <OpenLayers.LonLat> object built from the
+ * passed-in String.
+ */
+OpenLayers.LonLat.fromString = function(str) {
+ var pair = str.split(",");
+ return new OpenLayers.LonLat(parseFloat(pair[0]),
+ parseFloat(pair[1]));
+};
+/* ======================================================================
+ OpenLayers/BaseTypes/Pixel.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * 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:
+ * {<OpenLayers.Pixel>} 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 - {<OpenLayers.Pixel>}
+ *
+ * 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: add
+ *
+ * Parameters:
+ * x - {Integer}
+ * y - {Integer}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the
+ * values passed in.
+ */
+ add:function(x, y) {
+ if ( (x == null) || (y == null) ) {
+ var msg = OpenLayers.i18n("pixelAddError");
+ OpenLayers.Console.error(msg);
+ return null;
+ }
+ return new OpenLayers.Pixel(this.x + x, this.y + y);
+ },
+
+ /**
+ * APIMethod: offset
+ *
+ * Parameters
+ * px - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} 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/Control.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Class: OpenLayers.Control
+ * Controls affect the display or behavior of the map. They allow everything
+ * from panning and zooming to displaying a scale indicator. Controls by
+ * default are added to the map they are contained within however it is
+ * possible to add a control to an external div by passing the div in the
+ * options parameter.
+ *
+ * Example:
+ * The following example shows how to add many of the common controls
+ * to a map.
+ *
+ * > var map = new OpenLayers.Map('map', { controls: [] });
+ * >
+ * > map.addControl(new OpenLayers.Control.PanZoomBar());
+ * > map.addControl(new OpenLayers.Control.MouseToolbar());
+ * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
+ * > map.addControl(new OpenLayers.Control.Permalink());
+ * > map.addControl(new OpenLayers.Control.Permalink('permalink'));
+ * > map.addControl(new OpenLayers.Control.MousePosition());
+ * > map.addControl(new OpenLayers.Control.OverviewMap());
+ * > map.addControl(new OpenLayers.Control.KeyboardDefaults());
+ *
+ * The next code fragment is a quick example of how to intercept
+ * shift-mouse click to display the extent of the bounding box
+ * dragged out by the user. Usually controls are not created
+ * in exactly this manner. See the source for a more complete
+ * example:
+ *
+ * > var control = new OpenLayers.Control();
+ * > OpenLayers.Util.extend(control, {
+ * > draw: function () {
+ * > // this Handler.Box will intercept the shift-mousedown
+ * > // before Control.MouseDefault gets to see it
+ * > this.box = new OpenLayers.Handler.Box( control,
+ * > {"done": this.notice},
+ * > {keyMask: OpenLayers.Handler.MOD_SHIFT});
+ * > this.box.activate();
+ * > },
+ * >
+ * > notice: function (bounds) {
+ * > alert(bounds);
+ * > }
+ * > });
+ * > map.addControl(control);
+ *
+ */
+OpenLayers.Control = OpenLayers.Class({
+
+ /**
+ * Property: id
+ * {String}
+ */
+ id: null,
+
+ /**
+ * Property: map
+ * {<OpenLayers.Map>} this gets set in the addControl() function in
+ * OpenLayers.Map
+ */
+ map: null,
+
+ /**
+ * Property: div
+ * {DOMElement}
+ */
+ div: null,
+
+ /**
+ * Property: type
+ * {OpenLayers.Control.TYPES} Controls can have a 'type'. The type
+ * determines the type of interactions which are possible with them when
+ * they are placed into a toolbar.
+ */
+ type: null,
+
+ /**
+ * Property: allowSelection
+ * {Boolean} By deafault, controls do not allow selection, because
+ * it may interfere with map dragging. If this is true, OpenLayers
+ * will not prevent selection of the control.
+ * Default is false.
+ */
+ allowSelection: false,
+
+ /**
+ * Property: displayClass
+ * {string} This property is used for CSS related to the drawing of the
+ * Control.
+ */
+ displayClass: "",
+
+ /**
+ * Property: title
+ * {string} This property is used for showing a tooltip over the
+ * Control.
+ */
+ title: "",
+
+ /**
+ * Property: active
+ * {Boolean} The control is active.
+ */
+ active: null,
+
+ /**
+ * Property: handler
+ * {<OpenLayers.Handler>} null
+ */
+ handler: null,
+
+ /**
+ * APIProperty: eventListeners
+ * {Object} If set as an option at construction, the eventListeners
+ * object will be registered with <OpenLayers.Events.on>. Object
+ * structure must be a listeners object as shown in the example for
+ * the events.on method.
+ */
+ eventListeners: null,
+
+ /**
+ * Property: events
+ * {<OpenLayers.Events>} Events instance for triggering control specific
+ * events.
+ */
+ events: null,
+
+ /**
+ * Constant: EVENT_TYPES
+ * {Array(String)} Supported application event types. Register a listener
+ * for a particular event with the following syntax:
+ * (code)
+ * control.events.register(type, obj, listener);
+ * (end)
+ *
+ * Listeners will be called with a reference to an event object. The
+ * properties of this event depends on exactly what happened.
+ *
+ * All event objects have at least the following properties:
+ * - *object* {Object} A reference to control.events.object (a reference
+ * to the control).
+ * - *element* {DOMElement} A reference to control.events.element (which
+ * will be null unless documented otherwise).
+ *
+ * Supported map event types:
+ * - *activate* Triggered when activated.
+ * - *deactivate* Triggered when deactivated.
+ */
+ EVENT_TYPES: ["activate", "deactivate"],
+
+ /**
+ * Constructor: OpenLayers.Control
+ * Create an OpenLayers Control. The options passed as a parameter
+ * directly extend the control. For example passing the following:
+ *
+ * > var control = new OpenLayers.Control({div: myDiv});
+ *
+ * Overrides the default div attribute value of null.
+ *
+ * Parameters:
+ * options - {Object}
+ */
+ initialize: function (options) {
+ // We do this before the extend so that instances can override
+ // className in options.
+ this.displayClass =
+ this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, "");
+
+ OpenLayers.Util.extend(this, options);
+
+ this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
+ if(this.eventListeners instanceof Object) {
+ this.events.on(this.eventListeners);
+ }
+ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+ },
+
+ /**
+ * Method: destroy
+ * The destroy method is used to perform any clean up before the control
+ * is dereferenced. Typically this is where event listeners are removed
+ * to prevent memory leaks.
+ */
+ destroy: function () {
+ if(this.events) {
+ if(this.eventListeners) {
+ this.events.un(this.eventListeners);
+ }
+ this.events.destroy();
+ this.events = null;
+ }
+ this.eventListeners = null;
+
+ // eliminate circular references
+ if (this.handler) {
+ this.handler.destroy();
+ this.handler = null;
+ }
+ if(this.handlers) {
+ for(var key in this.handlers) {
+ if(this.handlers.hasOwnProperty(key) &&
+ typeof this.handlers[key].destroy == "function") {
+ this.handlers[key].destroy();
+ }
+ }
+ this.handlers = null;
+ }
+ if (this.map) {
+ this.map.removeControl(this);
+ this.map = null;
+ }
+ },
+
+ /**
+ * Method: setMap
+ * Set the map property for the control. This is done through an accessor
+ * so that subclasses can override this and take special action once
+ * they have their map variable set.
+ *
+ * Parameters:
+ * map - {<OpenLayers.Map>}
+ */
+ setMap: function(map) {
+ this.map = map;
+ if (this.handler) {
+ this.handler.setMap(map);
+ }
+ },
+
+ /**
+ * Method: draw
+ * The draw method is called when the control is ready to be displayed
+ * on the page. If a div has not been created one is created. Controls
+ * with a visual component will almost always want to override this method
+ * to customize the look of control.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>} The top-left pixel position of the control
+ * or null.
+ *
+ * Returns:
+ * {DOMElement} A reference to the DIV DOMElement containing the control
+ */
+ draw: function (px) {
+ if (this.div == null) {
+ this.div = OpenLayers.Util.createDiv(this.id);
+ this.div.className = this.displayClass;
+ if (!this.allowSelection) {
+ this.div.className += " olControlNoSelect";
+ this.div.setAttribute("unselectable", "on", 0);
+ this.div.onselectstart = function() { return(false); };
+ }
+ if (this.title != "") {
+ this.div.title = this.title;
+ }
+ }
+ if (px != null) {
+ this.position = px.clone();
+ }
+ this.moveTo(this.position);
+ return this.div;
+ },
+
+ /**
+ * Method: moveTo
+ * Sets the left and top style attributes to the passed in pixel
+ * coordinates.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ */
+ moveTo: function (px) {
+ if ((px != null) && (this.div != null)) {
+ this.div.style.left = px.x + "px";
+ this.div.style.top = px.y + "px";
+ }
+ },
+
+ /**
+ * Method: activate
+ * Explicitly activates a control and it's associated
+ * handler if one has been set. Controls can be
+ * deactivated by calling the deactivate() method.
+ *
+ * Returns:
+ * {Boolean} True if the control was successfully activated or
+ * false if the control was already active.
+ */
+ activate: function () {
+ if (this.active) {
+ return false;
+ }
+ if (this.handler) {
+ this.handler.activate();
+ }
+ this.active = true;
+ this.events.triggerEvent("activate");
+ return true;
+ },
+
+ /**
+ * Method: deactivate
+ * Deactivates a control and it's associated handler if any. The exact
+ * effect of this depends on the control itself.
+ *
+ * Returns:
+ * {Boolean} True if the control was effectively deactivated or false
+ * if the control was already inactive.
+ */
+ deactivate: function () {
+ if (this.active) {
+ if (this.handler) {
+ this.handler.deactivate();
+ }
+ this.active = false;
+ this.events.triggerEvent("deactivate");
+ return true;
+ }
+ return false;
+ },
+
+ CLASS_NAME: "OpenLayers.Control"
+});
+
+OpenLayers.Control.TYPE_BUTTON = 1;
+OpenLayers.Control.TYPE_TOGGLE = 2;
+OpenLayers.Control.TYPE_TOOL = 3;
+/* ======================================================================
+ OpenLayers/Icon.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * Class: OpenLayers.Icon
+ *
+ * The icon represents a graphical icon on the screen. Typically used in
+ * conjunction with a <OpenLayers.Marker> to represent markers on a screen.
+ *
+ * An icon has a url, size and position. It also contains an offset which
+ * allows the center point to be represented correctly. This can be
+ * provided either as a fixed offset or a function provided to calculate
+ * the desired offset.
+ *
+ */
+OpenLayers.Icon = OpenLayers.Class({
+
+ /**
+ * Property: url
+ * {String} image url
+ */
+ url: null,
+
+ /**
+ * Property: size
+ * {<OpenLayers.Size>}
+ */
+ size: null,
+
+ /**
+ * Property: offset
+ * {<OpenLayers.Pixel>} distance in pixels to offset the image when being rendered
+ */
+ offset: null,
+
+ /**
+ * Property: calculateOffset
+ * {<OpenLayers.Pixel>} Function to calculate the offset (based on the size)
+ */
+ calculateOffset: null,
+
+ /**
+ * Property: imageDiv
+ * {DOMElement}
+ */
+ imageDiv: null,
+
+ /**
+ * Property: px
+ * {<OpenLayers.Pixel>}
+ */
+ px: null,
+
+ /**
+ * Constructor: OpenLayers.Icon
+ * Creates an icon, which is an image tag in a div.
+ *
+ * url - {String}
+ * size - {<OpenLayers.Size>}
+ * offset - {<OpenLayers.Pixel>}
+ * calculateOffset - {Function}
+ */
+ initialize: function(url, size, offset, calculateOffset) {
+ this.url = url;
+ this.size = (size) ? size : new OpenLayers.Size(20,20);
+ this.offset = offset ? offset : new OpenLayers.Pixel(-(this.size.w/2), -(this.size.h/2));
+ this.calculateOffset = calculateOffset;
+
+ var id = OpenLayers.Util.createUniqueID("OL_Icon_");
+ this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);
+ },
+
+ /**
+ * Method: destroy
+ * Nullify references and remove event listeners to prevent circular
+ * references and memory leaks
+ */
+ destroy: function() {
+ OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);
+ this.imageDiv.innerHTML = "";
+ this.imageDiv = null;
+ },
+
+ /**
+ * Method: clone
+ *
+ * Returns:
+ * {<OpenLayers.Icon>} A fresh copy of the icon.
+ */
+ clone: function() {
+ return new OpenLayers.Icon(this.url,
+ this.size,
+ this.offset,
+ this.calculateOffset);
+ },
+
+ /**
+ * Method: setSize
+ *
+ * Parameters:
+ * size - {<OpenLayers.Size>}
+ */
+ setSize: function(size) {
+ if (size != null) {
+ this.size = size;
+ }
+ this.draw();
+ },
+
+ /**
+ * Method: setUrl
+ *
+ * Parameters:
+ * url - {String}
+ */
+ setUrl: function(url) {
+ if (url != null) {
+ this.url = url;
+ }
+ this.draw();
+ },
+
+ /**
+ * Method: draw
+ * Move the div to the given pixel.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {DOMElement} A new DOM Image of this icon set at the location passed-in
+ */
+ draw: function(px) {
+ OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,
+ null,
+ null,
+ this.size,
+ this.url,
+ "absolute");
+ this.moveTo(px);
+ return this.imageDiv;
+ },
+
+
+ /**
+ * Method: setOpacity
+ * Change the icon's opacity
+ *
+ * Parameters:
+ * opacity - {float}
+ */
+ setOpacity: function(opacity) {
+ OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null,
+ null, null, null, null, opacity);
+
+ },
+
+ /**
+ * Method: moveTo
+ * move icon to passed in px.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ */
+ moveTo: function (px) {
+ //if no px passed in, use stored location
+ if (px != null) {
+ this.px = px;
+ }
+
+ if (this.imageDiv != null) {
+ if (this.px == null) {
+ this.display(false);
+ } else {
+ if (this.calculateOffset) {
+ this.offset = this.calculateOffset(this.size);
+ }
+ var offsetPx = this.px.offset(this.offset);
+ OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, offsetPx);
+ }
+ }
+ },
+
+ /**
+ * Method: display
+ * Hide or show the icon
+ *
+ * Parameters:
+ * display - {Boolean}
+ */
+ display: function(display) {
+ this.imageDiv.style.display = (display) ? "" : "none";
+ },
+
+ CLASS_NAME: "OpenLayers.Icon"
+});
+/* ======================================================================
+ OpenLayers/Lang.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * Namespace: OpenLayers.Lang
+ * Internationalization namespace. Contains dictionaries in various languages
+ * and methods to set and get the current language.
+ */
+OpenLayers.Lang = {
+
+ /**
+ * Property: code
+ * {String} Current language code to use in OpenLayers. Use the
+ * <setCode> method to set this value and the <getCode> method to
+ * retrieve it.
+ */
+ code: null,
+
+ /**
+ * APIProperty: defaultCode
+ * {String} Default language to use when a specific language can't be
+ * found. Default is "en".
+ */
+ defaultCode: "en",
+
+ /**
+ * APIFunction: getCode
+ * Get the current language code.
+ *
+ * Returns:
+ * The current language code.
+ */
+ getCode: function() {
+ if(!OpenLayers.Lang.code) {
+ OpenLayers.Lang.setCode();
+ }
+ return OpenLayers.Lang.code;
+ },
+
+ /**
+ * APIFunction: setCode
+ * Set the language code for string translation. This code is used by
+ * the <OpenLayers.Lang.translate> method.
+ *
+ * Parameters-
+ * code - {String} These codes follow the IETF recommendations at
+ * http://www.ietf.org/rfc/rfc3066.txt. If no value is set, the
+ * browser's language setting will be tested. If no <OpenLayers.Lang>
+ * dictionary exists for the code, the <OpenLayers.String.defaultLang>
+ * will be used.
+ */
+ setCode: function(code) {
+ var lang;
+ if(!code) {
+ code = (OpenLayers.Util.getBrowserName() == "msie") ?
+ navigator.userLanguage : navigator.language;
+ }
+ var parts = code.split('-');
+ parts[0] = parts[0].toLowerCase();
+ if(typeof OpenLayers.Lang[parts[0]] == "object") {
+ lang = parts[0];
+ }
+
+ // check for regional extensions
+ if(parts[1]) {
+ var testLang = parts[0] + '-' + parts[1].toUpperCase();
+ if(typeof OpenLayers.Lang[testLang] == "object") {
+ lang = testLang;
+ }
+ }
+ if(!lang) {
+ OpenLayers.Console.warn(
+ 'Failed to find OpenLayers.Lang.' + parts.join("-") +
+ ' dictionary, falling back to default language'
+ );
+ lang = OpenLayers.Lang.defaultCode;
+ }
+
+ OpenLayers.Lang.code = lang;
+ },
+
+ /**
+ * APIMethod: translate
+ * Looks up a key from a dictionary based on the current language string.
+ * The value of <getCode> will be used to determine the appropriate
+ * dictionary. Dictionaries are stored in <OpenLayers.Lang>.
+ *
+ * Parameters:
+ * key - {String} The key for an i18n string value in the dictionary.
+ * context - {Object} Optional context to be used with
+ * <OpenLayers.String.format>.
+ *
+ * Returns:
+ * {String} A internationalized string.
+ */
+ translate: function(key, context) {
+ var dictionary = OpenLayers.Lang[OpenLayers.Lang.getCode()];
+ var message = dictionary[key];
+ if(!message) {
+ // Message not found, fall back to message key
+ message = key;
+ }
+ if(context) {
+ message = OpenLayers.String.format(message, context);
+ }
+ return message;
+ }
+
+};
+
+
+/**
+ * APIMethod: OpenLayers.i18n
+ * Alias for <OpenLayers.Lang.translate>. Looks up a key from a dictionary
+ * based on the current language string. The value of
+ * <OpenLayers.Lang.getCode> will be used to determine the appropriate
+ * dictionary. Dictionaries are stored in <OpenLayers.Lang>.
+ *
+ * Parameters:
+ * key - {String} The key for an i18n string value in the dictionary.
+ * context - {Object} Optional context to be used with
+ * <OpenLayers.String.format>.
+ *
+ * Returns:
+ * {String} A internationalized string.
+ */
+OpenLayers.i18n = OpenLayers.Lang.translate;
+/* ======================================================================
+ OpenLayers/Tween.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Namespace: OpenLayers.Tween
+ */
+OpenLayers.Tween = OpenLayers.Class({
+
+ /**
+ * Constant: INTERVAL
+ * {int} Interval in milliseconds between 2 steps
+ */
+ INTERVAL: 10,
+
+ /**
+ * APIProperty: easing
+ * {<OpenLayers.Easing>(Function)} Easing equation used for the animation
+ * Defaultly set to OpenLayers.Easing.Expo.easeOut
+ */
+ easing: null,
+
+ /**
+ * APIProperty: begin
+ * {Object} Values to start the animation with
+ */
+ begin: null,
+
+ /**
+ * APIProperty: finish
+ * {Object} Values to finish the animation with
+ */
+ finish: null,
+
+ /**
+ * APIProperty: duration
+ * {int} duration of the tween (number of steps)
+ */
+ duration: null,
+
+ /**
+ * APIProperty: callbacks
+ * {Object} An object with start, eachStep and done properties whose values
+ * are functions to be call during the animation. They are passed the
+ * current computed value as argument.
+ */
+ callbacks: null,
+
+ /**
+ * Property: time
+ * {int} Step counter
+ */
+ time: null,
+
+ /**
+ * Property: interval
+ * {int} Interval id returned by window.setInterval
+ */
+ interval: null,
+
+ /**
+ * Property: playing
+ * {Boolean} Tells if the easing is currently playing
+ */
+ playing: false,
+
+ /**
+ * Constructor: OpenLayers.Tween
+ * Creates a Tween.
+ *
+ * Parameters:
+ * easing - {<OpenLayers.Easing>(Function)} easing function method to use
+ */
+ initialize: function(easing) {
+ this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut;
+ },
+
+ /**
+ * APIMethod: start
+ * Plays the Tween, and calls the callback method on each step
+ *
+ * Parameters:
+ * begin - {Object} values to start the animation with
+ * finish - {Object} values to finish the animation with
+ * duration - {int} duration of the tween (number of steps)
+ * options - {Object} hash of options (for example callbacks (start, eachStep, done))
+ */
+ start: function(begin, finish, duration, options) {
+ this.playing = true;
+ this.begin = begin;
+ this.finish = finish;
+ this.duration = duration;
+ this.callbacks = options.callbacks;
+ this.time = 0;
+ if (this.interval) {
+ window.clearInterval(this.interval);
+ this.interval = null;
+ }
+ if (this.callbacks && this.callbacks.start) {
+ this.callbacks.start.call(this, this.begin);
+ }
+ this.interval = window.setInterval(
+ OpenLayers.Function.bind(this.play, this), this.INTERVAL);
+ },
+
+ /**
+ * APIMethod: stop
+ * Stops the Tween, and calls the done callback
+ * Doesn't do anything if animation is already finished
+ */
+ stop: function() {
+ if (!this.playing) {
+ return;
+ }
+
+ if (this.callbacks && this.callbacks.done) {
+ this.callbacks.done.call(this, this.finish);
+ }
+ window.clearInterval(this.interval);
+ this.interval = null;
+ this.playing = false;
+ },
+
+ /**
+ * Method: play
+ * Calls the appropriate easing method
+ */
+ play: function() {
+ var value = {};
+ for (var i in this.begin) {
+ var b = this.begin[i];
+ var f = this.finish[i];
+ if (b == null || f == null || isNaN(b) || isNaN(f)) {
+ OpenLayers.Console.error('invalid value for Tween');
+ }
+
+ var c = f - b;
+ value[i] = this.easing.apply(this, [this.time, b, c, this.duration]);
+ }
+ this.time++;
+
+ if (this.callbacks && this.callbacks.eachStep) {
+ this.callbacks.eachStep.call(this, value);
+ }
+
+ if (this.time > this.duration) {
+ if (this.callbacks && this.callbacks.done) {
+ this.callbacks.done.call(this, this.finish);
+ this.playing = false;
+ }
+ window.clearInterval(this.interval);
+ this.interval = null;
+ }
+ },
+
+ /**
+ * Create empty functions for all easing methods.
+ */
+ CLASS_NAME: "OpenLayers.Tween"
+});
+
+/**
+ * Namespace: OpenLayers.Easing
+ *
+ * Credits:
+ * Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>
+ */
+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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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/Control/ArgParser.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.ArgParser
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Parameter: center
+ * {<OpenLayers.LonLat>}
+ */
+ center: null,
+
+ /**
+ * Parameter: zoom
+ * {int}
+ */
+ zoom: null,
+
+ /**
+ * Parameter: layers
+ * {Array(<OpenLayers.Layer>)}
+ */
+ layers: null,
+
+ /**
+ * APIProperty: displayProjection
+ * {<OpenLayers.Projection>} Requires proj4js support.
+ * Projection used when reading the coordinates from the URL. This will
+ * reproject the map coordinates from the URL into the map's
+ * projection.
+ *
+ * If you are using this functionality, be aware that any permalink
+ * which is added to the map will determine the coordinate type which
+ * is read from the URL, which means you should not add permalinks with
+ * different displayProjections to the same map.
+ */
+ displayProjection: null,
+
+ /**
+ * Constructor: OpenLayers.Control.ArgParser
+ *
+ * Parameters:
+ * options - {Object}
+ */
+ initialize: function(options) {
+ OpenLayers.Control.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * Method: setMap
+ * Set the map property for the control.
+ *
+ * Parameters:
+ * map - {<OpenLayers.Map>}
+ */
+ setMap: function(map) {
+ OpenLayers.Control.prototype.setMap.apply(this, arguments);
+
+ //make sure we dont already have an arg parser attached
+ for(var i=0; i< this.map.controls.length; i++) {
+ var control = this.map.controls[i];
+ if ( (control != this) &&
+ (control.CLASS_NAME == "OpenLayers.Control.ArgParser") ) {
+
+ // If a second argparser is added to the map, then we
+ // override the displayProjection to be the one added to the
+ // map.
+ if (control.displayProjection != this.displayProjection) {
+ this.displayProjection = control.displayProjection;
+ }
+
+ break;
+ }
+ }
+ if (i == this.map.controls.length) {
+
+ var args = OpenLayers.Util.getParameters();
+ // Be careful to set layer first, to not trigger unnecessary layer loads
+ if (args.layers) {
+ this.layers = args.layers;
+
+ // when we add a new layer, set its visibility
+ this.map.events.register('addlayer', this,
+ this.configureLayers);
+ this.configureLayers();
+ }
+ if (args.lat && args.lon) {
+ this.center = new OpenLayers.LonLat(parseFloat(args.lon),
+ parseFloat(args.lat));
+ if (args.zoom) {
+ this.zoom = parseInt(args.zoom);
+ }
+
+ // when we add a new baselayer to see when we can set the center
+ this.map.events.register('changebaselayer', this,
+ this.setCenter);
+ this.setCenter();
+ }
+ }
+ },
+
+ /**
+ * Method: setCenter
+ * As soon as a baseLayer has been loaded, we center and zoom
+ * ...and remove the handler.
+ */
+ setCenter: function() {
+
+ if (this.map.baseLayer) {
+ //dont need to listen for this one anymore
+ this.map.events.unregister('changebaselayer', this,
+ this.setCenter);
+
+ if (this.displayProjection) {
+ this.center.transform(this.displayProjection,
+ this.map.getProjectionObject());
+ }
+
+ this.map.setCenter(this.center, this.zoom);
+ }
+ },
+
+ /**
+ * Method: configureLayers
+ * As soon as all the layers are loaded, cycle through them and
+ * hide or show them.
+ */
+ configureLayers: function() {
+
+ if (this.layers.length == this.map.layers.length) {
+ this.map.events.unregister('addlayer', this, this.configureLayers);
+
+ for(var i=0; i < this.layers.length; i++) {
+
+ var layer = this.map.layers[i];
+ var c = this.layers.charAt(i);
+
+ if (c == "B") {
+ this.map.setBaseLayer(layer);
+ } else if ( (c == "T") || (c == "F") ) {
+ layer.setVisibility(c == "T");
+ }
+ }
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Control.ArgParser"
+});
+/* ======================================================================
+ OpenLayers/Control/MousePosition.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.MousePosition
+ */
+OpenLayers.Control.MousePosition = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Property: element
+ * {DOMElement}
+ */
+ element: null,
+
+ /**
+ * APIProperty: prefix
+ * {String}
+ */
+ prefix: '',
+
+ /**
+ * APIProperty: separator
+ * {String}
+ */
+ separator: ', ',
+
+ /**
+ * APIProperty: suffix
+ * {String}
+ */
+ suffix: '',
+
+ /**
+ * APIProperty: numDigits
+ * {Integer}
+ */
+ numdigits: 5,
+
+ /**
+ * APIProperty: granularity
+ * {Integer}
+ */
+ granularity: 10,
+
+ /**
+ * Property: lastXy
+ * {<OpenLayers.LonLat>}
+ */
+ lastXy: null,
+
+ /**
+ * APIProperty: displayProjection
+ * {<OpenLayers.Projection>} A projection that the
+ * mousecontrol will display.
+ */
+ displayProjection: null,
+
+ /**
+ * Constructor: OpenLayers.Control.MousePosition
+ *
+ * Parameters:
+ * options - {DOMElement} Options for control.
+ */
+ initialize: function(options) {
+ OpenLayers.Control.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * Method: destroy
+ */
+ destroy: function() {
+ if (this.map) {
+ this.map.events.unregister('mousemove', this, this.redraw);
+ }
+ OpenLayers.Control.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: draw
+ * {DOMElement}
+ */
+ draw: function() {
+ OpenLayers.Control.prototype.draw.apply(this, arguments);
+
+ if (!this.element) {
+ this.div.left = "";
+ this.div.top = "";
+ this.element = this.div;
+ }
+
+ this.redraw();
+ return this.div;
+ },
+
+ /**
+ * Method: redraw
+ */
+ redraw: function(evt) {
+
+ var lonLat;
+
+ if (evt == null) {
+ lonLat = new OpenLayers.LonLat(0, 0);
+ } else {
+ if (this.lastXy == null ||
+ Math.abs(evt.xy.x - this.lastXy.x) > this.granularity ||
+ Math.abs(evt.xy.y - this.lastXy.y) > this.granularity)
+ {
+ this.lastXy = evt.xy;
+ return;
+ }
+
+ lonLat = this.map.getLonLatFromPixel(evt.xy);
+ if (!lonLat) {
+ // map has not yet been properly initialized
+ return;
+ }
+ if (this.displayProjection) {
+ lonLat.transform(this.map.getProjectionObject(),
+ this.displayProjection );
+ }
+ this.lastXy = evt.xy;
+
+ }
+
+ var newHtml = this.formatOutput(lonLat);
+
+ if (newHtml != this.element.innerHTML) {
+ this.element.innerHTML = newHtml;
+ }
+ },
+
+ /**
+ * Method: formatOutput
+ * Override to provide custom display output
+ *
+ * Parameters:
+ * lonLat - {<OpenLayers.LonLat>} Location to display
+ */
+ formatOutput: function(lonLat) {
+ var digits = parseInt(this.numdigits);
+ var newHtml =
+ this.prefix +
+ lonLat.lon.toFixed(digits) +
+ this.separator +
+ lonLat.lat.toFixed(digits) +
+ this.suffix;
+ return newHtml;
+ },
+
+ /**
+ * Method: setMap
+ */
+ setMap: function() {
+ OpenLayers.Control.prototype.setMap.apply(this, arguments);
+ this.map.events.register( 'mousemove', this, this.redraw);
+ },
+
+ CLASS_NAME: "OpenLayers.Control.MousePosition"
+});
+/* ======================================================================
+ OpenLayers/Control/PanZoom.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.PanZoom
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * APIProperty: slideFactor
+ * {Integer} Number of pixels by which we'll pan the map in any direction
+ * on clicking the arrow buttons.
+ */
+ slideFactor: 50,
+
+ /**
+ * Property: buttons
+ * {Array(DOMElement)} Array of Button Divs
+ */
+ buttons: null,
+
+ /**
+ * Property: position
+ * {<OpenLayers.Pixel>}
+ */
+ position: null,
+
+ /**
+ * Constructor: OpenLayers.Control.PanZoom
+ *
+ * Parameters:
+ * options - {Object}
+ */
+ initialize: function(options) {
+ this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,
+ OpenLayers.Control.PanZoom.Y);
+ OpenLayers.Control.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * APIMethod: destroy
+ */
+ destroy: function() {
+ OpenLayers.Control.prototype.destroy.apply(this, arguments);
+ while(this.buttons.length) {
+ var btn = this.buttons.shift();
+ btn.map = null;
+ OpenLayers.Event.stopObservingElement(btn);
+ }
+ this.buttons = null;
+ this.position = null;
+ },
+
+ /**
+ * Method: draw
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {DOMElement} A reference to the container div for the PanZoom control.
+ */
+ draw: function(px) {
+ // initialize our internal div
+ OpenLayers.Control.prototype.draw.apply(this, arguments);
+ px = this.position;
+
+ // place the controls
+ this.buttons = [];
+
+ var sz = new OpenLayers.Size(18,18);
+ var centered = new OpenLayers.Pixel(px.x+sz.w/2, px.y);
+
+ this._addButton("panup", "north-mini.png", centered, sz);
+ px.y = centered.y+sz.h;
+ this._addButton("panleft", "west-mini.png", px, sz);
+ this._addButton("panright", "east-mini.png", px.add(sz.w, 0), sz);
+ this._addButton("pandown", "south-mini.png",
+ centered.add(0, sz.h*2), sz);
+ this._addButton("zoomin", "zoom-plus-mini.png",
+ centered.add(0, sz.h*3+5), sz);
+ this._addButton("zoomworld", "zoom-world-mini.png",
+ centered.add(0, sz.h*4+5), sz);
+ this._addButton("zoomout", "zoom-minus-mini.png",
+ centered.add(0, sz.h*5+5), sz);
+ return this.div;
+ },
+
+ /**
+ * Method: _addButton
+ *
+ * Parameters:
+ * id - {String}
+ * img - {String}
+ * xy - {<OpenLayers.Pixel>}
+ * sz - {<OpenLayers.Size>}
+ *
+ * Returns:
+ * {DOMElement} A Div (an alphaImageDiv, to be precise) that contains the
+ * image of the button, and has all the proper event handlers set.
+ */
+ _addButton:function(id, img, xy, sz) {
+ var imgLocation = OpenLayers.Util.getImagesLocation() + img;
+ var btn = OpenLayers.Util.createAlphaImageDiv(
+ "OpenLayers_Control_PanZoom_" + id,
+ xy, sz, imgLocation, "absolute");
+
+ //we want to add the outer div
+ this.div.appendChild(btn);
+
+ OpenLayers.Event.observe(btn, "mousedown",
+ OpenLayers.Function.bindAsEventListener(this.buttonDown, btn));
+ OpenLayers.Event.observe(btn, "dblclick",
+ OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
+ OpenLayers.Event.observe(btn, "click",
+ OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
+ btn.action = id;
+ btn.map = this.map;
+ btn.slideFactor = this.slideFactor;
+
+ //we want to remember/reference the outer div
+ this.buttons.push(btn);
+ return btn;
+ },
+
+ /**
+ * Method: doubleClick
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean}
+ */
+ doubleClick: function (evt) {
+ OpenLayers.Event.stop(evt);
+ return false;
+ },
+
+ /**
+ * Method: buttonDown
+ *
+ * Parameters:
+ * evt - {Event}
+ */
+ buttonDown: function (evt) {
+ if (!OpenLayers.Event.isLeftClick(evt)) {
+ return;
+ }
+
+ switch (this.action) {
+ case "panup":
+ this.map.pan(0, -this.slideFactor);
+ break;
+ case "pandown":
+ this.map.pan(0, this.slideFactor);
+ break;
+ case "panleft":
+ this.map.pan(-this.slideFactor, 0);
+ break;
+ case "panright":
+ this.map.pan(this.slideFactor, 0);
+ break;
+ case "zoomin":
+ this.map.zoomIn();
+ break;
+ case "zoomout":
+ this.map.zoomOut();
+ break;
+ case "zoomworld":
+ this.map.zoomToMaxExtent();
+ break;
+ }
+
+ OpenLayers.Event.stop(evt);
+ },
+
+ CLASS_NAME: "OpenLayers.Control.PanZoom"
+});
+
+/**
+ * Constant: X
+ * {Integer}
+ */
+OpenLayers.Control.PanZoom.X = 4;
+
+/**
+ * Constant: Y
+ * {Integer}
+ */
+OpenLayers.Control.PanZoom.Y = 4;
+/* ======================================================================
+ OpenLayers/Control/ScaleLine.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.ScaleLine
+ * Display a small line indicator representing the current map scale on the map.
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ *
+ * Is a very close copy of:
+ * - <OpenLayers.Control.Scale>
+ */
+OpenLayers.Control.ScaleLine = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Property: maxWidth
+ * {Integer} Maximum width of the scale line in pixels. Default is 100.
+ */
+ maxWidth: 100,
+
+ /**
+ * Property: topOutUnits
+ * {String} Units for zoomed out on top bar. Default is km.
+ */
+ topOutUnits: "km",
+
+ /**
+ * Property: topInUnits
+ * {String} Units for zoomed in on top bar. Default is m.
+ */
+ topInUnits: "m",
+
+ /**
+ * Property: bottomOutUnits
+ * {String} Units for zoomed out on bottom bar. Default is mi.
+ */
+ bottomOutUnits: "mi",
+
+ /**
+ * Property: bottomInUnits
+ * {String} Units for zoomed in on bottom bar. Default is ft.
+ */
+ bottomInUnits: "ft",
+
+ /**
+ * Property: eTop
+ * {DOMElement}
+ */
+ eTop: null,
+
+ /**
+ * Property: eBottom
+ * {DOMElement}
+ */
+ eBottom:null,
+
+ /**
+ * Constructor: OpenLayers.ScaleLine
+ * Create a new scale line control.
+ *
+ * Parameters:
+ * options - {Object} An optional object whose properties will be used
+ * to extend the control.
+ */
+ initialize: function(options) {
+ OpenLayers.Control.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * Method: draw
+ *
+ * Returns:
+ * {DOMElement}
+ */
+ draw: function() {
+ OpenLayers.Control.prototype.draw.apply(this, arguments);
+ if (!this.eTop) {
+ this.div.style.display = "block";
+ this.div.style.position = "absolute";
+
+ // stick in the top bar
+ this.eTop = document.createElement("div");
+ this.eTop.className = this.displayClass + "Top";
+ var theLen = this.topInUnits.length;
+ this.div.appendChild(this.eTop);
+ if((this.topOutUnits == "") || (this.topInUnits == "")) {
+ this.eTop.style.visibility = "hidden";
+ } else {
+ this.eTop.style.visibility = "visible";
+ }
+
+ // and the bottom bar
+ this.eBottom = document.createElement("div");
+ this.eBottom.className = this.displayClass + "Bottom";
+ this.div.appendChild(this.eBottom);
+ if((this.bottomOutUnits == "") || (this.bottomInUnits == "")) {
+ this.eBottom.style.visibility = "hidden";
+ } else {
+ this.eBottom.style.visibility = "visible";
+ }
+ }
+ this.map.events.register('moveend', this, this.update);
+ this.update();
+ return this.div;
+ },
+
+ /**
+ * Method: getBarLen
+ * Given a number, round it down to the nearest 1,2,5 times a power of 10.
+ * That seems a fairly useful set of number groups to use.
+ *
+ * Parameters:
+ * maxLen - {float} the number we're rounding down from
+ *
+ * Returns:
+ * {Float} the rounded number (less than or equal to maxLen)
+ */
+ getBarLen: function(maxLen) {
+ // nearest power of 10 lower than maxLen
+ var digits = parseInt(Math.log(maxLen) / Math.log(10));
+ var pow10 = Math.pow(10, digits);
+
+ // ok, find first character
+ var firstChar = parseInt(maxLen / pow10);
+
+ // right, put it into the correct bracket
+ var barLen;
+ if(firstChar > 5) {
+ barLen = 5;
+ } else if(firstChar > 2) {
+ barLen = 2;
+ } else {
+ barLen = 1;
+ }
+
+ // scale it up the correct power of 10
+ return barLen * pow10;
+ },
+
+ /**
+ * Method: update
+ * Update the size of the bars, and the labels they contain.
+ */
+ update: function() {
+ var res = this.map.getResolution();
+ if (!res) {
+ return;
+ }
+
+ var curMapUnits = this.map.units;
+ var inches = OpenLayers.INCHES_PER_UNIT;
+
+ // convert maxWidth to map units
+ var maxSizeData = this.maxWidth * res * inches[curMapUnits];
+
+ // decide whether to use large or small scale units
+ var topUnits;
+ var bottomUnits;
+ if(maxSizeData > 100000) {
+ topUnits = this.topOutUnits;
+ bottomUnits = this.bottomOutUnits;
+ } else {
+ topUnits = this.topInUnits;
+ bottomUnits = this.bottomInUnits;
+ }
+
+ // and to map units units
+ var topMax = maxSizeData / inches[topUnits];
+ var bottomMax = maxSizeData / inches[bottomUnits];
+
+ // now trim this down to useful block length
+ var topRounded = this.getBarLen(topMax);
+ var bottomRounded = this.getBarLen(bottomMax);
+
+ // and back to display units
+ topMax = topRounded / inches[curMapUnits] * inches[topUnits];
+ bottomMax = bottomRounded / inches[curMapUnits] * inches[bottomUnits];
+
+ // and to pixel units
+ var topPx = topMax / res;
+ var bottomPx = bottomMax / res;
+
+ // now set the pixel widths
+ this.eTop.style.width = Math.round(topPx) + "px";
+ this.eBottom.style.width = Math.round(bottomPx) + "px";
+
+ // and the values inside them
+ this.eTop.innerHTML = topRounded + " " + topUnits;
+ this.eBottom.innerHTML = bottomRounded + " " + bottomUnits ;
+ },
+
+ CLASS_NAME: "OpenLayers.Control.ScaleLine"
+});
+
+/* ======================================================================
+ OpenLayers/Events.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Util.js
+ */
+
+/**
+ * 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_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: 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: 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 false
+ */
+ stop: function(event, allowDefault) {
+
+ if (!allowDefault) {
+ if (event.preventDefault) {
+ event.preventDefault();
+ } else {
+ event.returnValue = false;
+ }
+ }
+
+ if (event.stopPropagation) {
+ event.stopPropagation();
+ } else {
+ event.cancelBubble = true;
+ }
+ },
+
+ /**
+ * 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];
+ var args = new Array(entry.element,
+ entry.name,
+ entry.observer,
+ entry.useCapture);
+ var removed = OpenLayers.Event.stopObserving.apply(this, args);
+ }
+ }
+ },
+
+ /**
+ * 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);
+
+// FIXME: Remove this in 3.0. In 3.0, Event.stop will no longer be provided
+// by OpenLayers.
+if (window.Event) {
+ OpenLayers.Util.applyDefaults(window.Event, OpenLayers.Event);
+} else {
+ var Event = OpenLayers.Event;
+}
+
+/**
+ * Class: OpenLayers.Events
+ */
+OpenLayers.Events = OpenLayers.Class({
+
+ /**
+ * Constant: BROWSER_EVENTS
+ * {Array(String)} supported events
+ */
+ BROWSER_EVENTS: [
+ "mouseover", "mouseout",
+ "mousedown", "mouseup", "mousemove",
+ "click", "dblclick",
+ "resize", "focus", "blur"
+ ],
+
+ /**
+ * 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: eventTypes
+ * {Array(String)} list of support application events
+ */
+ eventTypes: null,
+
+ /**
+ * Property: eventHandler
+ * {Function} bound event handler attached to elements
+ */
+ eventHandler: null,
+
+ /**
+ * APIProperty: fallThrough
+ * {Boolean}
+ */
+ fallThrough: 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)} Array of custom application events
+ * fallThrough - {Boolean} Allow events to fall through after these have
+ * been handled?
+ */
+ initialize: function (object, element, eventTypes, fallThrough) {
+ this.object = object;
+ this.element = element;
+ this.eventTypes = eventTypes;
+ this.fallThrough = fallThrough;
+ this.listeners = {};
+
+ // 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
+ );
+
+ // if eventTypes is specified, create a listeners list for each
+ // custom application event.
+ if (this.eventTypes != null) {
+ for (var i = 0; i < this.eventTypes.length; i++) {
+ this.addEventType(this.eventTypes[i]);
+ }
+ }
+
+ // if a dom element is specified, add a listeners list
+ // for browser events on the element and register them
+ if (this.element != null) {
+ this.attachToElement(element);
+ }
+ },
+
+ /**
+ * APIMethod: destroy
+ */
+ destroy: function () {
+ if (this.element) {
+ OpenLayers.Event.stopObservingElement(this.element);
+ }
+ this.element = null;
+
+ this.listeners = null;
+ this.object = null;
+ this.eventTypes = null;
+ this.fallThrough = null;
+ this.eventHandler = null;
+ },
+
+ /**
+ * APIMethod: addEventType
+ * Add a new event type to this events object.
+ * If the event type has already been added, do nothing.
+ *
+ * Parameters:
+ * eventName - {String}
+ */
+ addEventType: function(eventName) {
+ if (!this.listeners[eventName]) {
+ this.listeners[eventName] = [];
+ }
+ },
+
+ /**
+ * Method: attachToElement
+ *
+ * Parameters:
+ * element - {HTMLDOMElement} a DOM element to attach browser events to
+ */
+ attachToElement: function (element) {
+ for (var i = 0; i < this.BROWSER_EVENTS.length; i++) {
+ var eventType = this.BROWSER_EVENTS[i];
+
+ // every browser event has a corresponding application event
+ // (whether it's listened for or not).
+ this.addEventType(eventType);
+
+ // use Prototype to register the event cross-browser
+ OpenLayers.Event.observe(element, eventType, this.eventHandler);
+ }
+ // disable dragstart in IE so that mousedown/move/up works normally
+ OpenLayers.Event.observe(element, "dragstart", OpenLayers.Event.stop);
+ },
+
+ /**
+ * Method: on
+ * Convenience method for registering listeners with a common scope.
+ *
+ * Example use:
+ * (code)
+ * events.on({
+ * "loadstart": loadStartListener,
+ * "loadend": loadEndListener,
+ * scope: object
+ * });
+ * (end)
+ */
+ on: function(object) {
+ for(var type in object) {
+ if(type != "scope") {
+ 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.
+ *
+ *
+ */
+ register: function (type, obj, func) {
+
+ if (func != null &&
+ ((this.eventTypes && OpenLayers.Util.indexOf(this.eventTypes, type) != -1) ||
+ OpenLayers.Util.indexOf(this.BROWSER_EVENTS, type) != -1)) {
+ if (obj == null) {
+ obj = this.object;
+ }
+ var listeners = this.listeners[type];
+ if (listeners != null) {
+ listeners.push( {obj: obj, func: func} );
+ }
+ }
+ },
+
+ /**
+ * 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) {
+
+ if (func != null) {
+ if (obj == null) {
+ obj = this.object;
+ }
+ var listeners = this.listeners[type];
+ if (listeners != null) {
+ listeners.unshift( {obj: obj, func: func} );
+ }
+ }
+ },
+
+ /**
+ * Method: un
+ * Convenience method for unregistering listeners with a common scope.
+ *
+ * Example use:
+ * (code)
+ * events.un({
+ * "loadstart": loadStartListener,
+ * "loadend": loadEndListener,
+ * scope: object
+ * });
+ * (end)
+ */
+ un: function(object) {
+ for(var type in object) {
+ if(type != "scope") {
+ 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; i < listeners.length; i++) {
+ if (listeners[i].obj == obj && listeners[i].func == func) {
+ listeners.splice(i, 1);
+ break;
+ }
+ }
+ }
+ },
+
+ /**
+ * Method: remove
+ * Remove all listeners for a given event type. If type is not registered,
+ * does nothing.
+ *
+ * Parameters:
+ * type - {String}
+ */
+ remove: function(type) {
+ if (this.listeners[type] != null) {
+ this.listeners[type] = [];
+ }
+ },
+
+ /**
+ * APIMethod: triggerEvent
+ * Trigger a specified registered event.
+ *
+ * Parameters:
+ * type - {String}
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} The last listener return. If a listener returns false, the
+ * chain of listeners will stop getting called.
+ */
+ triggerEvent: function (type, evt) {
+
+ // prep evt object with object & div references
+ if (evt == null) {
+ evt = {};
+ }
+ evt.object = this.object;
+ evt.element = this.element;
+ if(!evt.type) {
+ evt.type = type;
+ }
+
+ // execute all callbacks registered for specified type
+ // get a clone of the listeners array to
+ // allow for splicing during callbacks
+ var listeners = (this.listeners[type]) ?
+ this.listeners[type].slice() : null;
+ if ((listeners != null) && (listeners.length > 0)) {
+ var continueChain;
+ for (var i = 0; i < listeners.length; i++) {
+ var callback = listeners[i];
+ // bind the context to callback.obj
+ continueChain = callback.func.apply(callback.obj, [evt]);
+
+ if ((continueChain != undefined) && (continueChain == false)) {
+ // if callback returns false, execute no more callbacks.
+ break;
+ }
+ }
+ // don't fall through to other DOM elements
+ if (!this.fallThrough) {
+ OpenLayers.Event.stop(evt, true);
+ }
+ }
+ return continueChain;
+ },
+
+ /**
+ * Method: handleBrowserEvent
+ * Basically just a wrapper to the triggerEvent() function, but takes
+ * care to set a property 'xy' on the event with the current mouse
+ * position.
+ *
+ * Parameters:
+ * evt - {Event}
+ */
+ handleBrowserEvent: function (evt) {
+ evt.xy = this.getMousePosition(evt);
+ this.triggerEvent(evt.type, evt);
+ },
+
+ /**
+ * Method: getMousePosition
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} The current xy coordinate of the mouse, adjusted
+ * for offsets
+ */
+ getMousePosition: function (evt) {
+ if (!this.element.offsets) {
+ this.element.offsets = OpenLayers.Util.pagePosition(this.element);
+ this.element.offsets[0] += (document.documentElement.scrollLeft
+ || document.body.scrollLeft);
+ this.element.offsets[1] += (document.documentElement.scrollTop
+ || document.body.scrollTop);
+ }
+ return new OpenLayers.Pixel(
+ (evt.clientX + (document.documentElement.scrollLeft
+ || document.body.scrollLeft)) - this.element.offsets[0]
+ - (document.documentElement.clientLeft || 0),
+ (evt.clientY + (document.documentElement.scrollTop
+ || document.body.scrollTop)) - this.element.offsets[1]
+ - (document.documentElement.clientTop || 0)
+ );
+ },
+
+ CLASS_NAME: "OpenLayers.Events"
+});
+/* ======================================================================
+ OpenLayers/Lang/en.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Lang.js
+ */
+
+/**
+ * Namespace: OpenLayers.Lang["en"]
+ * Dictionary for English. Keys for entries are used in calls to
+ * <OpenLayers.Lang.translate>. Entry bodies are normal strings or
+ * strings formatted for use with <OpenLayers.String.format> calls.
+ */
+OpenLayers.Lang.en = {
+
+ 'unhandledRequest': "Unhandled request return ${statusText}",
+
+ 'permalink': "Permalink",
+
+ 'overlays': "Overlays",
+
+ 'baseLayer': "Base Layer",
+
+ 'sameProjection':
+ "The overview map only works when it is in the same projection as the main map",
+
+ 'readNotImplemented': "Read not implemented.",
+
+ 'writeNotImplemented': "Write not implemented.",
+
+ 'noFID': "Can't update a feature for which there is no FID.",
+
+ 'errorLoadingGML': "Error in loading GML file ${url}",
+
+ 'browserNotSupported':
+ "Your browser does not support vector rendering. Currently supported renderers are:\n${renderers}",
+
+ 'componentShouldBe': "addFeatures : component should be an ${geomType}",
+
+ // console message
+ 'getFeatureError':
+ "getFeatureFromEvent called on layer with no renderer. This usually means you " +
+ "destroyed a layer, but not some handler which is associated with it.",
+
+ // console message
+ 'minZoomLevelError':
+ "The minZoomLevel property is only intended for use " +
+ "with the FixedZoomLevels-descendent layers. That this " +
+ "wfs layer checks for minZoomLevel is a relic of the" +
+ "past. We cannot, however, remove it without possibly " +
+ "breaking OL based applications that may depend on it." +
+ " Therefore we are deprecating it -- the minZoomLevel " +
+ "check below will be removed at 3.0. Please instead " +
+ "use min/max resolution setting as described here: " +
+ "http://trac.openlayers.org/wiki/SettingZoomLevels",
+
+ 'commitSuccess': "WFS Transaction: SUCCESS ${response}",
+
+ 'commitFailed': "WFS Transaction: FAILED ${response}",
+
+ 'googleWarning':
+ "The Google Layer was unable to load correctly.<br><br>" +
+ "To get rid of this message, select a new BaseLayer " +
+ "in the layer switcher in the upper-right corner.<br><br>" +
+ "Most likely, this is because the Google Maps library " +
+ "script was either not included, or does not contain the " +
+ "correct API key for your site.<br><br>" +
+ "Developers: For help getting this working correctly, " +
+ "<a href='http://trac.openlayers.org/wiki/Google' " +
+ "target='_blank'>click here</a>",
+
+ 'getLayerWarning':
+ "The ${layerType} Layer was unable to load correctly.<br><br>" +
+ "To get rid of this message, select a new BaseLayer " +
+ "in the layer switcher in the upper-right corner.<br><br>" +
+ "Most likely, this is because the ${layerLib} library " +
+ "script was either not correctly included.<br><br>" +
+ "Developers: For help getting this working correctly, " +
+ "<a href='http://trac.openlayers.org/wiki/${layerLib}' " +
+ "target='_blank'>click here</a>",
+
+ 'scale': "Scale = 1 : ${scaleDenom}",
+
+ // console message
+ 'layerAlreadyAdded':
+ "You tried to add the layer: ${layerName} to the map, but it has already been added",
+
+ // console message
+ 'reprojectDeprecated':
+ "You are using the 'reproject' option " +
+ "on the ${layerName} layer. This option is deprecated: " +
+ "its use was designed to support displaying data over commercial " +
+ "basemaps, but that functionality should now be achieved by using " +
+ "Spherical Mercator support. More information is available from " +
+ "http://trac.openlayers.org/wiki/SphericalMercator.",
+
+ // console message
+ 'methodDeprecated':
+ "This method has been deprecated and will be removed in 3.0. " +
+ "Please use ${newMethod} instead.",
+
+ // console message
+ 'boundsAddError': "You must pass both x and y values to the add function.",
+
+ // console message
+ 'lonlatAddError': "You must pass both lon and lat values to the add function.",
+
+ // console message
+ 'pixelAddError': "You must pass both x and y values to the add function.",
+
+ // console message
+ 'unsupportedGeometryType': "Unsupported geometry type: ${geomType}",
+
+ // console message
+ 'pagePositionFailed':
+ "OpenLayers.Util.pagePosition failed: element with id ${elemId} may be misplaced.",
+
+ 'end': ''
+};
+/* ======================================================================
+ OpenLayers/Projection.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Util.js
+ */
+
+/**
+ * Class: OpenLayers.Projection
+ * Class for coordinate transforms between coordinate systems.
+ * Depends on the proj4js library. If proj4js is not available,
+ * then this is just an empty stub.
+ */
+OpenLayers.Projection = OpenLayers.Class({
+
+ /**
+ * Property: proj
+ * {Object} Proj4js.Proj instance.
+ */
+ proj: null,
+
+ /**
+ * Property: projCode
+ * {String}
+ */
+ projCode: null,
+
+ /**
+ * Constructor: OpenLayers.Projection
+ * This class offers several methods for interacting with a wrapped
+ * pro4js projection object.
+ *
+ * Parameters:
+ * options - {Object} An optional object with properties to set on the
+ * format
+ *
+ * Returns:
+ * {<OpenLayers.Projection>} A projection object.
+ */
+ initialize: function(projCode, options) {
+ OpenLayers.Util.extend(this, options);
+ this.projCode = projCode;
+ if (window.Proj4js) {
+ this.proj = new Proj4js.Proj(projCode);
+ }
+ },
+
+ /**
+ * APIMethod: getCode
+ * Get the string SRS code.
+ *
+ * Returns:
+ * {String} The SRS code.
+ */
+ getCode: function() {
+ return this.proj ? this.proj.srsCode : this.projCode;
+ },
+
+ /**
+ * APIMethod: getUnits
+ * Get the units string for the projection -- returns null if
+ * proj4js is not available.
+ *
+ * Returns:
+ * {String} The units abbreviation.
+ */
+ getUnits: function() {
+ return this.proj ? this.proj.units : null;
+ },
+
+ /**
+ * Method: toString
+ * Convert projection to string (getCode wrapper).
+ *
+ * Returns:
+ * {String} The projection code.
+ */
+ toString: function() {
+ return this.getCode();
+ },
+
+ /**
+ * Method: equals
+ * Test equality of two projection instances. Determines equality based
+ * soley on the projection code.
+ *
+ * Returns:
+ * {Boolean} The two projections are equivalent.
+ */
+ equals: function(projection) {
+ if (projection && projection.getCode) {
+ return this.getCode() == projection.getCode();
+ } else {
+ return false;
+ }
+ },
+
+ /* Method: destroy
+ * Destroy projection object.
+ */
+ destroy: function() {
+ delete this.proj;
+ delete this.projCode;
+ },
+
+ CLASS_NAME: "OpenLayers.Projection"
+});
+
+/**
+ * Property: transforms
+ * Transforms is an object, with from properties, each of which may
+ * have a to property. This allows you to define projections without
+ * requiring support for proj4js to be included.
+ *
+ * This object has keys which correspond to a 'source' projection object. The
+ * keys should be strings, corresponding to the projection.getCode() value.
+ * Each source projection object should have a set of destination projection
+ * keys included in the object.
+ *
+ * Each value in the destination object should be a transformation function,
+ * where the function is expected to be passed an object with a .x and a .y
+ * property. The function should return the object, with the .x and .y
+ * transformed according to the transformation function.
+ *
+ * Note - Properties on this object should not be set directly. To add a
+ * transform method to this object, use the <addTransform> method. For an
+ * example of usage, see the OpenLayers.Layer.SphericalMercator file.
+ */
+OpenLayers.Projection.transforms = {};
+
+/**
+ * APIMethod: addTransform
+ * Set a custom transform method between two projections. Use this method in
+ * cases where the proj4js lib is not available or where custom projections
+ * need to be handled.
+ *
+ * Parameters:
+ * from - {String} The code for the source projection
+ * to - {String} the code for the destination projection
+ * method - {Function} A function that takes a point as an argument and
+ * transforms that point from the source to the destination projection
+ * in place. The original point should be modified.
+ */
+OpenLayers.Projection.addTransform = function(from, to, method) {
+ if(!OpenLayers.Projection.transforms[from]) {
+ OpenLayers.Projection.transforms[from] = {};
+ }
+ OpenLayers.Projection.transforms[from][to] = method;
+};
+
+/**
+ * APIMethod: transform
+ * Transform a point coordinate from one projection to another. Note that
+ * the input point is transformed in place.
+ *
+ * Parameters:
+ * point - {{OpenLayers.Geometry.Point> | Object} An object with x and y
+ * properties representing coordinates in those dimensions.
+ * sourceProj - {OpenLayers.Projection} Source map coordinate system
+ * destProj - {OpenLayers.Projection} Destination map coordinate system
+ *
+ * Returns:
+ * point - {object} A transformed coordinate. The original point is modified.
+ */
+OpenLayers.Projection.transform = function(point, source, dest) {
+ if (source.proj && dest.proj) {
+ point = Proj4js.transform(source.proj, dest.proj, point);
+ } else if (source && dest &&
+ OpenLayers.Projection.transforms[source.getCode()] &&
+ OpenLayers.Projection.transforms[source.getCode()][dest.getCode()]) {
+ OpenLayers.Projection.transforms[source.getCode()][dest.getCode()](point);
+ }
+ return point;
+};
+/* ======================================================================
+ OpenLayers/Tile.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/*
+ * @requires OpenLayers/Util.js
+ */
+
+/*
+ * Class: OpenLayers.Tile
+ * This is a class designed to designate a single tile, however
+ * it is explicitly designed to do relatively little. Tiles store
+ * information about themselves -- such as the URL that they are related
+ * to, and their size - but do not add themselves to the layer div
+ * automatically, for example. Create a new tile with the
+ * <OpenLayers.Tile> constructor, or a subclass.
+ *
+ * TBD 3.0 - remove reference to url in above paragraph
+ *
+ */
+OpenLayers.Tile = OpenLayers.Class({
+
+ /**
+ * Constant: EVENT_TYPES
+ * {Array(String)} Supported application event types
+ */
+ EVENT_TYPES: [ "loadstart", "loadend", "reload", "unload"],
+
+ /**
+ * APIProperty: events
+ * {<OpenLayers.Events>} An events object that handles all
+ * events on the tile.
+ */
+ events: null,
+
+ /**
+ * Property: id
+ * {String} null
+ */
+ id: null,
+
+ /**
+ * Property: layer
+ * {<OpenLayers.Layer>} layer the tile is attached to
+ */
+ layer: null,
+
+ /**
+ * Property: url
+ * {String} url of the request.
+ *
+ * TBD 3.0
+ * Deprecated. The base tile class does not need an url. This should be
+ * handled in subclasses. Does not belong here.
+ */
+ url: null,
+
+ /**
+ * APIProperty: bounds
+ * {<OpenLayers.Bounds>} null
+ */
+ bounds: null,
+
+ /**
+ * Property: size
+ * {<OpenLayers.Size>} null
+ */
+ size: null,
+
+ /**
+ * Property: position
+ * {<OpenLayers.Pixel>} Top Left pixel of the tile
+ */
+ position: null,
+
+ /**
+ * Property: isLoading
+ * {Boolean} Is the tile loading?
+ */
+ isLoading: false,
+
+ /**
+ * Property: isBackBuffer
+ * {Boolean} Is this tile a back buffer tile?
+ */
+ isBackBuffer: false,
+
+ /**
+ * Property: lastRatio
+ * {Float} Used in transition code only. This is the previous ratio
+ * of the back buffer tile resolution to the map resolution. Compared
+ * with the current ratio to determine if zooming occurred.
+ */
+ lastRatio: 1,
+
+ /**
+ * Property: isFirstDraw
+ * {Boolean} Is this the first time the tile is being drawn?
+ * This is used to force resetBackBuffer to synchronize
+ * the backBufferTile with the foreground tile the first time
+ * the foreground tile loads so that if the user zooms
+ * before the layer has fully loaded, the backBufferTile for
+ * tiles that have been loaded can be used.
+ */
+ isFirstDraw: true,
+
+ /**
+ * Property: backBufferTile
+ * {<OpenLayers.Tile>} A clone of the tile used to create transition
+ * effects when the tile is moved or changes resolution.
+ */
+ backBufferTile: null,
+
+ /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor.
+ * there is no need for the base tile class to have a url.
+ *
+ * Constructor: OpenLayers.Tile
+ * Constructor for a new <OpenLayers.Tile> instance.
+ *
+ * Parameters:
+ * layer - {<OpenLayers.Layer>} layer that the tile will go in.
+ * position - {<OpenLayers.Pixel>}
+ * bounds - {<OpenLayers.Bounds>}
+ * url - {<String>}
+ * size - {<OpenLayers.Size>}
+ */
+ initialize: function(layer, position, bounds, url, size) {
+ this.layer = layer;
+ this.position = position.clone();
+ this.bounds = bounds.clone();
+ this.url = url;
+ this.size = size.clone();
+
+ //give the tile a unique id based on its BBOX.
+ this.id = OpenLayers.Util.createUniqueID("Tile_");
+
+ this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
+ },
+
+ /**
+ * Method: unload
+ * Call immediately before destroying if you are listening to tile
+ * events, so that counters are properly handled if tile is still
+ * loading at destroy-time. Will only fire an event if the tile is
+ * still loading.
+ */
+ unload: function() {
+ if (this.isLoading) {
+ this.isLoading = false;
+ this.events.triggerEvent("unload");
+ }
+ },
+
+ /**
+ * APIMethod: destroy
+ * Nullify references to prevent circular references and memory leaks.
+ */
+ destroy:function() {
+ if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS,
+ this.layer.transitionEffect) != -1) {
+ this.layer.events.unregister("loadend", this, this.resetBackBuffer);
+ this.events.unregister('loadend', this, this.resetBackBuffer);
+ } else {
+ this.events.unregister('loadend', this, this.showTile);
+ }
+ this.layer = null;
+ this.bounds = null;
+ this.size = null;
+ this.position = null;
+
+ this.events.destroy();
+ this.events = null;
+
+ /* clean up the backBufferTile if it exists */
+ if (this.backBufferTile) {
+ this.backBufferTile.destroy();
+ this.backBufferTile = null;
+ }
+ },
+
+ /**
+ * Method: clone
+ *
+ * Parameters:
+ * obj - {<OpenLayers.Tile>} The tile to be cloned
+ *
+ * Returns:
+ * {<OpenLayers.Tile>} An exact clone of this <OpenLayers.Tile>
+ */
+ clone: function (obj) {
+ if (obj == null) {
+ obj = new OpenLayers.Tile(this.layer,
+ this.position,
+ this.bounds,
+ this.url,
+ this.size);
+ }
+
+ // catch any randomly tagged-on properties
+ OpenLayers.Util.applyDefaults(obj, this);
+
+ return obj;
+ },
+
+ /**
+ * Method: draw
+ * Clear whatever is currently in the tile, then return whether or not
+ * it should actually be re-drawn.
+ *
+ * Returns:
+ * {Boolean} Whether or not the tile should actually be drawn. Note that
+ * this is not really the best way of doing things, but such is
+ * the way the code has been developed. Subclasses call this and
+ * depend on the return to know if they should draw or not.
+ */
+ draw: function() {
+ var maxExtent = this.layer.maxExtent;
+ var withinMaxExtent = (maxExtent &&
+ this.bounds.intersectsBounds(maxExtent, false));
+
+ // The only case where we *wouldn't* want to draw the tile is if the
+ // tile is outside its layer's maxExtent.
+ var drawTile = (withinMaxExtent || this.layer.displayOutsideMaxExtent);
+
+ if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS, this.layer.transitionEffect) != -1) {
+ if (drawTile) {
+ //we use a clone of this tile to create a double buffer for visual
+ //continuity. The backBufferTile is used to create transition
+ //effects while the tile in the grid is repositioned and redrawn
+ if (!this.backBufferTile) {
+ this.backBufferTile = this.clone();
+ this.backBufferTile.hide();
+ // this is important. It allows the backBuffer to place itself
+ // appropriately in the DOM. The Image subclass needs to put
+ // the backBufferTile behind the main tile so the tiles can
+ // load over top and display as soon as they are loaded.
+ this.backBufferTile.isBackBuffer = true;
+
+ // potentially end any transition effects when the tile loads
+ this.events.register('loadend', this, this.resetBackBuffer);
+
+ // clear transition back buffer tile only after all tiles in
+ // this layer have loaded to avoid visual glitches
+ this.layer.events.register("loadend", this, this.resetBackBuffer);
+ }
+ // run any transition effects
+ this.startTransition();
+ } else {
+ // if we aren't going to draw the tile, then the backBuffer should
+ // be hidden too!
+ if (this.backBufferTile) {
+ this.backBufferTile.clear();
+ }
+ }
+ } else {
+ if (drawTile && this.isFirstDraw) {
+ this.events.register('loadend', this, this.showTile);
+ this.isFirstDraw = false;
+ }
+ }
+ this.shouldDraw = drawTile;
+
+ //clear tile's contents and mark as not drawn
+ this.clear();
+
+ return drawTile;
+ },
+
+ /**
+ * Method: moveTo
+ * Reposition the tile.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * position - {<OpenLayers.Pixel>}
+ * redraw - {Boolean} Call draw method on tile after moving.
+ * Default is true
+ */
+ moveTo: function (bounds, position, redraw) {
+ if (redraw == null) {
+ redraw = true;
+ }
+
+ this.bounds = bounds.clone();
+ this.position = position.clone();
+ if (redraw) {
+ this.draw();
+ }
+ },
+
+ /**
+ * Method: clear
+ * Clear the tile of any bounds/position-related data so that it can
+ * be reused in a new location. To be implemented by subclasses.
+ */
+ clear: function() {
+ // to be implemented by subclasses
+ },
+
+ /**
+ * Method: getBoundsFromBaseLayer
+ * Take the pixel locations of the corner of the tile, and pass them to
+ * the base layer and ask for the location of those pixels, so that
+ * displaying tiles over Google works fine.
+ *
+ * Parameters:
+ * position - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * bounds - {<OpenLayers.Bounds>}
+ */
+ getBoundsFromBaseLayer: function(position) {
+ var msg = OpenLayers.i18n('reprojectDeprecated',
+ {'layerName':this.layer.name});
+ OpenLayers.Console.warn(msg);
+ var topLeft = this.layer.map.getLonLatFromLayerPx(position);
+ var bottomRightPx = position.clone();
+ bottomRightPx.x += this.size.w;
+ bottomRightPx.y += this.size.h;
+ var bottomRight = this.layer.map.getLonLatFromLayerPx(bottomRightPx);
+ // Handle the case where the base layer wraps around the date line.
+ // Google does this, and it breaks WMS servers to request bounds in
+ // that fashion.
+ if (topLeft.lon > bottomRight.lon) {
+ if (topLeft.lon < 0) {
+ topLeft.lon = -180 - (topLeft.lon+180);
+ } else {
+ bottomRight.lon = 180+bottomRight.lon+180;
+ }
+ }
+ var bounds = new OpenLayers.Bounds(topLeft.lon,
+ bottomRight.lat,
+ bottomRight.lon,
+ topLeft.lat);
+ return bounds;
+ },
+
+ /**
+ * Method: startTransition
+ * Prepare the tile for a transition effect. To be
+ * implemented by subclasses.
+ */
+ startTransition: function() {},
+
+ /**
+ * Method: resetBackBuffer
+ * Triggered by two different events, layer loadend, and tile loadend.
+ * In any of these cases, we check to see if we can hide the
+ * backBufferTile yet and update its parameters to match the
+ * foreground tile.
+ *
+ * Basic logic:
+ * - If the backBufferTile hasn't been drawn yet, reset it
+ * - If layer is still loading, show foreground tile but don't hide
+ * the backBufferTile yet
+ * - If layer is done loading, reset backBuffer tile and show
+ * foreground tile
+ */
+ resetBackBuffer: function() {
+ this.showTile();
+ if (this.backBufferTile &&
+ (this.isFirstDraw || !this.layer.numLoadingTiles)) {
+ this.isFirstDraw = false;
+ // check to see if the backBufferTile is within the max extents
+ // before rendering it
+ var maxExtent = this.layer.maxExtent;
+ var withinMaxExtent = (maxExtent &&
+ this.bounds.intersectsBounds(maxExtent, false));
+ if (withinMaxExtent) {
+ this.backBufferTile.position = this.position;
+ this.backBufferTile.bounds = this.bounds;
+ this.backBufferTile.size = this.size;
+ this.backBufferTile.imageSize = this.layer.imageSize || this.size;
+ this.backBufferTile.imageOffset = this.layer.imageOffset;
+ this.backBufferTile.resolution = this.layer.getResolution();
+ this.backBufferTile.renderTile();
+ }
+ }
+ },
+
+ /**
+ * Method: showTile
+ * Show the tile only if it should be drawn.
+ */
+ showTile: function() {
+ if (this.shouldDraw) {
+ this.show();
+ }
+ },
+
+ /**
+ * Method: show
+ * Show the tile. To be implemented by subclasses.
+ */
+ show: function() { },
+
+ /**
+ * Method: hide
+ * Hide the tile. To be implemented by subclasses.
+ */
+ hide: function() { },
+
+ CLASS_NAME: "OpenLayers.Tile"
+});
+/* ======================================================================
+ OpenLayers/Handler.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Events.js
+ */
+
+/**
+ * Class: OpenLayers.Handler
+ * Base class to construct a higher-level handler for event sequences. All
+ * handlers have activate and deactivate methods. In addition, they have
+ * methods named like browser events. When a handler is activated, any
+ * additional methods named like a browser event is registered as a
+ * listener for the corresponding event. When a handler is deactivated,
+ * those same methods are unregistered as event listeners.
+ *
+ * Handlers also typically have a callbacks object with keys named like
+ * the abstracted events or event sequences that they are in charge of
+ * handling. The controls that wrap handlers define the methods that
+ * correspond to these abstract events - so instead of listening for
+ * individual browser events, they only listen for the abstract events
+ * defined by the handler.
+ *
+ * Handlers are created by controls, which ultimately have the responsibility
+ * of making changes to the the state of the application. Handlers
+ * themselves may make temporary changes, but in general are expected to
+ * return the application in the same state that they found it.
+ */
+OpenLayers.Handler = OpenLayers.Class({
+
+ /**
+ * Property: id
+ * {String}
+ */
+ id: null,
+
+ /**
+ * APIProperty: control
+ * {<OpenLayers.Control>}. The control that initialized this handler. The
+ * control is assumed to have a valid map property - that map is used
+ * in the handler's own setMap method.
+ */
+ control: null,
+
+ /**
+ * Property: map
+ * {<OpenLayers.Map>}
+ */
+ map: null,
+
+ /**
+ * APIProperty: keyMask
+ * {Integer} Use bitwise operators and one or more of the OpenLayers.Handler
+ * constants to construct a keyMask. The keyMask is used by
+ * <checkModifiers>. If the keyMask matches the combination of keys
+ * down on an event, checkModifiers returns true.
+ *
+ * Example:
+ * (code)
+ * // handler only responds if the Shift key is down
+ * handler.keyMask = OpenLayers.Handler.MOD_SHIFT;
+ *
+ * // handler only responds if Ctrl-Shift is down
+ * handler.keyMask = OpenLayers.Handler.MOD_SHIFT |
+ * OpenLayers.Handler.MOD_CTRL;
+ * (end)
+ */
+ keyMask: null,
+
+ /**
+ * Property: active
+ * {Boolean}
+ */
+ active: false,
+
+ /**
+ * Property: evt
+ * {Event} This property references the last event handled by the handler.
+ * Note that this property is not part of the stable API. Use of the
+ * evt property should be restricted to controls in the library
+ * or other applications that are willing to update with changes to
+ * the OpenLayers code.
+ */
+ evt: null,
+
+ /**
+ * Constructor: OpenLayers.Handler
+ * Construct a handler.
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>} The control that initialized this
+ * handler. The control is assumed to have a valid map property; that
+ * map is used in the handler's own setMap method.
+ * 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;
+ if (control.map) {
+ this.setMap(control.map);
+ }
+
+ OpenLayers.Util.extend(this, options);
+
+ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+ },
+
+ /**
+ * Method: setMap
+ */
+ setMap: function (map) {
+ this.map = map;
+ },
+
+ /**
+ * Method: checkModifiers
+ * Check the keyMask on the handler. If no <keyMask> is set, this always
+ * returns true. If a <keyMask> is set and it matches the combination
+ * of keys down on an event, this returns true.
+ *
+ * Returns:
+ * {Boolean} The keyMask matches the keys down on an event.
+ */
+ checkModifiers: function (evt) {
+ if(this.keyMask == null) {
+ return true;
+ }
+ /* calculate the keyboard modifier mask for this event */
+ var keyModifiers =
+ (evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) |
+ (evt.ctrlKey ? OpenLayers.Handler.MOD_CTRL : 0) |
+ (evt.altKey ? OpenLayers.Handler.MOD_ALT : 0);
+
+ /* if it differs from the handler object's key mask,
+ bail out of the event handler */
+ return (keyModifiers == this.keyMask);
+ },
+
+ /**
+ * APIMethod: activate
+ * Turn on the handler. Returns false if the handler was already active.
+ *
+ * Returns:
+ * {Boolean} The handler was activated.
+ */
+ activate: function() {
+ if(this.active) {
+ return false;
+ }
+ // register for event handlers defined on this class.
+ var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
+ for (var i = 0; i < events.length; i++) {
+ if (this[events[i]]) {
+ this.register(events[i], this[events[i]]);
+ }
+ }
+ this.active = true;
+ return true;
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Turn off the handler. Returns false if the handler was already inactive.
+ *
+ * Returns:
+ * {Boolean} The handler was deactivated.
+ */
+ deactivate: function() {
+ if(!this.active) {
+ return false;
+ }
+ // unregister event handlers defined on this class.
+ var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
+ for (var i = 0; i < events.length; i++) {
+ if (this[events[i]]) {
+ this.unregister(events[i], this[events[i]]);
+ }
+ }
+ this.active = false;
+ return true;
+ },
+
+ /**
+ * Method: callback
+ * Trigger the control's named callback with the given arguments
+ *
+ * Parameters:
+ * name - {String} The key for the callback that is one of the properties
+ * of the handler's callbacks object.
+ * args - {Array(*)} An array of arguments (any type) with which to call
+ * the callback (defined by the control).
+ */
+ callback: function (name, args) {
+ if (name && this.callbacks[name]) {
+ this.callbacks[name].apply(this.control, args);
+ }
+ },
+
+ /**
+ * Method: register
+ * register an event on the map
+ */
+ register: function (name, method) {
+ // TODO: deal with registerPriority in 3.0
+ this.map.events.registerPriority(name, this, method);
+ this.map.events.registerPriority(name, this, this.setEvent);
+ },
+
+ /**
+ * Method: unregister
+ * unregister an event from the map
+ */
+ unregister: function (name, method) {
+ this.map.events.unregister(name, this, method);
+ this.map.events.unregister(name, this, this.setEvent);
+ },
+
+ /**
+ * Method: setEvent
+ * With each registered browser event, the handler sets its own evt
+ * property. This property can be accessed by controls if needed
+ * to get more information about the event that the handler is
+ * processing.
+ *
+ * This allows modifier keys on the event to be checked (alt, shift,
+ * and ctrl cannot be checked with the keyboard handler). For a
+ * control to determine which modifier keys are associated with the
+ * event that a handler is currently processing, it should access
+ * (code)handler.evt.altKey || handler.evt.shiftKey ||
+ * handler.evt.ctrlKey(end).
+ *
+ * Parameters:
+ * evt - {Event} The browser event.
+ */
+ setEvent: function(evt) {
+ this.evt = evt;
+ return true;
+ },
+
+ /**
+ * Method: destroy
+ * Deconstruct the handler.
+ */
+ destroy: function () {
+ // unregister event listeners
+ this.deactivate();
+ // eliminate circular references
+ this.control = this.map = null;
+ },
+
+ CLASS_NAME: "OpenLayers.Handler"
+});
+
+/**
+ * Constant: OpenLayers.Handler.MOD_NONE
+ * If set as the <keyMask>, <checkModifiers> returns false if any key is down.
+ */
+OpenLayers.Handler.MOD_NONE = 0;
+
+/**
+ * Constant: OpenLayers.Handler.MOD_SHIFT
+ * If set as the <keyMask>, <checkModifiers> returns false if Shift is down.
+ */
+OpenLayers.Handler.MOD_SHIFT = 1;
+
+/**
+ * Constant: OpenLayers.Handler.MOD_CTRL
+ * If set as the <keyMask>, <checkModifiers> returns false if Ctrl is down.
+ */
+OpenLayers.Handler.MOD_CTRL = 2;
+
+/**
+ * Constant: OpenLayers.Handler.MOD_ALT
+ * If set as the <keyMask>, <checkModifiers> returns false if Alt is down.
+ */
+OpenLayers.Handler.MOD_ALT = 4;
+
+
+/* ======================================================================
+ OpenLayers/Map.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Util.js
+ * @requires OpenLayers/Events.js
+ * @requires OpenLayers/Tween.js
+ */
+
+/**
+ * Class: OpenLayers.Map
+ * Instances of OpenLayers.Map are interactive maps embedded in a web page.
+ * Create a new map with the <OpenLayers.Map> constructor.
+ *
+ * On their own maps do not provide much functionality. To extend a map
+ * it's necessary to add controls (<OpenLayers.Control>) and
+ * layers (<OpenLayers.Layer>) 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, Popup: 750, Control: 1000 },
+
+ /**
+ * Constant: EVENT_TYPES
+ * {Array(String)} Supported application event types. 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* {<OpenLayers.Pixel>} The pixel location of the event (relative
+ * to the the map viewport).
+ * - other properties that come with browser events
+ *
+ * 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.
+ * - *addlayer* triggered after a layer has been added. The event object
+ * will include a *layer* property that references the added layer.
+ * - *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, or
+ * visibility change (due to resolution thresholds). 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,
+ * visibility, or order).
+ * - *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
+ * - *popupopen* triggered after a popup opens
+ * - *popupclose* triggered after a popup opens
+ * - *addmarker* triggered after a marker has been added
+ * - *removemarker* triggered after a marker has been removed
+ * - *clearmarkers* triggered after markers have been cleared
+ * - *mouseover* triggered after mouseover the map
+ * - *mouseout* triggered after mouseout the map
+ * - *mousemove* triggered after mousemove the map
+ * - *dragstart* triggered after the start of a drag
+ * - *drag* triggered after a drag
+ * - *dragend* triggered after the end of a drag
+ * - *changebaselayer* triggered after the base layer changes
+ */
+ EVENT_TYPES: [
+ "preaddlayer", "addlayer", "removelayer", "changelayer", "movestart",
+ "move", "moveend", "zoomend", "popupopen", "popupclose",
+ "addmarker", "removemarker", "clearmarkers", "mouseover",
+ "mouseout", "mousemove", "dragstart", "drag", "dragend",
+ "changebaselayer"],
+
+ /**
+ * 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
+ * <getResolutionForZoom> instead of layer.resolutions[zoom] as the
+ * former works for non-integer zoom levels.
+ */
+ fractionalZoom: false,
+
+ /**
+ * APIProperty: events
+ * {<OpenLayers.Events>} An events object that handles all
+ * events on the map
+ */
+ events: null,
+
+ /**
+ * APIProperty: div
+ * {DOMElement} The element that contains the map
+ */
+ div: null,
+
+ /**
+ * Property: dragging
+ * {Boolean} The map is currently being dragged.
+ */
+ dragging: false,
+
+ /**
+ * Property: size
+ * {<OpenLayers.Size>} Size of the main div (this.div)
+ */
+ size: null,
+
+ /**
+ * Property: viewPortDiv
+ * {HTMLDivElement} The element that represents the map viewport
+ */
+ viewPortDiv: null,
+
+ /**
+ * Property: layerContainerOrigin
+ * {<OpenLayers.LonLat>} 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(<OpenLayers.Layer>)} Ordered list of layers in the map
+ */
+ layers: null,
+
+ /**
+ * Property: controls
+ * {Array(<OpenLayers.Control>)} List of controls associated with the map
+ */
+ controls: null,
+
+ /**
+ * Property: popups
+ * {Array(<OpenLayers.Popup>)} List of popups associated with the map
+ */
+ popups: null,
+
+ /**
+ * APIProperty: baseLayer
+ * {<OpenLayers.Layer>} The currently selected base layer. This determines
+ * min/max zoom level, projection, etc.
+ */
+ baseLayer: null,
+
+ /**
+ * Property: center
+ * {<OpenLayers.LonLat>} 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: viewRequestID
+ * {String} Used to store a unique identifier that changes when the map
+ * view changes. viewRequestID should be used when adding data
+ * asynchronously to the map: viewRequestID is incremented when
+ * you initiate your request (right now during changing of
+ * baselayers and changing of zooms). It is stored here in the
+ * map and also in the data that will be coming back
+ * asynchronously. Before displaying this data on request
+ * completion, we check that the viewRequestID of the data is
+ * still the same as that of the map. Fix for #480
+ */
+ viewRequestID: 0,
+
+ // Options
+
+ /**
+ * APIProperty: tileSize
+ * {<OpenLayers.Size>} 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 override the default projection
+ * string this map - also set maxExtent, maxResolution, and
+ * units if appropriate.
+ */
+ projection: "EPSG:4326",
+
+ /**
+ * APIProperty: units
+ * {String} The map units. Defaults to 'degrees'. Possible values are
+ * 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
+ */
+ units: 'degrees',
+
+ /**
+ * 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} Default max is 360 deg / 256 px, which corresponds to
+ * zoom level 0 on gmaps. Specify a different value in the map
+ * options if you are not using a geographic projection and
+ * displaying the whole world.
+ */
+ maxResolution: 1.40625,
+
+ /**
+ * APIProperty: minResolution
+ * {Float}
+ */
+ minResolution: null,
+
+ /**
+ * APIProperty: maxScale
+ * {Float}
+ */
+ maxScale: null,
+
+ /**
+ * APIProperty: minScale
+ * {Float}
+ */
+ minScale: null,
+
+ /**
+ * APIProperty: maxExtent
+ * {<OpenLayers.Bounds>} 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.
+ */
+ maxExtent: null,
+
+ /**
+ * APIProperty: minExtent
+ * {<OpenLayers.Bounds>}
+ */
+ minExtent: null,
+
+ /**
+ * APIProperty: restrictedExtent
+ * {<OpenLayers.Bounds>} 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
+ * {<OpenLayers.Projection>} Requires proj4js support.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,
+
+ /**
+ * Property: panTween
+ * {OpenLayers.Tween} 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 <OpenLayers.Events.on>. Object
+ * structure must be a listeners object as shown in the example for
+ * the events.on method.
+ */
+ eventListeners: null,
+
+ /**
+ * Property: 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: paddingForPopups
+ * {<OpenLayers.Bounds>} Outside margin of the popup. Used to prevent
+ * the popup from getting too close to the map border.
+ */
+ paddingForPopups : null,
+
+ /**
+ * Constructor: OpenLayers.Map
+ * Constructor for a new OpenLayers.Map instance.
+ *
+ * Parameters:
+ * div - {String} Id of an element in your page that will contain the map.
+ * options - {Object} Optional object with properties to tag onto the map.
+ *
+ * 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 = {
+ * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000),
+ * maxResolution: 156543,
+ * units: 'm',
+ * projection: "EPSG:41001"
+ * };
+ * var map = new OpenLayers.Map("map2", options);
+ * (end)
+ */
+ initialize: function (div, options) {
+
+ // 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.maxExtent = new OpenLayers.Bounds(-180, -90, 180, 90);
+
+ this.paddingForPopups = new OpenLayers.Bounds(15, 15, 15, 15);
+
+ this.theme = OpenLayers._getScriptLocation() +
+ 'theme/default/style.css';
+
+ // now override default options
+ OpenLayers.Util.extend(this, options);
+
+ this.id = OpenLayers.Util.createUniqueID("OpenLayers.Map_");
+
+ this.div = OpenLayers.Util.getElement(div);
+
+ // the viewPortDiv is the outermost div we modify
+ var id = this.div.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);
+
+ // the layerContainerDiv is the one that holds all the layers
+ id = this.div.id + "_OpenLayers_Container";
+ this.layerContainerDiv = OpenLayers.Util.createDiv(id);
+ this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;
+
+ this.viewPortDiv.appendChild(this.layerContainerDiv);
+
+ this.events = new OpenLayers.Events(this,
+ this.div,
+ this.EVENT_TYPES,
+ this.fallThrough);
+ this.updateSize();
+ if(this.eventListeners instanceof Object) {
+ this.events.on(this.eventListeners);
+ }
+
+ // update the map size and location before the map moves
+ this.events.register("movestart", this, this.updateSize);
+
+ // Because Mozilla does not support the "resize" event for elements
+ // other than "window", we need to put a hack here.
+ if (OpenLayers.String.contains(navigator.appName, "Microsoft")) {
+ // If IE, register the resize on the div
+ this.events.register("resize", this, this.updateSize);
+ } else {
+ // Else 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; i<nodes.length; ++i) {
+ if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,
+ this.theme)) {
+ addNode = false;
+ break;
+ }
+ }
+ // only add a new node if one with an equivalent url hasn't already
+ // been added
+ if(addNode) {
+ var cssNode = document.createElement('link');
+ cssNode.setAttribute('rel', 'stylesheet');
+ cssNode.setAttribute('type', 'text/css');
+ cssNode.setAttribute('href', this.theme);
+ document.getElementsByTagName('head')[0].appendChild(cssNode);
+ }
+ }
+
+ this.layers = [];
+
+ if (this.controls == null) {
+ if (OpenLayers.Control != null) { // running full or lite?
+ this.controls = [ new OpenLayers.Control.Navigation(),
+ new OpenLayers.Control.PanZoom(),
+ new OpenLayers.Control.ArgParser(),
+ new OpenLayers.Control.Attribution()
+ ];
+ } else {
+ this.controls = [];
+ }
+ }
+
+ for(var i=0; i < this.controls.length; i++) {
+ this.addControlToMap(this.controls[i]);
+ }
+
+ this.popups = [];
+
+ this.unloadDestroy = OpenLayers.Function.bind(this.destroy, this);
+
+
+ // always call map.destroy()
+ OpenLayers.Event.observe(window, 'unload', this.unloadDestroy);
+
+ },
+
+ /**
+ * Method: unloadDestroy
+ * Function that is called to destroy the map on page unload. stored here
+ * so that if map is manually destroyed, we can unregister this.
+ */
+ unloadDestroy: null,
+
+ /**
+ * Method: updateSizeDestroy
+ * When the map is destroyed, we need to stop listening to updateSize
+ * events: this method stores the function we need to unregister in
+ * non-IE browsers.
+ */
+ updateSizeDestroy: null,
+
+ /**
+ * APIMethod: destroy
+ * Destroy this map
+ */
+ destroy:function() {
+ // if unloadDestroy is null, we've already been destroyed
+ if (!this.unloadDestroy) {
+ return false;
+ }
+
+ // map has been destroyed. dont do it again!
+ OpenLayers.Event.stopObserving(window, 'unload', this.unloadDestroy);
+ this.unloadDestroy = null;
+
+ if (this.updateSizeDestroy) {
+ OpenLayers.Event.stopObserving(window, 'resize',
+ this.updateSizeDestroy);
+ } else {
+ this.events.unregister("resize", this, this.updateSize);
+ }
+
+ this.paddingForPopups = null;
+
+ if (this.controls != null) {
+ for (var i = this.controls.length - 1; 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;
+
+ },
+
+ /**
+ * APIMethod: setOptions
+ * Change the map options
+ *
+ * Parameters:
+ * options - {Object} Hashtable of options to tag to the map
+ */
+ setOptions: function(options) {
+ OpenLayers.Util.extend(this, options);
+ },
+
+ /**
+ * APIMethod: getTileSize
+ * Get the tile size for the map
+ *
+ * Returns:
+ * {<OpenLayers.Size>}
+ */
+ 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.
+ *
+ * Parameter:
+ * 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(<OpenLayers.Layer>)} 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.
+ *
+ * Parameter:
+ * 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(<OpenLayers.Layer>)} 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).
+ *
+ * Parameter:
+ * 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(<OpenLayers.Layer>)} 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.
+ *
+ * Parameter:
+ * 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(<OpenLayers.Control>)} 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).
+ *
+ * Parameter:
+ * 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(<OpenLayers.Control>)} 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
+ *
+ * Parameter:
+ * id - {String} A layer id
+ *
+ * Returns:
+ * {<OpenLayers.Layer>} 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; i < this.layers.length; i++) {
+ var layer = this.layers[i];
+ if (layer.id == id) {
+ foundLayer = layer;
+ break;
+ }
+ }
+ return foundLayer;
+ },
+
+ /**
+ * Method: setLayerZIndex
+ *
+ * Parameters:
+ * layer - {<OpenLayers.Layer>}
+ * 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; i < this.layers.length; i++) {
+ var layer = this.layers[i];
+ this.setLayerZIndex(layer, i);
+ }
+ },
+
+ /**
+ * APIMethod: addLayer
+ *
+ * Parameters:
+ * layer - {<OpenLayers.Layer>}
+ */
+ addLayer: function (layer) {
+ for(var i=0; i < this.layers.length; i++) {
+ if (this.layers[i] == layer) {
+ var msg = OpenLayers.i18n('layerAlreadyAdded',
+ {'layerName':layer.name});
+ OpenLayers.Console.warn(msg);
+ return false;
+ }
+ }
+
+ this.events.triggerEvent("preaddlayer", {layer: layer});
+
+ 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) {
+ 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});
+ },
+
+ /**
+ * APIMethod: addLayers
+ *
+ * Parameters:
+ * layers - {Array(<OpenLayers.Layer>)}
+ */
+ addLayers: function (layers) {
+ for (var i = 0; i < layers.length; i++) {
+ this.addLayer(layers[i]);
+ }
+ },
+
+ /**
+ * APIMethod: removeLayer
+ * Removes a layer from the map by removing its visual element (the
+ * layer.div property), then removing it from the map's internal list
+ * of layers, setting the layer's map property to null.
+ *
+ * a "removelayer" event is triggered.
+ *
+ * very worthy of mention is that simply removing a layer from a map
+ * will not cause the removal of any popups which may have been created
+ * by the layer. this is due to the fact that it was decided at some
+ * point that popups would not belong to layers. thus there is no way
+ * for us to know here to which layer the popup belongs.
+ *
+ * A simple solution to this is simply to call destroy() on the layer.
+ * the default OpenLayers.Layer class's destroy() function
+ * automatically takes care to remove itself from whatever map it has
+ * been attached to.
+ *
+ * The correct solution is for the layer itself to register an
+ * event-handler on "removelayer" and when it is called, if it
+ * recognizes itself as the layer being removed, then it cycles through
+ * its own personal list of popups, removing them from the map.
+ *
+ * Parameters:
+ * layer - {<OpenLayers.Layer>}
+ * setNewBaseLayer - {Boolean} Default is true
+ */
+ removeLayer: function(layer, setNewBaseLayer) {
+ 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; i < this.layers.length; i++) {
+ var iLayer = this.layers[i];
+ if (iLayer.isBaseLayer) {
+ this.setBaseLayer(iLayer);
+ break;
+ }
+ }
+ }
+ }
+
+ this.resetLayersZIndex();
+
+ this.events.triggerEvent("removelayer", {layer: layer});
+ },
+
+ /**
+ * APIMethod: getNumLayers
+ *
+ * Returns:
+ * {Int} The number of layers attached to the map.
+ */
+ getNumLayers: function () {
+ return this.layers.length;
+ },
+
+ /**
+ * APIMethod: getLayerIndex
+ *
+ * Parameters:
+ * layer - {<OpenLayers.Layer>}
+ *
+ * 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 - {<OpenLayers.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; i < this.layers.length; i++) {
+ this.setLayerZIndex(this.layers[i], i);
+ }
+ this.events.triggerEvent("changelayer", {
+ layer: layer, property: "order"
+ });
+ }
+ },
+
+ /**
+ * APIMethod: raiseLayer
+ * Change the index of the given layer by delta. If delta is positive,
+ * the layer is moved up the map's layer stack; if delta is negative,
+ * the layer is moved down. Again, note that this cannot (or at least
+ * should not) be effectively used to raise base layers above overlays.
+ *
+ * Paremeters:
+ * layer - {<OpenLayers.Layer>}
+ * idx - {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 - {<OpenLayers.Layer>}
+ */
+ setBaseLayer: function(newBaseLayer) {
+ var oldExtent = null;
+ if (this.baseLayer) {
+ oldExtent = this.baseLayer.getExtent();
+ }
+
+ if (newBaseLayer != this.baseLayer) {
+
+ // is newBaseLayer an already loaded layer?m
+ if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) {
+
+ // make the old base layer invisible
+ if (this.baseLayer != null) {
+ this.baseLayer.setVisibility(false);
+ }
+
+ // set new baselayer
+ this.baseLayer = newBaseLayer;
+
+ // Increment viewRequestID since the baseLayer is
+ // changing. This is used by tiles to check if they should
+ // draw themselves.
+ this.viewRequestID++;
+ this.baseLayer.visibility = true;
+
+ //redraw all layers
+ var center = this.getCenter();
+ if (center != null) {
+
+ //either get the center from the old Extent or just from
+ // the current center of the map.
+ var newCenter = (oldExtent)
+ ? oldExtent.getCenterLonLat()
+ : center;
+
+ //the new zoom will either come from the old Extent or
+ // from the current resolution of the map
+ var newZoom = (oldExtent)
+ ? this.getZoomForExtent(oldExtent, true)
+ : this.getZoomForResolution(this.resolution, true);
+
+ // zoom and force zoom change
+ this.setCenter(newCenter, 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
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>}
+ * px - {<OpenLayers.Pixel>}
+ */
+ addControl: function (control, px) {
+ this.controls.push(control);
+ this.addControlToMap(control, px);
+ },
+
+ /**
+ * Method: addControlToMap
+ *
+ * Parameters:
+ *
+ * control - {<OpenLayers.Control>}
+ * px - {<OpenLayers.Pixel>}
+ */
+ 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 );
+ }
+ }
+ },
+
+ /**
+ * APIMethod: getControl
+ *
+ * Parameters:
+ * id - {String} ID of the control to return.
+ *
+ * Returns:
+ * {<OpenLayers.Control>} 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; i < this.controls.length; i++) {
+ var control = this.controls[i];
+ if (control.id == id) {
+ returnControl = control;
+ break;
+ }
+ }
+ return returnControl;
+ },
+
+ /**
+ * APIMethod: removeControl
+ * Remove a control from the map. Removes the control both from the map
+ * object's internal array of controls, as well as from the map's
+ * viewPort (assuming the control was not added outsideViewport)
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>} 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 - {<OpenLayers.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 - {<OpenLayers.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:
+ * {<OpenLayers.Size>} An <OpenLayers.Size> 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
+ this.events.element.offsets = null;
+ var newSize = this.getCurrentSize();
+ 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; i < this.layers.length; i++) {
+ this.layers[i].onMapResize();
+ }
+
+ if (this.baseLayer != null) {
+ var center = new OpenLayers.Pixel(newSize.w /2, newSize.h / 2);
+ var centerLL = this.getLonLatFromViewPortPx(center);
+ var zoom = this.getZoom();
+ this.zoom = null;
+ this.setCenter(this.getCenter(), zoom);
+ }
+
+ }
+ },
+
+ /**
+ * Method: getCurrentSize
+ *
+ * Returns:
+ * {<OpenLayers.Size>} A new <OpenLayers.Size> object with the dimensions
+ * of the map div
+ */
+ getCurrentSize: function() {
+
+ var size = new OpenLayers.Size(this.div.clientWidth,
+ this.div.clientHeight);
+
+ // Workaround for the fact that hidden elements return 0 for size.
+ if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {
+ var dim = OpenLayers.Element.getDimensions(this.div);
+ size.w = dim.width;
+ size.h = dim.height;
+ }
+ 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 - {<OpenLayers.LonLat>} Default is this.getCenter()
+ * resolution - {float} Default is this.getResolution()
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} A bounds based on resolution, center, and
+ * current mapsize.
+ */
+ calculateBounds: function(center, resolution) {
+
+ var extent = null;
+
+ if (center == null) {
+ center = this.getCenter();
+ }
+ if (resolution == null) {
+ resolution = this.getResolution();
+ }
+
+ if ((center != null) && (resolution != null)) {
+
+ var size = this.getSize();
+ var w_deg = size.w * resolution;
+ var h_deg = size.h * resolution;
+
+ extent = new OpenLayers.Bounds(center.lon - w_deg / 2,
+ center.lat - h_deg / 2,
+ center.lon + w_deg / 2,
+ center.lat + h_deg / 2);
+
+ }
+
+ 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:
+ * {<OpenLayers.LonLat>}
+ */
+ getCenter: function () {
+ 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) {
+ // this should be pushed to applyDefaults and extend
+ if (!options) {
+ options = {};
+ }
+ OpenLayers.Util.applyDefaults(options, {
+ animate: true,
+ dragging: false
+ });
+ // getCenter
+ var centerPx = this.getViewPortPxFromLonLat(this.getCenter());
+
+ // adjust
+ var newCenterPx = centerPx.add(dx, dy);
+
+ // only call setCenter if not dragging or there has been a change
+ if (!options.dragging || !newCenterPx.equals(centerPx)) {
+ var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx);
+ if (options.animate) {
+ this.panTo(newCenterLonLat);
+ } else {
+ this.setCenter(newCenterLonLat, null, options.dragging);
+ }
+ }
+
+ },
+
+ /**
+ * 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 - {<OpenLayers.Lonlat>}
+ */
+ panTo: function(lonlat) {
+ if (this.panMethod && this.getExtent().containsLonLat(lonlat)) {
+ if (!this.panTween) {
+ this.panTween = new OpenLayers.Tween(this.panMethod);
+ }
+ var center = this.getCenter();
+ var from = {
+ lon: center.lon,
+ lat: center.lat
+ };
+ var to = {
+ lon: lonlat.lon,
+ lat: lonlat.lat
+ };
+ this.panTween.start(from, to, 50, {
+ callbacks: {
+ start: OpenLayers.Function.bind(function(lonlat) {
+ this.events.triggerEvent("movestart");
+ }, this),
+ eachStep: OpenLayers.Function.bind(function(lonlat) {
+ lonlat = new OpenLayers.LonLat(lonlat.lon, lonlat.lat);
+ this.moveTo(lonlat, this.zoom, {
+ 'dragging': true,
+ 'noEvent': true
+ });
+ }, this),
+ done: OpenLayers.Function.bind(function(lonlat) {
+ lonlat = new OpenLayers.LonLat(lonlat.lon, lonlat.lat);
+ this.moveTo(lonlat, this.zoom, {
+ 'noEvent': true
+ });
+ this.events.triggerEvent("moveend");
+ }, this)
+ }
+ });
+ } else {
+ this.setCenter(lonlat);
+ }
+ },
+
+ /**
+ * APIMethod: setCenter
+ *
+ * Parameters:
+ * lonlat - {<OpenLayers.LonLat>}
+ * zoom - {Integer}
+ * 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.moveTo(lonlat, zoom, {
+ 'dragging': dragging,
+ 'forceZoomChange': forceZoomChange,
+ 'caller': 'setCenter'
+ });
+ },
+
+ /**
+ * Method: moveTo
+ *
+ * Parameters:
+ * lonlat - {<OpenLayers.LonLat>}
+ * zoom - {Integer}
+ * options - {Object}
+ */
+ moveTo: function(lonlat, zoom, options) {
+ if (!options) {
+ options = {};
+ }
+ // dragging is false by default
+ var dragging = options.dragging;
+ // forceZoomChange is false by default
+ var forceZoomChange = options.forceZoomChange;
+ // noEvent is false by default
+ var noEvent = options.noEvent;
+
+ if (this.panTween && options.caller == "setCenter") {
+ this.panTween.stop();
+ }
+
+ if (!this.center && !this.isValidLonLat(lonlat)) {
+ lonlat = this.maxExtent.getCenterLonLat();
+ }
+
+ if(this.restrictedExtent != null) {
+ // In 3.0, decide if we want to change interpretation of maxExtent.
+ if(lonlat == null) {
+ lonlat = this.getCenter();
+ }
+ 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) {
+
+ if (!this.dragging && !noEvent) {
+ 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();
+ }
+
+ // (re)set the layerContainerDiv's location
+ if ((zoomChanged) || (this.layerContainerOrigin == null)) {
+ this.layerContainerOrigin = this.center.clone();
+ this.layerContainerDiv.style.left = "0px";
+ this.layerContainerDiv.style.top = "0px";
+ }
+
+ if (zoomChanged) {
+ this.zoom = zoom;
+ this.resolution = this.getResolutionForZoom(zoom);
+ // zoom level has changed, increment viewRequestID.
+ this.viewRequestID++;
+ }
+
+ var bounds = this.getExtent();
+
+ //send the move call to the baselayer and all the overlays
+ this.baseLayer.moveTo(bounds, zoomChanged, dragging);
+
+ bounds = this.baseLayer.getExtent();
+
+ for (var i = 0; i < this.layers.length; i++) {
+ var layer = this.layers[i];
+ if (!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, dragging);
+ }
+ }
+ }
+
+ if (zoomChanged) {
+ //redraw popups
+ for (var i = 0; i < this.popups.length; i++) {
+ this.popups[i].updatePosition();
+ }
+ }
+
+ this.events.triggerEvent("move");
+
+ if (zoomChanged) { this.events.triggerEvent("zoomend"); }
+ }
+
+ // even if nothing was done, we want to notify of this
+ if (!dragging && !noEvent) {
+ this.events.triggerEvent("moveend");
+ }
+
+ // Store the map dragging state for later use
+ this.dragging = !!dragging;
+
+ },
+
+ /**
+ * Method: centerLayerContainer
+ * This function takes care to recenter the layerContainerDiv.
+ *
+ * Parameters:
+ * lonlat - {<OpenLayers.LonLat>}
+ */
+ centerLayerContainer: function (lonlat) {
+
+ var originPx = this.getViewPortPxFromLonLat(this.layerContainerOrigin);
+ var newPx = this.getViewPortPxFromLonLat(lonlat);
+
+ if ((originPx != null) && (newPx != null)) {
+ this.layerContainerDiv.style.left = Math.round(originPx.x - newPx.x) + "px";
+ this.layerContainerDiv.style.top = Math.round(originPx.y - newPx.y) + "px";
+ }
+ },
+
+ /**
+ * 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 - {<OpenLayers.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();
+ valid = maxExtent.containsLonLat(lonlat);
+ }
+ 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:
+ * {<OpenLayers.Projection>} 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
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>}
+ */
+ getMaxExtent: function () {
+ var maxExtent = null;
+ 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:
+ * {<OpenLayers.Bounds>} 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();
+ }
+ return resolution;
+ },
+
+ /**
+ * 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 - {<OpenLayers.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
+ *
+ * Parameter:
+ * 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
+ *
+ * Parameter:
+ * 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
+ *
+ * Parameters:
+ * zoom - {int}
+ */
+ zoomIn: function() {
+ this.zoomTo(this.getZoom() + 1);
+ },
+
+ /**
+ * APIMethod: zoomOut
+ *
+ * Parameters:
+ * zoom - {int}
+ */
+ zoomOut: function() {
+ this.zoomTo(this.getZoom() - 1);
+ },
+
+ /**
+ * APIMethod: zoomToExtent
+ * Zoom to the passed in bounds, recenter
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ */
+ zoomToExtent: function(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. Because our new bounds is at least partially
+ // outside the bounds of maxExtent, the new calculated center
+ // might also be. We don't want to pass a bad center value to
+ // setCenter, so we have it wrap itself across the date line.
+ //
+ center = bounds.getCenterLonLat().wrapDateLine(maxExtent);
+ }
+ this.setCenter(center, this.getZoomForExtent(bounds));
+ },
+
+ /**
+ * APIMethod: zoomToMaxExtent
+ * Zoom to the full extent and recenter.
+ */
+ zoomToMaxExtent: function() {
+ this.zoomToExtent(this.getMaxExtent());
+ },
+
+ /**
+ * APIMethod: zoomToScale
+ * Zoom to a specified scale
+ *
+ * Parameters:
+ * scale - {float}
+ */
+ zoomToScale: function(scale) {
+ var res = OpenLayers.Util.getResolutionFromScale(scale,
+ this.baseLayer.units);
+ var size = this.getSize();
+ var w_deg = size.w * res;
+ var h_deg = size.h * res;
+ var center = this.getCenter();
+
+ var extent = new OpenLayers.Bounds(center.lon - w_deg / 2,
+ center.lat - h_deg / 2,
+ center.lon + w_deg / 2,
+ center.lat + h_deg / 2);
+ this.zoomToExtent(extent);
+ },
+
+ /********************************************************/
+ /* */
+ /* Translation Functions */
+ /* */
+ /* The following functions translate between */
+ /* LonLat, LayerPx, and ViewPortPx */
+ /* */
+ /********************************************************/
+
+ //
+ // TRANSLATION: LonLat <-> ViewPortPx
+ //
+
+ /**
+ * Method: getLonLatFromViewPortPx
+ *
+ * Parameters:
+ * viewPortPx - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view
+ * port <OpenLayers.Pixel>, 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 - {<OpenLayers.LonLat>}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
+ * <OpenLayers.LonLat>, 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 - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} 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 - {<OpenLayers.LonLat>} A map location.
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} An OpenLayers.Pixel corresponding to the
+ * <OpenLayers.LonLat> 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;
+ },
+
+
+
+ //
+ // TRANSLATION: ViewPortPx <-> LayerPx
+ //
+
+ /**
+ * APIMethod: getViewPortPxFromLayerPx
+ *
+ * Parameters:
+ * layerPx - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} Layer Pixel translated into ViewPort Pixel
+ * coordinates
+ */
+ getViewPortPxFromLayerPx:function(layerPx) {
+ var viewPortPx = null;
+ if (layerPx != null) {
+ var dX = parseInt(this.layerContainerDiv.style.left);
+ var dY = parseInt(this.layerContainerDiv.style.top);
+ viewPortPx = layerPx.add(dX, dY);
+ }
+ return viewPortPx;
+ },
+
+ /**
+ * APIMethod: getLayerPxFromViewPortPx
+ *
+ * Parameters:
+ * viewPortPx - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} ViewPort Pixel translated into Layer Pixel
+ * coordinates
+ */
+ getLayerPxFromViewPortPx:function(viewPortPx) {
+ var layerPx = null;
+ if (viewPortPx != null) {
+ var dX = -parseInt(this.layerContainerDiv.style.left);
+ var dY = -parseInt(this.layerContainerDiv.style.top);
+ layerPx = viewPortPx.add(dX, dY);
+ if (isNaN(layerPx.x) || isNaN(layerPx.y)) {
+ layerPx = null;
+ }
+ }
+ return layerPx;
+ },
+
+ //
+ // TRANSLATION: LonLat <-> LayerPx
+ //
+
+ /**
+ * Method: getLonLatFromLayerPx
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>}
+ */
+ getLonLatFromLayerPx: function (px) {
+ //adjust for displacement of layerContainerDiv
+ px = this.getViewPortPxFromLayerPx(px);
+ return this.getLonLatFromViewPortPx(px);
+ },
+
+ /**
+ * APIMethod: getLayerPxFromLonLat
+ *
+ * Parameters:
+ * lonlat - {<OpenLayers.LonLat>} lonlat
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
+ * <OpenLayers.LonLat>, 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/Marker.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Events.js
+ * @requires OpenLayers/Icon.js
+ */
+
+/**
+ * Class: OpenLayers.Marker
+ * Instances of OpenLayers.Marker are a combination of a
+ * <OpenLayers.LonLat> and an <OpenLayers.Icon>.
+ *
+ * Markers are generally added to a special layer called
+ * <OpenLayers.Layer.Markers>.
+ *
+ * Example:
+ * (code)
+ * var markers = new OpenLayers.Layer.Markers( "Markers" );
+ * map.addLayer(markers);
+ *
+ * var size = new OpenLayers.Size(10,17);
+ * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
+ * var icon = new OpenLayers.Icon('http://boston.openguides.org/markers/AQUA.png',size,offset);
+ * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon));
+ * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone()));
+ *
+ * (end)
+ *
+ * Note that if you pass an icon into the Marker constructor, it will take
+ * that icon and use it. This means that you should not share icons between
+ * markers -- you use them once, but you should clone() for any additional
+ * markers using that same icon.
+ */
+OpenLayers.Marker = OpenLayers.Class({
+
+ /**
+ * Property: icon
+ * {<OpenLayers.Icon>} The icon used by this marker.
+ */
+ icon: null,
+
+ /**
+ * Property: lonlat
+ * {<OpenLayers.LonLat>} location of object
+ */
+ lonlat: null,
+
+ /**
+ * Property: events
+ * {<OpenLayers.Events>} the event handler.
+ */
+ events: null,
+
+ /**
+ * Property: map
+ * {<OpenLayers.Map>} the map this marker is attached to
+ */
+ map: null,
+
+ /**
+ * Constructor: OpenLayers.Marker
+ * Paraemeters:
+ * icon - {<OpenLayers.Icon>} the icon for this marker
+ * lonlat - {<OpenLayers.LonLat>} the position of this marker
+ */
+ initialize: function(lonlat, icon) {
+ this.lonlat = lonlat;
+
+ var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon();
+ if (this.icon == null) {
+ this.icon = newIcon;
+ } else {
+ this.icon.url = newIcon.url;
+ this.icon.size = newIcon.size;
+ this.icon.offset = newIcon.offset;
+ this.icon.calculateOffset = newIcon.calculateOffset;
+ }
+ this.events = new OpenLayers.Events(this, this.icon.imageDiv, null);
+ },
+
+ /**
+ * APIMethod: destroy
+ * Destroy the marker. You must first remove the marker from any
+ * layer which it has been added to, or you will get buggy behavior.
+ * (This can not be done within the marker since the marker does not
+ * know which layer it is attached to.)
+ */
+ destroy: function() {
+ this.map = null;
+
+ this.events.destroy();
+ this.events = null;
+
+ if (this.icon != null) {
+ this.icon.destroy();
+ this.icon = null;
+ }
+ },
+
+ /**
+ * Method: draw
+ * Calls draw on the icon, and returns that output.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {DOMElement} A new DOM Image with this marker's icon set at the
+ * location passed-in
+ */
+ draw: function(px) {
+ return this.icon.draw(px);
+ },
+
+ /**
+ * Method: moveTo
+ * Move the marker to the new location.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>} the pixel position to move to
+ */
+ moveTo: function (px) {
+ if ((px != null) && (this.icon != null)) {
+ this.icon.moveTo(px);
+ }
+ this.lonlat = this.map.getLonLatFromLayerPx(px);
+ },
+
+ /**
+ * Method: onScreen
+ *
+ * Returns:
+ * {Boolean} Whether or not the marker is currently visible on screen.
+ */
+ onScreen:function() {
+
+ var onScreen = false;
+ if (this.map) {
+ var screenBounds = this.map.getExtent();
+ onScreen = screenBounds.containsLonLat(this.lonlat);
+ }
+ return onScreen;
+ },
+
+ /**
+ * Method: inflate
+ * Englarges the markers icon by the specified ratio.
+ *
+ * Parameters:
+ * inflate - {float} the ratio to enlarge the marker by (passing 2
+ * will double the size).
+ */
+ inflate: function(inflate) {
+ if (this.icon) {
+ var newSize = new OpenLayers.Size(this.icon.size.w * inflate,
+ this.icon.size.h * inflate);
+ this.icon.setSize(newSize);
+ }
+ },
+
+ /**
+ * Method: setOpacity
+ * Change the opacity of the marker by changin the opacity of
+ * its icon
+ *
+ * Parameters:
+ * opacity - {float} Specified as fraction (0.4, etc)
+ */
+ setOpacity: function(opacity) {
+ this.icon.setOpacity(opacity);
+ },
+
+ /**
+ * Method: setUrl
+ * Change URL of the Icon Image.
+ *
+ * url - {String}
+ */
+ setUrl: function(url) {
+ this.icon.setUrl(url);
+ },
+
+ /**
+ * Method: display
+ * Hide or show the icon
+ *
+ * display - {Boolean}
+ */
+ display: function(display) {
+ this.icon.display(display);
+ },
+
+ CLASS_NAME: "OpenLayers.Marker"
+});
+
+
+/**
+ * Function: defaultIcon
+ * Creates a default <OpenLayers.Icon>.
+ *
+ * Returns:
+ * {<OpenLayers.Icon>} A default OpenLayers.Icon to use for a marker
+ */
+OpenLayers.Marker.defaultIcon = function() {
+ var url = OpenLayers.Util.getImagesLocation() + "marker.png";
+ var size = new OpenLayers.Size(21, 25);
+ var calculateOffset = function(size) {
+ return new OpenLayers.Pixel(-(size.w/2), -size.h);
+ };
+
+ return new OpenLayers.Icon(url, size, null, calculateOffset);
+};
+
+
+/* ======================================================================
+ OpenLayers/Tile/Image.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Tile.js
+ */
+
+/**
+ * Class: OpenLayers.Tile.Image
+ * Instances of OpenLayers.Tile.Image are used to manage the image tiles
+ * used by various layers. Create a new image tile with the
+ * <OpenLayers.Tile.Image> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Tile>
+ */
+OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
+
+ /**
+ * Property: url
+ * {String} The URL of the image being requested. No default. Filled in by
+ * layer.getURL() function.
+ */
+ url: null,
+
+ /**
+ * Property: imgDiv
+ * {DOMElement} The div element which wraps the image.
+ */
+ imgDiv: null,
+
+ /**
+ * Property: frame
+ * {DOMElement} The image element is appended to the frame. Any gutter on
+ * the image will be hidden behind the frame.
+ */
+ frame: null,
+
+
+ /**
+ * Property: layerAlphaHack
+ * {Boolean} True if the png alpha hack needs to be applied on the layer's div.
+ */
+ layerAlphaHack: null,
+
+ /** TBD 3.0 - reorder the parameters to the init function to remove
+ * URL. the getUrl() function on the layer gets called on
+ * each draw(), so no need to specify it here.
+ *
+ * Constructor: OpenLayers.Tile.Image
+ * Constructor for a new <OpenLayers.Tile.Image> instance.
+ *
+ * Parameters:
+ * layer - {<OpenLayers.Layer>} layer that the tile will go in.
+ * position - {<OpenLayers.Pixel>}
+ * bounds - {<OpenLayers.Bounds>}
+ * url - {<String>} Deprecated. Remove me in 3.0.
+ * size - {<OpenLayers.Size>}
+ */
+ initialize: function(layer, position, bounds, url, size) {
+ OpenLayers.Tile.prototype.initialize.apply(this, arguments);
+
+ this.url = url; //deprecated remove me
+
+ this.frame = document.createElement('div');
+ this.frame.style.overflow = 'hidden';
+ this.frame.style.position = 'absolute';
+
+ this.layerAlphaHack = this.layer.alpha && OpenLayers.Util.alphaHack();
+ },
+
+ /**
+ * APIMethod: destroy
+ * nullify references to prevent circular references and memory leaks
+ */
+ destroy: function() {
+ if (this.imgDiv != null) {
+ if (this.layerAlphaHack) {
+ OpenLayers.Event.stopObservingElement(this.imgDiv.childNodes[0].id);
+ } else {
+ OpenLayers.Event.stopObservingElement(this.imgDiv.id);
+ }
+ if (this.imgDiv.parentNode == this.frame) {
+ this.frame.removeChild(this.imgDiv);
+ this.imgDiv.map = null;
+ }
+ }
+ this.imgDiv = null;
+ if ((this.frame != null) && (this.frame.parentNode == this.layer.div)) {
+ this.layer.div.removeChild(this.frame);
+ }
+ this.frame = null;
+ OpenLayers.Tile.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: clone
+ *
+ * Parameters:
+ * obj - {<OpenLayers.Tile.Image>} The tile to be cloned
+ *
+ * Returns:
+ * {<OpenLayers.Tile.Image>} An exact clone of this <OpenLayers.Tile.Image>
+ */
+ clone: function (obj) {
+ if (obj == null) {
+ obj = new OpenLayers.Tile.Image(this.layer,
+ this.position,
+ this.bounds,
+ this.url,
+ this.size);
+ }
+
+ //pick up properties from superclass
+ obj = OpenLayers.Tile.prototype.clone.apply(this, [obj]);
+
+ //dont want to directly copy the image div
+ obj.imgDiv = null;
+
+
+ return obj;
+ },
+
+ /**
+ * Method: draw
+ * Check that a tile should be drawn, and draw it.
+ *
+ * Returns:
+ * {Boolean} Always returns true.
+ */
+ draw: function() {
+ if (this.layer != this.layer.map.baseLayer && this.layer.reproject) {
+ this.bounds = this.getBoundsFromBaseLayer(this.position);
+ }
+ if (!OpenLayers.Tile.prototype.draw.apply(this, arguments)) {
+ return false;
+ }
+
+ if (this.isLoading) {
+ //if we're already loading, send 'reload' instead of 'loadstart'.
+ this.events.triggerEvent("reload");
+ } else {
+ this.isLoading = true;
+ this.events.triggerEvent("loadstart");
+ }
+
+ return this.renderTile();
+ },
+
+ /**
+ * Method: renderTile
+ * Internal function to actually initialize the image tile,
+ * position it correctly, and set its url.
+ */
+ renderTile: function() {
+ if (this.imgDiv == null) {
+ this.initImgDiv();
+ }
+
+ this.imgDiv.viewRequestID = this.layer.map.viewRequestID;
+
+ this.url = this.layer.getURL(this.bounds);
+ // position the frame
+ OpenLayers.Util.modifyDOMElement(this.frame,
+ null, this.position, this.size);
+
+ var imageSize = this.layer.getImageSize();
+ if (this.layerAlphaHack) {
+ OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,
+ null, null, imageSize, this.url);
+ } else {
+ OpenLayers.Util.modifyDOMElement(this.imgDiv,
+ null, null, imageSize) ;
+ this.imgDiv.src = this.url;
+ }
+ return true;
+ },
+
+ /**
+ * Method: clear
+ * Clear the tile of any bounds/position-related data so that it can
+ * be reused in a new location.
+ */
+ clear: function() {
+ if(this.imgDiv) {
+ this.hide();
+ if (OpenLayers.Tile.Image.useBlankTile) {
+ this.imgDiv.src = OpenLayers.Util.getImagesLocation() + "blank.gif";
+ }
+ }
+ },
+
+ /**
+ * Method: initImgDiv
+ * Creates the imgDiv property on the tile.
+ */
+ initImgDiv: function() {
+
+ var offset = this.layer.imageOffset;
+ var size = this.layer.getImageSize();
+
+ if (this.layerAlphaHack) {
+ this.imgDiv = OpenLayers.Util.createAlphaImageDiv(null,
+ offset,
+ size,
+ null,
+ "relative",
+ null,
+ null,
+ null,
+ true);
+ } else {
+ this.imgDiv = OpenLayers.Util.createImage(null,
+ offset,
+ size,
+ null,
+ "relative",
+ null,
+ null,
+ true);
+ }
+
+ this.imgDiv.className = 'olTileImage';
+
+ /* checkImgURL used to be used to called as a work around, but it
+ ended up hiding problems instead of solving them and broke things
+ like relative URLs. See discussion on the dev list:
+ http://openlayers.org/pipermail/dev/2007-January/000205.html
+
+ OpenLayers.Event.observe( this.imgDiv, "load",
+ OpenLayers.Function.bind(this.checkImgURL, this) );
+ */
+ this.frame.style.zIndex = this.isBackBuffer ? 0 : 1;
+ this.frame.appendChild(this.imgDiv);
+ this.layer.div.appendChild(this.frame);
+
+ if(this.layer.opacity != null) {
+
+ OpenLayers.Util.modifyDOMElement(this.imgDiv, null, null, null,
+ null, null, null,
+ this.layer.opacity);
+ }
+
+ // we need this reference to check back the viewRequestID
+ this.imgDiv.map = this.layer.map;
+
+ //bind a listener to the onload of the image div so that we
+ // can register when a tile has finished loading.
+ var onload = function() {
+
+ //normally isLoading should always be true here but there are some
+ // right funky conditions where loading and then reloading a tile
+ // with the same url *really*fast*. this check prevents sending
+ // a 'loadend' if the msg has already been sent
+ //
+ if (this.isLoading) {
+ this.isLoading = false;
+ this.events.triggerEvent("loadend");
+ }
+ };
+
+ if (this.layerAlphaHack) {
+ OpenLayers.Event.observe(this.imgDiv.childNodes[0], 'load',
+ OpenLayers.Function.bind(onload, this));
+ } else {
+ OpenLayers.Event.observe(this.imgDiv, 'load',
+ OpenLayers.Function.bind(onload, this));
+ }
+
+
+ // Bind a listener to the onerror of the image div so that we
+ // can registere when a tile has finished loading with errors.
+ var onerror = function() {
+
+ // If we have gone through all image reload attempts, it is time
+ // to realize that we are done with this image. Since
+ // OpenLayers.Util.onImageLoadError already has taken care about
+ // the error, we can continue as if the image was loaded
+ // successfully.
+ if (this.imgDiv._attempts > OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
+ onload.call(this);
+ }
+ };
+ OpenLayers.Event.observe(this.imgDiv, "error",
+ OpenLayers.Function.bind(onerror, this));
+ },
+
+ /**
+ * Method: checkImgURL
+ * Make sure that the image that just loaded is the one this tile is meant
+ * to display, since panning/zooming might have changed the tile's URL in
+ * the meantime. If the tile URL did change before the image loaded, set
+ * the imgDiv display to 'none', as either (a) it will be reset to visible
+ * when the new URL loads in the image, or (b) we don't want to display
+ * this tile after all because its new bounds are outside our maxExtent.
+ *
+ * This function should no longer be neccesary with the improvements to
+ * Grid.js in OpenLayers 2.3. The lack of a good isEquivilantURL function
+ * caused problems in 2.2, but it's possible that with the improved
+ * isEquivilant URL function, this might be neccesary at some point.
+ *
+ * See discussion in the thread at
+ * http://openlayers.org/pipermail/dev/2007-January/000205.html
+ */
+ checkImgURL: function () {
+ // Sometimes our image will load after it has already been removed
+ // from the map, in which case this check is not needed.
+ if (this.layer) {
+ var loaded = this.layerAlphaHack ? this.imgDiv.firstChild.src : this.imgDiv.src;
+ if (!OpenLayers.Util.isEquivalentUrl(loaded, this.url)) {
+ this.hide();
+ }
+ }
+ },
+
+ /**
+ * Method: startTransition
+ * This method is invoked on tiles that are backBuffers for tiles in the
+ * grid. The grid tile is about to be cleared and a new tile source
+ * loaded. This is where the transition effect needs to be started
+ * to provide visual continuity.
+ */
+ startTransition: function() {
+ // backBufferTile has to be valid and ready to use
+ if (!this.backBufferTile || !this.backBufferTile.imgDiv) {
+ return;
+ }
+
+ // calculate the ratio of change between the current resolution of the
+ // backBufferTile and the layer. If several animations happen in a
+ // row, then the backBufferTile will scale itself appropriately for
+ // each request.
+ var ratio = 1;
+ if (this.backBufferTile.resolution) {
+ ratio = this.backBufferTile.resolution / this.layer.getResolution();
+ }
+
+ // if the ratio is not the same as it was last time (i.e. we are
+ // zooming), then we need to adjust the backBuffer tile
+ if (ratio != this.lastRatio) {
+ if (this.layer.transitionEffect == 'resize') {
+ // In this case, we can just immediately resize the
+ // backBufferTile.
+ var upperLeft = new OpenLayers.LonLat(
+ this.backBufferTile.bounds.left,
+ this.backBufferTile.bounds.top
+ );
+ var size = new OpenLayers.Size(
+ this.backBufferTile.size.w * ratio,
+ this.backBufferTile.size.h * ratio
+ );
+
+ var px = this.layer.map.getLayerPxFromLonLat(upperLeft);
+ OpenLayers.Util.modifyDOMElement(this.backBufferTile.frame,
+ null, px, size);
+ var imageSize = this.backBufferTile.imageSize;
+ imageSize = new OpenLayers.Size(imageSize.w * ratio,
+ imageSize.h * ratio);
+ var imageOffset = this.backBufferTile.imageOffset;
+ if(imageOffset) {
+ imageOffset = new OpenLayers.Pixel(
+ imageOffset.x * ratio, imageOffset.y * ratio
+ );
+ }
+
+ OpenLayers.Util.modifyDOMElement(
+ this.backBufferTile.imgDiv, null, imageOffset, imageSize
+ ) ;
+
+ this.backBufferTile.show();
+ }
+ } else {
+ // default effect is just to leave the existing tile
+ // until the new one loads if this is a singleTile and
+ // there was no change in resolution. Otherwise we
+ // don't bother to show the backBufferTile at all
+ if (this.layer.singleTile) {
+ this.backBufferTile.show();
+ } else {
+ this.backBufferTile.hide();
+ }
+ }
+ this.lastRatio = ratio;
+
+ },
+
+ /**
+ * Method: show
+ * Show the tile by showing its frame.
+ */
+ show: function() {
+ this.frame.style.display = '';
+ // Force a reflow on gecko based browsers to actually show the element
+ // before continuing execution.
+ if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS,
+ this.layer.transitionEffect) != -1) {
+ if (navigator.userAgent.toLowerCase().indexOf("gecko") != -1) {
+ this.frame.scrollLeft = this.frame.scrollLeft;
+ }
+ }
+ },
+
+ /**
+ * Method: hide
+ * Hide the tile by hiding its frame.
+ */
+ hide: function() {
+ this.frame.style.display = 'none';
+ },
+
+ CLASS_NAME: "OpenLayers.Tile.Image"
+ }
+);
+
+OpenLayers.Tile.Image.useBlankTile = (
+ OpenLayers.Util.getBrowserName() == "safari" ||
+ OpenLayers.Util.getBrowserName() == "opera");
+/* ======================================================================
+ OpenLayers/Control/OverviewMap.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/BaseTypes.js
+ * @requires OpenLayers/Events.js
+ */
+
+/**
+ * Class: OpenLayers.Control.OverviewMap
+ * Create an overview map to display the extent of your main map and provide
+ * additional navigation control. Create a new overview map with the
+ * <OpenLayers.Control.OverviewMap> constructor.
+ *
+ * Inerits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Property: element
+ * {DOMElement} The DOM element that contains the overview map
+ */
+ element: null,
+
+ /**
+ * APIProperty: ovmap
+ * {<OpenLayers.Map>} A reference to the overview map itself.
+ */
+ ovmap: null,
+
+ /**
+ * APIProperty: size
+ * {<OpenLayers.Size>} The overvew map size in pixels. Note that this is
+ * the size of the map itself - the element that contains the map (default
+ * class name olControlOverviewMapElement) may have padding or other style
+ * attributes added via CSS.
+ */
+ size: new OpenLayers.Size(180, 90),
+
+ /**
+ * APIProperty: layers
+ * {Array(<OpenLayers.Layer>)} Ordered list of layers in the overview map.
+ * If none are sent at construction, the base layer for the main map is used.
+ */
+ layers: null,
+
+ /**
+ * APIProperty: minRectSize
+ * {Integer} The minimum width or height (in pixels) of the extent
+ * rectangle on the overview map. When the extent rectangle reaches
+ * this size, it will be replaced depending on the value of the
+ * <minRectDisplayClass> property. Default is 15 pixels.
+ */
+ minRectSize: 15,
+
+ /**
+ * APIProperty: minRectDisplayClass
+ * {String} Replacement style class name for the extent rectangle when
+ * <minRectSize> is reached. This string will be suffixed on to the
+ * displayClass. Default is "RectReplacement".
+ *
+ * Example CSS declaration:
+ * (code)
+ * .olControlOverviewMapRectReplacement {
+ * overflow: hidden;
+ * cursor: move;
+ * background-image: url("img/overview_replacement.gif");
+ * background-repeat: no-repeat;
+ * background-position: center;
+ * }
+ * (end)
+ */
+ minRectDisplayClass: "RectReplacement",
+
+ /**
+ * APIProperty: minRatio
+ * {Float} The ratio of the overview map resolution to the main map
+ * resolution at which to zoom farther out on the overview map.
+ */
+ minRatio: 8,
+
+ /**
+ * APIProperty: maxRatio
+ * {Float} The ratio of the overview map resolution to the main map
+ * resolution at which to zoom farther in on the overview map.
+ */
+ maxRatio: 32,
+
+ /**
+ * APIProperty: mapOptions
+ * {Object} An object containing any non-default properties to be sent to
+ * the overview map's map constructor. These should include any non-default
+ * options that the main map was constructed with.
+ */
+ mapOptions: null,
+
+ /**
+ * Property: handlers
+ * {Object}
+ */
+ handlers: null,
+
+ /**
+ * Constructor: OpenLayers.Control.OverviewMap
+ * Create a new overview map
+ *
+ * Parameters:
+ * object - {Object} Properties of this object will be set on the overview
+ * map object. Note, to set options on the map object contained in this
+ * control, set <mapOptions> as one of the options properties.
+ */
+ initialize: function(options) {
+ this.layers = [];
+ this.handlers = {};
+ OpenLayers.Control.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * APIMethod: destroy
+ * Deconstruct the control
+ */
+ destroy: function() {
+ if (!this.mapDiv) { // we've already been destroyed
+ return;
+ }
+ this.handlers.click.destroy();
+
+ this.mapDiv.removeChild(this.extentRectangle);
+ this.extentRectangle = null;
+ this.rectEvents.destroy();
+ this.rectEvents = null;
+
+ this.ovmap.destroy();
+ this.ovmap = null;
+
+ this.element.removeChild(this.mapDiv);
+ this.mapDiv = null;
+
+ this.div.removeChild(this.element);
+ this.element = null;
+
+ if (this.maximizeDiv) {
+ OpenLayers.Event.stopObservingElement(this.maximizeDiv);
+ this.div.removeChild(this.maximizeDiv);
+ this.maximizeDiv = null;
+ }
+
+ if (this.minimizeDiv) {
+ OpenLayers.Event.stopObservingElement(this.minimizeDiv);
+ this.div.removeChild(this.minimizeDiv);
+ this.minimizeDiv = null;
+ }
+
+ this.map.events.un({
+ "moveend": this.update,
+ "changebaselayer": this.baseLayerDraw,
+ scope: this
+ });
+
+ OpenLayers.Control.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: draw
+ * Render the control in the browser.
+ */
+ draw: function() {
+ OpenLayers.Control.prototype.draw.apply(this, arguments);
+ if(!(this.layers.length > 0)) {
+ if (this.map.baseLayer) {
+ var layer = this.map.baseLayer.clone();
+ this.layers = [layer];
+ } else {
+ this.map.events.register("changebaselayer", this, this.baseLayerDraw);
+ return this.div;
+ }
+ }
+
+ // create overview map DOM elements
+ this.element = document.createElement('div');
+ this.element.className = this.displayClass + 'Element';
+ this.element.style.display = 'none';
+
+ this.mapDiv = document.createElement('div');
+ this.mapDiv.style.width = this.size.w + 'px';
+ this.mapDiv.style.height = this.size.h + 'px';
+ this.mapDiv.style.position = 'relative';
+ this.mapDiv.style.overflow = 'hidden';
+ this.mapDiv.id = OpenLayers.Util.createUniqueID('overviewMap');
+
+ this.extentRectangle = document.createElement('div');
+ this.extentRectangle.style.position = 'absolute';
+ this.extentRectangle.style.zIndex = 1000; //HACK
+ this.extentRectangle.className = this.displayClass+'ExtentRectangle';
+ this.mapDiv.appendChild(this.extentRectangle);
+
+ this.element.appendChild(this.mapDiv);
+
+ this.div.appendChild(this.element);
+
+ // Optionally add min/max buttons if the control will go in the
+ // map viewport.
+ if(!this.outsideViewport) {
+ this.div.className += " " + this.displayClass + 'Container';
+ var imgLocation = OpenLayers.Util.getImagesLocation();
+ // maximize button div
+ var img = imgLocation + 'layer-switcher-maximize.png';
+ this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
+ this.displayClass + 'MaximizeButton',
+ null,
+ new OpenLayers.Size(18,18),
+ img,
+ 'absolute');
+ this.maximizeDiv.style.display = 'none';
+ this.maximizeDiv.className = this.displayClass + 'MaximizeButton';
+ OpenLayers.Event.observe(this.maximizeDiv, 'click',
+ OpenLayers.Function.bindAsEventListener(this.maximizeControl,
+ this)
+ );
+ this.div.appendChild(this.maximizeDiv);
+
+ // minimize button div
+ var img = imgLocation + 'layer-switcher-minimize.png';
+ this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
+ 'OpenLayers_Control_minimizeDiv',
+ null,
+ new OpenLayers.Size(18,18),
+ img,
+ 'absolute');
+ this.minimizeDiv.style.display = 'none';
+ this.minimizeDiv.className = this.displayClass + 'MinimizeButton';
+ OpenLayers.Event.observe(this.minimizeDiv, 'click',
+ OpenLayers.Function.bindAsEventListener(this.minimizeControl,
+ this)
+ );
+ this.div.appendChild(this.minimizeDiv);
+
+ var eventsToStop = ['dblclick','mousedown'];
+
+ for (var i = 0; i < eventsToStop.length; i++) {
+
+ OpenLayers.Event.observe(this.maximizeDiv,
+ eventsToStop[i],
+ OpenLayers.Event.stop);
+
+ OpenLayers.Event.observe(this.minimizeDiv,
+ eventsToStop[i],
+ OpenLayers.Event.stop);
+ }
+
+ this.minimizeControl();
+ } else {
+ // show the overview map
+ this.element.style.display = '';
+ }
+ if(this.map.getExtent()) {
+ this.update();
+ }
+
+ this.map.events.register('moveend', this, this.update);
+
+ return this.div;
+ },
+
+ /**
+ * Method: baseLayerDraw
+ * Draw the base layer - called if unable to complete in the initial draw
+ */
+ baseLayerDraw: function() {
+ this.draw();
+ this.map.events.unregister("changebaselayer", this, this.baseLayerDraw);
+ },
+
+ /**
+ * Method: rectDrag
+ * Handle extent rectangle drag
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>} The pixel location of the drag.
+ */
+ rectDrag: function(px) {
+ var deltaX = this.handlers.drag.last.x - px.x;
+ var deltaY = this.handlers.drag.last.y - px.y;
+ if(deltaX != 0 || deltaY != 0) {
+ var rectTop = this.rectPxBounds.top;
+ var rectLeft = this.rectPxBounds.left;
+ var rectHeight = Math.abs(this.rectPxBounds.getHeight());
+ var rectWidth = this.rectPxBounds.getWidth();
+ // don't allow dragging off of parent element
+ var newTop = Math.max(0, (rectTop - deltaY));
+ newTop = Math.min(newTop,
+ this.ovmap.size.h - this.hComp - rectHeight);
+ var newLeft = Math.max(0, (rectLeft - deltaX));
+ newLeft = Math.min(newLeft,
+ this.ovmap.size.w - this.wComp - rectWidth);
+ this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
+ newTop + rectHeight,
+ newLeft + rectWidth,
+ newTop));
+ }
+ },
+
+ /**
+ * Method: mapDivClick
+ * Handle browser events
+ *
+ * Parameters:
+ * evt - {<OpenLayers.Event>} evt
+ */
+ mapDivClick: function(evt) {
+ var pxCenter = this.rectPxBounds.getCenterPixel();
+ var deltaX = evt.xy.x - pxCenter.x;
+ var deltaY = evt.xy.y - pxCenter.y;
+ var top = this.rectPxBounds.top;
+ var left = this.rectPxBounds.left;
+ var height = Math.abs(this.rectPxBounds.getHeight());
+ var width = this.rectPxBounds.getWidth();
+ var newTop = Math.max(0, (top + deltaY));
+ newTop = Math.min(newTop, this.ovmap.size.h - height);
+ var newLeft = Math.max(0, (left + deltaX));
+ newLeft = Math.min(newLeft, this.ovmap.size.w - width);
+ this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
+ newTop + height,
+ newLeft + width,
+ newTop));
+ this.updateMapToRect();
+ },
+
+ /**
+ * Method: maximizeControl
+ * Unhide the control. Called when the control is in the map viewport.
+ *
+ * Parameters:
+ * e - {<OpenLayers.Event>}
+ */
+ maximizeControl: function(e) {
+ this.element.style.display = '';
+ this.showToggle(false);
+ if (e != null) {
+ OpenLayers.Event.stop(e);
+ }
+ },
+
+ /**
+ * Method: minimizeControl
+ * Hide all the contents of the control, shrink the size,
+ * add the maximize icon
+ *
+ * Parameters:
+ * e - {<OpenLayers.Event>}
+ */
+ minimizeControl: function(e) {
+ this.element.style.display = 'none';
+ this.showToggle(true);
+ if (e != null) {
+ OpenLayers.Event.stop(e);
+ }
+ },
+
+ /**
+ * Method: showToggle
+ * Hide/Show the toggle depending on whether the control is minimized
+ *
+ * Parameters:
+ * minimize - {Boolean}
+ */
+ showToggle: function(minimize) {
+ this.maximizeDiv.style.display = minimize ? '' : 'none';
+ this.minimizeDiv.style.display = minimize ? 'none' : '';
+ },
+
+ /**
+ * Method: update
+ * Update the overview map after layers move.
+ */
+ update: function() {
+ if(this.ovmap == null) {
+ this.createMap();
+ }
+
+ if(!this.isSuitableOverview()) {
+ this.updateOverview();
+ }
+
+ // update extent rectangle
+ this.updateRectToMap();
+ },
+
+ /**
+ * Method: isSuitableOverview
+ * Determines if the overview map is suitable given the extent and
+ * resolution of the main map.
+ */
+ isSuitableOverview: function() {
+ var mapExtent = this.map.getExtent();
+ var maxExtent = this.map.maxExtent;
+ var testExtent = new OpenLayers.Bounds(
+ Math.max(mapExtent.left, maxExtent.left),
+ Math.max(mapExtent.bottom, maxExtent.bottom),
+ Math.min(mapExtent.right, maxExtent.right),
+ Math.min(mapExtent.top, maxExtent.top));
+ var resRatio = this.ovmap.getResolution() / this.map.getResolution();
+ return ((resRatio > this.minRatio) &&
+ (resRatio <= this.maxRatio) &&
+ (this.ovmap.getExtent().containsBounds(testExtent)));
+ },
+
+ /**
+ * Method updateOverview
+ * Called by <update> if <isSuitableOverview> returns true
+ */
+ updateOverview: function() {
+ var mapRes = this.map.getResolution();
+ var targetRes = this.ovmap.getResolution();
+ var resRatio = targetRes / mapRes;
+ if(resRatio > this.maxRatio) {
+ // zoom in overview map
+ targetRes = this.minRatio * mapRes;
+ } else if(resRatio <= this.minRatio) {
+ // zoom out overview map
+ targetRes = this.maxRatio * mapRes;
+ }
+ this.ovmap.setCenter(this.map.center,
+ this.ovmap.getZoomForResolution(targetRes));
+ this.updateRectToMap();
+ },
+
+ /**
+ * Method: createMap
+ * Construct the map that this control contains
+ */
+ createMap: function() {
+ // create the overview map
+ var options = OpenLayers.Util.extend(
+ {controls: [], maxResolution: 'auto',
+ fallThrough: false}, this.mapOptions);
+ this.ovmap = new OpenLayers.Map(this.mapDiv, options);
+
+ // prevent ovmap from being destroyed when the page unloads, because
+ // the OverviewMap control has to do this (and does it).
+ OpenLayers.Event.stopObserving(window, 'unload', this.ovmap.unloadDestroy);
+
+ this.ovmap.addLayers(this.layers);
+ this.ovmap.zoomToMaxExtent();
+ // check extent rectangle border width
+ this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+ 'border-left-width')) +
+ parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+ 'border-right-width'));
+ this.wComp = (this.wComp) ? this.wComp : 2;
+ this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+ 'border-top-width')) +
+ parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+ 'border-bottom-width'));
+ this.hComp = (this.hComp) ? this.hComp : 2;
+
+ this.handlers.drag = new OpenLayers.Handler.Drag(
+ this, {move: this.rectDrag, done: this.updateMapToRect},
+ {map: this.ovmap}
+ );
+ this.handlers.click = new OpenLayers.Handler.Click(
+ this, {
+ "click": this.mapDivClick
+ },{
+ "single": true, "double": false,
+ "stopSingle": true, "stopDouble": true,
+ "pixelTolerance": 1,
+ map: this.ovmap
+ }
+ );
+ this.handlers.click.activate();
+
+ this.rectEvents = new OpenLayers.Events(this, this.extentRectangle,
+ null, true);
+ this.rectEvents.register("mouseover", this, function(e) {
+ if(!this.handlers.drag.active && !this.map.dragging) {
+ this.handlers.drag.activate();
+ }
+ });
+ this.rectEvents.register("mouseout", this, function(e) {
+ if(!this.handlers.drag.dragging) {
+ this.handlers.drag.deactivate();
+ }
+ });
+
+ },
+
+ /**
+ * Method: updateRectToMap
+ * Updates the extent rectangle position and size to match the map extent
+ */
+ updateRectToMap: function() {
+ // The base layer for overview map needs to be in the same projection
+ // as the base layer for the main map. This should be made more robust.
+ if(this.map.units != 'degrees') {
+ if(this.ovmap.getProjection() && (this.map.getProjection() != this.ovmap.getProjection())) {
+ alert(OpenLayers.i18n("sameProjection"));
+ }
+ }
+ var pxBounds = this.getRectBoundsFromMapBounds(this.map.getExtent());
+ if (pxBounds) {
+ this.setRectPxBounds(pxBounds);
+ }
+ },
+
+ /**
+ * Method: updateMapToRect
+ * Updates the map extent to match the extent rectangle position and size
+ */
+ updateMapToRect: function() {
+ var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds);
+ this.map.panTo(lonLatBounds.getCenterLonLat());
+ },
+
+ /**
+ * Method: setRectPxBounds
+ * Set extent rectangle pixel bounds.
+ *
+ * Parameters:
+ * pxBounds - {<OpenLayers.Bounds>}
+ */
+ setRectPxBounds: function(pxBounds) {
+ var top = Math.max(pxBounds.top, 0);
+ var left = Math.max(pxBounds.left, 0);
+ var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()),
+ this.ovmap.size.h - this.hComp);
+ var right = Math.min(pxBounds.left + pxBounds.getWidth(),
+ this.ovmap.size.w - this.wComp);
+ var width = Math.max(right - left, 0);
+ var height = Math.max(bottom - top, 0);
+ if(width < this.minRectSize || height < this.minRectSize) {
+ this.extentRectangle.className = this.displayClass +
+ this.minRectDisplayClass;
+ var rLeft = left + (width / 2) - (this.minRectSize / 2);
+ var rTop = top + (height / 2) - (this.minRectSize / 2);
+ this.extentRectangle.style.top = Math.round(rTop) + 'px';
+ this.extentRectangle.style.left = Math.round(rLeft) + 'px';
+ this.extentRectangle.style.height = this.minRectSize + 'px';
+ this.extentRectangle.style.width = this.minRectSize + 'px';
+ } else {
+ this.extentRectangle.className = this.displayClass +
+ 'ExtentRectangle';
+ this.extentRectangle.style.top = Math.round(top) + 'px';
+ this.extentRectangle.style.left = Math.round(left) + 'px';
+ this.extentRectangle.style.height = Math.round(height) + 'px';
+ this.extentRectangle.style.width = Math.round(width) + 'px';
+ }
+ this.rectPxBounds = new OpenLayers.Bounds(
+ Math.round(left), Math.round(bottom),
+ Math.round(right), Math.round(top)
+ );
+ },
+
+ /**
+ * Method: getRectBoundsFromMapBounds
+ * Get the rect bounds from the map bounds.
+ *
+ * Parameters:
+ * lonLatBounds - {<OpenLayers.Bounds>}
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>}A bounds which is the passed-in map lon/lat extent
+ * translated into pixel bounds for the overview map
+ */
+ getRectBoundsFromMapBounds: function(lonLatBounds) {
+ var leftBottomLonLat = new OpenLayers.LonLat(lonLatBounds.left,
+ lonLatBounds.bottom);
+ var rightTopLonLat = new OpenLayers.LonLat(lonLatBounds.right,
+ lonLatBounds.top);
+ var leftBottomPx = this.getOverviewPxFromLonLat(leftBottomLonLat);
+ var rightTopPx = this.getOverviewPxFromLonLat(rightTopLonLat);
+ var bounds = null;
+ if (leftBottomPx && rightTopPx) {
+ bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y,
+ rightTopPx.x, rightTopPx.y);
+ }
+ return bounds;
+ },
+
+ /**
+ * Method: getMapBoundsFromRectBounds
+ * Get the map bounds from the rect bounds.
+ *
+ * Parameters:
+ * pxBounds - {<OpenLayers.Bounds>}
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} Bounds which is the passed-in overview rect bounds
+ * translated into lon/lat bounds for the overview map
+ */
+ getMapBoundsFromRectBounds: function(pxBounds) {
+ var leftBottomPx = new OpenLayers.Pixel(pxBounds.left,
+ pxBounds.bottom);
+ var rightTopPx = new OpenLayers.Pixel(pxBounds.right,
+ pxBounds.top);
+ var leftBottomLonLat = this.getLonLatFromOverviewPx(leftBottomPx);
+ var rightTopLonLat = this.getLonLatFromOverviewPx(rightTopPx);
+ return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat,
+ rightTopLonLat.lon, rightTopLonLat.lat);
+ },
+
+ /**
+ * Method: getLonLatFromOverviewPx
+ * Get a map location from a pixel location
+ *
+ * Parameters:
+ * overviewMapPx - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} Location which is the passed-in overview map
+ * OpenLayers.Pixel, translated into lon/lat by the overview map
+ */
+ getLonLatFromOverviewPx: function(overviewMapPx) {
+ var size = this.ovmap.size;
+ var res = this.ovmap.getResolution();
+ var center = this.ovmap.getExtent().getCenterLonLat();
+
+ var delta_x = overviewMapPx.x - (size.w / 2);
+ var delta_y = overviewMapPx.y - (size.h / 2);
+
+ return new OpenLayers.LonLat(center.lon + delta_x * res ,
+ center.lat - delta_y * res);
+ },
+
+ /**
+ * Method: getOverviewPxFromLonLat
+ * Get a pixel location from a map location
+ *
+ * Parameters:
+ * lonlat - {<OpenLayers.LonLat>}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} Location which is the passed-in OpenLayers.LonLat,
+ * translated into overview map pixels
+ */
+ getOverviewPxFromLonLat: function(lonlat) {
+ var res = this.ovmap.getResolution();
+ var extent = this.ovmap.getExtent();
+ var px = null;
+ if (extent) {
+ px = new OpenLayers.Pixel(
+ Math.round(1/res * (lonlat.lon - extent.left)),
+ Math.round(1/res * (extent.top - lonlat.lat)));
+ }
+ return px;
+ },
+
+ CLASS_NAME: 'OpenLayers.Control.OverviewMap'
+});
+/* ======================================================================
+ OpenLayers/Handler/Click.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Click
+ * A handler for mouse clicks. The intention of this handler is to give
+ * controls more flexibility with handling clicks. Browsers trigger
+ * click events twice for a double-click. In addition, the mousedown,
+ * mousemove, mouseup sequence fires a click event. With this handler,
+ * controls can decide whether to ignore clicks associated with a double
+ * click. By setting a <pixelTolerance>, controls can also ignore clicks
+ * that include a drag. Create a new instance with the
+ * <OpenLayers.Handler.Click> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
+
+ /**
+ * APIProperty: delay
+ * {Number} Number of milliseconds between clicks before the event is
+ * considered a double-click.
+ */
+ delay: 300,
+
+ /**
+ * APIProperty: single
+ * {Boolean} Handle single clicks. Default is true. If false, clicks
+ * will not be reported. If true, single-clicks will be reported.
+ */
+ single: true,
+
+ /**
+ * APIProperty: double
+ * {Boolean} Handle double-clicks. Default is false.
+ */
+ 'double': false,
+
+ /**
+ * APIProperty: pixelTolerance
+ * {Number} Maximum number of pixels between mouseup and mousedown for an
+ * event to be considered a click. Default is 0. If set to an
+ * integer value, clicks with a drag greater than the value will be
+ * ignored. This property can only be set when the handler is
+ * constructed.
+ */
+ pixelTolerance: 0,
+
+ /**
+ * APIProperty: stopSingle
+ * {Boolean} Stop other listeners from being notified of clicks. Default
+ * is false. If true, any click listeners registered before this one
+ * will not be notified of *any* click event (associated with double
+ * or single clicks).
+ */
+ stopSingle: false,
+
+ /**
+ * APIProperty: stopDouble
+ * {Boolean} Stop other listeners from being notified of double-clicks.
+ * Default is false. If true, any click listeners registered before
+ * this one will not be notified of *any* double-click events.
+ *
+ * The one caveat with stopDouble is that given a map with two click
+ * handlers, one with stopDouble true and the other with stopSingle
+ * true, the stopSingle handler should be activated last to get
+ * uniform cross-browser performance. Since IE triggers one click
+ * with a dblclick and FF triggers two, if a stopSingle handler is
+ * activated first, all it gets in IE is a single click when the
+ * second handler stops propagation on the dblclick.
+ */
+ stopDouble: false,
+
+ /**
+ * Property: timerId
+ * {Number} The id of the timeout waiting to clear the <delayedCall>.
+ */
+ timerId: null,
+
+ /**
+ * Property: down
+ * {<OpenLayers.Pixel>} The pixel location of the last mousedown.
+ */
+ down: null,
+
+ /**
+ * Constructor: OpenLayers.Handler.Click
+ * Create a new click handler.
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>} The control that is making use of
+ * this handler. If a handler is being used without a control, the
+ * handler's setMap method must be overridden to deal properly with
+ * the map.
+ * callbacks - {Object} An object with keys corresponding to callbacks
+ * that will be called by the handler. The callbacks should
+ * expect to recieve a single argument, the click event.
+ * Callbacks for 'click' and 'dblclick' are supported.
+ * options - {Object} Optional object whose properties will be set on the
+ * handler.
+ */
+ initialize: function(control, callbacks, options) {
+ OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+ // optionally register for mouseup and mousedown
+ if(this.pixelTolerance != null) {
+ this.mousedown = function(evt) {
+ this.down = evt.xy;
+ return true;
+ };
+ }
+ },
+
+ /**
+ * Method: mousedown
+ * Handle mousedown. Only registered as a listener if pixelTolerance is
+ * a non-zero value at construction.
+ *
+ * Returns:
+ * {Boolean} Continue propagating this event.
+ */
+ mousedown: null,
+
+ /**
+ * Method: dblclick
+ * Handle dblclick. For a dblclick, we get two clicks in some browsers
+ * (FF) and one in others (IE). So we need to always register for
+ * dblclick to properly handle single clicks.
+ *
+ * Returns:
+ * {Boolean} Continue propagating this event.
+ */
+ dblclick: function(evt) {
+ if(this.passesTolerance(evt)) {
+ if(this["double"]) {
+ this.callback('dblclick', [evt]);
+ }
+ this.clearTimer();
+ }
+ return !this.stopDouble;
+ },
+
+ /**
+ * Method: click
+ * Handle click.
+ *
+ * Returns:
+ * {Boolean} Continue propagating this event.
+ */
+ click: function(evt) {
+ if(this.passesTolerance(evt)) {
+ if(this.timerId != null) {
+ // already received a click
+ this.clearTimer();
+ } else {
+ // set the timer, send evt only if single is true
+ //use a clone of the event object because it will no longer
+ //be a valid event object in IE in the timer callback
+ var clickEvent = this.single ?
+ OpenLayers.Util.extend({}, evt) : null;
+ this.timerId = window.setTimeout(
+ OpenLayers.Function.bind(this.delayedCall, this, clickEvent),
+ this.delay
+ );
+ }
+ }
+ return !this.stopSingle;
+ },
+
+ /**
+ * Method: passesTolerance
+ * Determine whether the event is within the optional pixel tolerance. Note
+ * that the pixel tolerance check only works if mousedown events get to
+ * the listeners registered here. If they are stopped by other elements,
+ * the <pixelTolerance> will have no effect here (this method will always
+ * return true).
+ *
+ * Returns:
+ * {Boolean} The click is within the pixel tolerance (if specified).
+ */
+ passesTolerance: function(evt) {
+ var passes = true;
+ if(this.pixelTolerance != null && this.down) {
+ var dpx = Math.sqrt(
+ Math.pow(this.down.x - evt.xy.x, 2) +
+ Math.pow(this.down.y - evt.xy.y, 2)
+ );
+ if(dpx > this.pixelTolerance) {
+ passes = false;
+ }
+ }
+ return passes;
+ },
+
+ /**
+ * Method: clearTimer
+ * Clear the timer and set <timerId> to null.
+ */
+ clearTimer: function() {
+ if(this.timerId != null) {
+ window.clearTimeout(this.timerId);
+ this.timerId = null;
+ }
+ },
+
+ /**
+ * Method: delayedCall
+ * Sets <timerId> to null. And optionally triggers the click callback if
+ * evt is set.
+ */
+ delayedCall: function(evt) {
+ this.timerId = null;
+ if(evt) {
+ this.callback('click', [evt]);
+ }
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Deactivate the handler.
+ *
+ * Returns:
+ * {Boolean} The handler was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = false;
+ if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+ this.clearTimer();
+ this.down = null;
+ deactivated = true;
+ }
+ return deactivated;
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.Click"
+});
+/* ======================================================================
+ OpenLayers/Handler/Drag.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Drag
+ * The drag handler is used to deal with sequences of browser events related
+ * to dragging. The handler is used by controls that want to know when
+ * a drag sequence begins, when a drag is happening, and when it has
+ * finished.
+ *
+ * Controls that use the drag handler typically construct it with callbacks
+ * for 'down', 'move', and 'done'. Callbacks for these keys are called
+ * when the drag begins, with each move, and when the drag is done. In
+ * addition, controls can have callbacks keyed to 'up' and 'out' if they
+ * care to differentiate between the types of events that correspond with
+ * the end of a drag sequence. If no drag actually occurs (no mouse move)
+ * the 'down' and 'up' callbacks will be called, but not the 'done'
+ * callback.
+ *
+ * Create a new drag handler with the <OpenLayers.Handler.Drag> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, {
+
+ /**
+ * Property: started
+ * {Boolean} When a mousedown event is received, we want to record it, but
+ * not set 'dragging' until the mouse moves after starting.
+ */
+ started: false,
+
+ /**
+ * Property: stopDown
+ * {Boolean} Stop propagation of mousedown events from getting to listeners
+ * on the same element. Default is true.
+ */
+ stopDown: true,
+
+ /**
+ * Property: dragging
+ * {Boolean}
+ */
+ dragging: false,
+
+ /**
+ * Property: last
+ * {<OpenLayers.Pixel>} The last pixel location of the drag.
+ */
+ last: null,
+
+ /**
+ * Property: start
+ * {<OpenLayers.Pixel>} The first pixel location of the drag.
+ */
+ start: null,
+
+ /**
+ * Property: oldOnselectstart
+ * {Function}
+ */
+ oldOnselectstart: null,
+
+ /**
+ * Constructor: OpenLayers.Handler.Drag
+ * Returns OpenLayers.Handler.Drag
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>} The control that is making use of
+ * this handler. If a handler is being used without a control, the
+ * handlers setMap method must be overridden to deal properly with
+ * the map.
+ * callbacks - {Object} An object containing a single function to be
+ * called when the drag operation is finished. The callback should
+ * expect to recieve a single argument, the pixel location of the event.
+ * Callbacks for 'move' and 'done' are supported. You can also speficy
+ * callbacks for 'down', 'up', and 'out' to respond to those events.
+ * options - {Object}
+ */
+ initialize: function(control, callbacks, options) {
+ OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * The four methods below (down, move, up, and out) are used by subclasses
+ * to do their own processing related to these mouse events.
+ */
+
+ /**
+ * Method: down
+ * This method is called during the handling of the mouse down event.
+ * Subclasses can do their own processing here.
+ *
+ * Parameters:
+ * evt - {Event} The mouse down event
+ */
+ down: function(evt) {
+ },
+
+ /**
+ * Method: move
+ * This method is called during the handling of the mouse move event.
+ * Subclasses can do their own processing here.
+ *
+ * Parameters:
+ * evt - {Event} The mouse move event
+ *
+ */
+ move: function(evt) {
+ },
+
+ /**
+ * Method: up
+ * This method is called during the handling of the mouse up event.
+ * Subclasses can do their own processing here.
+ *
+ * Parameters:
+ * evt - {Event} The mouse up event
+ */
+ up: function(evt) {
+ },
+
+ /**
+ * Method: out
+ * This method is called during the handling of the mouse out event.
+ * Subclasses can do their own processing here.
+ *
+ * Parameters:
+ * evt - {Event} The mouse out event
+ */
+ out: function(evt) {
+ },
+
+ /**
+ * The methods below are part of the magic of event handling. Because
+ * they are named like browser events, they are registered as listeners
+ * for the events they represent.
+ */
+
+ /**
+ * Method: mousedown
+ * Handle mousedown events
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} Let the event propagate.
+ */
+ mousedown: function (evt) {
+ var propagate = true;
+ this.dragging = false;
+ if (this.checkModifiers(evt) && OpenLayers.Event.isLeftClick(evt)) {
+ this.started = true;
+ this.start = evt.xy;
+ this.last = evt.xy;
+ // TBD replace with CSS classes
+ this.map.div.style.cursor = "move";
+ this.down(evt);
+ this.callback("down", [evt.xy]);
+ OpenLayers.Event.stop(evt);
+
+ if(!this.oldOnselectstart) {
+ this.oldOnselectstart = (document.onselectstart) ? document.onselectstart : function() { return true; };
+ document.onselectstart = function() {return false;};
+ }
+
+ propagate = !this.stopDown;
+ } else {
+ this.started = false;
+ this.start = null;
+ this.last = null;
+ }
+ return propagate;
+ },
+
+ /**
+ * Method: mousemove
+ * Handle mousemove events
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} Let the event propagate.
+ */
+ mousemove: function (evt) {
+ if (this.started) {
+ if(evt.xy.x != this.last.x || evt.xy.y != this.last.y) {
+ this.dragging = true;
+ this.move(evt);
+ this.callback("move", [evt.xy]);
+ if(!this.oldOnselectstart) {
+ this.oldOnselectstart = document.onselectstart;
+ document.onselectstart = function() {return false;};
+ }
+ this.last = evt.xy;
+ }
+ }
+ return true;
+ },
+
+ /**
+ * Method: mouseup
+ * Handle mouseup events
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} Let the event propagate.
+ */
+ mouseup: function (evt) {
+ if (this.started) {
+ var dragged = (this.start != this.last);
+ this.started = false;
+ this.dragging = false;
+ // TBD replace with CSS classes
+ this.map.div.style.cursor = "";
+ this.up(evt);
+ this.callback("up", [evt.xy]);
+ if(dragged) {
+ this.callback("done", [evt.xy]);
+ }
+ document.onselectstart = this.oldOnselectstart;
+ }
+ return true;
+ },
+
+ /**
+ * Method: mouseout
+ * Handle mouseout events
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} Let the event propagate.
+ */
+ mouseout: function (evt) {
+ if (this.started && OpenLayers.Util.mouseLeft(evt, this.map.div)) {
+ var dragged = (this.start != this.last);
+ this.started = false;
+ this.dragging = false;
+ // TBD replace with CSS classes
+ this.map.div.style.cursor = "";
+ this.out(evt);
+ this.callback("out", []);
+ if(dragged) {
+ this.callback("done", [evt.xy]);
+ }
+ if(document.onselectstart) {
+ document.onselectstart = this.oldOnselectstart;
+ }
+ }
+ return true;
+ },
+
+ /**
+ * Method: click
+ * The drag handler captures the click event. If something else registers
+ * for clicks on the same element, its listener will not be called
+ * after a drag.
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} Let the event propagate.
+ */
+ click: function (evt) {
+ // let the click event propagate only if the mouse moved
+ return (this.start == this.last);
+ },
+
+ /**
+ * Method: activate
+ * Activate the handler.
+ *
+ * Returns:
+ * {Boolean} The handler was successfully activated.
+ */
+ activate: function() {
+ var activated = false;
+ if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+ this.dragging = false;
+ activated = true;
+ }
+ return activated;
+ },
+
+ /**
+ * Method: deactivate
+ * Deactivate the handler.
+ *
+ * Returns:
+ * {Boolean} The handler was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = false;
+ if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+ this.started = false;
+ this.dragging = false;
+ this.start = null;
+ this.last = null;
+ deactivated = true;
+ }
+ return deactivated;
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.Drag"
+});
+/* ======================================================================
+ OpenLayers/Handler/MouseWheel.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.MouseWheel
+ * Handler for wheel up/down events.
+ *
+ * Inherits from:
+ * - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, {
+ /**
+ * Property: wheelListener
+ * {function}
+ */
+ wheelListener: null,
+
+ /**
+ * Property: mousePosition
+ * {<OpenLayers.Pixel>} mousePosition is necessary because
+ * evt.clientX/Y is buggy in Moz on wheel events, so we cache and use the
+ * value from the last mousemove.
+ */
+ mousePosition: null,
+
+ /**
+ * Constructor: OpenLayers.Handler.MouseWheel
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>}
+ * callbacks - {Object} An object containing a single function to be
+ * called when the drag operation is finished.
+ * The callback should expect to recieve a single
+ * argument, the point geometry.
+ * options - {Object}
+ */
+ initialize: function(control, callbacks, options) {
+ OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+ this.wheelListener = OpenLayers.Function.bindAsEventListener(
+ this.onWheelEvent, this
+ );
+ },
+
+ /**
+ * Method: destroy
+ */
+ destroy: function() {
+ OpenLayers.Handler.prototype.destroy.apply(this, arguments);
+ this.wheelListener = null;
+ },
+
+ /**
+ * Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/
+ */
+
+ /**
+ * Method: onWheelEvent
+ * Catch the wheel event and handle it xbrowserly
+ *
+ * Parameters:
+ * e - {Event}
+ */
+ onWheelEvent: function(e){
+
+ // make sure we have a map and check keyboard modifiers
+ if (!this.map || !this.checkModifiers(e)) {
+ return;
+ }
+
+ // Ride up the element's DOM hierarchy to determine if it or any of
+ // its ancestors was:
+ // * specifically marked as scrollable
+ // * one of our layer divs
+ // * the map div
+ //
+ var overScrollableDiv = false;
+ var overLayerDiv = false;
+ var overMapDiv = false;
+
+ var elem = OpenLayers.Event.element(e);
+ while((elem != null) && !overMapDiv && !overScrollableDiv) {
+
+ if (!overScrollableDiv) {
+ try {
+ if (elem.currentStyle) {
+ overflow = elem.currentStyle["overflow"];
+ } else {
+ var style =
+ document.defaultView.getComputedStyle(elem, null);
+ var overflow = style.getPropertyValue("overflow");
+ }
+ overScrollableDiv = ( overflow &&
+ (overflow == "auto") || (overflow == "scroll") );
+ } catch(err) {
+ //sometimes when scrolling in a popup, this causes
+ // obscure browser error
+ }
+ }
+
+ if (!overLayerDiv) {
+ for(var i=0; i < this.map.layers.length; i++) {
+ // Are we in the layer div? Note that we have two cases
+ // here: one is to catch EventPane layers, which have a
+ // pane above the layer (layer.pane)
+ if (elem == this.map.layers[i].div
+ || elem == this.map.layers[i].pane) {
+ overLayerDiv = true;
+ break;
+ }
+ }
+ }
+ overMapDiv = (elem == this.map.div);
+
+ elem = elem.parentNode;
+ }
+
+ // Logic below is the following:
+ //
+ // If we are over a scrollable div or not over the map div:
+ // * do nothing (let the browser handle scrolling)
+ //
+ // otherwise
+ //
+ // If we are over the layer div:
+ // * zoom/in out
+ // then
+ // * kill event (so as not to also scroll the page after zooming)
+ //
+ // otherwise
+ //
+ // Kill the event (dont scroll the page if we wheel over the
+ // layerswitcher or the pan/zoom control)
+ //
+ if (!overScrollableDiv && overMapDiv) {
+ if (overLayerDiv) {
+ 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 = 0;
+ if (!e) {
+ e = window.event;
+ }
+ if (e.wheelDelta) {
+ delta = e.wheelDelta/120;
+ if (window.opera && window.opera.version() < 9.2) {
+ delta = -delta;
+ }
+ } else if (e.detail) {
+ delta = -e.detail / 3;
+ }
+ if (delta) {
+ // add the mouse position to the event because mozilla has
+ // a bug with clientX and clientY (see
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=352179)
+ // getLonLatFromViewPortPx(e) returns wrong values
+ if (this.mousePosition) {
+ e.xy = this.mousePosition;
+ }
+ if (!e.xy) {
+ // If the mouse hasn't moved over the map yet, then
+ // we don't have a mouse position (in FF), so we just
+ // act as if the mouse was at the center of the map.
+ // Note that we can tell we are in the map -- and
+ // this.map is ensured to be true above.
+ e.xy = this.map.getPixelFromLonLat(
+ this.map.getCenter()
+ );
+ }
+ if (delta < 0) {
+ this.callback("down", [e, delta]);
+ } else {
+ this.callback("up", [e, delta]);
+ }
+ }
+ },
+
+ /**
+ * Method: mousemove
+ * Update the stored mousePosition on every move.
+ *
+ * Parameters:
+ * evt - {Event} The browser event
+ *
+ * Returns:
+ * {Boolean} Allow event propagation
+ */
+ mousemove: function (evt) {
+ this.mousePosition = evt.xy;
+ },
+
+ /**
+ * Method: activate
+ */
+ activate: function (evt) {
+ if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+ //register mousewheel events specifically on the window and document
+ var wheelListener = this.wheelListener;
+ OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener);
+ OpenLayers.Event.observe(window, "mousewheel", wheelListener);
+ OpenLayers.Event.observe(document, "mousewheel", wheelListener);
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Method: deactivate
+ */
+ deactivate: function (evt) {
+ if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+ // unregister mousewheel events specifically on the window and document
+ var wheelListener = this.wheelListener;
+ OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener);
+ OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener);
+ OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener);
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.MouseWheel"
+});
+/* ======================================================================
+ OpenLayers/Layer.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @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,
+
+ /**
+ * Property: opacity
+ * {Float} The layer's opacity. Float number between 0.0 and 1.0.
+ */
+ opacity: null,
+
+ /**
+ * Constant: EVENT_TYPES
+ * {Array(String)} Supported application event types. Register a listener
+ * for a particular event with the following syntax:
+ * (code)
+ * layer.events.register(type, obj, listener);
+ * (end)
+ *
+ * Listeners will be called with a reference to an event object. The
+ * properties of this event depends on exactly what happened.
+ *
+ * All event objects have at least the following properties:
+ * - *object* {Object} A reference to layer.events.object.
+ * - *element* {DOMElement} A reference to layer.events.element.
+ *
+ * Supported map event types:
+ * - *loadstart* Triggered when layer loading starts.
+ * - *loadend* Triggered when layer loading ends.
+ * - *loadcancel* Triggered when layer loading is canceled.
+ * - *visibilitychanged* Triggered when layer visibility is changed.
+ */
+ EVENT_TYPES: ["loadstart", "loadend", "loadcancel", "visibilitychanged"],
+
+ /**
+ * APIProperty: events
+ * {<OpenLayers.Events>}
+ */
+ events: null,
+
+ /**
+ * APIProperty: map
+ * {<OpenLayers.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
+ * <OpenLayers.Control.Attribution> 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 <OpenLayers.Map.setCenter> whenever the zoom
+ * changes.
+ */
+ inRange: false,
+
+ /**
+ * Propery: imageSize
+ * {<OpenLayers.Size>} For layers with a gutter, the image is larger than
+ * the tile by twice the gutter in each dimension.
+ */
+ imageSize: null,
+
+ /**
+ * Property: imageOffset
+ * {<OpenLayers.Pixel>} For layers with a gutter, the image offset
+ * represents displacement due to the gutter.
+ */
+ imageOffset: 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 <OpenLayers.Events.on>. 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
+ * {<OpenLayers.Projection>} or {<String>} Set in the layer options to
+ * override the default projection string this layer - also set maxExtent,
+ * maxResolution, and units if appropriate. Can be either a string or
+ * an <OpenLayers.Projection> object when created -- will be converted
+ * to an object when setMap is called if a string is passed.
+ */
+ projection: null,
+
+ /**
+ * APIProperty: units
+ * {String} The layer map units. Defaults to 'degrees'. Possible values
+ * are 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
+ */
+ 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 <resolutions> 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
+ * {<OpenLayers.Bounds>} The center of these bounds will not stray outside
+ * of the viewport extent during panning. In addition, if
+ * <displayOutsideMaxExtent> is set to false, data will not be
+ * requested that falls completely outside of these bounds.
+ */
+ maxExtent: null,
+
+ /**
+ * APIProperty: minExtent
+ * {<OpenLayers.Bounds>}
+ */
+ 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 a geographic projection 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} #487 for more info.
+ */
+ wrapDateLine: false,
+
+ /**
+ * APIProperty: transitionEffect
+ * {String} The transition effect to use when the map is panned or
+ * zoomed.
+ *
+ * There are currently two supported 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.
+ */
+ transitionEffect: null,
+
+ /**
+ * Property: SUPPORTED_TRANSITIONS
+ * {Array} An immutable (that means don't change it!) list of supported
+ * transitionEffect values.
+ */
+ SUPPORTED_TRANSITIONS: ['resize'],
+
+ /**
+ * 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.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.events = new OpenLayers.Events(this, this.div,
+ this.EVENT_TYPES);
+ if(this.eventListeners instanceof Object) {
+ this.events.on(this.eventListeners);
+ }
+
+ }
+
+ if (this.wrapDateLine) {
+ this.displayOutsideMaxExtent = true;
+ }
+ },
+
+ /**
+ * 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 - {<OpenLayers.Layer>} The layer to be cloned
+ *
+ * Returns:
+ * {<OpenLayers.Layer>} An exact clone of this <OpenLayers.Layer>
+ */
+ clone: function (obj) {
+
+ if (obj == null) {
+ obj = new OpenLayers.Layer(this.name, this.options);
+ }
+
+ // 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;
+ },
+
+ /**
+ * 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}
+ */
+ addOptions: function (newOptions) {
+
+ if (this.options == null) {
+ this.options = {};
+ }
+
+ // update our copy for clone
+ OpenLayers.Util.extend(this.options, newOptions);
+
+ // add new options to this
+ OpenLayers.Util.extend(this, newOptions);
+ },
+
+ /**
+ * 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) {
+ this.moveTo(extent, true, false);
+ redrawn = true;
+ }
+ }
+ return redrawn;
+ },
+
+ /**
+ * Method: moveTo
+ *
+ * Parameters:
+ * bound - {<OpenLayers.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: 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 - {<OpenLayers.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.projection = this.projection || this.map.projection;
+
+ if (this.projection && 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();
+ }
+ },
+
+ /**
+ * 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 - {<OpenLayers.Map>}
+ */
+ removeMap: function(map) {
+ //to be overridden by subclasses
+ },
+
+ /**
+ * APIMethod: getImageSize
+ *
+ * Returns:
+ * {<OpenLayers.Size>} The size that the image should be, taking into
+ * account gutters.
+ */
+ getImageSize: function() {
+ return (this.imageSize || this.tileSize);
+ },
+
+ /**
+ * APIMethod: setTileSize
+ * Set the tile size based on the map size. This also sets layer.imageSize
+ * and layer.imageOffset for use by Tile.Image.
+ *
+ * Parameters:
+ * size - {<OpenLayers.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.imageOffset = new OpenLayers.Pixel(-this.gutter,
+ -this.gutter);
+ 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:
+ * visible - {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
+ *
+ * Parameters:
+ * display - {Boolean}
+ */
+ display: function(display) {
+ var inRange = this.calculateInRange();
+ if (display != (this.div.style.display != "none")) {
+ this.div.style.display = (display && inRange) ? "block" : "none";
+ }
+ },
+
+ /**
+ * Method: calculateInRange
+ *
+ * Returns:
+ * {Boolean} The layer is displayable at the current map's current
+ * resolution.
+ */
+ calculateInRange: function() {
+ var inRange = false;
+ 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() {
+
+ // These are the relevant options which are used for calculating
+ // resolutions information.
+ //
+ var props = new Array(
+ 'projection', 'units',
+ 'scales', 'resolutions',
+ 'maxScale', 'minScale',
+ 'maxResolution', 'minResolution',
+ 'minExtent', 'maxExtent',
+ 'numZoomLevels', 'maxZoomLevel'
+ );
+
+ // First we create a new object where we will store all of the
+ // resolution-related properties that we find in either the layer's
+ // 'options' array or from the map.
+ //
+ var confProps = {};
+ for(var i=0; i < props.length; i++) {
+ var property = props[i];
+ confProps[property] = this.options[property] || this.map[property];
+ }
+
+ // Do not use the scales/resolutions at the map level if
+ // minScale/minResolution and maxScale/maxResolution are
+ // specified at the layer level
+ if (this.options.minScale != null &&
+ this.options.maxScale != null &&
+ this.options.scales == null) {
+ confProps.scales = null;
+ }
+ if (this.options.minResolution != null &&
+ this.options.maxResolution != null &&
+ this.options.resolutions == null) {
+ confProps.resolutions = null;
+ }
+
+ // If numZoomLevels hasn't been set and the maxZoomLevel *has*,
+ // then use maxZoomLevel to calculate numZoomLevels
+ //
+ if ( (!confProps.numZoomLevels) && (confProps.maxZoomLevel) ) {
+ confProps.numZoomLevels = confProps.maxZoomLevel + 1;
+ }
+
+ // First off, we take whatever hodge-podge of values we have and
+ // calculate/distill them down into a resolutions[] array
+ //
+ if ((confProps.scales != null) || (confProps.resolutions != null)) {
+ //preset levels
+ if (confProps.scales != null) {
+ confProps.resolutions = [];
+ for(var i = 0; i < confProps.scales.length; i++) {
+ var scale = confProps.scales[i];
+ confProps.resolutions[i] =
+ OpenLayers.Util.getResolutionFromScale(scale,
+ confProps.units);
+ }
+ }
+ confProps.numZoomLevels = confProps.resolutions.length;
+
+ } else {
+ //maxResolution and numZoomLevels based calculation
+
+ // determine maxResolution
+ if (confProps.minScale) {
+ confProps.maxResolution =
+ OpenLayers.Util.getResolutionFromScale(confProps.minScale,
+ confProps.units);
+ } else if (confProps.maxResolution == "auto") {
+ var viewSize = this.map.getSize();
+ var wRes = confProps.maxExtent.getWidth() / viewSize.w;
+ var hRes = confProps.maxExtent.getHeight()/ viewSize.h;
+ confProps.maxResolution = Math.max(wRes, hRes);
+ }
+
+ // determine minResolution
+ if (confProps.maxScale != null) {
+ confProps.minResolution =
+ OpenLayers.Util.getResolutionFromScale(confProps.maxScale,
+ confProps.units);
+ } else if ( (confProps.minResolution == "auto") &&
+ (confProps.minExtent != null) ) {
+ var viewSize = this.map.getSize();
+ var wRes = confProps.minExtent.getWidth() / viewSize.w;
+ var hRes = confProps.minExtent.getHeight()/ viewSize.h;
+ confProps.minResolution = Math.max(wRes, hRes);
+ }
+
+ // determine numZoomLevels if not already set on the layer
+ // this gives numZoomLevels assuming approximately base 2 scaling
+ if (confProps.minResolution != null &&
+ this.options.numZoomLevels == undefined) {
+ var ratio = confProps.maxResolution / confProps.minResolution;
+ confProps.numZoomLevels =
+ Math.floor(Math.log(ratio) / Math.log(2)) + 1;
+ }
+
+ // now we have numZoomLevels and maxResolution,
+ // we can populate the resolutions array
+ confProps.resolutions = new Array(confProps.numZoomLevels);
+ var base = 2;
+ if(typeof confProps.minResolution == "number" &&
+ confProps.numZoomLevels > 1) {
+ /**
+ * If maxResolution and minResolution are set (or related
+ * scale properties), we calculate the base for exponential
+ * scaling that starts at maxResolution and ends at
+ * minResolution in numZoomLevels steps.
+ */
+ base = Math.pow(
+ (confProps.maxResolution / confProps.minResolution),
+ (1 / (confProps.numZoomLevels - 1))
+ );
+ }
+ for (var i=0; i < confProps.numZoomLevels; i++) {
+ var res = confProps.maxResolution / Math.pow(base, i);
+ confProps.resolutions[i] = res;
+ }
+ }
+
+ //sort resolutions array ascendingly
+ //
+ confProps.resolutions.sort( function(a, b) { return(b-a); } );
+
+ // now set our newly calculated values back to the layer
+ // Note: We specifically do *not* set them to layer.options, which we
+ // will preserve as it was when we added this layer to the map.
+ // this way cloned layers reset themselves to new map div
+ // dimensions)
+ //
+
+ this.resolutions = confProps.resolutions;
+ this.maxResolution = confProps.resolutions[0];
+ var lastIndex = confProps.resolutions.length - 1;
+ this.minResolution = confProps.resolutions[lastIndex];
+
+ this.scales = [];
+ for(var i = 0; i < confProps.resolutions.length; i++) {
+ this.scales[i] =
+ OpenLayers.Util.getScaleFromResolution(confProps.resolutions[i],
+ confProps.units);
+ }
+ this.minScale = this.scales[0];
+ this.maxScale = this.scales[this.scales.length - 1];
+
+ this.numZoomLevels = confProps.numZoomLevels;
+ },
+
+ /**
+ * APIMethod: getResolution
+ *
+ * Returns:
+ * {Float} The currently selected resolution of the map, taken from the
+ * resolutions array, indexed by current zoom level.
+ */
+ getResolution: function() {
+ var zoom = this.map.getZoom();
+ return this.getResolutionForZoom(zoom);
+ },
+
+ /**
+ * APIMethod: getExtent
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} 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:
+ * bounds - {<OpenLayers.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} 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:
+ * {<OpenLayers.Bounds>}
+ */
+ getDataExtent: function () {
+ //to be implemented by subclasses
+ },
+
+ /**
+ * APIMethod: getResolutionForZoom
+ *
+ * Parameter:
+ * 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[high] +
+ ((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;
+ 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(var i=0; i<this.resolutions.length; ++i) {
+ res = this.resolutions[i];
+ if(res >= resolution) {
+ highRes = res;
+ lowZoom = i;
+ }
+ if(res <= resolution) {
+ lowRes = res;
+ highZoom = i;
+ break;
+ }
+ }
+ var dRes = highRes - lowRes;
+ if(dRes > 0) {
+ zoom = lowZoom + ((resolution - lowRes) / dRes);
+ } else {
+ zoom = lowZoom;
+ }
+ } else {
+ var diff;
+ var minDiff = Number.POSITIVE_INFINITY;
+ for(var i=0; i < this.resolutions.length; i++) {
+ if (closest) {
+ diff = Math.abs(this.resolutions[i] - resolution);
+ if (diff > minDiff) {
+ break;
+ }
+ minDiff = diff;
+ } else {
+ if (this.resolutions[i] < resolution) {
+ break;
+ }
+ }
+ }
+ zoom = Math.max(0, i-1);
+ }
+ return zoom;
+ },
+
+ /**
+ * APIMethod: getLonLatFromViewPortPx
+ *
+ * Parameters:
+ * viewPortPx - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in
+ * view port <OpenLayers.Pixel>, translated into lon/lat by the layer.
+ */
+ getLonLatFromViewPortPx: function (viewPortPx) {
+ var lonlat = null;
+ if (viewPortPx != null) {
+ var size = this.map.getSize();
+ var center = this.map.getCenter();
+ if (center) {
+ var res = this.map.getResolution();
+
+ var delta_x = viewPortPx.x - (size.w / 2);
+ var delta_y = viewPortPx.y - (size.h / 2);
+
+ lonlat = new OpenLayers.LonLat(center.lon + delta_x * res ,
+ center.lat - delta_y * res);
+
+ if (this.wrapDateLine) {
+ lonlat = lonlat.wrapDateLine(this.maxExtent);
+ }
+ } // else { DEBUG STATEMENT }
+ }
+ return lonlat;
+ },
+
+ /**
+ * APIMethod: getViewPortPxFromLonLat
+ * Returns a pixel location given a map location. This method will return
+ * fractional pixel values.
+ *
+ * Parameters:
+ * lonlat - {<OpenLayers.LonLat>}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} An <OpenLayers.Pixel> which is the passed-in
+ * <OpenLayers.LonLat>,translated into view port pixels.
+ */
+ getViewPortPxFromLonLat: function (lonlat) {
+ var px = null;
+ if (lonlat != null) {
+ var resolution = this.map.getResolution();
+ var extent = this.map.getExtent();
+ 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)
+ *
+ * Parameter:
+ * opacity - {Float}
+ */
+ setOpacity: function(opacity) {
+ if (opacity != this.opacity) {
+ this.opacity = opacity;
+ for(var i=0; i<this.div.childNodes.length; ++i) {
+ var element = this.div.childNodes[i].firstChild;
+ OpenLayers.Util.modifyDOMElement(element, null, null, null,
+ null, null, null, opacity);
+ }
+ }
+ },
+
+ /**
+ * 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 - {<OpenLayers.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()
+ };
+ bounds = bounds.wrapDateLine(this.maxExtent, wrappingOptions);
+
+ }
+ return bounds;
+ },
+
+ CLASS_NAME: "OpenLayers.Layer"
+});
+/* ======================================================================
+ OpenLayers/Marker/Box.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Marker.js
+ */
+
+/**
+ * Class: OpenLayers.Marker.Box
+ *
+ * Inherits from:
+ * - <OpenLayers.Marker>
+ */
+OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, {
+
+ /**
+ * Property: bounds
+ * {<OpenLayers.Bounds>}
+ */
+ bounds: null,
+
+ /**
+ * Property: div
+ * {DOMElement}
+ */
+ div: null,
+
+ /**
+ * Constructor: OpenLayers.Marker.Box
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * borderColor - {String}
+ * borderWidth - {int}
+ */
+ initialize: function(bounds, borderColor, borderWidth) {
+ this.bounds = bounds;
+ this.div = OpenLayers.Util.createDiv();
+ this.div.style.overflow = 'hidden';
+ this.events = new OpenLayers.Events(this, this.div, null);
+ this.setBorder(borderColor, borderWidth);
+ },
+
+ /**
+ * Method: destroy
+ */
+ destroy: function() {
+
+ this.bounds = null;
+ this.div = null;
+
+ OpenLayers.Marker.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: setBorder
+ * Allow the user to change the box's color and border width
+ *
+ * Parameters:
+ * color - {String} Default is "red"
+ * width - {int} Default is 2
+ */
+ setBorder: function (color, width) {
+ if (!color) {
+ color = "red";
+ }
+ if (!width) {
+ width = 2;
+ }
+ this.div.style.border = width + "px solid " + color;
+ },
+
+ /**
+ * Method: draw
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ * sz - {<OpenLayers.Size>}
+ *
+ * Returns:
+ * {DOMElement} A new DOM Image with this marker´s icon set at the
+ * location passed-in
+ */
+ draw: function(px, sz) {
+ OpenLayers.Util.modifyDOMElement(this.div, null, px, sz);
+ return this.div;
+ },
+
+ /**
+ * Method: onScreen
+ *
+ * Rreturn:
+ * {Boolean} Whether or not the marker is currently visible on screen.
+ */
+ onScreen:function() {
+ var onScreen = false;
+ if (this.map) {
+ var screenBounds = this.map.getExtent();
+ onScreen = screenBounds.containsBounds(this.bounds, true, true);
+ }
+ return onScreen;
+ },
+
+ /**
+ * Method: display
+ * Hide or show the icon
+ *
+ * Parameters:
+ * display - {Boolean}
+ */
+ display: function(display) {
+ this.div.style.display = (display) ? "" : "none";
+ },
+
+ CLASS_NAME: "OpenLayers.Marker.Box"
+});
+
+/* ======================================================================
+ OpenLayers/Control/DragPan.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Handler/Drag.js
+ */
+
+/**
+ * Class: OpenLayers.Control.DragPan
+ * DragPan control.
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Property: type
+ * {OpenLayers.Control.TYPES}
+ */
+ type: OpenLayers.Control.TYPE_TOOL,
+
+ /**
+ * Property: panned
+ * {Boolean} The map moved.
+ */
+ panned: false,
+
+ /**
+ * Method: draw
+ * Creates a Drag handler, using <panMap> and
+ * <panMapDone> as callbacks.
+ */
+ draw: function() {
+ this.handler = new OpenLayers.Handler.Drag(this,
+ {"move": this.panMap, "done": this.panMapDone});
+ },
+
+ /**
+ * Method: panMap
+ *
+ * Parameters:
+ * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
+ */
+ panMap: function(xy) {
+ this.panned = true;
+ this.map.pan(
+ this.handler.last.x - xy.x,
+ this.handler.last.y - xy.y,
+ {dragging: this.handler.dragging, animate: false}
+ );
+ },
+
+ /**
+ * Method: panMapDone
+ * Finish the panning operation. Only call setCenter (through <panMap>)
+ * if the map has actually been moved.
+ *
+ * Parameters:
+ * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
+ */
+ panMapDone: function(xy) {
+ if(this.panned) {
+ this.panMap(xy);
+ this.panned = false;
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Control.DragPan"
+});
+/* ======================================================================
+ OpenLayers/Handler/Box.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ * @requires OpenLayers/Handler/Drag.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Box
+ * Handler for dragging a rectangle across the map. Box is displayed
+ * on mouse down, moves on mouse move, and is finished on mouse up.
+ *
+ * Inherits from:
+ * - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, {
+
+ /**
+ * Property: dragHandler
+ * {<OpenLayers.Handler.Drag>}
+ */
+ dragHandler: null,
+
+ /**
+ * APIProperty: boxDivClassName
+ * {String} The CSS class to use for drawing the box. Default is
+ * olHandlerBoxZoomBox
+ */
+ boxDivClassName: 'olHandlerBoxZoomBox',
+
+ /**
+ * Constructor: OpenLayers.Handler.Box
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>}
+ * callbacks - {Object} An object containing a single function to be
+ * called when the drag operation is finished.
+ * The callback should expect to recieve a single
+ * argument, the point geometry.
+ * options - {Object}
+ */
+ initialize: function(control, callbacks, options) {
+ OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+ var callbacks = {
+ "down": this.startBox,
+ "move": this.moveBox,
+ "out": this.removeBox,
+ "up": this.endBox
+ };
+ this.dragHandler = new OpenLayers.Handler.Drag(
+ this, callbacks, {keyMask: this.keyMask});
+ },
+
+ /**
+ * Method: setMap
+ */
+ setMap: function (map) {
+ OpenLayers.Handler.prototype.setMap.apply(this, arguments);
+ if (this.dragHandler) {
+ this.dragHandler.setMap(map);
+ }
+ },
+
+ /**
+ * Method: startBox
+ *
+ * Parameters:
+ * evt - {Event}
+ */
+ startBox: function (xy) {
+ this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
+ this.dragHandler.start);
+ this.zoomBox.className = this.boxDivClassName;
+ this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
+ this.map.viewPortDiv.appendChild(this.zoomBox);
+
+ // TBD: use CSS classes instead
+ this.map.div.style.cursor = "crosshair";
+ },
+
+ /**
+ * Method: moveBox
+ */
+ moveBox: function (xy) {
+ var deltaX = Math.abs(this.dragHandler.start.x - xy.x);
+ var deltaY = Math.abs(this.dragHandler.start.y - xy.y);
+ this.zoomBox.style.width = Math.max(1, deltaX) + "px";
+ this.zoomBox.style.height = Math.max(1, deltaY) + "px";
+ if (xy.x < this.dragHandler.start.x) {
+ this.zoomBox.style.left = xy.x+"px";
+ }
+ if (xy.y < this.dragHandler.start.y) {
+ this.zoomBox.style.top = xy.y+"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();
+
+ // TBD: use CSS classes instead
+ this.map.div.style.cursor = "";
+
+ 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;
+ },
+
+ /**
+ * Method: activate
+ */
+ activate: function () {
+ if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+ this.dragHandler.activate();
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Method: deactivate
+ */
+ deactivate: function () {
+ if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+ this.dragHandler.deactivate();
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.Box"
+});
+/* ======================================================================
+ OpenLayers/Layer/HTTPRequest.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.HTTPRequest
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer>
+ */
+OpenLayers.Layer.HTTPRequest = OpenLayers.Class(OpenLayers.Layer, {
+
+ /**
+ * Constant: URL_HASH_FACTOR
+ * {Float} Used to hash URL param strings for multi-WMS server selection.
+ * Set to the Golden Ratio per Knuth's recommendation.
+ */
+ URL_HASH_FACTOR: (Math.sqrt(5) - 1) / 2,
+
+ /**
+ * Property: url
+ * {Array(String) or String} This is either an array of url strings or
+ * a single url string.
+ */
+ url: null,
+
+ /**
+ * Property: params
+ * {Object} Hashtable of key/value parameters
+ */
+ params: null,
+
+ /**
+ * APIProperty: reproject
+ * *Deprecated*. See http://trac.openlayers.org/wiki/SpatialMercator
+ * for information on the replacement for this functionality.
+ * {Boolean} Whether layer should reproject itself based on base layer
+ * locations. This allows reprojection onto commercial layers.
+ * Default is false: Most layers can't reproject, but layers
+ * which can create non-square geographic pixels can, like WMS.
+ *
+ */
+ reproject: false,
+
+ /**
+ * Constructor: OpenLayers.Layer.HTTPRequest
+ *
+ * Parameters:
+ * name - {String}
+ * url - {Array(String) or String}
+ * params - {Object}
+ * options - {Object} Hashtable of extra options to tag onto the layer
+ */
+ initialize: function(name, url, params, options) {
+ var newArguments = arguments;
+ newArguments = [name, options];
+ OpenLayers.Layer.prototype.initialize.apply(this, newArguments);
+ this.url = url;
+ this.params = OpenLayers.Util.extend( {}, params);
+ },
+
+ /**
+ * APIMethod: destroy
+ */
+ destroy: function() {
+ this.url = null;
+ this.params = null;
+ OpenLayers.Layer.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * APIMethod: clone
+ *
+ * Parameters:
+ * obj - {Object}
+ *
+ * Returns:
+ * {<OpenLayers.Layer.HTTPRequest>} An exact clone of this
+ * <OpenLayers.Layer.HTTPRequest>
+ */
+ clone: function (obj) {
+
+ if (obj == null) {
+ obj = new OpenLayers.Layer.HTTPRequest(this.name,
+ this.url,
+ this.params,
+ this.options);
+ }
+
+ //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);
+ return this.redraw();
+ },
+
+ /**
+ * 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; i < paramString.length; i++) {
+ product *= paramString.charCodeAt(i) * this.URL_HASH_FACTOR;
+ product -= Math.floor(product);
+ }
+ return urls[Math.floor(product * urls.length)];
+ },
+
+ /**
+ * Method: getFullRequestString
+ * Combine url with layer's params and these newParams.
+ *
+ * does checking on the serverPath variable, allowing for cases when it
+ * is supplied with trailing ? or &, as well as cases where not.
+ *
+ * return in formatted string like this:
+ * "server?key1=value1&key2=value2&key3=value3"
+ *
+ * WARNING: The altUrl parameter is deprecated and will be removed in 3.0.
+ *
+ * Parameters:
+ * newParams - {Object}
+ * altUrl - {String} Use this as the url instead of the layer's url
+ *
+ * Returns:
+ * {String}
+ */
+ getFullRequestString:function(newParams, altUrl) {
+
+ // if not altUrl passed in, use layer's url
+ var url = altUrl || this.url;
+
+ // create a new params hashtable with all the layer params and the
+ // new params together. then convert to string
+ var allParams = OpenLayers.Util.extend({}, this.params);
+ allParams = OpenLayers.Util.extend(allParams, newParams);
+ var paramsString = OpenLayers.Util.getParameterString(allParams);
+
+ // if url is not a string, it should be an array of strings,
+ // in which case we will deterministically select one of them in
+ // order to evenly distribute requests to different urls.
+ //
+ if (url instanceof Array) {
+ url = this.selectUrl(paramsString, url);
+ }
+
+ // ignore parameters that are already in the url search string
+ var urlParams =
+ OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));
+ for(var key in allParams) {
+ if(key.toUpperCase() in urlParams) {
+ delete allParams[key];
+ }
+ }
+ paramsString = OpenLayers.Util.getParameterString(allParams);
+
+ // requestString always starts with url
+ var requestString = url;
+
+ if (paramsString != "") {
+ var lastServerChar = url.charAt(url.length - 1);
+ if ((lastServerChar == "&") || (lastServerChar == "?")) {
+ requestString += paramsString;
+ } else {
+ if (url.indexOf('?') == -1) {
+ //serverPath has no ? -- add one
+ requestString += '?' + paramsString;
+ } else {
+ //serverPath contains ?, so must already have
+ // paramsString at the end
+ requestString += '&' + paramsString;
+ }
+ }
+ }
+ return requestString;
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.HTTPRequest"
+});
+/* ======================================================================
+ OpenLayers/Control/ZoomBox.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Handler/Box.js
+ */
+
+/**
+ * Class: OpenLayers.Control.ZoomBox
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, {
+ /**
+ * Property: type
+ * {OpenLayers.Control.TYPE}
+ */
+ type: OpenLayers.Control.TYPE_TOOL,
+
+ /**
+ * Property: out
+ * {Boolean} Should the control be used for zooming out?
+ */
+ out: false,
+
+ /**
+ * Method: draw
+ */
+ draw: function() {
+ this.handler = new OpenLayers.Handler.Box( this,
+ {done: this.zoomBox}, {keyMask: this.keyMask} );
+ },
+
+ /**
+ * Method: zoomBox
+ *
+ * Parameters:
+ * position - {<OpenLayers.Bounds>} or {<OpenLayers.Pixel>}
+ */
+ zoomBox: function (position) {
+ if (position instanceof OpenLayers.Bounds) {
+ if (!this.out) {
+ var minXY = this.map.getLonLatFromPixel(
+ new OpenLayers.Pixel(position.left, position.bottom));
+ var maxXY = this.map.getLonLatFromPixel(
+ new OpenLayers.Pixel(position.right, position.top));
+ var 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;
+ var bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax);
+ }
+ this.map.zoomToExtent(bounds);
+ } else { // it's a pixel
+ if (!this.out) {
+ this.map.setCenter(this.map.getLonLatFromPixel(position),
+ this.map.getZoom() + 1);
+ } else {
+ this.map.setCenter(this.map.getLonLatFromPixel(position),
+ this.map.getZoom() - 1);
+ }
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Control.ZoomBox"
+});
+/* ======================================================================
+ OpenLayers/Layer/Grid.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/HTTPRequest.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.Grid
+ * Base class for layers that use a lattice of tiles. Create a new grid
+ * layer with the <OpenLayers.Layer.Grid> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer.HTTPRequest>
+ */
+OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
+
+ /**
+ * APIProperty: tileSize
+ * {<OpenLayers.Size>}
+ */
+ tileSize: null,
+
+ /**
+ * Property: grid
+ * {Array(Array(<OpenLayers.Tile>))} This is an array of rows, each row is
+ * an array of tiles.
+ */
+ grid: null,
+
+ /**
+ * APIProperty: singleTile
+ * {Boolean} Moves the layer into single-tile mode, meaning that one tile
+ * will be loaded. The tile's size will be determined by the 'ratio'
+ * property. When the tile is dragged such that it does not cover the
+ * entire viewport, it is reloaded.
+ */
+ singleTile: false,
+
+ /** APIProperty: ratio
+ * {Float} Used only when in single-tile mode, this specifies the
+ * ratio of the size of the single tile to the size of the map.
+ */
+ ratio: 1.5,
+
+ /**
+ * APIProperty: buffer
+ * {Integer} Used only when in gridded mode, this specifies the number of
+ * extra rows and colums of tiles on each side which will
+ * surround the minimum grid tiles to cover the map.
+ */
+ buffer: 2,
+
+ /**
+ * APIProperty: numLoadingTiles
+ * {Integer} How many tiles are still loading?
+ */
+ numLoadingTiles: 0,
+
+ /**
+ * Constructor: OpenLayers.Layer.Grid
+ * Create a new grid layer
+ *
+ * Parameters:
+ * name - {String}
+ * url - {String}
+ * params - {Object}
+ * options - {Object} Hashtable of extra options to tag onto the layer
+ */
+ initialize: function(name, url, params, options) {
+ OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,
+ arguments);
+
+ //grid layers will trigger 'tileloaded' when each new tile is
+ // loaded, as a means of progress update to listeners.
+ // listeners can access 'numLoadingTiles' if they wish to keep track
+ // of the loading progress
+ //
+ this.events.addEventType("tileloaded");
+
+ this.grid = [];
+ },
+
+ /**
+ * APIMethod: destroy
+ * Deconstruct the layer and clear the grid.
+ */
+ destroy: function() {
+ this.clearGrid();
+ this.grid = null;
+ this.tileSize = null;
+ OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: clearGrid
+ * Go through and remove all tiles from the grid, calling
+ * destroy() on each of them to kill circular references
+ */
+ clearGrid:function() {
+ if (this.grid) {
+ for(var iRow=0; iRow < this.grid.length; iRow++) {
+ var row = this.grid[iRow];
+ for(var iCol=0; iCol < row.length; iCol++) {
+ var tile = row[iCol];
+ this.removeTileMonitoringHooks(tile);
+ tile.destroy();
+ }
+ }
+ this.grid = [];
+ }
+ },
+
+ /**
+ * APIMethod: clone
+ * Create a clone of this layer
+ *
+ * Parameters:
+ * obj - {Object} Is this ever used?
+ *
+ * Returns:
+ * {<OpenLayers.Layer.Grid>} An exact clone of this OpenLayers.Layer.Grid
+ */
+ clone: function (obj) {
+
+ if (obj == null) {
+ obj = new OpenLayers.Layer.Grid(this.name,
+ this.url,
+ this.params,
+ this.options);
+ }
+
+ //get all additions from superclasses
+ obj = OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this, [obj]);
+
+ // copy/set any non-init, non-simple values here
+ if (this.tileSize != null) {
+ obj.tileSize = this.tileSize.clone();
+ }
+
+ // we do not want to copy reference to grid, so we make a new array
+ obj.grid = [];
+
+ return obj;
+ },
+
+ /**
+ * Method: moveTo
+ * This function is called whenever the map is moved. All the moving
+ * of actual 'tiles' is done by the map, but moveTo's role is to accept
+ * a bounds and make sure the data that that bounds requires is pre-loaded.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * zoomChanged - {Boolean}
+ * dragging - {Boolean}
+ */
+ moveTo:function(bounds, zoomChanged, dragging) {
+ OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this, arguments);
+
+ bounds = bounds || this.map.getExtent();
+
+ if (bounds != null) {
+
+ // if grid is empty or zoom has changed, we *must* re-tile
+ var forceReTile = !this.grid.length || zoomChanged;
+
+ // total bounds of the tiles
+ var tilesBounds = this.getTilesBounds();
+
+ if (this.singleTile) {
+
+ // We want to redraw whenever even the slightest part of the
+ // current bounds is not contained by our tile.
+ // (thus, we do not specify partial -- its default is false)
+ if ( forceReTile ||
+ (!dragging && !tilesBounds.containsBounds(bounds))) {
+ this.initSingleTile(bounds);
+ }
+ } else {
+
+ // if the bounds have changed such that they are not even
+ // *partially* contained by our tiles (IE user has
+ // programmatically panned to the other side of the earth)
+ // then we want to reTile (thus, partial true).
+ //
+ if (forceReTile || !tilesBounds.containsBounds(bounds, true)) {
+ this.initGriddedTiles(bounds);
+ } else {
+ //we might have to shift our buffer tiles
+ this.moveGriddedTiles(bounds);
+ }
+ }
+ }
+ },
+
+ /**
+ * APIMethod: setTileSize
+ * Check if we are in singleTile mode and if so, set the size as a ratio
+ * of the map size (as specified by the layer's 'ratio' property).
+ *
+ * Parameters:
+ * size - {<OpenLayers.Size>}
+ */
+ setTileSize: function(size) {
+ if (this.singleTile) {
+ size = this.map.getSize().clone();
+ size.h = parseInt(size.h * this.ratio);
+ size.w = parseInt(size.w * this.ratio);
+ }
+ OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this, [size]);
+ },
+
+ /**
+ * Method: getGridBounds
+ * Deprecated. This function will be removed in 3.0. Please use
+ * getTilesBounds() instead.
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
+ * currently loaded tiles (including those partially or not at all seen
+ * onscreen)
+ */
+ getGridBounds: function() {
+ var msg = "The getGridBounds() function is deprecated. It will be " +
+ "removed in 3.0. Please use getTilesBounds() instead.";
+ OpenLayers.Console.warn(msg);
+ return this.getTilesBounds();
+ },
+
+ /**
+ * APIMethod: getTilesBounds
+ * Return the bounds of the tile grid.
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
+ * currently loaded tiles (including those partially or not at all seen
+ * onscreen).
+ */
+ getTilesBounds: function() {
+ var bounds = null;
+
+ if (this.grid.length) {
+ var bottom = this.grid.length - 1;
+ var bottomLeftTile = this.grid[bottom][0];
+
+ var right = this.grid[0].length - 1;
+ var topRightTile = this.grid[0][right];
+
+ bounds = new OpenLayers.Bounds(bottomLeftTile.bounds.left,
+ bottomLeftTile.bounds.bottom,
+ topRightTile.bounds.right,
+ topRightTile.bounds.top);
+
+ }
+ return bounds;
+ },
+
+ /**
+ * Method: initSingleTile
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ */
+ initSingleTile: function(bounds) {
+
+ //determine new tile bounds
+ var center = bounds.getCenterLonLat();
+ var tileWidth = bounds.getWidth() * this.ratio;
+ var tileHeight = bounds.getHeight() * this.ratio;
+
+ var tileBounds =
+ new OpenLayers.Bounds(center.lon - (tileWidth/2),
+ center.lat - (tileHeight/2),
+ center.lon + (tileWidth/2),
+ center.lat + (tileHeight/2));
+
+ var ul = new OpenLayers.LonLat(tileBounds.left, tileBounds.top);
+ var px = this.map.getLayerPxFromLonLat(ul);
+
+ if (!this.grid.length) {
+ this.grid[0] = [];
+ }
+
+ var tile = this.grid[0][0];
+ if (!tile) {
+ tile = this.addTile(tileBounds, px);
+
+ this.addTileMonitoringHooks(tile);
+ tile.draw();
+ this.grid[0][0] = tile;
+ } else {
+ tile.moveTo(tileBounds, px);
+ }
+
+ //remove all but our single tile
+ this.removeExcessTiles(1,1);
+ },
+
+ /**
+ * Method: calculateGridLayout
+ * Generate parameters for the grid layout. This
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bound>}
+ * extent - {<OpenLayers.Bounds>}
+ * resolution - {Number}
+ *
+ * Returns:
+ * Object containing properties tilelon, tilelat, tileoffsetlat,
+ * tileoffsetlat, tileoffsetx, tileoffsety
+ */
+ calculateGridLayout: function(bounds, extent, resolution) {
+ var tilelon = resolution * this.tileSize.w;
+ var tilelat = resolution * this.tileSize.h;
+
+ var offsetlon = bounds.left - extent.left;
+ var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
+ var tilecolremain = offsetlon/tilelon - tilecol;
+ var tileoffsetx = -tilecolremain * this.tileSize.w;
+ var tileoffsetlon = extent.left + tilecol * tilelon;
+
+ var offsetlat = bounds.top - (extent.bottom + tilelat);
+ var tilerow = Math.ceil(offsetlat/tilelat) + this.buffer;
+ var tilerowremain = tilerow - offsetlat/tilelat;
+ var tileoffsety = -tilerowremain * this.tileSize.h;
+ var tileoffsetlat = extent.bottom + tilerow * tilelat;
+
+ return {
+ tilelon: tilelon, tilelat: tilelat,
+ tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
+ tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
+ };
+
+ },
+
+ /**
+ * Method: initGriddedTiles
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ */
+ initGriddedTiles:function(bounds) {
+
+ // work out mininum number of rows and columns; this is the number of
+ // tiles required to cover the viewport plus at least one for panning
+
+ var viewSize = this.map.getSize();
+ var minRows = Math.ceil(viewSize.h/this.tileSize.h) +
+ Math.max(1, 2 * this.buffer);
+ var minCols = Math.ceil(viewSize.w/this.tileSize.w) +
+ Math.max(1, 2 * this.buffer);
+
+ var extent = this.map.getMaxExtent();
+ var resolution = this.map.getResolution();
+
+ var tileLayout = this.calculateGridLayout(bounds, extent, resolution);
+
+ var tileoffsetx = Math.round(tileLayout.tileoffsetx); // heaven help us
+ var tileoffsety = Math.round(tileLayout.tileoffsety);
+
+ var tileoffsetlon = tileLayout.tileoffsetlon;
+ var tileoffsetlat = tileLayout.tileoffsetlat;
+
+ var tilelon = tileLayout.tilelon;
+ var tilelat = tileLayout.tilelat;
+
+ this.origin = new OpenLayers.Pixel(tileoffsetx, tileoffsety);
+
+ var startX = tileoffsetx;
+ var startLon = tileoffsetlon;
+
+ var rowidx = 0;
+
+ var layerContainerDivLeft = parseInt(this.map.layerContainerDiv.style.left);
+ var layerContainerDivTop = parseInt(this.map.layerContainerDiv.style.top);
+
+
+ do {
+ var row = this.grid[rowidx++];
+ if (!row) {
+ row = [];
+ this.grid.push(row);
+ }
+
+ tileoffsetlon = startLon;
+ tileoffsetx = startX;
+ var colidx = 0;
+
+ do {
+ var tileBounds =
+ new OpenLayers.Bounds(tileoffsetlon,
+ tileoffsetlat,
+ tileoffsetlon + tilelon,
+ tileoffsetlat + tilelat);
+
+ var x = tileoffsetx;
+ x -= layerContainerDivLeft;
+
+ var y = tileoffsety;
+ y -= layerContainerDivTop;
+
+ var px = new OpenLayers.Pixel(x, y);
+ var tile = row[colidx++];
+ if (!tile) {
+ tile = this.addTile(tileBounds, px);
+ this.addTileMonitoringHooks(tile);
+ row.push(tile);
+ } else {
+ tile.moveTo(tileBounds, px, false);
+ }
+
+ tileoffsetlon += tilelon;
+ tileoffsetx += this.tileSize.w;
+ } while ((tileoffsetlon <= bounds.right + tilelon * this.buffer)
+ || colidx < minCols)
+
+ tileoffsetlat -= tilelat;
+ tileoffsety += this.tileSize.h;
+ } while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer)
+ || rowidx < minRows)
+
+ //shave off exceess rows and colums
+ this.removeExcessTiles(rowidx, colidx);
+
+ //now actually draw the tiles
+ this.spiralTileLoad();
+ },
+
+ /**
+ * Method: spiralTileLoad
+ * Starts at the top right corner of the grid and proceeds in a spiral
+ * towards the center, adding tiles one at a time to the beginning of a
+ * queue.
+ *
+ * Once all the grid's tiles have been added to the queue, we go back
+ * and iterate through the queue (thus reversing the spiral order from
+ * outside-in to inside-out), calling draw() on each tile.
+ */
+ spiralTileLoad: function() {
+ var tileQueue = [];
+
+ var directions = ["right", "down", "left", "up"];
+
+ var iRow = 0;
+ var iCell = -1;
+ var direction = OpenLayers.Util.indexOf(directions, "right");
+ var directionsTried = 0;
+
+ while( directionsTried < directions.length) {
+
+ var testRow = iRow;
+ var testCell = iCell;
+
+ switch (directions[direction]) {
+ case "right":
+ testCell++;
+ break;
+ case "down":
+ testRow++;
+ break;
+ case "left":
+ testCell--;
+ break;
+ case "up":
+ testRow--;
+ break;
+ }
+
+ // if the test grid coordinates are within the bounds of the
+ // grid, get a reference to the tile.
+ var tile = null;
+ if ((testRow < this.grid.length) && (testRow >= 0) &&
+ (testCell < this.grid[0].length) && (testCell >= 0)) {
+ tile = this.grid[testRow][testCell];
+ }
+
+ if ((tile != null) && (!tile.queued)) {
+ //add tile to beginning of queue, mark it as queued.
+ tileQueue.unshift(tile);
+ tile.queued = true;
+
+ //restart the directions counter and take on the new coords
+ directionsTried = 0;
+ iRow = testRow;
+ iCell = testCell;
+ } else {
+ //need to try to load a tile in a different direction
+ direction = (direction + 1) % 4;
+ directionsTried++;
+ }
+ }
+
+ // now we go through and draw the tiles in forward order
+ for(var i=0; i < tileQueue.length; i++) {
+ var tile = tileQueue[i];
+ tile.draw();
+ //mark tile as unqueued for the next time (since tiles are reused)
+ tile.queued = false;
+ }
+ },
+
+ /**
+ * APIMethod: addTile
+ * Gives subclasses of Grid the opportunity to create an
+ * OpenLayer.Tile of their choosing. The implementer should initialize
+ * the new tile and take whatever steps necessary to display it.
+ *
+ * Parameters
+ * bounds - {<OpenLayers.Bounds>}
+ * position - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Tile>} The added OpenLayers.Tile
+ */
+ addTile:function(bounds, position) {
+ // Should be implemented by subclasses
+ },
+
+ /**
+ * Method: addTileMonitoringHooks
+ * This function takes a tile as input and adds the appropriate hooks to
+ * the tile so that the layer can keep track of the loading tiles.
+ *
+ * Parameters:
+ * tile - {<OpenLayers.Tile>}
+ */
+ addTileMonitoringHooks: function(tile) {
+
+ tile.onLoadStart = function() {
+ //if that was first tile then trigger a 'loadstart' on the layer
+ if (this.numLoadingTiles == 0) {
+ this.events.triggerEvent("loadstart");
+ }
+ this.numLoadingTiles++;
+ };
+ tile.events.register("loadstart", this, tile.onLoadStart);
+
+ tile.onLoadEnd = function() {
+ this.numLoadingTiles--;
+ this.events.triggerEvent("tileloaded");
+ //if that was the last tile, then trigger a 'loadend' on the layer
+ if (this.numLoadingTiles == 0) {
+ this.events.triggerEvent("loadend");
+ }
+ };
+ tile.events.register("loadend", this, tile.onLoadEnd);
+ tile.events.register("unload", this, tile.onLoadEnd);
+ },
+
+ /**
+ * Method: removeTileMonitoringHooks
+ * This function takes a tile as input and removes the tile hooks
+ * that were added in addTileMonitoringHooks()
+ *
+ * Parameters:
+ * tile - {<OpenLayers.Tile>}
+ */
+ removeTileMonitoringHooks: function(tile) {
+ tile.unload();
+ tile.events.un({
+ "loadstart": tile.onLoadStart,
+ "loadend": tile.onLoadEnd,
+ "unload": tile.onLoadEnd,
+ scope: this
+ });
+ },
+
+ /**
+ * Method: moveGriddedTiles
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ */
+ moveGriddedTiles: function(bounds) {
+ var buffer = this.buffer || 1;
+ while (true) {
+ var tlLayer = this.grid[0][0].position;
+ var tlViewPort =
+ this.map.getViewPortPxFromLayerPx(tlLayer);
+ if (tlViewPort.x > -this.tileSize.w * (buffer - 1)) {
+ this.shiftColumn(true);
+ } else if (tlViewPort.x < -this.tileSize.w * buffer) {
+ this.shiftColumn(false);
+ } else if (tlViewPort.y > -this.tileSize.h * (buffer - 1)) {
+ this.shiftRow(true);
+ } else if (tlViewPort.y < -this.tileSize.h * buffer) {
+ this.shiftRow(false);
+ } else {
+ break;
+ }
+ };
+ },
+
+ /**
+ * Method: shiftRow
+ * Shifty grid work
+ *
+ * Parameters:
+ * prepend - {Boolean} if true, prepend to beginning.
+ * if false, then append to end
+ */
+ shiftRow:function(prepend) {
+ var modelRowIndex = (prepend) ? 0 : (this.grid.length - 1);
+ var grid = this.grid;
+ var modelRow = grid[modelRowIndex];
+
+ var resolution = this.map.getResolution();
+ var deltaY = (prepend) ? -this.tileSize.h : this.tileSize.h;
+ var deltaLat = resolution * -deltaY;
+
+ var row = (prepend) ? grid.pop() : grid.shift();
+
+ for (var i=0; i < modelRow.length; i++) {
+ var modelTile = modelRow[i];
+ var bounds = modelTile.bounds.clone();
+ var position = modelTile.position.clone();
+ bounds.bottom = bounds.bottom + deltaLat;
+ bounds.top = bounds.top + deltaLat;
+ position.y = position.y + deltaY;
+ row[i].moveTo(bounds, position);
+ }
+
+ if (prepend) {
+ grid.unshift(row);
+ } else {
+ grid.push(row);
+ }
+ },
+
+ /**
+ * Method: shiftColumn
+ * Shift grid work in the other dimension
+ *
+ * Parameters:
+ * prepend - {Boolean} if true, prepend to beginning.
+ * if false, then append to end
+ */
+ shiftColumn: function(prepend) {
+ var deltaX = (prepend) ? -this.tileSize.w : this.tileSize.w;
+ var resolution = this.map.getResolution();
+ var deltaLon = resolution * deltaX;
+
+ for (var i=0; i<this.grid.length; i++) {
+ var row = this.grid[i];
+ var modelTileIndex = (prepend) ? 0 : (row.length - 1);
+ var modelTile = row[modelTileIndex];
+
+ var bounds = modelTile.bounds.clone();
+ var position = modelTile.position.clone();
+ bounds.left = bounds.left + deltaLon;
+ bounds.right = bounds.right + deltaLon;
+ position.x = position.x + deltaX;
+
+ var tile = prepend ? this.grid[i].pop() : this.grid[i].shift();
+ tile.moveTo(bounds, position);
+ if (prepend) {
+ row.unshift(tile);
+ } else {
+ row.push(tile);
+ }
+ }
+ },
+
+ /**
+ * Method: removeExcessTiles
+ * When the size of the map or the buffer changes, we may need to
+ * remove some excess rows and columns.
+ *
+ * Parameters:
+ * rows - {Integer} Maximum number of rows we want our grid to have.
+ * colums - {Integer} Maximum number of columns we want our grid to have.
+ */
+ removeExcessTiles: function(rows, columns) {
+
+ // remove extra rows
+ while (this.grid.length > rows) {
+ var row = this.grid.pop();
+ for (var i=0, l=row.length; i<l; i++) {
+ var tile = row[i];
+ this.removeTileMonitoringHooks(tile);
+ tile.destroy();
+ }
+ }
+
+ // remove extra columns
+ while (this.grid[0].length > columns) {
+ for (var i=0, l=this.grid.length; i<l; i++) {
+ var row = this.grid[i];
+ var tile = row.pop();
+ this.removeTileMonitoringHooks(tile);
+ tile.destroy();
+ }
+ }
+ },
+
+ /**
+ * Method: onMapResize
+ * For singleTile layers, this will set a new tile size according to the
+ * dimensions of the map pane.
+ */
+ onMapResize: function() {
+ if (this.singleTile) {
+ this.clearGrid();
+ this.setTileSize();
+ }
+ },
+
+ /**
+ * APIMethod: getTileBounds
+ * Returns The tile bounds for a layer given a pixel location.
+ *
+ * Parameters:
+ * viewPortPx - {<OpenLayers.Pixel>} The location in the viewport.
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} Bounds of the tile at the given pixel location.
+ */
+ getTileBounds: function(viewPortPx) {
+ var maxExtent = this.map.getMaxExtent();
+ 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/Control/Navigation.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control/ZoomBox.js
+ * @requires OpenLayers/Control/DragPan.js
+ * @requires OpenLayers/Handler/MouseWheel.js
+ * @requires OpenLayers/Handler/Click.js
+ */
+
+/**
+ * Class: OpenLayers.Control.Navigation
+ * The navigation control handles map browsing with mouse events (dragging,
+ * double-clicking, and scrolling the wheel). Create a new navigation
+ * control with the <OpenLayers.Control.Navigation> control.
+ *
+ * Note that this control is added to the map by default (if no controls
+ * array is sent in the options object to the <OpenLayers.Map>
+ * constructor).
+ *
+ * Inherits:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Property: dragPan
+ * {<OpenLayers.Control.DragPan>}
+ */
+ dragPan: null,
+
+ /**
+ * Property: zoomBox
+ * {<OpenLayers.Control.ZoomBox>}
+ */
+ zoomBox: null,
+
+ /**
+ * APIProperty: zoomWheelEnabled
+ * {Boolean} Whether the mousewheel should zoom the map
+ */
+ zoomWheelEnabled: true,
+
+ /**
+ * Constructor: OpenLayers.Control.Navigation
+ * Create a new navigation control
+ *
+ * Parameters:
+ * options - {Object} An optional object whose properties will be set on
+ * the control
+ */
+ initialize: function(options) {
+ this.handlers = {};
+ OpenLayers.Control.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * Method: destroy
+ * The destroy method is used to perform any clean up before the control
+ * is dereferenced. Typically this is where event listeners are removed
+ * to prevent memory leaks.
+ */
+ destroy: function() {
+ this.deactivate();
+
+ if (this.dragPan) {
+ this.dragPan.destroy();
+ }
+ this.dragPan = null;
+
+ if (this.zoomBox) {
+ this.zoomBox.destroy();
+ }
+ this.zoomBox = null;
+ OpenLayers.Control.prototype.destroy.apply(this,arguments);
+ },
+
+ /**
+ * Method: activate
+ */
+ activate: function() {
+ this.dragPan.activate();
+ if (this.zoomWheelEnabled) {
+ this.handlers.wheel.activate();
+ }
+ this.handlers.click.activate();
+ this.zoomBox.activate();
+ return OpenLayers.Control.prototype.activate.apply(this,arguments);
+ },
+
+ /**
+ * Method: deactivate
+ */
+ deactivate: function() {
+ this.zoomBox.deactivate();
+ this.dragPan.deactivate();
+ this.handlers.click.deactivate();
+ this.handlers.wheel.deactivate();
+ return OpenLayers.Control.prototype.deactivate.apply(this,arguments);
+ },
+
+ /**
+ * Method: draw
+ */
+ draw: function() {
+ this.handlers.click = new OpenLayers.Handler.Click(this,
+ { 'dblclick': this.defaultDblClick },
+ {
+ 'double': true,
+ 'stopDouble': true
+ });
+ this.dragPan = new OpenLayers.Control.DragPan({map: this.map});
+ this.zoomBox = new OpenLayers.Control.ZoomBox(
+ {map: this.map, keyMask: OpenLayers.Handler.MOD_SHIFT});
+ this.dragPan.draw();
+ this.zoomBox.draw();
+ this.handlers.wheel = new OpenLayers.Handler.MouseWheel(
+ this, {"up" : this.wheelUp,
+ "down": this.wheelDown} );
+ this.activate();
+ },
+
+ /**
+ * Method: defaultDblClick
+ *
+ * Parameters:
+ * evt - {Event}
+ */
+ defaultDblClick: function (evt) {
+ var newCenter = this.map.getLonLatFromViewPortPx( evt.xy );
+ this.map.setCenter(newCenter, this.map.zoom + 1);
+ },
+
+ /**
+ * Method: wheelChange
+ *
+ * Parameters:
+ * evt - {Event}
+ * deltaZ - {Integer}
+ */
+ wheelChange: function(evt, deltaZ) {
+ var newZoom = this.map.getZoom() + deltaZ;
+ if (!this.map.isValidZoomLevel(newZoom)) {
+ 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}
+ */
+ wheelUp: function(evt) {
+ this.wheelChange(evt, 1);
+ },
+
+ /**
+ * Method: wheelDown
+ * User spun scroll wheel down
+ *
+ * Parameters:
+ * evt - {Event}
+ */
+ wheelDown: function(evt) {
+ this.wheelChange(evt, -1);
+ },
+
+ /**
+ * 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/MapGuide.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * licence. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Ajax.js
+ * @requires OpenLayers/Layer/Grid.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.MapGuide
+ * Instances of OpenLayers.Layer.MapGuide are used to display
+ * data from a MapGuide OS instance.
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+ /**
+ * APIProperty: isBaseLayer
+ * {Boolean} Treat this layer as a base layer. Default is true.
+ **/
+ isBaseLayer: true,
+
+ /**
+ * APIProperty: singleTile
+ * {Boolean} use tile server or request single tile image. Note that using
+ * singleTile *and* isBaseLayer false is *not recommend*: it uses synchronous
+ * XMLHttpRequests to load tiles, and this will *lock up users browsers*
+ * during requests.
+ **/
+ singleTile: false,
+
+ /**
+ * Constant: TILE_PARAMS
+ * {Object} Hashtable of default parameter key/value pairs for tiled layer
+ */
+ TILE_PARAMS: {
+ operation: 'GETTILEIMAGE',
+ version: '1.2.0'
+ },
+
+ /**
+ * Constant: SINGLE_TILE_PARAMS
+ * {Object} Hashtable of default parameter key/value pairs for untiled layer
+ */
+ SINGLE_TILE_PARAMS: {
+ operation: 'GETMAPIMAGE',
+ format: 'PNG',
+ locale: 'en',
+ clip: '1',
+ version: '1.0.0'
+ },
+
+ /**
+ * Property: defaultSize
+ * {<OpenLayers.Size>} Tile size as produced by MapGuide server
+ **/
+ defaultSize: new OpenLayers.Size(300,300),
+
+ /**
+ * Constructor: OpenLayers.Layer.MapGuide
+ * Create a new Mapguide layer, either tiled or untiled.
+ *
+ * For tiled layers, the 'groupName' and 'mapDefnition' options
+ * must be specified as options.
+ *
+ * For untiled layers, specify either combination of 'mapName' and
+ * 'session', or 'mapDefinition' and 'locale'.
+ *
+ * Parameters:
+ * name - {String} Name of the layer displayed in the interface
+ * url - {String} Location of the MapGuide mapagent executable
+ * (e.g. http://localhost:8008/mapguide/mapagent/mapagent.fcgi)
+ * params - {Object} hashtable of additional parameters to use. Some
+ * parameters may require additional code on the serer. The ones that
+ * you may want to use are:
+ * - mapDefinition - {String} The MapGuide resource definition
+ * (e.g. Library://Samples/Gmap/Maps/gmapTiled.MapDefinition)
+ * - locale - Locale setting
+ * (for untiled overlays layers only)
+ * - mapName - {String} Name of the map as stored in the MapGuide session.
+ * (for untiled layers with a session parameter only)
+ * - session - { String} MapGuide session ID
+ * (for untiled overlays layers only)
+ * - basemaplayergroupname - {String} GroupName for tiled MapGuide layers only
+ * - format - Image format to be returned (for untiled overlay layers only)
+ * - showLayers - {String} A comma separated list of GUID's for the
+ * layers to display eg: 'cvc-xcv34,453-345-345sdf'.
+ * - hideLayers - {String} A comma separated list of GUID's for the
+ * layers to hide eg: 'cvc-xcv34,453-345-345sdf'.
+ * - showGroups - {String} A comma separated list of GUID's for the
+ * groups to display eg: 'cvc-xcv34,453-345-345sdf'.
+ * - hideGroups - {String} A comma separated list of GUID's for the
+ * groups to hide eg: 'cvc-xcv34,453-345-345sdf'
+ * - selectionXml - {String} A selection xml string Some server plumbing
+ * is required to read such a value.
+ * options - {Ojbect} Hashtable of extra options to tag onto the layer;
+ * will vary depending if tiled or untiled maps are being requested
+ */
+ initialize: function(name, url, params, options) {
+
+ OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments);
+
+ // unless explicitly set in options, if the layer is transparent,
+ // it will be an overlay
+ if (options == null || options.isBaseLayer == null) {
+ this.isBaseLayer = ((this.transparent != "true") &&
+ (this.transparent != true));
+ }
+
+ //initialize for untiled layers
+ if (this.singleTile) {
+ OpenLayers.Util.applyDefaults(
+ this.params,
+ this.SINGLE_TILE_PARAMS
+ );
+ } else {
+ //initialize for tiled layers
+ OpenLayers.Util.applyDefaults(
+ this.params,
+ this.TILE_PARAMS
+ );
+ this.setTileSize(this.defaultSize);
+ }
+ },
+
+ /**
+ * Method: clone
+ * Create a clone of this layer
+ *
+ * Returns:
+ * {<OpenLayers.Layer.MapGuide>} An exact clone of this layer
+ */
+ clone: function (obj) {
+ if (obj == null) {
+ obj = new OpenLayers.Layer.MapGuide(this.name,
+ this.url,
+ this.params,
+ this.options);
+ }
+ //get all additions from superclasses
+ obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+ return obj;
+ },
+
+ /**
+ * Method: addTile
+ * Creates a tile, initializes it, and adds it to the layer div.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * position - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+ */
+ addTile:function(bounds,position) {
+ return new OpenLayers.Tile.Image(this, position, bounds,
+ null, this.tileSize);
+ },
+
+ /**
+ * Method: getURL
+ * Return a query string for this layer
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox
+ * for the request
+ *
+ * Returns:
+ * {String} A string with the layer's url and parameters and also
+ * the passed-in bounds and appropriate tile size specified
+ * as parameters.
+ */
+ getURL: function (bounds) {
+ var url;
+ var center = bounds.getCenterLonLat();
+ var mapSize = this.map.getCurrentSize();
+
+ if (this.singleTile) {
+ //set up the call for GETMAPIMAGE or GETDYNAMICMAPOVERLAY
+ var params = {};
+ params.setdisplaydpi = OpenLayers.DOTS_PER_INCH;
+ params.setdisplayheight = mapSize.h*this.ratio;
+ params.setdisplaywidth = mapSize.w*this.ratio;
+ params.setviewcenterx = center.lon;
+ params.setviewcentery = center.lat;
+ params.setviewscale = this.map.getScale();
+
+ if (!this.isBaseLayer) {
+ // in this case the main image operation is remapped to this
+ this.params.operation = "GETDYNAMICMAPOVERLAYIMAGE";
+
+ //but we first need to call GETVISIBLEMAPEXTENT to set the extent
+ var getVisParams = {};
+ getVisParams.operation = "GETVISIBLEMAPEXTENT";
+ getVisParams.version = "1.0.0";
+ getVisParams.session = this.params.session;
+ getVisParams.mapName = this.params.mapName;
+ getVisParams.format = 'text/xml';
+ getVisParams = OpenLayers.Util.extend(getVisParams, params);
+
+ new OpenLayers.Ajax.Request(this.url,
+ { parameters: getVisParams,
+ method: 'get',
+ asynchronous: false //must be synchronous call to return control here
+ });
+ }
+
+ //construct the full URL
+ url = this.getFullRequestString( params );
+ } else {
+
+ //tiled version
+ var currentRes = this.map.getResolution();
+ var colidx = Math.floor((bounds.left-this.maxExtent.left)/currentRes);
+ colidx = Math.round(colidx/this.tileSize.w);
+ var rowidx = Math.floor((this.maxExtent.top-bounds.top)/currentRes);
+ rowidx = Math.round(rowidx/this.tileSize.h);
+
+ url = this.getFullRequestString(
+ {
+ tilecol: colidx,
+ tilerow: rowidx,
+ scaleindex: this.resolutions.length - this.map.zoom - 1
+ });
+ }
+
+ return url;
+ },
+
+ /**
+ * Method: getFullRequestString
+ * getFullRequestString on MapGuide layers is special, because we
+ * do a regular expression replace on ',' in parameters to '+'.
+ * This is why it is subclassed here.
+ *
+ * Parameters:
+ * altUrl - {String} Alternative base URL to use.
+ *
+ * Returns:
+ * {String} A string with the layer's url appropriately encoded for MapGuide
+ */
+ getFullRequestString:function(newParams, altUrl) {
+ // use layer's url unless altUrl passed in
+ var url = (altUrl == null) ? this.url : altUrl;
+
+ // if url is not a string, it should be an array of strings,
+ // in which case we will randomly select one of them in order
+ // to evenly distribute requests to different urls.
+ if (typeof url == "object") {
+ url = url[Math.floor(Math.random()*url.length)];
+ }
+ // requestString always starts with url
+ var requestString = url;
+
+ // create a new params hashtable with all the layer params and the
+ // new params together. then convert to string
+ var allParams = OpenLayers.Util.extend({}, this.params);
+ allParams = OpenLayers.Util.extend(allParams, newParams);
+ // ignore parameters that are already in the url search string
+ var urlParams = OpenLayers.Util.upperCaseObject(
+ OpenLayers.Util.getArgs(url));
+ for(var key in allParams) {
+ if(key.toUpperCase() in urlParams) {
+ delete allParams[key];
+ }
+ }
+ var paramsString = OpenLayers.Util.getParameterString(allParams);
+
+ /* MapGuide needs '+' seperating things like bounds/height/width.
+ Since typically this is URL encoded, we use a slight hack: we
+ depend on the list-like functionality of getParameterString to
+ leave ',' only in the case of list items (since otherwise it is
+ encoded) then do a regular expression replace on the , characters
+ to '+' */
+ paramsString = paramsString.replace(/,/g, "+");
+
+ if (paramsString != "") {
+ var lastServerChar = url.charAt(url.length - 1);
+ if ((lastServerChar == "&") || (lastServerChar == "?")) {
+ requestString += paramsString;
+ } else {
+ if (url.indexOf('?') == -1) {
+ //serverPath has no ? -- add one
+ requestString += '?' + paramsString;
+ } else {
+ //serverPath contains ?, so must already have paramsString at the end
+ requestString += '&' + paramsString;
+ }
+ }
+ }
+ return requestString;
+ },
+
+ /**
+ * Method: calculateGridLayout
+ * Generate parameters for the grid layout. This
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bound>}
+ * extent - {<OpenLayers.Bounds>}
+ * resolution - {Number}
+ *
+ * Returns:
+ * Object containing properties tilelon, tilelat, tileoffsetlat,
+ * tileoffsetlat, tileoffsetx, tileoffsety
+ */
+ calculateGridLayout: function(bounds, extent, resolution) {
+ var tilelon = resolution * this.tileSize.w;
+ var tilelat = resolution * this.tileSize.h;
+
+ var offsetlon = bounds.left - extent.left;
+ var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
+ var tilecolremain = offsetlon/tilelon - tilecol;
+ var tileoffsetx = -tilecolremain * this.tileSize.w;
+ var tileoffsetlon = extent.left + tilecol * tilelon;
+
+ var offsetlat = extent.top - bounds.top + tilelat;
+ var tilerow = Math.floor(offsetlat/tilelat) - this.buffer;
+ var tilerowremain = tilerow - offsetlat/tilelat;
+ var tileoffsety = tilerowremain * this.tileSize.h;
+ var tileoffsetlat = extent.top - tilelat*tilerow;
+
+ return {
+ tilelon: tilelon, tilelat: tilelat,
+ tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
+ tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
+ };
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.MapGuide"
+});
+/* ======================================================================
+ OpenLayers/Layer/MapServer.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.MapServer
+ * Instances of OpenLayers.Layer.MapServer are used to display
+ * data from a MapServer CGI instance.
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.MapServer = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+ /**
+ * Constant: DEFAULT_PARAMS
+ * {Object} Hashtable of default parameter key/value pairs
+ */
+ DEFAULT_PARAMS: {
+ mode: "map",
+ map_imagetype: "png"
+ },
+
+ /**
+ * Constructor: OpenLayers.Layer.MapServer
+ * Create a new MapServer layer object
+ *
+ * Parameters:
+ * name - {String} A name for the layer
+ * url - {String} Base url for the MapServer CGI
+ * (e.g. http://www2.dmsolutions.ca/cgi-bin/mapserv)
+ * params - {Object} An object with key/value pairs representing the
+ * GetMap query string parameters and parameter values.
+ * options - {Ojbect} Hashtable of extra options to tag onto the layer
+ */
+ initialize: function(name, url, params, options) {
+ var newArguments = [];
+ newArguments.push(name, url, params, options);
+ OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
+
+ if (arguments.length > 0) {
+ OpenLayers.Util.applyDefaults(
+ this.params,
+ this.DEFAULT_PARAMS
+ );
+ }
+
+ // unless explicitly set in options, if the layer is transparent,
+ // it will be an overlay
+ if (options == null || options.isBaseLayer == null) {
+ this.isBaseLayer = ((this.params.transparent != "true") &&
+ (this.params.transparent != true));
+ }
+ },
+
+ /**
+ * Method: clone
+ * Create a clone of this layer
+ *
+ * Returns:
+ * {<OpenLayers.Layer.MapServer>} An exact clone of this layer
+ */
+ clone: function (obj) {
+ if (obj == null) {
+ obj = new OpenLayers.Layer.MapServer(this.name,
+ this.url,
+ this.params,
+ this.options);
+ }
+ //get all additions from superclasses
+ obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+ // copy/set any non-init, non-simple values here
+
+ return obj;
+ },
+
+ /**
+ * Method: addTile
+ * Creates a tile, initializes it, and adds it to the layer div.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * position - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+ */
+ addTile:function(bounds,position) {
+ return new OpenLayers.Tile.Image(this, position, bounds,
+ null, this.tileSize);
+ },
+
+ /**
+ * Method: getURL
+ * Return a query string for this layer
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox
+ * for the request
+ *
+ * Returns:
+ * {String} A string with the layer's url and parameters and also
+ * the passed-in bounds and appropriate tile size specified
+ * as parameters.
+ */
+ getURL: function (bounds) {
+ bounds = this.adjustBounds(bounds);
+ // Make a list, so that getFullRequestString uses literal ","
+ var extent = [bounds.left, bounds. bottom, bounds.right, bounds.top];
+
+ var imageSize = this.getImageSize();
+
+ // make lists, so that literal ','s are used
+ var url = this.getFullRequestString(
+ {mapext: extent,
+ imgext: extent,
+ map_size: [imageSize.w, imageSize.h],
+ imgx: imageSize.w / 2,
+ imgy: imageSize.h / 2,
+ imgxy: [imageSize.w, imageSize.h]
+ });
+
+ return url;
+ },
+
+ /**
+ * Method: getFullRequestString
+ * combine the layer's url with its params and these newParams.
+ *
+ * Parameter:
+ * newParams - {Object} New parameters that should be added to the
+ * request string.
+ * altUrl - {String} (optional) Replace the URL in the full request
+ * string with the provided URL.
+ *
+ * Returns:
+ * {String} A string with the layer's url and parameters embedded in it.
+ */
+ getFullRequestString:function(newParams, altUrl) {
+ // use layer's url unless altUrl passed in
+ var url = (altUrl == null) ? this.url : altUrl;
+
+ // create a new params hashtable with all the layer params and the
+ // new params together. then convert to string
+ var allParams = OpenLayers.Util.extend({}, this.params);
+ allParams = OpenLayers.Util.extend(allParams, newParams);
+ var paramsString = OpenLayers.Util.getParameterString(allParams);
+
+ // if url is not a string, it should be an array of strings,
+ // in which case we will deterministically select one of them in
+ // order to evenly distribute requests to different urls.
+ if (url instanceof Array) {
+ url = this.selectUrl(paramsString, url);
+ }
+
+ // ignore parameters that are already in the url search string
+ var urlParams = OpenLayers.Util.upperCaseObject(
+ OpenLayers.Util.getParameters(url));
+ for(var key in allParams) {
+ if(key.toUpperCase() in urlParams) {
+ delete allParams[key];
+ }
+ }
+ paramsString = OpenLayers.Util.getParameterString(allParams);
+
+ // requestString always starts with url
+ var requestString = url;
+
+ // MapServer needs '+' seperating things like bounds/height/width.
+ // Since typically this is URL encoded, we use a slight hack: we
+ // depend on the list-like functionality of getParameterString to
+ // leave ',' only in the case of list items (since otherwise it is
+ // encoded) then do a regular expression replace on the , characters
+ // to '+'
+ //
+ paramsString = paramsString.replace(/,/g, "+");
+
+ if (paramsString != "") {
+ var lastServerChar = url.charAt(url.length - 1);
+ if ((lastServerChar == "&") || (lastServerChar == "?")) {
+ requestString += paramsString;
+ } else {
+ if (url.indexOf('?') == -1) {
+ //serverPath has no ? -- add one
+ requestString += '?' + paramsString;
+ } else {
+ //serverPath contains ?, so must already have paramsString at the end
+ requestString += '&' + paramsString;
+ }
+ }
+ }
+ return requestString;
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.MapServer"
+});
+/* ======================================================================
+ OpenLayers/Layer/WMS.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ * @requires OpenLayers/Tile/Image.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.WMS
+ * Instances of OpenLayers.Layer.WMS are used to display data from OGC Web
+ * Mapping Services. Create a new WMS layer with the <OpenLayers.Layer.WMS>
+ * constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.WMS = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+ /**
+ * Constant: DEFAULT_PARAMS
+ * {Object} Hashtable of default parameter key/value pairs
+ */
+ DEFAULT_PARAMS: { service: "WMS",
+ version: "1.1.1",
+ request: "GetMap",
+ styles: "",
+ exceptions: "application/vnd.ogc.se_inimage",
+ format: "image/jpeg"
+ },
+
+ /**
+ * Property: reproject
+ * *Deprecated*. See http://trac.openlayers.org/wiki/SphericalMercator
+ * for information on the replacement for this functionality.
+ * {Boolean} Try to reproject this layer if its coordinate reference system
+ * is different than that of the base layer. Default is true.
+ * Set this in the layer options. Should be set to false in
+ * most cases.
+ */
+ reproject: false,
+
+ /**
+ * APIProperty: isBaseLayer
+ * {Boolean} Default is true for WMS layer
+ */
+ isBaseLayer: true,
+
+ /**
+ * APIProperty: encodeBBOX
+ * {Boolean} Should the BBOX commas be encoded? The WMS spec says 'no',
+ * but some services want it that way. Default false.
+ */
+ encodeBBOX: false,
+
+ /**
+ * Constructor: OpenLayers.Layer.WMS
+ * Create a new WMS layer object
+ *
+ * Example:
+ * (code)
+ * var wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
+ * "http://wms.jpl.nasa.gov/wms.cgi",
+ * {layers: "modis,global_mosaic"});
+ * (end)
+ *
+ * Parameters:
+ * name - {String} A name for the layer
+ * url - {String} Base url for the WMS
+ * (e.g. http://wms.jpl.nasa.gov/wms.cgi)
+ * params - {Object} An object with key/value pairs representing the
+ * GetMap query string parameters and parameter values.
+ * options - {Ojbect} Hashtable of extra options to tag onto the layer
+ */
+ initialize: function(name, url, params, options) {
+ var newArguments = [];
+ //uppercase params
+ params = OpenLayers.Util.upperCaseObject(params);
+ 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.params.TRANSPARENT &&
+ this.params.TRANSPARENT.toString().toLowerCase() == "true") {
+
+ // unless explicitly set in options, make layer an overlay
+ if ( (options == null) || (!options.isBaseLayer) ) {
+ this.isBaseLayer = false;
+ }
+
+ // jpegs can never be transparent, so intelligently switch the
+ // format, depending on teh browser's capabilities
+ if (this.params.FORMAT == "image/jpeg") {
+ this.params.FORMAT = OpenLayers.Util.alphaHack() ? "image/gif"
+ : "image/png";
+ }
+ }
+
+ },
+
+ /**
+ * Method: destroy
+ * Destroy this layer
+ */
+ destroy: function() {
+ // for now, nothing special to do here.
+ OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);
+ },
+
+
+ /**
+ * Method: clone
+ * Create a clone of this layer
+ *
+ * Returns:
+ * {<OpenLayers.Layer.WMS>} An exact clone of this layer
+ */
+ clone: function (obj) {
+
+ if (obj == null) {
+ obj = new OpenLayers.Layer.WMS(this.name,
+ this.url,
+ this.params,
+ this.options);
+ }
+
+ //get all additions from superclasses
+ obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+ // copy/set any non-init, non-simple values here
+
+ return obj;
+ },
+
+ /**
+ * Method: getURL
+ * Return a GetMap query string for this layer
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the
+ * request.
+ *
+ * Returns:
+ * {String} A string with the layer's url and parameters and also the
+ * passed-in bounds and appropriate tile size specified as
+ * parameters.
+ */
+ getURL: function (bounds) {
+ bounds = this.adjustBounds(bounds);
+
+ var imageSize = this.getImageSize();
+ var newParams = {
+ 'BBOX': this.encodeBBOX ? bounds.toBBOX() : bounds.toArray(),
+ 'WIDTH': imageSize.w,
+ 'HEIGHT': imageSize.h
+ };
+ var requestString = this.getFullRequestString(newParams);
+ return requestString;
+ },
+
+ /**
+ * Method: addTile
+ * addTile creates a tile, initializes it, and adds it to the layer div.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * position - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+ */
+ addTile:function(bounds,position) {
+ return new OpenLayers.Tile.Image(this, position, bounds,
+ null, this.tileSize);
+ },
+
+ /**
+ * 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, we will need to re-init our tiles.
+ *
+ * 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);
+ },
+
+ /**
+ * Method: getFullRequestString
+ * Combine the layer's url with its params and these newParams.
+ *
+ * Add the SRS parameter from projection -- this is probably
+ * more eloquently done via a setProjection() method, but this
+ * works for now and always.
+ *
+ * Parameters:
+ * newParams - {Object}
+ * altUrl - {String} Use this as the url instead of the layer's url
+ *
+ * Returns:
+ * {String}
+ */
+ getFullRequestString:function(newParams, altUrl) {
+ var projectionCode = this.map.getProjection();
+ this.params.SRS = (projectionCode == "none") ? null : projectionCode;
+
+ return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(
+ this, arguments);
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.WMS"
+});
Modified: sandbox/aboudreault/lib/OpenLayers/OpenLayersCompressed.js
===================================================================
--- sandbox/aboudreault/lib/OpenLayers/OpenLayersCompressed.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/OpenLayers/OpenLayersCompressed.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -2,8 +2,8 @@
OpenLayers.js -- OpenLayers Map Viewer Library
- Copyright 2005-2007 MetaCarta, Inc., released under a modified BSD license.
- Please see http://svn.openlayers.org/trunk/openlayers/repository-license.txt
+ Copyright 2005-2008 MetaCarta, Inc., released under the Clear BSD 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:
@@ -21,7 +21,7 @@
* Prototype is freely distributable under the terms of an MIT-style license.
* For details, see the Prototype web site: http://prototype.conio.net/
*
-/*--------------------------------------------------------------------------*/
+ *--------------------------------------------------------------------------*/
/**
*
@@ -43,410 +43,487 @@
*
**/
-OpenLayers={singleFile:true};(function(){var singleFile=(typeof OpenLayers=="object"&&OpenLayers.singleFile);OpenLayers={_scriptName:(!singleFile)?"lib/OpenLayers.js":"OpenLayers.js",_getScriptLocation:function(){var scriptLocation="";var scriptName=OpenLayers._scriptName;var scripts=document.getElementsByTagName('script');for(var i=0;i<scripts.length;i++){var src=scripts[i].getAttribute('src');if(src){var index=src.lastIndexOf(scriptName);if((index>-1)&&(index+scriptName.length==src.length)){scriptLocation=src.slice(0,-scriptName.length);break;}}}
-return scriptLocation;}};if(!singleFile){var jsfiles=new Array("OpenLayers/Util.js","OpenLayers/BaseTypes.js","OpenLayers/BaseTypes/Class.js","OpenLayers/BaseTypes/Bounds.js","OpenLayers/BaseTypes/Element.js","OpenLayers/BaseTypes/LonLat.js","OpenLayers/BaseTypes/Pixel.js","OpenLayers/BaseTypes/Size.js","OpenLayers/Console.js","Rico/Corner.js","Rico/Color.js","OpenLayers/Ajax.js","OpenLayers/Events.js","OpenLayers/Map.js","OpenLayers/Layer.js","OpenLayers/Icon.js","OpenLayers/Marker.js","OpenLayers/Marker/Box.js","OpenLayers/Popup.js","OpenLayers/Tile.js","OpenLayers/Tile/Image.js","OpenLayers/Tile/WFS.js","OpenLayers/Layer/Image.js","OpenLayers/Layer/SphericalMercator.js","OpenLayers/Layer/EventPane.js","OpenLayers/Layer/FixedZoomLevels.js","OpenLayers/Layer/Google.js","OpenLayers/Layer/VirtualEarth.js","OpenLayers/Layer/Yahoo.js","OpenLayers/Layer/HTTPRequest.js","OpenLayers/Layer/Grid.js","OpenLayers/Layer/MapServer.js","OpenLayers/Layer/MapGuide.js","OpenLayers/Layer/MapServer/Untiled.js","OpenLayers/Layer/KaMap.js","OpenLayers/Layer/MultiMap.js","OpenLayers/Layer/Markers.js","OpenLayers/Layer/Text.js","OpenLayers/Layer/WorldWind.js","OpenLayers/Layer/WMS.js","OpenLayers/Layer/WMS/Untiled.js","OpenLayers/Layer/GeoRSS.js","OpenLayers/Layer/Boxes.js","OpenLayers/Layer/TMS.js","OpenLayers/Layer/TileCache.js","OpenLayers/Popup/Anchored.js","OpenLayers/Popup/AnchoredBubble.js","OpenLayers/Feature.js","OpenLayers/Feature/Vector.js","OpenLayers/Feature/WFS.js","OpenLayers/Handler.js","OpenLayers/Handler/Point.js","OpenLayers/Handler/Path.js","OpenLayers/Handler/Polygon.js","OpenLayers/Handler/Feature.js","OpenLayers/Handler/Drag.js","OpenLayers/Handler/RegularPolygon.js","OpenLayers/Handler/Box.js","OpenLayers/Handler/MouseWheel.js","OpenLayers/Handler/Keyboard.js","OpenLayers/Control.js","OpenLayers/Control/Attribution.js","OpenLayers/Control/ZoomBox.js","OpenLayers/Control/ZoomToMaxExtent.js","OpenLayers/Control/DragPan.js","OpenLayers/Control/Navigation.js","OpenLayers/Control/MouseDefaults.js","OpenLayers/Control/MousePosition.js","OpenLayers/Control/OverviewMap.js","OpenLayers/Control/KeyboardDefaults.js","OpenLayers/Control/PanZoom.js","OpenLayers/Control/PanZoomBar.js","OpenLayers/Control/ArgParser.js","OpenLayers/Control/Permalink.js","OpenLayers/Control/Scale.js","OpenLayers/Control/LayerSwitcher.js","OpenLayers/Control/DrawFeature.js","OpenLayers/Control/DragFeature.js","OpenLayers/Control/ModifyFeature.js","OpenLayers/Control/Panel.js","OpenLayers/Control/SelectFeature.js","OpenLayers/Geometry.js","OpenLayers/Geometry/Rectangle.js","OpenLayers/Geometry/Collection.js","OpenLayers/Geometry/Point.js","OpenLayers/Geometry/MultiPoint.js","OpenLayers/Geometry/Curve.js","OpenLayers/Geometry/LineString.js","OpenLayers/Geometry/LinearRing.js","OpenLayers/Geometry/Polygon.js","OpenLayers/Geometry/MultiLineString.js","OpenLayers/Geometry/MultiPolygon.js","OpenLayers/Geometry/Surface.js","OpenLayers/Renderer.js","OpenLayers/Renderer/Elements.js","OpenLayers/Renderer/SVG.js","OpenLayers/Renderer/VML.js","OpenLayers/Layer/Vector.js","OpenLayers/Layer/GML.js","OpenLayers/Format.js","OpenLayers/Format/XML.js","OpenLayers/Format/GML.js","OpenLayers/Format/KML.js","OpenLayers/Format/GeoRSS.js","OpenLayers/Format/WFS.js","OpenLayers/Format/WKT.js","OpenLayers/Format/JSON.js","OpenLayers/Format/GeoJSON.js","OpenLayers/Layer/WFS.js","OpenLayers/Control/MouseToolbar.js","OpenLayers/Control/NavToolbar.js","OpenLayers/Control/EditingToolbar.js","OpenLayers/Projection.js","OpenLayers/Strings/en.js");var allScriptTags="";var host=OpenLayers._getScriptLocation()+"lib/";for(var i=0;i<jsfiles.length;i++){if(/MSIE/.test(navigator.userAgent)||/Safari/.test(navigator.userAgent)){var currentScriptTag="<script src='"+host+jsfiles[i]+"'></script>";allScriptTags+=currentScriptTag;}else{var s=document.createElement("script");s.src=host+jsfiles[i];var h=document.getElementsByTagName("head").length?document.getElementsByTagName("head")[0]:document.body;h.appendChild(s);}}
-if(allScriptTags)document.write(allScriptTags);}})();OpenLayers.VERSION_NUMBER="$Revision$";OpenLayers.Util={};OpenLayers.Util.getElement=function(){var elements=[];for(var i=0;i<arguments.length;i++){var element=arguments[i];if(typeof element=='string'){element=document.getElementById(element);}
-if(arguments.length==1){return element;}
-elements.push(element);}
-return elements;};if($==null){var $=OpenLayers.Util.getElement;}
-OpenLayers.Util.extend=function(destination,source){if(destination&&source){for(var property in source){destination[property]=source[property];}
-if(source.hasOwnProperty&&source.hasOwnProperty('toString')){destination.toString=source.toString;}}
-return destination;};OpenLayers.Util.removeItem=function(array,item){for(var i=0;i<array.length;i++){if(array[i]==item){array.splice(i,1);}}
-return array;};OpenLayers.Util.clearArray=function(array){var msg=OpenLayers.String.translate("clearArrayDeprecated");OpenLayers.Console.warn(msg);array.length=0;};OpenLayers.Util.indexOf=function(array,obj){for(var i=0;i<array.length;i++){if(array[i]==obj)return i;}
-return-1;};OpenLayers.Util.modifyDOMElement=function(element,id,px,sz,position,border,overflow,opacity){if(id){element.id=id;}
-if(px){element.style.left=px.x+"px";element.style.top=px.y+"px";}
-if(sz){element.style.width=sz.w+"px";element.style.height=sz.h+"px";}
-if(position){element.style.position=position;}
-if(border){element.style.border=border;}
-if(overflow){element.style.overflow=overflow;}
-if(opacity){element.style.opacity=opacity;element.style.filter='alpha(opacity='+(opacity*100)+')';}};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";OpenLayers.Event.observe(image,"load",OpenLayers.Function.bind(OpenLayers.Util.onImageLoad,image));OpenLayers.Event.observe(image,"error",OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError,image));}
-image.style.alt=id;image.galleryImg="no";if(imgURL){image.src=imgURL;}
-return image;};OpenLayers.Util.setOpacity=function(element,opacity){OpenLayers.Util.modifyDOMElement(element,null,null,null,null,null,null,opacity);}
-OpenLayers.Util.onImageLoad=function(){if(!this.viewRequestID||(this.map&&this.viewRequestID==this.map.viewRequestID)){this.style.backgroundColor=null;this.style.display="";}};OpenLayers.Util.onImageLoadErrorColor="pink";OpenLayers.IMAGE_RELOAD_ATTEMPTS=0;OpenLayers.Util.onImageLoadError=function(){this._attempts=(this._attempts)?(this._attempts+1):1;if(this._attempts<=OpenLayers.IMAGE_RELOAD_ATTEMPTS){this.src=this.src;}else{this.style.backgroundColor=OpenLayers.Util.onImageLoadErrorColor;}
-this.style.display="";};OpenLayers.Util.alphaHack=function(){var arVersion=navigator.appVersion.split("MSIE");var version=parseFloat(arVersion[1]);var filter=false;try{filter=document.body.filters;}catch(e){}
-return(filter&&(version>=5.5)&&(version<7));}
-OpenLayers.Util.modifyAlphaImageDiv=function(div,id,px,sz,imgURL,position,border,sizing,opacity){OpenLayers.Util.modifyDOMElement(div,id,px,sz);var img=div.childNodes[0];if(imgURL){img.src=imgURL;}
-OpenLayers.Util.modifyDOMElement(img,div.id+"_innerImage",null,sz,"relative",border);if(opacity){div.style.opacity=opacity;div.style.filter='alpha(opacity='+(opacity*100)+')';}
-if(OpenLayers.Util.alphaHack()){div.style.display="inline-block";if(sizing==null){sizing="scale";}
-div.style.filter="progid:DXImageTransform.Microsoft"+".AlphaImageLoader(src='"+img.src+"', "+"sizingMethod='"+sizing+"')";if(div.style.opacity){div.style.filter+=" alpha(opacity="+div.style.opacity*100+")";}
-img.style.filter="progid:DXImageTransform.Microsoft"+".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,false);div.appendChild(img);if(delayDisplay){img.style.display="none";OpenLayers.Event.observe(img,"load",OpenLayers.Function.bind(OpenLayers.Util.onImageLoad,div));OpenLayers.Event.observe(img,"error",OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError,div));}
-OpenLayers.Util.modifyAlphaImageDiv(div,id,px,sz,imgURL,position,border,sizing,opacity);return div;};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){for(var key in from){if(to[key]==null){to[key]=from[key];}}};OpenLayers.Util.getParameterString=function(params){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=[];for(var itemIndex=0;itemIndex<value.length;itemIndex++){encodedItemArray.push(encodeURIComponent(value[itemIndex]));}
-encodedValue=encodedItemArray.join(",");}
-else{encodedValue=encodeURIComponent(value);}
-paramsArray.push(encodeURIComponent(key)+"="+encodedValue);}}
-return paramsArray.join("&");};OpenLayers.ImgPath='';OpenLayers.Util.getImagesLocation=function(){return OpenLayers.ImgPath||(OpenLayers._getScriptLocation()+"img/");};OpenLayers.Util.Try=function(){var returnValue=null;for(var i=0;i<arguments.length;i++){var lambda=arguments[i];try{returnValue=lambda();break;}catch(e){}}
-return returnValue;}
-OpenLayers.Util.getNodes=function(p,tagName){var nodes=OpenLayers.Util.Try(function(){return OpenLayers.Util._getNodes(p.documentElement.childNodes,tagName);},function(){return OpenLayers.Util._getNodes(p.childNodes,tagName);});return nodes;};OpenLayers.Util._getNodes=function(nodes,tagName){var retArray=[];for(var i=0;i<nodes.length;i++){if(nodes[i].nodeName==tagName){retArray.push(nodes[i]);}}
-return retArray;};OpenLayers.Util.getTagText=function(parent,item,index){var result=OpenLayers.Util.getNodes(parent,item);if(result&&(result.length>0))
-{if(!index){index=0;}
-if(result[index].childNodes.length>1){return result.childNodes[1].nodeValue;}
-else if(result[index].childNodes.length==1){return result[index].firstChild.nodeValue;}}else{return"";}};OpenLayers.Util.getXmlNodeValue=function(node){var val=null;OpenLayers.Util.Try(function(){val=node.text;if(!val)
-val=node.textContent;if(!val)
-val=node.firstChild.nodeValue;},function(){val=node.textContent;});return val;};OpenLayers.Util.mouseLeft=function(evt,div){var target=(evt.relatedTarget)?evt.relatedTarget:evt.toElement;while(target!=div&&target!=null){target=target.parentNode;}
-return(target!=div);};OpenLayers.Util.rad=function(x){return x*Math.PI/180;};OpenLayers.Util.distVincenty=function(p1,p2){var a=6378137,b=6356752.3142,f=1/298.257223563;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;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.getParameters=function(url){url=url||window.location.href
-if(url==null){url=window.location.href;}
-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;i<pairs.length;++i){var keyValue=pairs[i].split('=');if(keyValue[0]){var key=decodeURIComponent(keyValue[0]);var value=keyValue[1]||'';value=value.split(",");for(var j=0;j<value.length;j++){value[j]=decodeURIComponent(value[j]);}
-if(value.length==1){value=value[0];}
-parameters[key]=value;}}
-return parameters;};OpenLayers.Util.getArgs=function(url){var err=OpenLayers.String.translate("getArgsDeprecated");OpenLayers.Console.warn(err);return OpenLayers.Util.getParameters(url);};OpenLayers.Util.lastSeqID=0;OpenLayers.Util.createUniqueID=function(prefix){if(prefix==null){prefix="id_";}
-OpenLayers.Util.lastSeqID+=1;return prefix+OpenLayers.Util.lastSeqID;};OpenLayers.INCHES_PER_UNIT={'inches':1.0,'ft':12.0,'mi':63360.0,'m':39.3701,'km':39370.1,'dd':4374754};OpenLayers.INCHES_PER_UNIT["in"]=OpenLayers.INCHES_PER_UNIT.inches;OpenLayers.INCHES_PER_UNIT["degrees"]=OpenLayers.INCHES_PER_UNIT.dd;OpenLayers.DOTS_PER_INCH=72;OpenLayers.Util.normalizeScale=function(scale){var normScale=(scale>1.0)?(1.0/scale):scale;return normScale;};OpenLayers.Util.getResolutionFromScale=function(scale,units){if(units==null){units="degrees";}
-var normScale=OpenLayers.Util.normalizeScale(scale);var 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.safeStopPropagation=function(evt){OpenLayers.Event.stop(evt,true);};OpenLayers.Util.pagePosition=function(forElement){var valueT=0,valueL=0;var element=forElement;var child=forElement;while(element){if(element==document.body){if(OpenLayers.Element.getStyle(child,'position')=='absolute'){break;}}
-valueT+=element.offsetTop||0;valueL+=element.offsetLeft||0;child=element;try{element=element.offsetParent;}catch(e){OpenLayers.Console.error(OpenLayers.String.translate("pagePositionFailed",element.id));break;}}
-element=forElement;while(element){valueT-=element.scrollTop||0;valueL-=element.scrollLeft||0;element=element.parentNode;}
-return[valueL,valueT];};OpenLayers.Util.isEquivalentUrl=function(url1,url2,options){options=options||{};OpenLayers.Util.applyDefaults(options,{ignoreCase:true,ignorePort80:true,ignoreHash:true});urlObj1=OpenLayers.Util.createUrlObject(url1,options);urlObj2=OpenLayers.Util.createUrlObject(url2,options);for(var key in urlObj1){if(options.test){alert(key+"\n1:"+urlObj1[key]+"\n2:"+urlObj2[key]);}
-var val1=urlObj1[key];var val2=urlObj2[key];switch(key){case"args":break;case"host":case"port":case"protocol":if((val1=="")||(val2=="")){break;}
-default:if((key!="args")&&(urlObj1[key]!=urlObj2[key])){return false;}
-break;}}
-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||{};var urlObject={};if(options.ignoreCase){url=url.toLowerCase();}
-var a=document.createElement('a');a.href=url;urlObject.host=a.host;var port=a.port;if(port.length<=0){var newHostLength=urlObject.host.length-(port.length);urlObject.host=urlObject.host.substring(0,newHostLength);}
-urlObject.protocol=a.protocol;urlObject.port=((port=="80")&&(options.ignorePort80))?"":port;urlObject.hash=(options.ignoreHash)?"":a.hash;var queryString=a.search;if(!queryString){var qMark=url.indexOf("?");queryString=(qMark!=-1)?url.substr(qMark):"";}
-urlObject.args=OpenLayers.Util.getParameters(queryString);if(((urlObject.protocol=="file:")&&(url.indexOf("file:")!=-1))||((urlObject.protocol!="file:")&&(urlObject.host!=""))){urlObject.pathname=a.pathname;var qIndex=urlObject.pathname.indexOf("?");if(qIndex!=-1){urlObject.pathname=urlObject.pathname.substring(0,qIndex);}}else{var relStr=OpenLayers.Util.removeTail(url);var backs=0;do{var index=relStr.indexOf("../");if(index==0){backs++
-relStr=relStr.substr(3);}else if(index>=0){var prevChunk=relStr.substr(0,index-1);var slash=prevChunk.indexOf("/");prevChunk=(slash!=-1)?prevChunk.substr(0,slash+1):"";var postChunk=relStr.substr(index+3);relStr=prevChunk+postChunk;}}while(index!=-1)
-var windowAnchor=document.createElement("a");var windowUrl=window.location.href;if(options.ignoreCase){windowUrl=windowUrl.toLowerCase();}
-windowAnchor.href=windowUrl;urlObject.protocol=windowAnchor.protocol;var splitter=(windowAnchor.pathname.indexOf("/")!=-1)?"/":"\\";var dirs=windowAnchor.pathname.split(splitter);dirs.pop();while((backs>0)&&(dirs.length>0)){dirs.pop();backs--;}
-relStr=dirs.join("/")+"/"+relStr;urlObject.pathname=relStr;}
-if((urlObject.protocol=="file:")||(urlObject.protocol=="")){urlObject.host="localhost";}
-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.Util.getBrowserName=function(){var browserName="";var ua=navigator.userAgent.toLowerCase();if(ua.indexOf("opera")!=-1){browserName="opera";}else if(ua.indexOf("msie")!=-1){browserName="msie";}else if(ua.indexOf("safari")!=-1){browserName="safari";}else if(ua.indexOf("mozilla")!=-1){if(ua.indexOf("firefox")!=-1){browserName="firefox";}else{browserName="mozilla";}}
-return browserName;};OpenLayers.Console={log:function(){},debug:function(){},info:function(){},warn:function(){},error:function(){},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(){if(window.console){var scripts=document.getElementsByTagName("script");for(var i=0;i<scripts.length;++i){if(scripts[i].src.indexOf("firebug.js")!=-1){OpenLayers.Util.extend(OpenLayers.Console,console);break;}}}})();OpenLayers.String={startsWith:function(str,sub){return(str.indexOf(sub)==0);},contains:function(str,sub){return(str.indexOf(sub)!=-1);},trim:function(str){return str.replace(/^\s*(.*?)\s*$/,"$1");},camelize:function(str){var oStringList=str.split('-');var camelizedString=oStringList[0];for(var i=1;i<oStringList.length;i++){var s=oStringList[i];camelizedString+=s.charAt(0).toUpperCase()+s.substring(1);}
-return camelizedString;},langCode:(OpenLayers.Util.getBrowserName()=="msie")?navigator.userLanguage.substring(0,2):navigator.language.substring(0,2),defaultLangCode:'en',translate:function(key){var langCode=OpenLayers.String.langCode;if(!OpenLayers.Strings[langCode]){var msg='failed to find '+OpenLayers.String.langCode+' dictionary, falling back to default language';OpenLayers.Console.log(msg);OpenLayers.Strings[langCode]=OpenLayers.Strings[OpenLayers.String.defaultLangCode];langCode=OpenLayers.String.defaultLangCode;}
-var dictionary=OpenLayers.Strings[langCode];var message="NoMsgsFound";var msgValue=dictionary[key];if(!msgValue){message=key;}else{message=msgValue;if(arguments[this.translate.length]){var varArgs=[].slice.call(arguments,this.translate.length);varArgs.unshift(message);message=this.formatMessage.apply(this,varArgs);}}
-return message;},formatMessage:function(messageTemplate)
-{var message=messageTemplate;var varArgs=[].slice.call(arguments,this.formatMessage.length);for(var i in varArgs){var parm=new RegExp("\\{"+i+"\\}","g");message=message.replace(parm,varArgs[i]);}
-return message;}};OpenLayers.Strings={};if(!String.prototype.startsWith){String.prototype.startsWith=function(sStart){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.String.startsWith"));return OpenLayers.String.startsWith(this,sStart);};}
-if(!String.prototype.contains){String.prototype.contains=function(str){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.String.contains"));return OpenLayers.String.contains(this,str);};}
-if(!String.prototype.trim){String.prototype.trim=function(){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.String.trim"));return OpenLayers.String.trim(this);};}
-if(!String.prototype.camelize){String.prototype.camelize=function(){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.String.camelize"));return OpenLayers.String.camelize(this);};}
-OpenLayers.Number={limitSigDigs:function(num,sig){var fig;if(sig>0){fig=parseFloat(num.toPrecision(sig));}else{fig=0;}
-return fig;}};if(!Number.prototype.limitSigDigs){Number.prototype.limitSigDigs=function(sig){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.Number.limitSigDigs"));return OpenLayers.Number.limitSigDigs(this,sig);};}
-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);};}};if(!Function.prototype.bind){Function.prototype.bind=function(){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.Function.bind"));Array.prototype.unshift.apply(arguments,[this]);return OpenLayers.Function.bind.apply(null,arguments);};}
-if(!Function.prototype.bindAsEventListener){Function.prototype.bindAsEventListener=function(object){OpenLayers.Console.warn(OpenLayers.String.translate("methodDeprecated","OpenLayers.Function.bindAsEventListener"));return OpenLayers.Function.bindAsEventListener(this,object);};}
-OpenLayers.Class=function(){var Class=function(){if(arguments&&arguments[0]!=OpenLayers.Class.isPrototype){this.initialize.apply(this,arguments);}}
-var extended={};var parent;for(var i=0;i<arguments.length;++i){if(typeof arguments[i]=="function"){parent=arguments[i].prototype;}else{parent=arguments[i];}
-OpenLayers.Util.extend(extended,parent);}
-Class.prototype=extended;return Class;}
-OpenLayers.Class.isPrototype=function(){};OpenLayers.Class.create=function(){return function(){if(arguments&&arguments[0]!=OpenLayers.Class.isPrototype)
-this.initialize.apply(this,arguments);}}
-OpenLayers.Class.inherit=function(){var superClass=arguments[0];var proto=new superClass(OpenLayers.Class.isPrototype);for(var i=1;i<arguments.length;i++){if(typeof arguments[i]=="function"){var mixin=arguments[i];arguments[i]=new mixin(OpenLayers.Class.isPrototype);}
-OpenLayers.Util.extend(proto,arguments[i]);}
-return proto;}
-OpenLayers.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.Bounds=OpenLayers.Class({left:null,bottom:null,right:null,top:null,initialize:function(left,bottom,right,top){if(left!=null){this.left=parseFloat(left);}
-if(bottom!=null){this.bottom=parseFloat(bottom);}
-if(right!=null){this.right=parseFloat(right);}
-if(top!=null){this.top=parseFloat(top);}},clone:function(){return new OpenLayers.Bounds(this.left,this.bottom,this.right,this.top);},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;},toString:function(){return("left-bottom=("+this.left+","+this.bottom+")"
-+" right-top=("+this.right+","+this.top+")");},toArray:function(){return[this.left,this.bottom,this.right,this.top];},toBBOX:function(decimal){if(decimal==null){decimal=6;}
-var mult=Math.pow(10,decimal);var bbox=Math.round(this.left*mult)/mult+","+
-Math.round(this.bottom*mult)/mult+","+
-Math.round(this.right*mult)/mult+","+
-Math.round(this.top*mult)/mult;return bbox;},getWidth:function(){return(this.right-this.left);},getHeight:function(){return(this.top-this.bottom);},getSize:function(){return new OpenLayers.Size(this.getWidth(),this.getHeight());},getCenterPixel:function(){return new OpenLayers.Pixel((this.left+this.right)/2,(this.bottom+this.top)/2);},getCenterLonLat:function(){return new OpenLayers.LonLat((this.left+this.right)/2,(this.bottom+this.top)/2);},add:function(x,y){if((x==null)||(y==null)){var msg=OpenLayers.String.translate("boundsAddError");OpenLayers.Console.error(msg);return null;}
-return new OpenLayers.Bounds(this.left+x,this.bottom+y,this.right+x,this.top+y);},extend:function(object){var bounds=null;if(object){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){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;}}}},containsLonLat:function(ll,inclusive){return this.contains(ll.lon,ll.lat,inclusive);},containsPixel:function(px,inclusive){return this.contains(px.x,px.y,inclusive);},contains:function(x,y,inclusive){if(inclusive==null){inclusive=true;}
-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;},intersectsBounds:function(bounds,inclusive){if(inclusive==null){inclusive=true;}
-var inBottom=(bounds.bottom==this.bottom&&bounds.top==this.top)?true:(((bounds.bottom>this.bottom)&&(bounds.bottom<this.top))||((this.bottom>bounds.bottom)&&(this.bottom<bounds.top)));var inTop=(bounds.bottom==this.bottom&&bounds.top==this.top)?true:(((bounds.top>this.bottom)&&(bounds.top<this.top))||((this.top>bounds.bottom)&&(this.top<bounds.top)));var inRight=(bounds.right==this.right&&bounds.left==this.left)?true:(((bounds.right>this.left)&&(bounds.right<this.right))||((this.right>bounds.left)&&(this.right<bounds.right)));var inLeft=(bounds.right==this.right&&bounds.left==this.left)?true:(((bounds.left>this.left)&&(bounds.left<this.right))||((this.left>bounds.left)&&(this.left<bounds.right)));return(this.containsBounds(bounds,true,inclusive)||bounds.containsBounds(this,true,inclusive)||((inTop||inBottom)&&(inLeft||inRight)));},containsBounds:function(bounds,partial,inclusive){if(partial==null){partial=false;}
-if(inclusive==null){inclusive=true;}
-var inLeft;var inTop;var inRight;var inBottom;if(inclusive){inLeft=(bounds.left>=this.left)&&(bounds.left<=this.right);inTop=(bounds.top>=this.bottom)&&(bounds.top<=this.top);inRight=(bounds.right>=this.left)&&(bounds.right<=this.right);inBottom=(bounds.bottom>=this.bottom)&&(bounds.bottom<=this.top);}else{inLeft=(bounds.left>this.left)&&(bounds.left<this.right);inTop=(bounds.top>this.bottom)&&(bounds.top<this.top);inRight=(bounds.right>this.left)&&(bounds.right<this.right);inBottom=(bounds.bottom>this.bottom)&&(bounds.bottom<this.top);}
-return(partial)?(inTop||inBottom)&&(inLeft||inRight):(inTop&&inLeft&&inBottom&&inRight);},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;},wrapDateLine:function(maxExtent,options){options=options||{};var leftTolerance=options.leftTolerance||0;var rightTolerance=options.rightTolerance||0;var newBounds=this.clone();if(maxExtent){while(newBounds.left<maxExtent.left&&(newBounds.right-rightTolerance)<=maxExtent.left){newBounds=newBounds.add(maxExtent.getWidth(),0);}
-while((newBounds.left+leftTolerance)>=maxExtent.right&&newBounds.right>maxExtent.right){newBounds=newBounds.add(-maxExtent.getWidth(),0);}}
-return newBounds;},CLASS_NAME:"OpenLayers.Bounds"});OpenLayers.Bounds.fromString=function(str){var bounds=str.split(",");return OpenLayers.Bounds.fromArray(bounds);};OpenLayers.Bounds.fromArray=function(bbox){return new OpenLayers.Bounds(parseFloat(bbox[0]),parseFloat(bbox[1]),parseFloat(bbox[2]),parseFloat(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;i<arguments.length;i++){var element=OpenLayers.Util.getElement(arguments[i]);var display=OpenLayers.Element.visible(element)?'hide':'show';OpenLayers.Element[display](element);}},hide:function(){for(var i=0;i<arguments.length;i++){var element=OpenLayers.Util.getElement(arguments[i]);element.style.display='none';}},show:function(){for(var i=0;i<arguments.length;i++){var element=OpenLayers.Util.getElement(arguments[i]);element.style.display='';}},remove:function(element){element=OpenLayers.Util.getElement(element);element.parentNode.removeChild(element);},getHeight:function(element){element=OpenLayers.Util.getElement(element);return element.offsetHeight;},getDimensions:function(element){element=OpenLayers.Util.getElement(element);if(OpenLayers.Element.getStyle(element,'display')!='none'){return{width:element.offsetWidth,height:element.offsetHeight};}
-var els=element.style;var originalVisibility=els.visibility;var originalPosition=els.position;els.visibility='hidden';els.position='absolute';els.display='';var originalWidth=element.clientWidth;var originalHeight=element.clientHeight;els.display='none';els.position=originalPosition;els.visibility=originalVisibility;return{width:originalWidth,height:originalHeight};},getStyle:function(element,style){element=OpenLayers.Util.getElement(element);var value=element.style[OpenLayers.String.camelize(style)];if(!value){if(document.defaultView&&document.defaultView.getComputedStyle){var css=document.defaultView.getComputedStyle(element,null);value=css?css.getPropertyValue(style):null;}else if(element.currentStyle){value=element.currentStyle[OpenLayers.String.camelize(style)];}}
-var positions=['left','top','right','bottom'];if(window.opera&&(OpenLayers.Util.indexOf(positions,style)!=-1)&&(OpenLayers.Element.getStyle(element,'position')=='static')){value='auto';}
-return value=='auto'?null:value;}};OpenLayers.LonLat=OpenLayers.Class({lon:0.0,lat:0.0,initialize:function(lon,lat){this.lon=parseFloat(lon);this.lat=parseFloat(lat);},toString:function(){return("lon="+this.lon+",lat="+this.lat);},toShortString:function(){return(this.lon+", "+this.lat);},clone:function(){return new OpenLayers.LonLat(this.lon,this.lat);},add:function(lon,lat){if((lon==null)||(lat==null)){var msg=OpenLayers.String.translate("lonlatAddError");OpenLayers.Console.error(msg);return null;}
-return new OpenLayers.LonLat(this.lon+lon,this.lat+lat);},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;},wrapDateLine:function(maxExtent){var newLonLat=this.clone();if(maxExtent){while(newLonLat.lon<maxExtent.left){newLonLat.lon+=maxExtent.getWidth();}
-while(newLonLat.lon>maxExtent.right){newLonLat.lon-=maxExtent.getWidth();}}
-return newLonLat;},CLASS_NAME:"OpenLayers.LonLat"});OpenLayers.LonLat.fromString=function(str){var pair=str.split(",");return new OpenLayers.LonLat(parseFloat(pair[0]),parseFloat(pair[1]));};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;},add:function(x,y){if((x==null)||(y==null)){var msg=OpenLayers.String.translate("pixelAddError");OpenLayers.Console.error(msg);return null;}
-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.ProxyHost="";OpenLayers.nullHandler=function(request){alert(OpenLayers.String.translate("unhandledRequest",request.statusText));};OpenLayers.loadURL=function(uri,params,caller,onComplete,onFailure){if(OpenLayers.ProxyHost&&OpenLayers.String.startsWith(uri,"http")){uri=OpenLayers.ProxyHost+escape(uri);}
-var success=(onComplete)?OpenLayers.Function.bind(onComplete,caller):OpenLayers.nullHandler;var failure=(onFailure)?OpenLayers.Function.bind(onFailure,caller):OpenLayers.nullHandler;new OpenLayers.Ajax.Request(uri,{method:'get',parameters:params,onComplete:success,onFailure:failure});};OpenLayers.parseXMLString=function(text){var index=text.indexOf('<');if(index>0){text=text.substring(index);}
-var ajaxResponse=OpenLayers.Util.Try(function(){var xmldom=new ActiveXObject('Microsoft.XMLDOM');xmldom.loadXML(text);return xmldom;},function(){return new DOMParser().parseFromString(text,'text/xml');},function(){var req=new XMLHttpRequest();req.open("GET","data:"+"text/xml"+";charset=utf-8,"+encodeURIComponent(text),false);if(req.overrideMimeType){req.overrideMimeType("text/xml");}
-req.send(null);return req.responseXML;});return ajaxResponse;};OpenLayers.Ajax={emptyFunction:function(){},getTransport:function(){return OpenLayers.Util.Try(function(){return new ActiveXObject('Msxml2.XMLHTTP')},function(){return new ActiveXObject('Microsoft.XMLHTTP')},function(){return new XMLHttpRequest()})||false;},activeRequestCount:0};OpenLayers.Ajax.Responders={responders:[],register:function(responderToAdd){for(var i=0;i<this.responders.length;i++)
-if(responderToAdd==this.responders[i])
-return;this.responders.push(responderToAdd);},dispatch:function(callback,request,transport,json){var responder;for(var i=0;i<this.responders.length;i++){responder=this.responders[i];if(responder[callback]&&typeof responder[callback]=='function'){try{responder[callback].apply(responder,[request,transport,json]);}catch(e){}}}}};OpenLayers.Ajax.Responders.register({onCreate:function(){OpenLayers.Ajax.activeRequestCount++;},onComplete:function(){OpenLayers.Ajax.activeRequestCount--;}});OpenLayers.Ajax.Base=function(){};OpenLayers.Ajax.Base.prototype={setOptions:function(options){this.options={'method':'post','asynchronous':true,'parameters':''};OpenLayers.Util.extend(this.options,options||{});},responseIsSuccess:function(){return this.transport.status==undefined||this.transport.status==0||(this.transport.status>=200&&this.transport.status<300);},responseIsFailure:function(){return!this.responseIsSuccess();}};OpenLayers.Ajax.Request=OpenLayers.Class(OpenLayers.Ajax.Base,{initialize:function(url,options){this.transport=OpenLayers.Ajax.getTransport();this.setOptions(options);this.request(url);},request:function(url){var parameters=this.options.parameters||'';if(parameters.length>0)parameters+='&_=';try{this.url=url;if(this.options.method=='get'&¶meters.length>0){this.url+=(this.url.match(/\?/)?'&':'?')+parameters;}
-OpenLayers.Ajax.Responders.dispatch('onCreate',this,this.transport);this.transport.open(this.options.method,this.url,this.options.asynchronous);if(this.options.asynchronous){this.transport.onreadystatechange=OpenLayers.Function.bind(this.onStateChange,this);setTimeout(OpenLayers.Function.bind((function(){this.respondToReadyState(1)}),this),10);}
-this.setRequestHeaders();var body=this.options.postBody?this.options.postBody:parameters;this.transport.send(this.options.method=='post'?body:null);if(!this.options.asynchronous&&this.transport.overrideMimeType){this.onStateChange();}}catch(e){this.dispatchException(e);}},setRequestHeaders:function(){var requestHeaders=['X-Requested-With','XMLHttpRequest','X-Prototype-Version','OpenLayers'];if(this.options.method=='post'&&!this.options.postBody){requestHeaders.push('Content-type','application/x-www-form-urlencoded');if(this.transport.overrideMimeType){requestHeaders.push('Connection','close');}}
-if(this.options.requestHeaders){requestHeaders.push.apply(requestHeaders,this.options.requestHeaders);}
-for(var i=0;i<requestHeaders.length;i+=2){this.transport.setRequestHeader(requestHeaders[i],requestHeaders[i+1]);}},onStateChange:function(){var readyState=this.transport.readyState;if(readyState!=1){this.respondToReadyState(this.transport.readyState);}},header:function(name){try{return this.transport.getResponseHeader(name);}catch(e){}},evalJSON:function(){try{return eval(this.header('X-JSON'));}catch(e){}},evalResponse:function(){try{return eval(this.transport.responseText);}catch(e){this.dispatchException(e);}},respondToReadyState:function(readyState){var event=OpenLayers.Ajax.Request.Events[readyState];var transport=this.transport,json=this.evalJSON();if(event=='Complete'){try{var responseSuccess=this.responseIsSuccess()?'Success':'Failure';(this.options['on'+this.transport.status]||this.options['on'+responseSuccess]||OpenLayers.Ajax.emptyFunction)(transport,json);}catch(e){this.dispatchException(e);}
-var contentType=this.header('Content-type')||'';if(contentType.match(/^text\/javascript/i)){this.evalResponse();}}
-try{(this.options['on'+event]||OpenLayers.Ajax.emptyFunction)(transport,json);OpenLayers.Ajax.Responders.dispatch('on'+event,this,transport,json);}catch(e){this.dispatchException(e);}
-if(event=='Complete'){this.transport.onreadystatechange=OpenLayers.Ajax.emptyFunction;}},dispatchException:function(exception){if(this.options.onException){this.options.onException(this,exception);}else{throw exception;}
-OpenLayers.Ajax.Responders.dispatch('onException',this,exception);}});OpenLayers.Ajax.Request.Events=['Uninitialized','Loading','Loaded','Interactive','Complete'];OpenLayers.Ajax.getElementsByTagNameNS=function(parentnode,nsuri,nsprefix,tagname){var elem=null;if(parentnode.getElementsByTagNameNS){elem=parentnode.getElementsByTagNameNS(nsuri,tagname);}else{elem=parentnode.getElementsByTagName(nsprefix+':'+tagname);}
-return elem;};OpenLayers.Ajax.serializeXMLToString=function(xmldom){var serializer=new XMLSerializer();data=serializer.serializeToString(xmldom);return data;}
-OpenLayers.Control=OpenLayers.Class({id:null,map:null,div:null,type:null,displayClass:"",active:null,handler:null,initialize:function(options){this.displayClass=this.CLASS_NAME.replace("OpenLayers.","ol").replace(/\./g,"");OpenLayers.Util.extend(this,options);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){if(this.handler){this.handler.destroy();}
-this.map=null;},setMap:function(map){this.map=map;if(this.handler){this.handler.setMap(map);}},draw:function(px){if(this.div==null){this.div=OpenLayers.Util.createDiv();this.div.id=this.id;this.div.className=this.displayClass;}
-if(px!=null){this.position=px.clone();}
-this.moveTo(this.position);return this.div;},moveTo:function(px){if((px!=null)&&(this.div!=null)){this.div.style.left=px.x+"px";this.div.style.top=px.y+"px";}},activate:function(){if(this.active){return false;}
-if(this.handler){this.handler.activate();}
-this.active=true;return true;},deactivate:function(){if(this.active){if(this.handler){this.handler.deactivate();}
-this.active=false;return true;}
-return false;},CLASS_NAME:"OpenLayers.Control"});OpenLayers.Control.TYPE_BUTTON=1;OpenLayers.Control.TYPE_TOGGLE=2;OpenLayers.Control.TYPE_TOOL=3;OpenLayers.Icon=OpenLayers.Class({url:null,size:null,offset:null,calculateOffset:null,imageDiv:null,px:null,initialize:function(url,size,offset,calculateOffset){this.url=url;this.size=(size)?size:new OpenLayers.Size(20,20);this.offset=offset?offset:new OpenLayers.Pixel(-(this.size.w/2),-(this.size.h/2));this.calculateOffset=calculateOffset;var id=OpenLayers.Util.createUniqueID("OL_Icon_");this.imageDiv=OpenLayers.Util.createAlphaImageDiv(id);},destroy:function(){OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);this.imageDiv.innerHTML="";this.imageDiv=null;},clone:function(){return new OpenLayers.Icon(this.url,this.size,this.offset,this.calculateOffset);},setSize:function(size){if(size!=null){this.size=size;}
-this.draw();},draw:function(px){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,this.size,this.url,"absolute");this.moveTo(px);return this.imageDiv;},setOpacity:function(opacity){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,null,null,null,null,null,opacity);},moveTo:function(px){if(px!=null){this.px=px;}
-if(this.imageDiv!=null){if(this.px==null){this.display(false);}else{if(this.calculateOffset){this.offset=this.calculateOffset(this.size);}
-var offsetPx=this.px.offset(this.offset);OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,offsetPx);}}},display:function(display){this.imageDiv.style.display=(display)?"":"none";},CLASS_NAME:"OpenLayers.Icon"});OpenLayers.Strings.en={'test1':'this is a test','test2':'and another test','test3':'arg one:{0} arg two: {1}','unhandledRequest':"Unhandled request return {0}",'permalink':"Permalink",'overlays':"Overlays",'baseLayer':"Base Layer",'sameProjection':"The overview map only works when it is in the same projection as the main map",'readNotImplemented':"Read not implemented.",'writeNotImplemented':"Write not implemented.",'noFID':"Can't update a feature for which there is no FID.",'errorLoadingGML':"Error in loading GML file {0}",'browserNotSupported':"Your browser does not support vector rendering. Currently supported renderers are:\n{0}",'componentShouldBe':"addFeatures : component should be an {0}",'getFeatureError':"getFeatureFromEvent called on layer with no renderer. "+"This usually means you destroyed a layer, but not some handler which is associated with it.",'minZoomLevelError':"The minZoomLevel property is only intended for use "+"with the FixedZoomLevels-descendent layers. That this "+"wfs layer checks for minZoomLevel is a relic of the"+"past. We cannot, however, remove it without possibly "+"breaking OL based applications that may depend on it."+" Therefore we are deprecating it -- the minZoomLevel "+"check below will be removed at 3.0. Please instead "+"use min/max resolution setting as described here: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS Transaction: SUCCESS {0}",'commitFailed':"WFS Transaction: FAILED {0}",'googleWarning':"The Google Layer was unable to load correctly.<br><br>"+"To get rid of this message, select a new BaseLayer "+"in the layer switcher in the upper-right corner.<br><br>"+"Most likely, this is because the Google Maps library "+"script was either not included, or does not contain the "+"correct API key for your site.<br><br>"+"Developers: For help getting this working correctly, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>click here</a>",'getLayerWarning':"The {0} Layer was unable to load correctly.<br><br>"+"To get rid of this message, select a new BaseLayer "+"in the layer switcher in the upper-right corner.<br><br>"+"Most likely, this is because the {0} library "+"script was either not correctly included.<br><br>"+"Developers: For help getting this working correctly, "+"<a href='http://trac.openlayers.org/wiki/{1}' "+"target='_blank'>click here</a>",'scale':"Scale = 1 : {0}",'layerAlreadyAdded':"You tried to add the layer: {0} to the map, but it has already been added",'reprojectDeprecated':"You are using the 'reproject' option "+"on the {0} layer. This option is deprecated: "+"its use was designed to support displaying data over commercial "+"basemaps, but that functionality should now be achieved by using "+"Spherical Mercator support. More information is available from "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"This method has been deprecated and will be removed in 3.0. "+"Please use {0} instead.",'boundsAddError':"You must pass both x and y values to the add function.",'lonlatAddError':"You must pass both lon and lat values to the add function.",'pixelAddError':"You must pass both x and y values to the add function.",'unsupportedGeometryType':"Unsupported geometry type: {0}",'clearArrayDeprecated':"OpenLayers.Util.clearArray() is Deprecated."+" Please use 'array.length = 0' instead.",'getArgsDeprecated':"The getArgs() function is deprecated and will be removed "+"with the 3.0 version of OpenLayers. Please instead use "+"OpenLayers.Util.getParameters().",'pagePositionFailed':"OpenLayers.Util.pagePosition failed: element with id {0} may be misplaced.",'end':''};OpenLayers.Control.ArgParser=OpenLayers.Class(OpenLayers.Control,{center:null,zoom:null,layers:null,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);},setMap:function(map){OpenLayers.Control.prototype.setMap.apply(this,arguments);for(var i=0;i<this.map.controls.length;i++){var control=this.map.controls[i];if((control!=this)&&(control.CLASS_NAME=="OpenLayers.Control.ArgParser")){break;}}
-if(i==this.map.controls.length){var args=OpenLayers.Util.getParameters();if(args.lat&&args.lon){this.center=new OpenLayers.LonLat(parseFloat(args.lon),parseFloat(args.lat));if(args.zoom){this.zoom=parseInt(args.zoom);}
-this.map.events.register('changebaselayer',this,this.setCenter);this.setCenter();}
-if(args.layers){this.layers=args.layers;this.map.events.register('addlayer',this,this.configureLayers);this.configureLayers();}}},setCenter:function(){if(this.map.baseLayer){this.map.events.unregister('changebaselayer',this,this.setCenter);this.map.setCenter(this.center,this.zoom);}},configureLayers:function(){if(this.layers.length==this.map.layers.length){this.map.events.unregister('addlayer',this,this.configureLayers);for(var i=0;i<this.layers.length;i++){var layer=this.map.layers[i];var c=this.layers.charAt(i);if(c=="B"){this.map.setBaseLayer(layer);}else if((c=="T")||(c=="F")){layer.setVisibility(c=="T");}}}},CLASS_NAME:"OpenLayers.Control.ArgParser"});OpenLayers.Control.PanZoom=OpenLayers.Class(OpenLayers.Control,{slideFactor:50,buttons:null,position:null,initialize:function(options){this.position=new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,OpenLayers.Control.PanZoom.Y);OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){OpenLayers.Control.prototype.destroy.apply(this,arguments);while(this.buttons.length){var btn=this.buttons.shift();btn.map=null;OpenLayers.Event.stopObservingElement(btn);}
-this.buttons=null;this.position=null;},draw:function(px){OpenLayers.Control.prototype.draw.apply(this,arguments);px=this.position;this.buttons=[];var sz=new OpenLayers.Size(18,18);var centered=new OpenLayers.Pixel(px.x+sz.w/2,px.y);this._addButton("panup","north-mini.png",centered,sz);px.y=centered.y+sz.h;this._addButton("panleft","west-mini.png",px,sz);this._addButton("panright","east-mini.png",px.add(sz.w,0),sz);this._addButton("pandown","south-mini.png",centered.add(0,sz.h*2),sz);this._addButton("zoomin","zoom-plus-mini.png",centered.add(0,sz.h*3+5),sz);this._addButton("zoomworld","zoom-world-mini.png",centered.add(0,sz.h*4+5),sz);this._addButton("zoomout","zoom-minus-mini.png",centered.add(0,sz.h*5+5),sz);return this.div;},_addButton:function(id,img,xy,sz){var imgLocation=OpenLayers.Util.getImagesLocation()+img;var btn=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_PanZoom_"+id,xy,sz,imgLocation,"absolute");this.div.appendChild(btn);OpenLayers.Event.observe(btn,"mousedown",OpenLayers.Function.bindAsEventListener(this.buttonDown,btn));OpenLayers.Event.observe(btn,"dblclick",OpenLayers.Function.bindAsEventListener(this.doubleClick,btn));OpenLayers.Event.observe(btn,"click",OpenLayers.Function.bindAsEventListener(this.doubleClick,btn));btn.action=id;btn.map=this.map;btn.slideFactor=this.slideFactor;this.buttons.push(btn);return btn;},doubleClick:function(evt){OpenLayers.Event.stop(evt);return false;},buttonDown:function(evt){if(!OpenLayers.Event.isLeftClick(evt))return;switch(this.action){case"panup":this.map.pan(0,-50);break;case"pandown":this.map.pan(0,50);break;case"panleft":this.map.pan(-50,0);break;case"panright":this.map.pan(50,0);break;case"zoomin":this.map.zoomIn();break;case"zoomout":this.map.zoomOut();break;case"zoomworld":this.map.zoomToMaxExtent();break;}
-OpenLayers.Event.stop(evt);},CLASS_NAME:"OpenLayers.Control.PanZoom"});OpenLayers.Control.PanZoom.X=4;OpenLayers.Control.PanZoom.Y=4;OpenLayers.Event={observers:false,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;},isLeftClick:function(event){return(((event.which)&&(event.which==1))||((event.button)&&(event.button==1)));},stop:function(event,allowDefault){if(!allowDefault){if(event.preventDefault){event.preventDefault();}else{event.returnValue=false;}}
-if(event.stopPropagation){event.stopPropagation();}else{event.cancelBubble=true;}},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];var args=new Array(entry.element,entry.name,entry.observer,entry.useCapture);var removed=OpenLayers.Event.stopObserving.apply(this,args);}}},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<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++;}}
-if(element.removeEventListener){element.removeEventListener(name,observer,useCapture);}else if(element&&element.detachEvent){element.detachEvent('on'+name,observer);}
-return foundEntry;},unloadCache:function(){if(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"};OpenLayers.Event.observe(window,'unload',OpenLayers.Event.unloadCache,false);if(window.Event){OpenLayers.Util.applyDefaults(window.Event,OpenLayers.Event);}else{var Event=OpenLayers.Event;}
-OpenLayers.Events=OpenLayers.Class({BROWSER_EVENTS:["mouseover","mouseout","mousedown","mouseup","mousemove","click","dblclick","resize","focus","blur"],listeners:null,object:null,element:null,eventTypes:null,eventHandler:null,fallThrough:null,initialize:function(object,element,eventTypes,fallThrough){this.object=object;this.element=element;this.eventTypes=eventTypes;this.fallThrough=fallThrough;this.listeners={};this.eventHandler=OpenLayers.Function.bindAsEventListener(this.handleBrowserEvent,this);if(this.eventTypes!=null){for(var i=0;i<this.eventTypes.length;i++){this.addEventType(this.eventTypes[i]);}}
-if(this.element!=null){this.attachToElement(element);}},destroy:function(){if(this.element){OpenLayers.Event.stopObservingElement(this.element);}
-this.element=null;this.listeners=null;this.object=null;this.eventTypes=null;this.fallThrough=null;this.eventHandler=null;},addEventType:function(eventName){if(!this.listeners[eventName]){this.listeners[eventName]=[];}},attachToElement:function(element){for(var i=0;i<this.BROWSER_EVENTS.length;i++){var eventType=this.BROWSER_EVENTS[i];this.addEventType(eventType);OpenLayers.Event.observe(element,eventType,this.eventHandler);}
-OpenLayers.Event.observe(element,"dragstart",OpenLayers.Event.stop);},register:function(type,obj,func){if(func!=null){if(obj==null){obj=this.object;}
-var listeners=this.listeners[type];if(listeners!=null){listeners.push({obj:obj,func:func});}}},registerPriority:function(type,obj,func){if(func!=null){if(obj==null){obj=this.object;}
-var listeners=this.listeners[type];if(listeners!=null){listeners.unshift({obj:obj,func:func});}}},unregister:function(type,obj,func){if(obj==null){obj=this.object;}
-var listeners=this.listeners[type];if(listeners!=null){for(var i=0;i<listeners.length;i++){if(listeners[i].obj==obj&&listeners[i].func==func){listeners.splice(i,1);break;}}}},remove:function(type){if(this.listeners[type]!=null){this.listeners[type]=[];}},triggerEvent:function(type,evt){if(evt==null){evt={};}
-evt.object=this.object;evt.element=this.element;var listeners=(this.listeners[type])?this.listeners[type].slice():null;if((listeners!=null)&&(listeners.length>0)){for(var i=0;i<listeners.length;i++){var callback=listeners[i];var continueChain;if(callback.obj!=null){continueChain=callback.func.call(callback.obj,evt);}else{continueChain=callback.func(evt);}
-if((continueChain!=null)&&(continueChain==false)){break;}}
-if(!this.fallThrough){OpenLayers.Event.stop(evt,true);}}},handleBrowserEvent:function(evt){evt.xy=this.getMousePosition(evt);this.triggerEvent(evt.type,evt)},getMousePosition:function(evt){if(!this.element.offsets){this.element.offsets=OpenLayers.Util.pagePosition(this.element);this.element.offsets[0]+=(document.documentElement.scrollLeft||document.body.scrollLeft);this.element.offsets[1]+=(document.documentElement.scrollTop||document.body.scrollTop);}
-return new OpenLayers.Pixel((evt.clientX+(document.documentElement.scrollLeft||document.body.scrollLeft))-this.element.offsets[0]
--(document.documentElement.clientLeft||0),(evt.clientY+(document.documentElement.scrollTop||document.body.scrollTop))-this.element.offsets[1]
--(document.documentElement.clientTop||0));},CLASS_NAME:"OpenLayers.Events"});OpenLayers.Projection=OpenLayers.Class({initialize:function(projCode,options){OpenLayers.Util.extend(this,options);this.projCode=projCode;if(window.Proj4js){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;},CLASS_NAME:"OpenLayers.Projection"});OpenLayers.Projection.transform=function(point,source,dest){if(source.proj&&dest.proj){point=Proj4js.transform(source.proj,dest.proj,point);}
-return point;};OpenLayers.Tile=OpenLayers.Class({EVENT_TYPES:["loadstart","loadend","reload"],events:null,id:null,layer:null,url:null,bounds:null,size:null,position:null,isLoading:false,initialize:function(layer,position,bounds,url,size){this.layer=layer;this.position=position.clone();this.bounds=bounds.clone();this.url=url;this.size=size.clone();this.id=OpenLayers.Util.createUniqueID("Tile_");this.events=new OpenLayers.Events(this,null,this.EVENT_TYPES);},destroy:function(){this.layer=null;this.bounds=null;this.size=null;this.position=null;this.events.destroy();this.events=null;},draw:function(){this.clear();var maxExtent=this.layer.maxExtent;var withinMaxExtent=true;if(this.layer.restrictedExtent){withinMaxExtent=(maxExtent&&this.bounds.intersectsBounds(maxExtent,false));}
-return(withinMaxExtent||this.layer.displayOutsideMaxExtent);},moveTo:function(bounds,position,redraw){if(redraw==null){redraw=true;}
-this.bounds=bounds.clone();this.position=position.clone();if(redraw){this.draw();}},clear:function(){},getBoundsFromBaseLayer:function(position){OpenLayers.Console.warn(OpenLayers.String.translate("layerAlreadyAdded",this.layer.name));var topLeft=this.layer.map.getLonLatFromLayerPx(position);var bottomRightPx=position.clone();bottomRightPx.x+=this.size.w;bottomRightPx.y+=this.size.h;var bottomRight=this.layer.map.getLonLatFromLayerPx(bottomRightPx);if(topLeft.lon>bottomRight.lon){if(topLeft.lon<0){topLeft.lon=-180-(topLeft.lon+180);}else{bottomRight.lon=180+bottomRight.lon+180;}}
-bounds=new OpenLayers.Bounds(topLeft.lon,bottomRight.lat,bottomRight.lon,topLeft.lat);return bounds;},CLASS_NAME:"OpenLayers.Tile"});OpenLayers.Control.OverviewMap=OpenLayers.Class(OpenLayers.Control,{id:"OverviewMap",element:null,ovmap:null,size:new OpenLayers.Size(180,90),layers:null,minRatio:8,maxRatio:32,mapOptions:null,initialize:function(options){this.layers=[];OpenLayers.Control.prototype.initialize.apply(this,[options]);},destroy:function(){if(!this.mapDiv){return;}
-this.mapDiv.removeChild(this.extentRectangle);this.extentRectangle=null;this.rectEvents.destroy();this.rectEvents=null;this.ovmap.destroy();this.ovmap=null;this.element.removeChild(this.mapDiv);this.mapDiv=null;this.mapDivEvents.destroy();this.mapDivEvents=null;this.div.removeChild(this.element);this.element=null;this.elementEvents.destroy();this.elementEvents=null;if(this.maximizeDiv){OpenLayers.Event.stopObservingElement(this.maximizeDiv);this.div.removeChild(this.maximizeDiv);this.maximizeDiv=null;}
-if(this.minimizeDiv){OpenLayers.Event.stopObservingElement(this.minimizeDiv);this.div.removeChild(this.minimizeDiv);this.minimizeDiv=null;}
-this.map.events.unregister('moveend',this,this.update);this.map.events.unregister("changebaselayer",this,this.baseLayerDraw);OpenLayers.Control.prototype.destroy.apply(this,arguments);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!(this.layers.length>0)){if(this.map.baseLayer){var layer=this.map.baseLayer.clone();this.layers=[layer];}else{this.map.events.register("changebaselayer",this,this.baseLayerDraw);return this.div;}}
-this.element=document.createElement('div');this.element.className=this.displayClass+'Element';this.element.style.display='none';this.mapDiv=document.createElement('div');this.mapDiv.style.width=this.size.w+'px';this.mapDiv.style.height=this.size.h+'px';this.mapDiv.style.position='relative';this.mapDiv.style.overflow='hidden';this.mapDiv.id=OpenLayers.Util.createUniqueID('overviewMap');this.extentRectangle=document.createElement('div');this.extentRectangle.style.position='absolute';this.extentRectangle.style.zIndex=1000;this.extentRectangle.style.overflow='hidden';this.extentRectangle.style.backgroundImage='url('+
-OpenLayers.Util.getImagesLocation()+'blank.gif)';this.extentRectangle.className=this.displayClass+'ExtentRectangle';this.mapDiv.appendChild(this.extentRectangle);this.element.appendChild(this.mapDiv);this.div.appendChild(this.element);this.map.events.register('moveend',this,this.update);this.elementEvents=new OpenLayers.Events(this,this.element);this.elementEvents.register('mousedown',this,function(e){OpenLayers.Event.stop(e);});this.elementEvents.register('click',this,function(e){OpenLayers.Event.stop(e);});this.elementEvents.register('dblclick',this,function(e){OpenLayers.Event.stop(e);});this.rectEvents=new OpenLayers.Events(this,this.extentRectangle,null,true);this.rectEvents.register('mouseout',this,this.rectMouseOut);this.rectEvents.register('mousedown',this,this.rectMouseDown);this.rectEvents.register('mousemove',this,this.rectMouseMove);this.rectEvents.register('mouseup',this,this.rectMouseUp);this.rectEvents.register('click',this,function(e){OpenLayers.Event.stop(e);});this.rectEvents.register('dblclick',this,this.rectDblClick);this.mapDivEvents=new OpenLayers.Events(this,this.mapDiv);this.mapDivEvents.register('click',this,this.mapDivClick);if(!this.outsideViewport){this.div.className=this.displayClass+'Container';var imgLocation=OpenLayers.Util.getImagesLocation();var img=imgLocation+'layer-switcher-maximize.png';this.maximizeDiv=OpenLayers.Util.createAlphaImageDiv(this.displayClass+'MaximizeButton',null,new OpenLayers.Size(18,18),img,'absolute');this.maximizeDiv.style.display='none';this.maximizeDiv.className=this.displayClass+'MaximizeButton';OpenLayers.Event.observe(this.maximizeDiv,'click',OpenLayers.Function.bindAsEventListener(this.maximizeControl,this));this.div.appendChild(this.maximizeDiv);var img=imgLocation+'layer-switcher-minimize.png';this.minimizeDiv=OpenLayers.Util.createAlphaImageDiv('OpenLayers_Control_minimizeDiv',null,new OpenLayers.Size(18,18),img,'absolute');this.minimizeDiv.style.display='none';this.minimizeDiv.className=this.displayClass+'MinimizeButton';OpenLayers.Event.observe(this.minimizeDiv,'click',OpenLayers.Function.bindAsEventListener(this.minimizeControl,this));this.div.appendChild(this.minimizeDiv);var eventsToStop=['dblclick','mousedown'];for(var i=0;i<eventsToStop.length;i++){OpenLayers.Event.observe(this.maximizeDiv,eventsToStop[i],OpenLayers.Event.stop);OpenLayers.Event.observe(this.minimizeDiv,eventsToStop[i],OpenLayers.Event.stop);}
-this.minimizeControl();}else{this.element.style.display='';}
-if(this.map.getExtent()){this.update();}
-return this.div;},baseLayerDraw:function(){this.draw();this.map.events.unregister("changebaselayer",this,this.baseLayerDraw);},rectMouseOut:function(evt){if(this.rectDragStart!=null){if(this.performedRectDrag){this.rectMouseMove(evt);var rectPxBounds=this.getRectPxBounds();if((rectPxBounds.top<=0)||(rectPxBounds.left<=0)||(rectPxBounds.bottom>=this.size.h-this.hComp)||(rectPxBounds.right>=this.size.w-this.wComp)){this.updateMapToRect();}else{return;}}
-document.onselectstart=null;this.rectDragStart=null;}},rectMouseDown:function(evt){if(!OpenLayers.Event.isLeftClick(evt))return;this.rectDragStart=evt.xy.clone();this.performedRectDrag=false;OpenLayers.Event.stop(evt);},rectMouseMove:function(evt){if(this.rectDragStart!=null){var deltaX=this.rectDragStart.x-evt.xy.x;var deltaY=this.rectDragStart.y-evt.xy.y;var rectPxBounds=this.getRectPxBounds();var rectTop=rectPxBounds.top;var rectLeft=rectPxBounds.left;var rectHeight=Math.abs(rectPxBounds.getHeight());var rectWidth=rectPxBounds.getWidth();var newTop=Math.max(0,(rectTop-deltaY));newTop=Math.min(newTop,this.ovmap.size.h-this.hComp-rectHeight);var newLeft=Math.max(0,(rectLeft-deltaX));newLeft=Math.min(newLeft,this.ovmap.size.w-this.wComp-rectWidth);this.setRectPxBounds(new OpenLayers.Bounds(newLeft,newTop+rectHeight,newLeft+rectWidth,newTop));this.rectDragStart=evt.xy.clone();this.performedRectDrag=true;OpenLayers.Event.stop(evt);}},rectMouseUp:function(evt){if(!OpenLayers.Event.isLeftClick(evt))return;if(this.performedRectDrag){this.updateMapToRect();OpenLayers.Event.stop(evt);}
-document.onselectstart=null;this.rectDragStart=null;},rectDblClick:function(evt){this.performedRectDrag=false;OpenLayers.Event.stop(evt);this.updateOverview();},mapDivClick:function(evt){var pxBounds=this.getRectPxBounds();var pxCenter=pxBounds.getCenterPixel();var deltaX=evt.xy.x-pxCenter.x;var deltaY=evt.xy.y-pxCenter.y;var top=pxBounds.top;var left=pxBounds.left;var height=Math.abs(pxBounds.getHeight());var width=pxBounds.getWidth();var newTop=Math.max(0,(top+deltaY));newTop=Math.min(newTop,this.ovmap.size.h-height);var newLeft=Math.max(0,(left+deltaX));newLeft=Math.min(newLeft,this.ovmap.size.w-width);this.setRectPxBounds(new OpenLayers.Bounds(newLeft,newTop+height,newLeft+width,newTop));this.updateMapToRect();OpenLayers.Event.stop(evt);},maximizeControl:function(e){this.element.style.display='';this.showToggle(false);if(e!=null){OpenLayers.Event.stop(e);}},minimizeControl:function(e){this.element.style.display='none';this.showToggle(true);if(e!=null){OpenLayers.Event.stop(e);}},showToggle:function(minimize){this.maximizeDiv.style.display=minimize?'':'none';this.minimizeDiv.style.display=minimize?'none':'';},update:function(){if(this.ovmap==null){this.createMap();}
-if(!this.isSuitableOverview()){this.updateOverview();}
-this.updateRectToMap();},isSuitableOverview:function(){var mapExtent=this.map.getExtent();var maxExtent=this.map.maxExtent;var testExtent=new OpenLayers.Bounds(Math.max(mapExtent.left,maxExtent.left),Math.max(mapExtent.bottom,maxExtent.bottom),Math.min(mapExtent.right,maxExtent.right),Math.min(mapExtent.top,maxExtent.top));var resRatio=this.ovmap.getResolution()/this.map.getResolution();return((resRatio>this.minRatio)&&(resRatio<=this.maxRatio)&&(this.ovmap.getExtent().containsBounds(testExtent)));},updateOverview:function(){var mapRes=this.map.getResolution();var targetRes=this.ovmap.getResolution();var resRatio=targetRes/mapRes;if(resRatio>this.maxRatio){targetRes=this.minRatio*mapRes;}else if(resRatio<=this.minRatio){targetRes=this.maxRatio*mapRes;}
-this.ovmap.setCenter(this.map.center,this.ovmap.getZoomForResolution(targetRes));this.updateRectToMap();},createMap:function(){var options=OpenLayers.Util.extend({controls:[],maxResolution:'auto'},this.mapOptions);this.ovmap=new OpenLayers.Map(this.mapDiv,options);this.ovmap.addLayers(this.layers);this.ovmap.zoomToMaxExtent();this.wComp=parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-left-width'))+
-parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-right-width'));this.wComp=(this.wComp)?this.wComp:2;this.hComp=parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-top-width'))+
-parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-bottom-width'));this.hComp=(this.hComp)?this.hComp:2;},updateRectToMap:function(){var pxBounds=this.getRectBoundsFromMapBounds(this.map.getExtent());if(pxBounds){this.setRectPxBounds(pxBounds);}},updateMapToRect:function(){var pxBounds=this.getRectPxBounds();var lonLatBounds=this.getMapBoundsFromRectBounds(pxBounds);this.map.setCenter(lonLatBounds.getCenterLonLat(),this.map.zoom);},getRectPxBounds:function(){var top=parseInt(this.extentRectangle.style.top);var left=parseInt(this.extentRectangle.style.left);var height=parseInt(this.extentRectangle.style.height);var width=parseInt(this.extentRectangle.style.width);return new OpenLayers.Bounds(left,top+height,left+width,top);},setRectPxBounds:function(pxBounds){var top=Math.max(pxBounds.top,0);var left=Math.max(pxBounds.left,0);var bottom=Math.min(pxBounds.top+Math.abs(pxBounds.getHeight()),this.ovmap.size.h-this.hComp);var right=Math.min(pxBounds.left+pxBounds.getWidth(),this.ovmap.size.w-this.wComp);this.extentRectangle.style.top=parseInt(top)+'px';this.extentRectangle.style.left=parseInt(left)+'px';this.extentRectangle.style.height=parseInt(Math.max(bottom-top,0))+'px';this.extentRectangle.style.width=parseInt(Math.max(right-left,0))+'px';},getRectBoundsFromMapBounds:function(lonLatBounds){var leftBottomLonLat=new OpenLayers.LonLat(lonLatBounds.left,lonLatBounds.bottom);var rightTopLonLat=new OpenLayers.LonLat(lonLatBounds.right,lonLatBounds.top);var leftBottomPx=this.getOverviewPxFromLonLat(leftBottomLonLat);var rightTopPx=this.getOverviewPxFromLonLat(rightTopLonLat);var bounds=null;if(leftBottomPx&&rightTopPx){bounds=new OpenLayers.Bounds(leftBottomPx.x,leftBottomPx.y,rightTopPx.x,rightTopPx.y);}
-return bounds;},getMapBoundsFromRectBounds:function(pxBounds){var leftBottomPx=new OpenLayers.Pixel(pxBounds.left,pxBounds.bottom);var rightTopPx=new OpenLayers.Pixel(pxBounds.right,pxBounds.top);var leftBottomLonLat=this.getLonLatFromOverviewPx(leftBottomPx);var rightTopLonLat=this.getLonLatFromOverviewPx(rightTopPx);return new OpenLayers.Bounds(leftBottomLonLat.lon,leftBottomLonLat.lat,rightTopLonLat.lon,rightTopLonLat.lat);},getLonLatFromOverviewPx:function(overviewMapPx){var size=this.ovmap.size;var res=this.ovmap.getResolution();var center=this.ovmap.getExtent().getCenterLonLat();var delta_x=overviewMapPx.x-(size.w/2);var delta_y=overviewMapPx.y-(size.h/2);return new OpenLayers.LonLat(center.lon+delta_x*res,center.lat-delta_y*res);},getOverviewPxFromLonLat:function(lonlat){var res=this.ovmap.getResolution();var extent=this.ovmap.getExtent();var px=null;if(extent){px=new OpenLayers.Pixel(Math.round(1/res*(lonlat.lon-extent.left)),Math.round(1/res*(extent.top-lonlat.lat)));}
-return px;},CLASS_NAME:'OpenLayers.Control.OverviewMap'});OpenLayers.Handler=OpenLayers.Class({id:null,control:null,map:null,keyMask:null,active:false,evt:null,initialize:function(control,callbacks,options){OpenLayers.Util.extend(this,options);this.control=control;this.callbacks=callbacks;if(control.map){this.setMap(control.map);}
-OpenLayers.Util.extend(this,options);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},setMap:function(map){this.map=map;},checkModifiers:function(evt){if(this.keyMask==null){return true;}
-var keyModifiers=(evt.shiftKey?OpenLayers.Handler.MOD_SHIFT:0)|(evt.ctrlKey?OpenLayers.Handler.MOD_CTRL:0)|(evt.altKey?OpenLayers.Handler.MOD_ALT:0);return(keyModifiers==this.keyMask);},activate:function(){if(this.active){return false;}
-var events=OpenLayers.Events.prototype.BROWSER_EVENTS;for(var i=0;i<events.length;i++){if(this[events[i]]){this.register(events[i],this[events[i]]);}}
-this.active=true;return true;},deactivate:function(){if(!this.active){return false;}
-var events=OpenLayers.Events.prototype.BROWSER_EVENTS;for(var i=0;i<events.length;i++){if(this[events[i]]){this.unregister(events[i],this[events[i]]);}}
-this.active=false;return true;},callback:function(name,args){if(this.callbacks[name]){this.callbacks[name].apply(this.control,args);}},register:function(name,method){this.map.events.registerPriority(name,this,method);this.map.events.registerPriority(name,this,this.setEvent);},unregister:function(name,method){this.map.events.unregister(name,this,method);this.map.events.unregister(name,this,this.setEvent);},setEvent:function(evt){this.evt=evt;return true;},destroy:function(){this.deactivate();this.control=this.map=null;},CLASS_NAME:"OpenLayers.Handler"});OpenLayers.Handler.MOD_NONE=0;OpenLayers.Handler.MOD_SHIFT=1;OpenLayers.Handler.MOD_CTRL=2;OpenLayers.Handler.MOD_ALT=4;OpenLayers.Map=OpenLayers.Class({Z_INDEX_BASE:{BaseLayer:100,Overlay:325,Popup:750,Control:1000},EVENT_TYPES:["addlayer","removelayer","changelayer","movestart","move","moveend","zoomend","popupopen","popupclose","addmarker","removemarker","clearmarkers","mouseover","mouseout","mousemove","dragstart","drag","dragend","changebaselayer"],id:null,events:null,div:null,size:null,viewPortDiv:null,layerContainerOrigin:null,layerContainerDiv:null,layers:null,controls:null,popups:null,baseLayer:null,center:null,zoom:0,viewRequestID:0,tileSize:null,projection:"EPSG:4326",units:'degrees',resolutions:null,maxResolution:1.40625,minResolution:null,maxScale:null,minScale:null,maxExtent:null,minExtent:null,restrictedExtent:'auto',numZoomLevels:16,theme:null,fallThrough:false,initialize:function(div,options){this.setOptions(options);this.id=OpenLayers.Util.createUniqueID("OpenLayers.Map_");this.div=OpenLayers.Util.getElement(div);var id=this.div.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);id=this.div.id+"_OpenLayers_Container";this.layerContainerDiv=OpenLayers.Util.createDiv(id);this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;this.viewPortDiv.appendChild(this.layerContainerDiv);this.events=new OpenLayers.Events(this,this.div,this.EVENT_TYPES,this.fallThrough);this.updateSize();this.events.register("movestart",this,this.updateSize);if(OpenLayers.String.contains(navigator.appName,"Microsoft")){this.events.register("resize",this,this.updateSize);}else{OpenLayers.Event.observe(window,'resize',OpenLayers.Function.bind(this.updateSize,this));}
-if(this.theme){var addNode=true;var nodes=document.getElementsByTagName('link');for(var i=0;i<nodes.length;++i){if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,this.theme)){addNode=false;break;}}
-if(addNode){var cssNode=document.createElement('link');cssNode.setAttribute('rel','stylesheet');cssNode.setAttribute('type','text/css');cssNode.setAttribute('href',this.theme);document.getElementsByTagName('head')[0].appendChild(cssNode);}}
-this.layers=[];if(this.controls==null){if(OpenLayers.Control!=null){this.controls=[new OpenLayers.Control.Navigation(),new OpenLayers.Control.PanZoom(),new OpenLayers.Control.ArgParser(),new OpenLayers.Control.Attribution()];}else{this.controls=[];}}
-for(var i=0;i<this.controls.length;i++){this.addControlToMap(this.controls[i]);}
-this.popups=[];this.unloadDestroy=OpenLayers.Function.bind(this.destroy,this);OpenLayers.Event.observe(window,'unload',this.unloadDestroy);},unloadDestroy:null,destroy:function(){if(!this.unloadDestroy){return false;}
-OpenLayers.Event.stopObserving(window,'unload',this.unloadDestroy);this.unloadDestroy=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.controls!=null){for(var i=this.controls.length-1;i>=0;--i){this.controls[i].destroy();}
-this.controls=null;}
-if(this.viewPortDiv){this.div.removeChild(this.viewPortDiv);}
-this.viewPortDiv=null;this.events.destroy();this.events=null;},setOptions:function(options){this.tileSize=new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,OpenLayers.Map.TILE_HEIGHT);this.maxExtent=new OpenLayers.Bounds(-180,-90,180,90);this.theme=OpenLayers._getScriptLocation()+'theme/default/style.css';OpenLayers.Util.extend(this,options);},getTileSize:function(){return this.tileSize;},getLayer:function(id){var foundLayer=null;for(var i=0;i<this.layers.length;i++){var layer=this.layers[i];if(layer.id==id){foundLayer=layer;}}
-return foundLayer;},setLayerZIndex:function(layer,zIdx){layer.setZIndex(this.Z_INDEX_BASE[layer.isBaseLayer?'BaseLayer':'Overlay']
-+zIdx*5);},addLayer:function(layer){for(var i=0;i<this.layers.length;i++){if(this.layers[i]==layer){OpenLayers.Console.warn(OpenLayers.String.translate("layerAlreadyAdded",layer.name));return false;}}
-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){if(this.baseLayer==null){this.setBaseLayer(layer);}else{layer.setVisibility(false);}}else{layer.redraw();}
-this.events.triggerEvent("addlayer");},addLayers:function(layers){for(var i=0;i<layers.length;i++){this.addLayer(layers[i]);}},removeLayer:function(layer,setNewBaseLayer){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(setNewBaseLayer&&(this.baseLayer==layer)){this.baseLayer=null;for(i=0;i<this.layers.length;i++){var iLayer=this.layers[i];if(iLayer.isBaseLayer){this.setBaseLayer(iLayer);break;}}}
-this.events.triggerEvent("removelayer");},getNumLayers:function(){return this.layers.length;},getLayerIndex:function(layer){return OpenLayers.Util.indexOf(this.layers,layer);},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;i<this.layers.length;i++){this.setLayerZIndex(this.layers[i],i);}
-this.events.triggerEvent("changelayer");}},raiseLayer:function(layer,delta){var idx=this.getLayerIndex(layer)+delta;this.setLayerIndex(layer,idx);},setBaseLayer:function(newBaseLayer){var oldExtent=null;if(this.baseLayer){oldExtent=this.baseLayer.getExtent();}
-if(newBaseLayer!=this.baseLayer){if(OpenLayers.Util.indexOf(this.layers,newBaseLayer)!=-1){if(this.baseLayer!=null){this.baseLayer.setVisibility(false);}
-this.baseLayer=newBaseLayer;this.maxExtent=newBaseLayer.maxExtent;this.minExtent=newBaseLayer.minExtent;this.maxScale=newBaseLayer.maxScale;this.minScale=newBaseLayer.minScale;this.maxResolution=newBaseLayer.maxResolution;this.minResolution=newBaseLayer.minResolution;this.units=newBaseLayer.units;this.projection=newBaseLayer.projection;this.viewRequestID++;this.baseLayer.visibility=true;var center=this.getCenter();if(center!=null){if(oldExtent==null){this.setCenter(center,this.getZoom(),false,true);}else{this.setCenter(oldExtent.getCenterLonLat(),this.getZoomForExtent(oldExtent),false,true);}}
-this.events.triggerEvent("changebaselayer");}}},addControl:function(control,px){this.controls.push(control);this.addControlToMap(control,px);},addControlToMap:function(control,px){control.outsideViewport=(control.div!=null);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);}}},getControl:function(id){var returnControl=null;for(var i=0;i<this.controls.length;i++){var control=this.controls[i];if(control.id==id){returnControl=control;break;}}
-return returnControl;},removeControl:function(control){if((control)&&(control==this.getControl(control.id))){if(!control.outsideViewport){this.viewPortDiv.removeChild(control.div)}
-OpenLayers.Util.removeItem(this.controls,control);}},addPopup:function(popup,exclusive){if(exclusive){for(var i=0;i<this.popups.length;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(){this.events.element.offsets=null;var newSize=this.getCurrentSize();var oldSize=this.getSize();if(oldSize==null)
-this.size=oldSize=newSize;if(!newSize.equals(oldSize)){this.size=newSize;for(var i=0;i<this.layers.length;i++){this.layers[i].onMapResize();}
-if(this.baseLayer!=null){var center=new OpenLayers.Pixel(newSize.w/2,newSize.h/2);var centerLL=this.getLonLatFromViewPortPx(center);var zoom=this.getZoom();this.zoom=null;this.setCenter(this.getCenter(),zoom);}}},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)){var dim=OpenLayers.Element.getDimensions(this.div);size.w=dim.width;size.h=dim.height;}
-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;},calculateBounds:function(center,resolution){var extent=null;if(center==null){center=this.getCenter();}
-if(resolution==null){resolution=this.getResolution();}
-if((center!=null)&&(resolution!=null)){var size=this.getSize();var w_deg=size.w*resolution;var h_deg=size.h*resolution;extent=new OpenLayers.Bounds(center.lon-w_deg/2,center.lat-h_deg/2,center.lon+w_deg/2,center.lat+h_deg/2);}
-return extent;},getCenter:function(){return this.center;},getZoom:function(){return this.zoom;},pan:function(dx,dy){var centerPx=this.getViewPortPxFromLonLat(this.getCenter());var newCenterPx=centerPx.add(dx,dy);if(!newCenterPx.equals(centerPx)){var newCenterLonLat=this.getLonLatFromViewPortPx(newCenterPx);this.setCenter(newCenterLonLat);}},setCenter:function(lonlat,zoom,dragging,forceZoomChange){if(!this.center&&!this.isValidLonLat(lonlat)){lonlat=this.maxExtent.getCenterLonLat();}
-if(this.restrictedExtent&&this.restrictedExtent!='auto'){if(lonlat==null){lonlat=this.getCenter();}
-if(zoom==null){zoom=this.getZoom();}
-var resolution=null;if(this.baseLayer!=null){resolution=this.baseLayer.resolutions[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=!lonlat.equals(this.center);if(this.restrictedExtent=='auto'){centerChanged=this.isValidLonLat(lonlat)&¢erChanged;}
-if(zoomChanged||centerChanged||!dragging){if(!dragging){this.events.triggerEvent("movestart");}
-if(centerChanged){if((!zoomChanged)&&(this.center)){this.centerLayerContainer(lonlat);}
-this.center=lonlat.clone();}
-if((zoomChanged)||(this.layerContainerOrigin==null)){this.layerContainerOrigin=this.center.clone();this.layerContainerDiv.style.left="0px";this.layerContainerDiv.style.top="0px";}
-if(zoomChanged){this.zoom=zoom;this.viewRequestID++;}
-var bounds=this.getExtent();this.baseLayer.moveTo(bounds,zoomChanged,dragging);bounds=this.baseLayer.getExtent();for(var i=0;i<this.layers.length;i++){var layer=this.layers[i];if(!layer.isBaseLayer){var moveLayer;var inRange=layer.calculateInRange();if(layer.inRange!=inRange){layer.inRange=inRange;moveLayer=true;this.events.triggerEvent("changelayer");}else{moveLayer=(layer.visibility&&layer.inRange);}
-if(moveLayer){layer.moveTo(bounds,zoomChanged,dragging);}}}
-if(zoomChanged){for(var i=0;i<this.popups.length;i++){this.popups[i].updatePosition();}}
-this.events.triggerEvent("move");if(zoomChanged){this.events.triggerEvent("zoomend");}}
-if(!dragging){this.events.triggerEvent("moveend");}},centerLayerContainer:function(lonlat){var originPx=this.getViewPortPxFromLonLat(this.layerContainerOrigin);var newPx=this.getViewPortPxFromLonLat(lonlat);if((originPx!=null)&&(newPx!=null)){this.layerContainerDiv.style.left=(originPx.x-newPx.x)+"px";this.layerContainerDiv.style.top=(originPx.y-newPx.y)+"px";}},isValidZoomLevel:function(zoomLevel){return((zoomLevel!=null)&&(zoomLevel>=0)&&(zoomLevel<this.getNumZoomLevels()));},isValidLonLat:function(lonlat){var valid=false;if(lonlat!=null){var maxExtent=this.getMaxExtent();valid=maxExtent.containsLonLat(lonlat);}
-return valid;},getProjection:function(){var projection=null;if(this.baseLayer!=null){projection=this.baseLayer.projection;}
-return projection;},getMaxResolution:function(){var maxResolution=null;if(this.baseLayer!=null){maxResolution=this.baseLayer.maxResolution;}
-return maxResolution;},getMaxExtent:function(){var maxExtent=null;if(this.baseLayer!=null){maxExtent=this.baseLayer.maxExtent;}
-return maxExtent;},getNumZoomLevels:function(){var numZoomLevels=null;if(this.baseLayer!=null){numZoomLevels=this.baseLayer.numZoomLevels;}
-return numZoomLevels;},getExtent:function(){var extent=null;if(this.baseLayer!=null){extent=this.baseLayer.getExtent();}
-return extent;},getResolution:function(){var resolution=null;if(this.baseLayer!=null){resolution=this.baseLayer.getResolution();}
-return resolution;},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){var zoom=null;if(this.baseLayer!=null){zoom=this.baseLayer.getZoomForExtent(bounds);}
-return zoom;},getZoomForResolution:function(resolution){var zoom=null;if(this.baseLayer!=null){zoom=this.baseLayer.getZoomForResolution(resolution);}
-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){var center=bounds.getCenterLonLat();if(this.baseLayer.wrapDateLine){var maxExtent=this.getMaxExtent();bounds=bounds.clone();while(bounds.right<bounds.left){bounds.right+=maxExtent.getWidth();}
-center=bounds.getCenterLonLat().wrapDateLine(maxExtent);}
-this.setCenter(center,this.getZoomForExtent(bounds));},zoomToMaxExtent:function(){this.zoomToExtent(this.getMaxExtent());},zoomToScale:function(scale){var res=OpenLayers.Util.getResolutionFromScale(scale,this.baseLayer.units);var size=this.getSize();var w_deg=size.w*res;var h_deg=size.h*res;var center=this.getCenter();var extent=new OpenLayers.Bounds(center.lon-w_deg/2,center.lat-h_deg/2,center.lon+w_deg/2,center.lat+h_deg/2);this.zoomToExtent(extent);},getLonLatFromViewPortPx:function(viewPortPx){var lonlat=null;if(this.baseLayer!=null){lonlat=this.baseLayer.getLonLatFromViewPortPx(viewPortPx);}
-return lonlat;},getViewPortPxFromLonLat:function(lonlat){var px=null;if(this.baseLayer!=null){px=this.baseLayer.getViewPortPxFromLonLat(lonlat);}
-return px;},getLonLatFromPixel:function(px){return this.getLonLatFromViewPortPx(px);},getPixelFromLonLat:function(lonlat){return this.getViewPortPxFromLonLat(lonlat);},getViewPortPxFromLayerPx:function(layerPx){var viewPortPx=null;if(layerPx!=null){var dX=parseInt(this.layerContainerDiv.style.left);var dY=parseInt(this.layerContainerDiv.style.top);viewPortPx=layerPx.add(dX,dY);}
-return viewPortPx;},getLayerPxFromViewPortPx:function(viewPortPx){var layerPx=null;if(viewPortPx!=null){var dX=-parseInt(this.layerContainerDiv.style.left);var dY=-parseInt(this.layerContainerDiv.style.top);layerPx=viewPortPx.add(dX,dY);if(isNaN(layerPx.x)||isNaN(layerPx.y)){layerPx=null;}}
-return layerPx;},getLonLatFromLayerPx:function(px){px=this.getViewPortPxFromLayerPx(px);return this.getLonLatFromViewPortPx(px);},getLayerPxFromLonLat:function(lonlat){var px=this.getViewPortPxFromLonLat(lonlat);return this.getLayerPxFromViewPortPx(px);},CLASS_NAME:"OpenLayers.Map"});OpenLayers.Map.TILE_WIDTH=256;OpenLayers.Map.TILE_HEIGHT=256;OpenLayers.Marker=OpenLayers.Class({icon:null,lonlat:null,events:null,map:null,initialize:function(lonlat,icon){this.lonlat=lonlat;var newIcon=(icon)?icon:OpenLayers.Marker.defaultIcon();if(this.icon==null){this.icon=newIcon;}else{this.icon.url=newIcon.url;this.icon.size=newIcon.size;this.icon.offset=newIcon.offset;this.icon.calculateOffset=newIcon.calculateOffset;}
-this.events=new OpenLayers.Events(this,this.icon.imageDiv,null);},destroy:function(){this.map=null;this.events.destroy();this.events=null;if(this.icon!=null){this.icon.destroy();this.icon=null;}},draw:function(px){return this.icon.draw(px);},moveTo:function(px){if((px!=null)&&(this.icon!=null)){this.icon.moveTo(px);}
-this.lonlat=this.map.getLonLatFromLayerPx(px);},onScreen:function(){var onScreen=false;if(this.map){var screenBounds=this.map.getExtent();onScreen=screenBounds.containsLonLat(this.lonlat);}
-return onScreen;},inflate:function(inflate){if(this.icon){var newSize=new OpenLayers.Size(this.icon.size.w*inflate,this.icon.size.h*inflate);this.icon.setSize(newSize);}},setOpacity:function(opacity){this.icon.setOpacity(opacity);},display:function(display){this.icon.display(display);},CLASS_NAME:"OpenLayers.Marker"});OpenLayers.Marker.defaultIcon=function(){var url=OpenLayers.Util.getImagesLocation()+"marker.png";var size=new OpenLayers.Size(21,25);var calculateOffset=function(size){return new OpenLayers.Pixel(-(size.w/2),-size.h);};return new OpenLayers.Icon(url,size,null,calculateOffset);};OpenLayers.Tile.Image=OpenLayers.Class(OpenLayers.Tile,{url:null,imgDiv:null,frame:null,initialize:function(layer,position,bounds,url,size){OpenLayers.Tile.prototype.initialize.apply(this,arguments);this.url=url;this.frame=document.createElement('div');this.frame.style.overflow='hidden';this.frame.style.position='absolute';},destroy:function(){if(this.imgDiv!=null){OpenLayers.Event.stopObservingElement(this.imgDiv.id);if(this.imgDiv.parentNode==this.frame){this.frame.removeChild(this.imgDiv);this.imgDiv.map=null;}}
-this.imgDiv=null;if((this.frame!=null)&&(this.frame.parentNode==this.layer.div)){this.layer.div.removeChild(this.frame);}
-this.frame=null;OpenLayers.Tile.prototype.destroy.apply(this,arguments);},draw:function(){if(this.layer!=this.layer.map.baseLayer&&this.layer.reproject){this.bounds=this.getBoundsFromBaseLayer(this.position);}
-if(!OpenLayers.Tile.prototype.draw.apply(this,arguments)){return false;}
-if(this.isLoading){this.events.triggerEvent("reload");}else{this.isLoading=true;this.events.triggerEvent("loadstart");}
-if(this.imgDiv==null){this.initImgDiv();}
-this.imgDiv.viewRequestID=this.layer.map.viewRequestID;this.url=this.layer.getURL(this.bounds);OpenLayers.Util.modifyDOMElement(this.frame,null,this.position,this.size);var imageSize=this.layer.getImageSize();if(this.layer.alpha){OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,null,null,imageSize,this.url);}else{this.imgDiv.src=this.url;OpenLayers.Util.modifyDOMElement(this.imgDiv,null,null,imageSize);}
-return true;},clear:function(){if(this.imgDiv){this.imgDiv.style.display="none";}},initImgDiv:function(){var offset=this.layer.imageOffset;var size=this.layer.getImageSize();if(this.layer.alpha){this.imgDiv=OpenLayers.Util.createAlphaImageDiv(null,offset,size,null,"relative",null,null,null,true);}else{this.imgDiv=OpenLayers.Util.createImage(null,offset,size,null,"relative",null,null,true);}
-this.imgDiv.className='olTileImage';this.frame.appendChild(this.imgDiv);this.layer.div.appendChild(this.frame);if(this.layer.opacity!=null){OpenLayers.Util.modifyDOMElement(this.imgDiv,null,null,null,null,null,null,this.layer.opacity);}
-this.imgDiv.map=this.layer.map;var onload=function(){if(this.isLoading){this.isLoading=false;this.events.triggerEvent("loadend");}}
-OpenLayers.Event.observe(this.imgDiv,'load',OpenLayers.Function.bind(onload,this));},checkImgURL:function(){if(this.layer){var loaded=this.layer.alpha?this.imgDiv.firstChild.src:this.imgDiv.src;if(!OpenLayers.Util.isEquivalentUrl(loaded,this.url)){this.imgDiv.style.display="none";}}},CLASS_NAME:"OpenLayers.Tile.Image"});OpenLayers.Handler.Click=OpenLayers.Class(OpenLayers.Handler,{delay:300,single:true,'double':false,pixelTolerance:0,stopSingle:false,stopDouble:false,timerId:null,down:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);if(this.pixelTolerance!=null){this.mousedown=function(evt){this.down=evt.xy;return true;};}},mousedown:null,dblclick:function(evt){if(this.passesTolerance(evt)){if(this["double"]){this.callback('dblclick',[evt]);}
-this.clearTimer();}
-return!this.stopDouble;},click:function(evt){if(this.passesTolerance(evt)){if(this.timerId!=null){this.clearTimer();}else{var clickEvent=this.single?OpenLayers.Util.extend({},evt):null;this.timerId=window.setTimeout(OpenLayers.Function.bind(this.delayedCall,this,clickEvent),this.delay);}}
-return!this.stopSingle;},passesTolerance:function(evt){var passes=true;if(this.pixelTolerance!=null&&this.down){var dpx=Math.sqrt(Math.pow(this.down.x-evt.xy.x,2)+
-Math.pow(this.down.y-evt.xy.y,2));if(dpx>this.pixelTolerance){passes=false;}}
-return passes;},clearTimer:function(){if(this.timerId!=null){window.clearTimeout(this.timerId);this.timerId=null;}},delayedCall:function(evt){this.timerId=null;if(evt){this.callback('click',[evt]);}},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.clearTimer();this.down=null;deactivated=true;}
-return deactivated;},CLASS_NAME:"OpenLayers.Handler.Click"});OpenLayers.Handler.Drag=OpenLayers.Class(OpenLayers.Handler,{started:false,dragging:false,last:null,start:null,oldOnselectstart:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);},down:function(evt){},move:function(evt){},up:function(evt){},out:function(evt){},mousedown:function(evt){var propagate=true;this.dragging=false;if(this.checkModifiers(evt)&&OpenLayers.Event.isLeftClick(evt)){this.started=true;this.start=evt.xy;this.last=evt.xy;this.map.div.style.cursor="move";this.down(evt);this.callback("down",[evt.xy]);OpenLayers.Event.stop(evt);if(!this.oldOnselectstart){this.oldOnselectstart=document.onselectstart;document.onselectstart=function(){return false;}}
-propagate=false;}else{this.started=false;this.start=null;this.last=null;}
-return propagate;},mousemove:function(evt){if(this.started){if(evt.xy.x!=this.last.x||evt.xy.y!=this.last.y){this.dragging=true;this.move(evt);this.callback("move",[evt.xy]);if(!this.oldOnselectstart){this.oldOnselectstart=document.onselectstart;document.onselectstart=function(){return false;}}
-this.last=evt.xy;}}
-return true;},mouseup:function(evt){if(this.started){this.started=false;this.dragging=false;this.map.div.style.cursor="";this.up(evt);this.callback("up",[evt.xy]);this.callback("done",[evt.xy]);document.onselectstart=this.oldOnselectstart;}
-return true;},mouseout:function(evt){if(this.started&&OpenLayers.Util.mouseLeft(evt,this.map.div)){this.started=false;this.dragging=false;this.map.div.style.cursor="";this.out(evt);this.callback("out",[]);if(document.onselectstart){document.onselectstart=this.oldOnselectstart;}
-this.callback("done",[evt.xy])}
-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.started=false;this.dragging=false;this.start=null;this.last=null;deactivated=true;}
-return deactivated;},CLASS_NAME:"OpenLayers.Handler.Drag"});OpenLayers.Handler.MouseWheel=OpenLayers.Class(OpenLayers.Handler,{wheelListener:null,mousePosition:null,initialize:function(control,callbacks,options){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(e){if(!this.checkModifiers(e))return;var inMap=false;var elem=OpenLayers.Event.element(e);while(elem!=null){if(this.map&&elem==this.map.div){inMap=true;break;}
-elem=elem.parentNode;}
-if(inMap){var delta=0;if(!e){e=window.event;}
-if(e.wheelDelta){delta=e.wheelDelta/120;if(window.opera){delta=-delta;}}else if(e.detail){delta=-e.detail/3;}
-if(delta){if(this.mousePosition){e.xy=this.mousePosition;}
-if(!e.xy){e.xy=this.map.getPixelFromLonLat(this.map.getCenter());}
-if(delta<0){this.callback("down",[e,delta]);}else{this.callback("up",[e,delta]);}}
-OpenLayers.Event.stop(e);}},mousemove:function(evt){this.mousePosition=evt.xy;},activate:function(evt){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){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;}},deactivate:function(evt){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){var wheelListener=this.wheelListener;OpenLayers.Event.stopObserving(window,"DOMMouseScroll",wheelListener);OpenLayers.Event.stopObserving(window,"mousewheel",wheelListener);OpenLayers.Event.stopObserving(document,"mousewheel",wheelListener);return true;}else{return false;}},CLASS_NAME:"OpenLayers.Handler.MouseWheel"});OpenLayers.Layer=OpenLayers.Class({id:null,name:null,div:null,EVENT_TYPES:["loadstart","loadend","loadcancel","visibilitychanged"],events:null,map:null,isBaseLayer:false,alpha:false,displayInLayerSwitcher:true,visibility:true,attribution:null,inRange:false,imageSize:null,imageOffset:null,options: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:false,wrapDateLine:false,initialize:function(name,options){this.addOptions(options);this.name=name;if(this.id==null){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");this.div=OpenLayers.Util.createDiv();this.div.style.width="100%";this.div.style.height="100%";this.div.id=this.id;this.events=new OpenLayers.Events(this,this.div,this.EVENT_TYPES);}
-if(this.wrapDateLine){this.displayOutsideMaxExtent=true;}},destroy:function(setNewBaseLayer){if(setNewBaseLayer==null){setNewBaseLayer=true;}
-if(this.map!=null){this.map.removeLayer(this,setNewBaseLayer);}
-this.map=null;this.name=null;this.div=null;this.options=null;if(this.events){this.events.destroy();}
-this.events=null;},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer(this.name,this.options);}
-OpenLayers.Util.applyDefaults(obj,this);obj.map=null;return obj;},setName:function(newName){if(newName!=this.name){this.name=newName;if(this.map!=null){this.map.events.triggerEvent("changelayer");}}},addOptions:function(newOptions){if(this.options==null){this.options={};}
-OpenLayers.Util.extend(this.options,newOptions);OpenLayers.Util.extend(this,newOptions);},onMapResize:function(){},redraw:function(){var redrawn=false;if(this.map){this.inRange=this.calculateInRange();var extent=this.getExtent();if(extent&&this.inRange&&this.visibility){this.moveTo(extent,true,false);redrawn=true;}}
-return redrawn;},moveTo:function(bounds,zoomChanged,dragging){var display=this.visibility;if(!this.isBaseLayer){display=display&&this.inRange;}
-this.display(display);},setMap:function(map){if(this.map==null){this.map=map;this.maxExtent=this.maxExtent||this.map.maxExtent;this.projection=this.projection||this.map.projection;if(this.projection&&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();}},removeMap:function(map){},getImageSize:function(){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.imageOffset=new OpenLayers.Pixel(-this.gutter,-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");}
-this.events.triggerEvent("visibilitychanged");}},display:function(display){if(display!=(this.div.style.display!="none")){this.div.style.display=(display)?"block":"none";}},calculateInRange:function(){var inRange=false;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("changelayer");}}},initResolutions:function(){var props=new Array('projection','units','scales','resolutions','maxScale','minScale','maxResolution','minResolution','minExtent','maxExtent','numZoomLevels','maxZoomLevel');var confProps={};for(var i=0;i<props.length;i++){var property=props[i];confProps[property]=this.options[property]||this.map[property];}
-if((!confProps.numZoomLevels)&&(confProps.maxZoomLevel)){confProps.numZoomLevels=confProps.maxZoomLevel+1;}
-if((confProps.scales!=null)||(confProps.resolutions!=null)){if(confProps.scales!=null){confProps.resolutions=[];for(var i=0;i<confProps.scales.length;i++){var scale=confProps.scales[i];confProps.resolutions[i]=OpenLayers.Util.getResolutionFromScale(scale,confProps.units);}}
-confProps.numZoomLevels=confProps.resolutions.length;}else{confProps.resolutions=[];if(confProps.minScale){confProps.maxResolution=OpenLayers.Util.getResolutionFromScale(confProps.minScale,confProps.units);}else if(confProps.maxResolution=="auto"){var viewSize=this.map.getSize();var wRes=confProps.maxExtent.getWidth()/viewSize.w;var hRes=confProps.maxExtent.getHeight()/viewSize.h;confProps.maxResolution=Math.max(wRes,hRes);}
-if(confProps.maxScale!=null){confProps.minResolution=OpenLayers.Util.getResolutionFromScale(confProps.maxScale);}else if((confProps.minResolution=="auto")&&(confProps.minExtent!=null)){var viewSize=this.map.getSize();var wRes=confProps.minExtent.getWidth()/viewSize.w;var hRes=confProps.minExtent.getHeight()/viewSize.h;confProps.minResolution=Math.max(wRes,hRes);}
-if(confProps.minResolution!=null){var ratio=confProps.maxResolution/confProps.minResolution;confProps.numZoomLevels=Math.floor(Math.log(ratio)/Math.log(2))+1;}
-for(var i=0;i<confProps.numZoomLevels;i++){var res=confProps.maxResolution/Math.pow(2,i)
-confProps.resolutions.push(res);}}
-confProps.resolutions.sort(function(a,b){return(b-a);});this.resolutions=confProps.resolutions;this.maxResolution=confProps.resolutions[0];var lastIndex=confProps.resolutions.length-1;this.minResolution=confProps.resolutions[lastIndex];this.scales=[];for(var i=0;i<confProps.resolutions.length;i++){this.scales[i]=OpenLayers.Util.getScaleFromResolution(confProps.resolutions[i],confProps.units);}
-this.minScale=this.scales[0];this.maxScale=this.scales[this.scales.length-1];this.numZoomLevels=confProps.numZoomLevels;},getResolution:function(){var zoom=this.map.getZoom();return this.resolutions[zoom];},getExtent:function(){return this.map.calculateBounds();},getZoomForExtent:function(extent){var viewSize=this.map.getSize();var idealResolution=Math.max(extent.getWidth()/viewSize.w,extent.getHeight()/viewSize.h);return this.getZoomForResolution(idealResolution);},getDataExtent:function(){},getZoomForResolution:function(resolution){var zoom,diff;var minDiff=Number.POSITIVE_INFINITY;for(var i=0;i<this.resolutions.length;i++){diff=Math.abs(this.resolutions[i]-resolution);if(diff<minDiff){zoom=i;minDiff=diff;}else if(diff>minDiff){break;}}
-return zoom;},getLonLatFromViewPortPx:function(viewPortPx){var lonlat=null;if(viewPortPx!=null){var size=this.map.getSize();var center=this.map.getCenter();if(center){var res=this.map.getResolution();var delta_x=viewPortPx.x-(size.w/2);var delta_y=viewPortPx.y-(size.h/2);lonlat=new OpenLayers.LonLat(center.lon+delta_x*res,center.lat-delta_y*res);if(this.wrapDateLine){lonlat=lonlat.wrapDateLine(this.maxExtent);}}}
-return lonlat;},getViewPortPxFromLonLat:function(lonlat){var px=null;if(lonlat!=null){var resolution=this.map.getResolution();var extent=this.map.getExtent();px=new OpenLayers.Pixel(Math.round(1/resolution*(lonlat.lon-extent.left)),Math.round(1/resolution*(extent.top-lonlat.lat)));}
-return px;},setOpacity:function(opacity){if(opacity!=this.opacity){this.opacity=opacity;for(var i=0;i<this.div.childNodes.length;++i){var element=this.div.childNodes[i].firstChild;OpenLayers.Util.modifyDOMElement(element,null,null,null,null,null,null,opacity);}}},setZIndex:function(zIndex){this.div.style.zIndex=zIndex;},adjustBounds:function(bounds){if(this.gutter){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){var wrappingOptions={'rightTolerance':this.getResolution()};bounds=bounds.wrapDateLine(this.maxExtent,wrappingOptions);}
-return bounds;},CLASS_NAME:"OpenLayers.Layer"});OpenLayers.Marker.Box=OpenLayers.Class(OpenLayers.Marker,{bounds:null,div:null,initialize:function(bounds,borderColor,borderWidth){this.bounds=bounds;this.div=OpenLayers.Util.createDiv();this.div.style.overflow='hidden';this.events=new OpenLayers.Events(this,this.div,null);this.setBorder(borderColor,borderWidth);},destroy:function(){this.bounds=null;this.div=null;OpenLayers.Marker.prototype.destroy.apply(this,arguments);},setBorder:function(color,width){if(!color){color="red";}
-if(!width){width=2;}
-this.div.style.border=width+"px solid "+color;},draw:function(px,sz){OpenLayers.Util.modifyDOMElement(this.div,null,px,sz);return this.div;},onScreen:function(){var onScreen=false;if(this.map){var screenBounds=this.map.getExtent();onScreen=screenBounds.containsBounds(this.bounds,true,true);}
-return onScreen;},display:function(display){this.div.style.display=(display)?"":"none";},CLASS_NAME:"OpenLayers.Marker.Box"});OpenLayers.Control.DragPan=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:false,draw:function(){this.handler=new OpenLayers.Handler.Drag(this,{"move":this.panMap,"done":this.panMapDone});},panMap:function(xy){this.panned=true;var deltaX=this.handler.last.x-xy.x;var deltaY=this.handler.last.y-xy.y;var size=this.map.getSize();var newXY=new OpenLayers.Pixel(size.w/2+deltaX,size.h/2+deltaY);var newCenter=this.map.getLonLatFromViewPortPx(newXY);this.map.setCenter(newCenter,null,this.handler.dragging);},panMapDone:function(xy){if(this.panned){this.panMap(xy);this.panned=false;}},CLASS_NAME:"OpenLayers.Control.DragPan"});OpenLayers.Handler.Box=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);var callbacks={"down":this.startBox,"move":this.moveBox,"out":this.removeBox,"up":this.endBox};this.dragHandler=new OpenLayers.Handler.Drag(this,callbacks,{keyMask:this.keyMask});},setMap:function(map){OpenLayers.Handler.prototype.setMap.apply(this,arguments);if(this.dragHandler){this.dragHandler.setMap(map);}},startBox:function(xy){this.zoomBox=OpenLayers.Util.createDiv('zoomBox',this.dragHandler.start,null,null,"absolute","2px solid red");this.zoomBox.style.backgroundColor="white";this.zoomBox.style.filter="alpha(opacity=50)";this.zoomBox.style.opacity="0.50";this.zoomBox.style.fontSize="1px";this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE["Popup"]-1;this.map.viewPortDiv.appendChild(this.zoomBox);this.map.div.style.cursor="crosshair";},moveBox:function(xy){var deltaX=Math.abs(this.dragHandler.start.x-xy.x);var deltaY=Math.abs(this.dragHandler.start.y-xy.y);this.zoomBox.style.width=Math.max(1,deltaX)+"px";this.zoomBox.style.height=Math.max(1,deltaY)+"px";if(xy.x<this.dragHandler.start.x){this.zoomBox.style.left=xy.x+"px";}
-if(xy.y<this.dragHandler.start.y){this.zoomBox.style.top=xy.y+"px";}},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();}
-this.removeBox();this.map.div.style.cursor="";this.callback("done",[result]);},removeBox:function(){this.map.viewPortDiv.removeChild(this.zoomBox);this.zoomBox=null;},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();return true;}else{return false;}},CLASS_NAME:"OpenLayers.Handler.Box"});OpenLayers.Layer.HTTPRequest=OpenLayers.Class(OpenLayers.Layer,{URL_HASH_FACTOR:(Math.sqrt(5)-1)/2,url:null,params:null,reproject:false,initialize:function(name,url,params,options){var newArguments=arguments;newArguments=[name,options];OpenLayers.Layer.prototype.initialize.apply(this,newArguments);this.url=url;this.params=OpenLayers.Util.extend({},params);},destroy:function(){this.url=null;this.params=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.HTTPRequest(this.name,this.url,this.params,this.options);}
-obj=OpenLayers.Layer.prototype.clone.apply(this,[obj]);return obj;},setUrl:function(newUrl){this.url=newUrl;},mergeNewParams:function(newParams){this.params=OpenLayers.Util.extend(this.params,newParams);this.redraw();},selectUrl:function(paramString,urls){var product=1;for(var i=0;i<paramString.length;i++){product*=paramString.charCodeAt(i)*this.URL_HASH_FACTOR;product-=Math.floor(product);}
-return urls[Math.floor(product*urls.length)];},getFullRequestString:function(newParams,altUrl){var url=altUrl||this.url;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var paramsString=OpenLayers.Util.getParameterString(allParams);if(url instanceof Array){url=this.selectUrl(paramsString,url);}
-var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
-paramsString=OpenLayers.Util.getParameterString(allParams);var requestString=url;if(paramsString!=""){var lastServerChar=url.charAt(url.length-1);if((lastServerChar=="&")||(lastServerChar=="?")){requestString+=paramsString;}else{if(url.indexOf('?')==-1){requestString+='?'+paramsString;}else{requestString+='&'+paramsString;}}}
-return requestString;},CLASS_NAME:"OpenLayers.Layer.HTTPRequest"});OpenLayers.Layer.Markers=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:false,markers:null,drawn:false,initialize:function(name,options){OpenLayers.Layer.prototype.initialize.apply(this,arguments);this.markers=[];},destroy:function(){this.clearMarkers();this.markers=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments);},moveTo:function(bounds,zoomChanged,dragging){OpenLayers.Layer.prototype.moveTo.apply(this,arguments);if(zoomChanged||!this.drawn){for(i=0;i<this.markers.length;i++){this.drawMarker(this.markers[i]);}
-this.drawn=true;}},addMarker:function(marker){this.markers.push(marker);if(this.map&&this.map.getExtent()){marker.map=this.map;this.drawMarker(marker);}},removeMarker:function(marker){OpenLayers.Util.removeItem(this.markers,marker);if((marker.icon!=null)&&(marker.icon.imageDiv!=null)&&(marker.icon.imageDiv.parentNode==this.div)){this.div.removeChild(marker.icon.imageDiv);marker.drawn=false;}},clearMarkers:function(){if(this.markers!=null){while(this.markers.length>0){this.removeMarker(this.markers[0]);}}},drawMarker:function(marker){var px=this.map.getLayerPxFromLonLat(marker.lonlat);if(px==null){marker.display(false);}else{var markerImg=marker.draw(px);if(!marker.drawn){this.div.appendChild(markerImg);marker.drawn=true;}}},getDataExtent:function(){var maxExtent=null;if(this.markers&&(this.markers.length>0)){var maxExtent=new OpenLayers.Bounds();for(var i=0;i<this.markers.length;i++){var marker=this.markers[i];maxExtent.extend(marker.lonlat);}}
-return maxExtent;},CLASS_NAME:"OpenLayers.Layer.Markers"});OpenLayers.Control.ZoomBox=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,draw:function(){this.handler=new OpenLayers.Handler.Box(this,{done:this.zoomBox},{keyMask:this.keyMask});},zoomBox:function(position){if(position instanceof OpenLayers.Bounds){var minXY=this.map.getLonLatFromPixel(new OpenLayers.Pixel(position.left,position.bottom));var maxXY=this.map.getLonLatFromPixel(new OpenLayers.Pixel(position.right,position.top));var bounds=new OpenLayers.Bounds(minXY.lon,minXY.lat,maxXY.lon,maxXY.lat);this.map.zoomToExtent(bounds);}else{this.map.setCenter(this.map.getLonLatFromPixel(position),this.map.getZoom()+1);}},CLASS_NAME:"OpenLayers.Control.ZoomBox"});OpenLayers.Layer.Grid=OpenLayers.Class(OpenLayers.Layer.HTTPRequest,{tileSize:null,grid:null,singleTile:false,ratio:1.5,buffer:2,numLoadingTiles:0,initialize:function(name,url,params,options){OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,arguments);this.events.addEventType("tileloaded");this.grid=[];},destroy:function(){this.clearGrid();this.grid=null;this.tileSize=null;OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this,arguments);},clearGrid:function(){if(this.grid){for(var iRow=0;iRow<this.grid.length;iRow++){var row=this.grid[iRow];for(var iCol=0;iCol<row.length;iCol++){var tile=row[iCol];this.removeTileMonitoringHooks(tile);tile.destroy();}}
-this.grid=[];}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.Grid(this.name,this.url,this.params,this.options);}
-obj=OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this,[obj]);if(this.tileSize!=null){obj.tileSize=this.tileSize.clone();}
-obj.grid=[];return obj;},moveTo:function(bounds,zoomChanged,dragging){OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this,arguments);bounds=bounds||this.map.getExtent();if(bounds!=null){var forceReTile=!this.grid.length||zoomChanged;var tilesBounds=this.getTilesBounds();if(this.singleTile){if(forceReTile||(!dragging&&!tilesBounds.containsBounds(bounds))){this.initSingleTile(bounds);}}else{if(forceReTile||!tilesBounds.containsBounds(bounds,true)){this.initGriddedTiles(bounds);}else{this.moveGriddedTiles(bounds);}}}},setTileSize:function(size){if(this.singleTile){var size=this.map.getSize().clone();size.h=parseInt(size.h*this.ratio);size.w=parseInt(size.w*this.ratio);}
-OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this,[size]);},getGridBounds:function(){var msg="The getGridBounds() function is deprecated. It will be "+"removed in 3.0. Please use getTilesBounds() instead.";OpenLayers.Console.warn(msg);return this.getTilesBounds();},getTilesBounds:function(){var bounds=null;if(this.grid.length){var bottom=this.grid.length-1;var bottomLeftTile=this.grid[bottom][0];var right=this.grid[0].length-1;var topRightTile=this.grid[0][right];bounds=new OpenLayers.Bounds(bottomLeftTile.bounds.left,bottomLeftTile.bounds.bottom,topRightTile.bounds.right,topRightTile.bounds.top);}
-return bounds;},initSingleTile:function(bounds){var center=bounds.getCenterLonLat();var tileWidth=bounds.getWidth()*this.ratio;var tileHeight=bounds.getHeight()*this.ratio;var tileBounds=new OpenLayers.Bounds(center.lon-(tileWidth/2),center.lat-(tileHeight/2),center.lon+(tileWidth/2),center.lat+(tileHeight/2));var ul=new OpenLayers.LonLat(tileBounds.left,tileBounds.top);var px=this.map.getLayerPxFromLonLat(ul);if(!this.grid.length){this.grid[0]=[];}
-var tile=this.grid[0][0];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);tile.draw();this.grid[0][0]=tile;}else{tile.moveTo(tileBounds,px);}
-this.removeExcessTiles(1,1);},initGriddedTiles:function(bounds){var viewSize=this.map.getSize();var minRows=Math.ceil(viewSize.h/this.tileSize.h)+
-Math.max(1,2*this.buffer);var minCols=Math.ceil(viewSize.w/this.tileSize.w)+
-Math.max(1,2*this.buffer);var extent=this.map.getMaxExtent();var resolution=this.map.getResolution();var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left-extent.left;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var tilecolremain=offsetlon/tilelon-tilecol;var tileoffsetx=-tilecolremain*this.tileSize.w;var tileoffsetlon=extent.left+tilecol*tilelon;var offsetlat=bounds.top-(extent.bottom+tilelat);var tilerow=Math.ceil(offsetlat/tilelat)+this.buffer;var tilerowremain=tilerow-offsetlat/tilelat;var tileoffsety=-tilerowremain*this.tileSize.h;var tileoffsetlat=extent.bottom+tilerow*tilelat;tileoffsetx=Math.round(tileoffsetx);tileoffsety=Math.round(tileoffsety);this.origin=new OpenLayers.Pixel(tileoffsetx,tileoffsety);var startX=tileoffsetx;var startLon=tileoffsetlon;var rowidx=0;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-=parseInt(this.map.layerContainerDiv.style.left);var y=tileoffsety;y-=parseInt(this.map.layerContainerDiv.style.top);var px=new OpenLayers.Pixel(x,y);var tile=row[colidx++];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);row.push(tile);}else{tile.moveTo(tileBounds,px,false);}
-tileoffsetlon+=tilelon;tileoffsetx+=this.tileSize.w;}while((tileoffsetlon<=bounds.right+tilelon*this.buffer)||colidx<minCols)
-tileoffsetlat-=tilelat;tileoffsety+=this.tileSize.h;}while((tileoffsetlat>=bounds.bottom-tilelat*this.buffer)||rowidx<minRows)
-this.removeExcessTiles(rowidx,colidx);this.spiralTileLoad();},spiralTileLoad:function(){var tileQueue=[];var directions=["right","down","left","up"];var iRow=0;var iCell=-1;var direction=OpenLayers.Util.indexOf(directions,"right");var directionsTried=0;while(directionsTried<directions.length){var testRow=iRow;var testCell=iCell;switch(directions[direction]){case"right":testCell++;break;case"down":testRow++;break;case"left":testCell--;break;case"up":testRow--;break;}
-var tile=null;if((testRow<this.grid.length)&&(testRow>=0)&&(testCell<this.grid[0].length)&&(testCell>=0)){tile=this.grid[testRow][testCell];}
-if((tile!=null)&&(!tile.queued)){tileQueue.unshift(tile);tile.queued=true;directionsTried=0;iRow=testRow;iCell=testCell;}else{direction=(direction+1)%4;directionsTried++;}}
-for(var i=0;i<tileQueue.length;i++){var tile=tileQueue[i];tile.draw();tile.queued=false;}},addTile:function(bounds,position){},addTileMonitoringHooks:function(tile){tile.onLoadStart=function(){if(this.numLoadingTiles==0){this.events.triggerEvent("loadstart");}
-this.numLoadingTiles++;};tile.events.register("loadstart",this,tile.onLoadStart);tile.onLoadEnd=function(){this.numLoadingTiles--;this.events.triggerEvent("tileloaded");if(this.numLoadingTiles==0){this.events.triggerEvent("loadend");}};tile.events.register("loadend",this,tile.onLoadEnd);},removeTileMonitoringHooks:function(tile){tile.events.unregister("loadstart",this,tile.onLoadStart);tile.events.unregister("loadend",this,tile.onLoadEnd);},moveGriddedTiles:function(bounds){var buffer=this.buffer||1;while(true){var tlLayer=this.grid[0][0].position;var tlViewPort=this.map.getViewPortPxFromLayerPx(tlLayer);if(tlViewPort.x>-this.tileSize.w*(buffer-1)){this.shiftColumn(true);}else if(tlViewPort.x<-this.tileSize.w*buffer){this.shiftColumn(false);}else if(tlViewPort.y>-this.tileSize.h*(buffer-1)){this.shiftRow(true);}else if(tlViewPort.y<-this.tileSize.h*buffer){this.shiftRow(false);}else{break;}};},shiftRow:function(prepend){var modelRowIndex=(prepend)?0:(this.grid.length-1);var modelRow=this.grid[modelRowIndex];var resolution=this.map.getResolution();var deltaY=(prepend)?-this.tileSize.h:this.tileSize.h;var deltaLat=resolution*-deltaY;var row=(prepend)?this.grid.pop():this.grid.shift();for(var i=0;i<modelRow.length;i++){var modelTile=modelRow[i];var bounds=modelTile.bounds.clone();var position=modelTile.position.clone();bounds.bottom=bounds.bottom+deltaLat;bounds.top=bounds.top+deltaLat;position.y=position.y+deltaY;row[i].moveTo(bounds,position);}
-if(prepend){this.grid.unshift(row);}else{this.grid.push(row);}},shiftColumn:function(prepend){var deltaX=(prepend)?-this.tileSize.w:this.tileSize.w;var resolution=this.map.getResolution();var deltaLon=resolution*deltaX;for(var i=0;i<this.grid.length;i++){var row=this.grid[i];var modelTileIndex=(prepend)?0:(row.length-1);var modelTile=row[modelTileIndex];var bounds=modelTile.bounds.clone();var position=modelTile.position.clone();bounds.left=bounds.left+deltaLon;bounds.right=bounds.right+deltaLon;position.x=position.x+deltaX;var tile=prepend?this.grid[i].pop():this.grid[i].shift();tile.moveTo(bounds,position);if(prepend){this.grid[i].unshift(tile);}else{this.grid[i].push(tile);}}},removeExcessTiles:function(rows,columns){while(this.grid.length>rows){var row=this.grid.pop();for(var i=0,l=row.length;i<l;i++){var tile=row[i];this.removeTileMonitoringHooks(tile);tile.destroy();}}
-while(this.grid[0].length>columns){for(var i=0,l=this.grid.length;i<l;i++){var row=this.grid[i];var tile=row.pop();this.removeTileMonitoringHooks(tile);tile.destroy();}}},onMapResize:function(){if(this.singleTile){this.clearGrid();this.setTileSize();this.initSingleTile(this.map.getExtent());}},getTileBounds:function(viewPortPx){var maxExtent=this.map.getMaxExtent();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.Control.Navigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,zoomBox:null,wheelHandler:null,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);},activate:function(){this.dragPan.activate();this.wheelHandler.activate();this.zoomBox.activate();return OpenLayers.Control.prototype.activate.apply(this,arguments);},deactivate:function(){this.zoomBox.deactivate();this.dragPan.deactivate();this.wheelHandler.deactivate();return OpenLayers.Control.prototype.deactivate.apply(this,arguments);},draw:function(){this.map.events.register("dblclick",this,this.defaultDblClick);this.dragPan=new OpenLayers.Control.DragPan({map:this.map});this.zoomBox=new OpenLayers.Control.ZoomBox({map:this.map,keyMask:OpenLayers.Handler.MOD_SHIFT});this.dragPan.draw();this.zoomBox.draw();this.wheelHandler=new OpenLayers.Handler.MouseWheel(this,{"up":this.wheelUp,"down":this.wheelDown});this.activate();},defaultDblClick:function(evt){var newCenter=this.map.getLonLatFromViewPortPx(evt.xy);this.map.setCenter(newCenter,this.map.zoom+1);OpenLayers.Event.stop(evt);return false;},wheelChange:function(evt,deltaZ){var newZoom=this.map.getZoom()+deltaZ;if(!this.map.isValidZoomLevel(newZoom))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.resolutions[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);},wheelUp:function(evt){this.wheelChange(evt,1);},wheelDown:function(evt){this.wheelChange(evt,-1);},CLASS_NAME:"OpenLayers.Control.Navigation"});OpenLayers.Layer.MapGuide=OpenLayers.Class(OpenLayers.Layer.Grid,{reproject:false,isBaseLayer:true,TILE_PARAMS:{operation:'GETTILEIMAGE',version:'1.2.0'},SINGLE_TILE_PARAMS:{operation:'GETMAPIMAGE',format:'PNG',version:'1.0.0'},session:null,mapName:null,groupName:null,initialize:function(name,url,params,options){var newArguments=new Array();newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);if(options==null||options.isBaseLayer==null){this.isBaseLayer=((this.params.transparent!="true")&&(this.params.transparent!=true));}
-if(arguments.length>0){if(this.options.singleTile){this.session=params.session;this.mapName=params.mapname;OpenLayers.Util.applyDefaults(this.params,this.SINGLE_TILE_PARAMS);if(!this.isBaseLayer){this.params.operation="GETDYNAMICMAPOVERLAYIMAGE";}}else{this.groupName=params.groupname;OpenLayers.Util.applyDefaults(this.params,this.TILE_PARAMS);this.setTileSize(new OpenLayers.Size(300,300));}}},updateExtents:function(a){var center=this.map.getExtent().getCenterLonLat();var mapSize=this.map.getCurrentSize();var sParams="operation=GETVISIBLEMAPEXTENT&version=1.0.0";sParams+="&session="+this.session;sParams+="&mapname="+this.mapName;sParams+="&setdisplaydpi="+OpenLayers.DOTS_PER_INCH;sParams+="&setdisplayheight="+mapSize.h*this.ratio;sParams+="&setdisplaywidth="+mapSize.w*this.ratio;sParams+="&setviewcenterx="+center.lon;sParams+="&setviewcentery="+center.lat;sParams+="&setviewscale="+this.map.getScale();if(this.options.showLayers)sParams+="&showlayers="+this.options.showLayers;if(this.options.hideLayers)sParams+="&hidelayers="+this.options.hideLayers;if(this.options.showGroups)sParams+="&showgroups="+this.options.showGroups;if(this.options.hideGroups)sParams+="&hidegroups="+this.options.hideGroups;if(this.options.refreshLayers)sParams+="&refreshlayers="+this.options.refreshLayers;sParams+="&ts="+(new Date()).getTime();new OpenLayers.Ajax.Request(this.url,{parameters:sParams,onSuccess:this._getExtentSuccess,onFailure:this._getExtentFailure,asynchronous:false});},_getExtentSuccess:function(transport){var temp=transport.responseXML;},_getExtentFailure:function(r){},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.MapGuide(this.name,this.url,this.params,this.options);}
-obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,url,this.tileSize);},getURL:function(bounds){var center=bounds.getCenterLonLat();var mapSize=this.map.getCurrentSize();if(this.options.singleTile){var params={};params.session=this.session;params.mapname=this.mapName;if(this.isBaseLayer){params.locale="en";params.setdisplaydpi=OpenLayers.DOTS_PER_INCH;params.setdisplayheight=mapSize.h*this.ratio;params.setdisplaywidth=mapSize.w*this.ratio;params.setviewcenterx=center.lon;params.setviewcentery=center.lat;params.setviewscale=this.map.getScale();params.clip="1";if(this.options.showLayers)params.showlayers=this.options.showLayers;if(this.options.hideLayers)params.hidelayers=this.options.hideLayers;if(this.options.showGroups)params.showgroups=this.options.showGroups;if(this.options.hideGroups)params.hidegroups=this.options.hideGroups;if(this.options.refreshLayers)params.refreshlayers=this.options.refreshLayers;}else{this.updateExtents();}
-params.ts=(new Date()).getTime();var url=this.getFullRequestString(params);}else{var currentRes=this.map.getResolution();var colidx=Math.floor((bounds.left-this.maxExtent.left)/currentRes);colidx=Math.round(colidx/this.tileSize.w);var rowidx=Math.floor((this.maxExtent.top-bounds.top)/currentRes);rowidx=Math.round(rowidx/this.tileSize.h);var url=this.getFullRequestString({tilecol:colidx,tilerow:rowidx,scaleindex:this.resolutions.length-this.map.zoom-1});}
-return url;},getFullRequestString:function(newParams,altUrl){var url=(altUrl==null)?this.url:altUrl;if(typeof url=="object"){url=url[Math.floor(Math.random()*url.length)];}
-var requestString=url;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getArgs(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
-var paramsString=OpenLayers.Util.getParameterString(allParams);paramsString=paramsString.replace(/,/g,"+");if(paramsString!=""){var lastServerChar=url.charAt(url.length-1);if((lastServerChar=="&")||(lastServerChar=="?")){requestString+=paramsString;}else{if(url.indexOf('?')==-1){requestString+='?'+paramsString;}else{requestString+='&'+paramsString;}}}
-return requestString;},initGriddedTiles:function(bounds){var viewSize=this.map.getSize();var minRows=Math.ceil(viewSize.h/this.tileSize.h)+1;var minCols=Math.ceil(viewSize.w/this.tileSize.w)+1;var extent=this.map.getMaxExtent();var resolution=this.map.getResolution();var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left-extent.left;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var tilecolremain=offsetlon/tilelon-tilecol;var tileoffsetx=-tilecolremain*this.tileSize.w;var tileoffsetlon=extent.left+tilecol*tilelon;var offsetlat=extent.top-bounds.top+tilelat;var tilerow=Math.floor(offsetlat/tilelat)-this.buffer;var tilerowremain=tilerow-offsetlat/tilelat;var tileoffsety=tilerowremain*this.tileSize.h;var tileoffsetlat=extent.top-tilelat*tilerow;tileoffsetx=Math.round(tileoffsetx);tileoffsety=Math.round(tileoffsety);this.origin=new OpenLayers.Pixel(tileoffsetx,tileoffsety);var startX=tileoffsetx;var startLon=tileoffsetlon;var rowidx=0;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-=parseInt(this.map.layerContainerDiv.style.left);var y=tileoffsety;var px=new OpenLayers.Pixel(x,y);var tile=row[colidx++];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);row.push(tile);}else{tile.moveTo(tileBounds,px,false);}
-tileoffsetlon+=tilelon;tileoffsetx+=this.tileSize.w;}while((tileoffsetlon<=bounds.right+tilelon*this.buffer)||colidx<minCols)
-tileoffsetlat-=tilelat;tileoffsety+=this.tileSize.h;}while((tileoffsetlat>=bounds.bottom-tilelat*this.buffer)||rowidx<minRows)
-this.removeExcessTiles(rowidx,colidx);this.spiralTileLoad();},CLASS_NAME:"OpenLayers.Layer.MapGuide"});OpenLayers.Layer.MapServer=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{mode:"map",map_imagetype:"png"},initialize:function(name,url,params,options){var newArguments=[];newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);if(arguments.length>0){OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS);}
-if(options==null||options.isBaseLayer==null){this.isBaseLayer=((this.params.transparent!="true")&&(this.params.transparent!=true));}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.MapServer(this.name,this.url,this.params,this.options);}
-obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},getURL:function(bounds){bounds=this.adjustBounds(bounds);var extent=[bounds.left,bounds.bottom,bounds.right,bounds.top];var imageSize=this.getImageSize();var url=this.getFullRequestString({mapext:extent,imgext:extent,map_size:[imageSize.w,imageSize.h],imgx:imageSize.w/2,imgy:imageSize.h/2,imgxy:[imageSize.w,imageSize.h]});return url;},getFullRequestString:function(newParams,altUrl){var url=(altUrl==null)?this.url:altUrl;if(typeof url=="object"){url=url[Math.floor(Math.random()*url.length)];}
-var requestString=url;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
-var paramsString=OpenLayers.Util.getParameterString(allParams);paramsString=paramsString.replace(/,/g,"+");if(paramsString!=""){var lastServerChar=url.charAt(url.length-1);if((lastServerChar=="&")||(lastServerChar=="?")){requestString+=paramsString;}else{if(url.indexOf('?')==-1){requestString+='?'+paramsString;}else{requestString+='&'+paramsString;}}}
-return requestString;},CLASS_NAME:"OpenLayers.Layer.MapServer"});OpenLayers.Layer.WMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{service:"WMS",version:"1.1.1",request:"GetMap",styles:"",exceptions:"application/vnd.ogc.se_inimage",format:"image/jpeg"},reproject:false,isBaseLayer:true,encodeBBOX:false,initialize:function(name,url,params,options){var newArguments=[];params=OpenLayers.Util.upperCaseObject(params);newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS));if(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";}}},destroy:function(){OpenLayers.Layer.Grid.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.options);}
-obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},getURL:function(bounds){bounds=this.adjustBounds(bounds);var imageSize=this.getImageSize();return this.getFullRequestString({BBOX:this.encodeBBOX?bounds.toBBOX():bounds.toArray(),WIDTH:imageSize.w,HEIGHT:imageSize.h});},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},mergeNewParams:function(newParams){var upperParams=OpenLayers.Util.upperCaseObject(newParams);var newArguments=[upperParams];OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,newArguments);},getFullRequestString:function(newParams){var projection=this.map.getProjection();this.params.SRS=(projection=="none")?null:projection.getCode();return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments);},CLASS_NAME:"OpenLayers.Layer.WMS"});
+var OpenLayers={singleFile:true};(function(){var singleFile=(typeof OpenLayers=="object"&&OpenLayers.singleFile);window.OpenLayers={_scriptName:(!singleFile)?"lib/OpenLayers.js":"OpenLayers.js",_getScriptLocation:function(){var scriptLocation="";var scriptName=OpenLayers._scriptName;var scripts=document.getElementsByTagName('script');for(var i=0;i<scripts.length;i++){var src=scripts[i].getAttribute('src');if(src){var index=src.lastIndexOf(scriptName);var pathLength=src.lastIndexOf('?');if(pathLength<0){pathLength=src.length;}
+if((index>-1)&&(index+scriptName.length==pathLength)){scriptLocation=src.slice(0,pathLength-scriptName.length);break;}}}
+return scriptLocation;}};if(!singleFile){var jsfiles=new Array("OpenLayers/Util.js","OpenLayers/BaseTypes.js","OpenLayers/BaseTypes/Class.js","OpenLayers/BaseTypes/Bounds.js","OpenLayers/BaseTypes/Element.js","OpenLayers/BaseTypes/LonLat.js","OpenLayers/BaseTypes/Pixel.js","OpenLayers/BaseTypes/Size.js","OpenLayers/Console.js","OpenLayers/Tween.js","Rico/Corner.js","Rico/Color.js","OpenLayers/Ajax.js","OpenLayers/Events.js","OpenLayers/Projection.js","OpenLayers/Map.js","OpenLayers/Layer.js","OpenLayers/Icon.js","OpenLayers/Marker.js","OpenLayers/Marker/Box.js","OpenLayers/Popup.js","OpenLayers/Tile.js","OpenLayers/Tile/Image.js","OpenLayers/Tile/WFS.js","OpenLayers/Layer/Image.js","OpenLayers/Layer/SphericalMercator.js","OpenLayers/Layer/EventPane.js","OpenLayers/Layer/FixedZoomLevels.js","OpenLayers/Layer/Google.js","OpenLayers/Layer/VirtualEarth.js","OpenLayers/Layer/Yahoo.js","OpenLayers/Layer/HTTPRequest.js","OpenLayers/Layer/Grid.js","OpenLayers/Layer/MapGuide.js","OpenLayers/Layer/MapServer.js","OpenLayers/Layer/MapServer/Untiled.js","OpenLayers/Layer/KaMap.js","OpenLayers/Layer/MultiMap.js","OpenLayers/Layer/Markers.js","OpenLayers/Layer/Text.js","OpenLayers/Layer/WorldWind.js","OpenLayers/Layer/WMS.js","OpenLayers/Layer/WMS/Untiled.js","OpenLayers/Layer/GeoRSS.js","OpenLayers/Layer/Boxes.js","OpenLayers/Layer/TMS.js","OpenLayers/Layer/TileCache.js","OpenLayers/Popup/Anchored.js","OpenLayers/Popup/AnchoredBubble.js","OpenLayers/Popup/Framed.js","OpenLayers/Popup/FramedCloud.js","OpenLayers/Feature.js","OpenLayers/Feature/Vector.js","OpenLayers/Feature/WFS.js","OpenLayers/Handler.js","OpenLayers/Handler/Click.js","OpenLayers/Handler/Hover.js","OpenLayers/Handler/Point.js","OpenLayers/Handler/Path.js","OpenLayers/Handler/Polygon.js","OpenLayers/Handler/Feature.js","OpenLayers/Handler/Drag.js","OpenLayers/Handler/RegularPolygon.js","OpenLayers/Handler/Box.js","OpenLayers/Handler/MouseWheel.js","OpenLayers/Handler/Keyboard.js","OpenLayers/Control.js","OpenLayers/Control/Attribution.js","OpenLayers/Control/Button.js","OpenLayers/Control/ZoomBox.js","OpenLayers/Control/ZoomToMaxExtent.js","OpenLayers/Control/DragPan.js","OpenLayers/Control/Navigation.js","OpenLayers/Control/MouseDefaults.js","OpenLayers/Control/MousePosition.js","OpenLayers/Control/OverviewMap.js","OpenLayers/Control/KeyboardDefaults.js","OpenLayers/Control/PanZoom.js","OpenLayers/Control/PanZoomBar.js","OpenLayers/Control/ArgParser.js","OpenLayers/Control/Permalink.js","OpenLayers/Control/Scale.js","OpenLayers/Control/ScaleLine.js","OpenLayers/Control/LayerSwitcher.js","OpenLayers/Control/DrawFeature.js","OpenLayers/Control/DragFeature.js","OpenLayers/Control/ModifyFeature.js","OpenLayers/Control/Panel.js","OpenLayers/Control/SelectFeature.js","OpenLayers/Control/NavigationHistory.js","OpenLayers/Geometry.js","OpenLayers/Geometry/Rectangle.js","OpenLayers/Geometry/Collection.js","OpenLayers/Geometry/Point.js","OpenLayers/Geometry/MultiPoint.js","OpenLayers/Geometry/Curve.js","OpenLayers/Geometry/LineString.js","OpenLayers/Geometry/LinearRing.js","OpenLayers/Geometry/Polygon.js","OpenLayers/Geometry/MultiLineString.js","OpenLayers/Geometry/MultiPolygon.js","OpenLayers/Geometry/Surface.js","OpenLayers/Renderer.js","OpenLayers/Renderer/Elements.js","OpenLayers/Renderer/SVG.js","OpenLayers/Renderer/VML.js","OpenLayers/Layer/Vector.js","OpenLayers/Layer/PointTrack.js","OpenLayers/Layer/GML.js","OpenLayers/Style.js","OpenLayers/StyleMap.js","OpenLayers/Rule.js","OpenLayers/Filter.js","OpenLayers/Filter/FeatureId.js","OpenLayers/Filter/Logical.js","OpenLayers/Filter/Comparison.js","OpenLayers/Format.js","OpenLayers/Format/XML.js","OpenLayers/Format/GML.js","OpenLayers/Format/KML.js","OpenLayers/Format/GeoRSS.js","OpenLayers/Format/WFS.js","OpenLayers/Format/WKT.js","OpenLayers/Format/OSM.js","OpenLayers/Format/SLD.js","OpenLayers/Format/SLD/v1.js","OpenLayers/Format/SLD/v1_0_0.js","OpenLayers/Format/Text.js","OpenLayers/Format/JSON.js","OpenLayers/Format/GeoJSON.js","OpenLayers/Format/WMC.js","OpenLayers/Format/WMC/v1.js","OpenLayers/Format/WMC/v1_0_0.js","OpenLayers/Format/WMC/v1_1_0.js","OpenLayers/Layer/WFS.js","OpenLayers/Control/MouseToolbar.js","OpenLayers/Control/NavToolbar.js","OpenLayers/Control/EditingToolbar.js","OpenLayers/Lang.js","OpenLayers/Lang/en.js");var agent=navigator.userAgent;var docWrite=(agent.match("MSIE")||agent.match("Safari"));if(docWrite){var allScriptTags=new Array(jsfiles.length);}
+var host=OpenLayers._getScriptLocation()+"lib/";for(var i=0;i<jsfiles.length;i++){if(docWrite){allScriptTags[i]="<script src='"+host+jsfiles[i]+"'></script>";}else{var s=document.createElement("script");s.src=host+jsfiles[i];var h=document.getElementsByTagName("head").length?document.getElementsByTagName("head")[0]:document.body;h.appendChild(s);}}
+if(docWrite){document.write(allScriptTags.join(""));}}})();OpenLayers.VERSION_NUMBER="$Revision$";OpenLayers.String={startsWith:function(str,sub){return(str.indexOf(sub)==0);},contains:function(str,sub){return(str.indexOf(sub)!=-1);},trim:function(str){return str.replace(/^\s*(.*?)\s*$/,"$1");},camelize:function(str){var oStringList=str.split('-');var camelizedString=oStringList[0];for(var i=1;i<oStringList.length;i++){var s=oStringList[i];camelizedString+=s.charAt(0).toUpperCase()+s.substring(1);}
+return camelizedString;},format:function(template,context,args){if(!context){context=window;}
+var tokens=template.split("${");var item,last,replacement;for(var i=1;i<tokens.length;i++){item=tokens[i];last=item.indexOf("}");if(last>0){replacement=context[item.substring(0,last)];if(typeof replacement=="function"){replacement=args?replacement.apply(null,args):replacement();}
+tokens[i]=replacement+item.substring(++last);}else{tokens[i]="${"+item;}}
+return tokens.join("");}};if(!String.prototype.startsWith){String.prototype.startsWith=function(sStart){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'OpenLayers.String.startsWith'}));return OpenLayers.String.startsWith(this,sStart);};}
+if(!String.prototype.contains){String.prototype.contains=function(str){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'OpenLayers.String.contains'}));return OpenLayers.String.contains(this,str);};}
+if(!String.prototype.trim){String.prototype.trim=function(){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'OpenLayers.String.trim'}));return OpenLayers.String.trim(this);};}
+if(!String.prototype.camelize){String.prototype.camelize=function(){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'OpenLayers.String.camelize'}));return OpenLayers.String.camelize(this);};}
+OpenLayers.Number={decimalSeparator:".",thousandsSeparator:",",limitSigDigs:function(num,sig){var fig=0;if(sig>0){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;}};if(!Number.prototype.limitSigDigs){Number.prototype.limitSigDigs=function(sig){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'OpenLayers.String.limitSigDigs'}));return OpenLayers.Number.limitSigDigs(this,sig);};}
+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);};}};if(!Function.prototype.bind){Function.prototype.bind=function(){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'OpenLayers.String.bind'}));Array.prototype.unshift.apply(arguments,[this]);return OpenLayers.Function.bind.apply(null,arguments);};}
+if(!Function.prototype.bindAsEventListener){Function.prototype.bindAsEventListener=function(object){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'OpenLayers.String.bindAsEventListener'}));return OpenLayers.Function.bindAsEventListener(this,object);};}
+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;i<len;i++){if(i in array){var val=array[i];if(callback.call(caller,val,i,array)){selected.push(val);}}}}
+return selected;}};OpenLayers.Class=function(){var Class=function(){if(arguments&&arguments[0]!=OpenLayers.Class.isPrototype){this.initialize.apply(this,arguments);}};var extended={};var parent;for(var i=0;i<arguments.length;++i){if(typeof arguments[i]=="function"){parent=arguments[i].prototype;}else{parent=arguments[i];}
+OpenLayers.Util.extend(extended,parent);}
+Class.prototype=extended;return Class;};OpenLayers.Class.isPrototype=function(){};OpenLayers.Class.create=function(){return function(){if(arguments&&arguments[0]!=OpenLayers.Class.isPrototype){this.initialize.apply(this,arguments);}};};OpenLayers.Class.inherit=function(){var superClass=arguments[0];var proto=new superClass(OpenLayers.Class.isPrototype);for(var i=1;i<arguments.length;i++){if(typeof arguments[i]=="function"){var mixin=arguments[i];arguments[i]=new mixin(OpenLayers.Class.isPrototype);}
+OpenLayers.Util.extend(proto,arguments[i]);}
+return proto;};OpenLayers.Util={};OpenLayers.Util.getElement=function(){var elements=[];for(var i=0;i<arguments.length;i++){var element=arguments[i];if(typeof element=='string'){element=document.getElementById(element);}
+if(arguments.length==1){return element;}
+elements.push(element);}
+return elements;};if($==null){var $=OpenLayers.Util.getElement;}
+OpenLayers.Util.extend=function(destination,source){if(destination&&source){for(var property in source){var value=source[property];if(value!==undefined){destination[property]=value;}}
+var sourceIsEvt=typeof window.Event=="function"&&source instanceof window.Event;if(!sourceIsEvt&&source.hasOwnProperty&&source.hasOwnProperty('toString')){destination.toString=source.toString;}}
+return destination;};OpenLayers.Util.removeItem=function(array,item){for(var i=array.length-1;i>=0;i--){if(array[i]==item){array.splice(i,1);}}
+return array;};OpenLayers.Util.clearArray=function(array){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'array = []'}));array.length=0;};OpenLayers.Util.indexOf=function(array,obj){for(var i=0;i<array.length;i++){if(array[i]==obj){return i;}}
+return-1;};OpenLayers.Util.modifyDOMElement=function(element,id,px,sz,position,border,overflow,opacity){if(id){element.id=id;}
+if(px){element.style.left=px.x+"px";element.style.top=px.y+"px";}
+if(sz){element.style.width=sz.w+"px";element.style.height=sz.h+"px";}
+if(position){element.style.position=position;}
+if(border){element.style.border=border;}
+if(overflow){element.style.overflow=overflow;}
+if(parseFloat(opacity)>=0.0&&parseFloat(opacity)<1.0){element.style.filter='alpha(opacity='+(opacity*100)+')';element.style.opacity=opacity;}else if(parseFloat(opacity)==1.0){element.style.filter='';element.style.opacity='';}};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";OpenLayers.Event.observe(image,"load",OpenLayers.Function.bind(OpenLayers.Util.onImageLoad,image));OpenLayers.Event.observe(image,"error",OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError,image));}
+image.style.alt=id;image.galleryImg="no";if(imgURL){image.src=imgURL;}
+return image;};OpenLayers.Util.setOpacity=function(element,opacity){OpenLayers.Util.modifyDOMElement(element,null,null,null,null,null,null,opacity);};OpenLayers.Util.onImageLoad=function(){if(!this.viewRequestID||(this.map&&this.viewRequestID==this.map.viewRequestID)){this.style.backgroundColor=null;this.style.display="";}};OpenLayers.Util.onImageLoadErrorColor="pink";OpenLayers.IMAGE_RELOAD_ATTEMPTS=0;OpenLayers.Util.onImageLoadError=function(){this._attempts=(this._attempts)?(this._attempts+1):1;if(this._attempts<=OpenLayers.IMAGE_RELOAD_ATTEMPTS){this.src=this.src;}else{this.style.backgroundColor=OpenLayers.Util.onImageLoadErrorColor;}
+this.style.display="";};OpenLayers.Util.alphaHack=function(){var arVersion=navigator.appVersion.split("MSIE");var version=parseFloat(arVersion[1]);var filter=false;try{filter=!!(document.body.filters);}catch(e){}
+return(filter&&(version>=5.5)&&(version<7));};OpenLayers.Util.modifyAlphaImageDiv=function(div,id,px,sz,imgURL,position,border,sizing,opacity){OpenLayers.Util.modifyDOMElement(div,id,px,sz,null,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()){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,false);div.appendChild(img);if(delayDisplay){img.style.display="none";OpenLayers.Event.observe(img,"load",OpenLayers.Function.bind(OpenLayers.Util.onImageLoad,div));OpenLayers.Event.observe(img,"error",OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError,div));}
+OpenLayers.Util.modifyAlphaImageDiv(div,id,px,sz,imgURL,position,border,sizing,opacity);return div;};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){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.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=[];for(var itemIndex=0;itemIndex<value.length;itemIndex++){encodedItemArray.push(encodeURIComponent(value[itemIndex]));}
+encodedValue=encodedItemArray.join(",");}
+else{encodedValue=encodeURIComponent(value);}
+paramsArray.push(encodeURIComponent(key)+"="+encodedValue);}}
+return paramsArray.join("&");};OpenLayers.ImgPath='';OpenLayers.Util.getImagesLocation=function(){return OpenLayers.ImgPath||(OpenLayers._getScriptLocation()+"img/");};OpenLayers.Util.Try=function(){var returnValue=null;for(var i=0;i<arguments.length;i++){var lambda=arguments[i];try{returnValue=lambda();break;}catch(e){}}
+return returnValue;};OpenLayers.Util.getNodes=function(p,tagName){var nodes=OpenLayers.Util.Try(function(){return OpenLayers.Util._getNodes(p.documentElement.childNodes,tagName);},function(){return OpenLayers.Util._getNodes(p.childNodes,tagName);});return nodes;};OpenLayers.Util._getNodes=function(nodes,tagName){var retArray=[];for(var i=0;i<nodes.length;i++){if(nodes[i].nodeName==tagName){retArray.push(nodes[i]);}}
+return retArray;};OpenLayers.Util.getTagText=function(parent,item,index){var result=OpenLayers.Util.getNodes(parent,item);if(result&&(result.length>0))
+{if(!index){index=0;}
+if(result[index].childNodes.length>1){return result.childNodes[1].nodeValue;}
+else if(result[index].childNodes.length==1){return result[index].firstChild.nodeValue;}}else{return"";}};OpenLayers.Util.getXmlNodeValue=function(node){var val=null;OpenLayers.Util.Try(function(){val=node.text;if(!val){val=node.textContent;}
+if(!val){val=node.firstChild.nodeValue;}},function(){val=node.textContent;});return val;};OpenLayers.Util.mouseLeft=function(evt,div){var target=(evt.relatedTarget)?evt.relatedTarget:evt.toElement;while(target!=div&&target!=null){target=target.parentNode;}
+return(target!=div);};OpenLayers.Util.rad=function(x){return x*Math.PI/180;};OpenLayers.Util.distVincenty=function(p1,p2){var a=6378137,b=6356752.3142,f=1/298.257223563;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;}
+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.getParameters=function(url){url=url||window.location.href;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;i<pairs.length;++i){var keyValue=pairs[i].split('=');if(keyValue[0]){var key=decodeURIComponent(keyValue[0]);var value=keyValue[1]||'';value=value.split(",");for(var j=0;j<value.length;j++){value[j]=decodeURIComponent(value[j]);}
+if(value.length==1){value=value[0];}
+parameters[key]=value;}}
+return parameters;};OpenLayers.Util.getArgs=function(url){OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",{'newMethod':'OpenLayers.Util.getParameters'}));return OpenLayers.Util.getParameters(url);};OpenLayers.Util.lastSeqID=0;OpenLayers.Util.createUniqueID=function(prefix){if(prefix==null){prefix="id_";}
+OpenLayers.Util.lastSeqID+=1;return prefix+OpenLayers.Util.lastSeqID;};OpenLayers.INCHES_PER_UNIT={'inches':1.0,'ft':12.0,'mi':63360.0,'m':39.3701,'km':39370.1,'dd':4374754,'yd':36};OpenLayers.INCHES_PER_UNIT["in"]=OpenLayers.INCHES_PER_UNIT.inches;OpenLayers.INCHES_PER_UNIT["degrees"]=OpenLayers.INCHES_PER_UNIT.dd;OpenLayers.INCHES_PER_UNIT["nmi"]=1852*OpenLayers.INCHES_PER_UNIT.m;OpenLayers.DOTS_PER_INCH=72;OpenLayers.Util.normalizeScale=function(scale){var normScale=(scale>1.0)?(1.0/scale):scale;return normScale;};OpenLayers.Util.getResolutionFromScale=function(scale,units){if(units==null){units="degrees";}
+var normScale=OpenLayers.Util.normalizeScale(scale);var 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.safeStopPropagation=function(evt){OpenLayers.Event.stop(evt,true);};OpenLayers.Util.pagePosition=function(forElement){var valueT=0,valueL=0;var element=forElement;var child=forElement;while(element){if(element==document.body){if(child&&child.style&&OpenLayers.Element.getStyle(child,'position')=='absolute'){break;}}
+valueT+=element.offsetTop||0;valueL+=element.offsetLeft||0;child=element;try{element=element.offsetParent;}catch(e){OpenLayers.Console.error(OpenLayers.i18n("pagePositionFailed",{'elemId':element.id}));break;}}
+element=forElement;while(element){valueT-=element.scrollTop||0;valueL-=element.scrollLeft||0;element=element.parentNode;}
+return[valueL,valueT];};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(options.test){alert(key+"\n1:"+urlObj1[key]+"\n2:"+urlObj2[key]);}
+var val1=urlObj1[key];var val2=urlObj2[key];switch(key){case"args":break;case"host":case"port":case"protocol":if((val1=="")||(val2=="")){break;}
+default:if((key!="args")&&(urlObj1[key]!=urlObj2[key])){return false;}
+break;}}
+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||{};var urlObject={};if(options.ignoreCase){url=url.toLowerCase();}
+var a=document.createElement('a');a.href=url;urlObject.host=a.host;var port=a.port;if(port.length<=0){var newHostLength=urlObject.host.length-(port.length);urlObject.host=urlObject.host.substring(0,newHostLength);}
+urlObject.protocol=a.protocol;urlObject.port=((port=="80")&&(options.ignorePort80))?"":port;urlObject.hash=(options.ignoreHash)?"":a.hash;var queryString=a.search;if(!queryString){var qMark=url.indexOf("?");queryString=(qMark!=-1)?url.substr(qMark):"";}
+urlObject.args=OpenLayers.Util.getParameters(queryString);if(((urlObject.protocol=="file:")&&(url.indexOf("file:")!=-1))||((urlObject.protocol!="file:")&&(urlObject.host!=""))){urlObject.pathname=a.pathname;var qIndex=urlObject.pathname.indexOf("?");if(qIndex!=-1){urlObject.pathname=urlObject.pathname.substring(0,qIndex);}}else{var relStr=OpenLayers.Util.removeTail(url);var backs=0;do{var index=relStr.indexOf("../");if(index==0){backs++;relStr=relStr.substr(3);}else if(index>=0){var prevChunk=relStr.substr(0,index-1);var slash=prevChunk.indexOf("/");prevChunk=(slash!=-1)?prevChunk.substr(0,slash+1):"";var postChunk=relStr.substr(index+3);relStr=prevChunk+postChunk;}}while(index!=-1)
+var windowAnchor=document.createElement("a");var windowUrl=window.location.href;if(options.ignoreCase){windowUrl=windowUrl.toLowerCase();}
+windowAnchor.href=windowUrl;urlObject.protocol=windowAnchor.protocol;var splitter=(windowAnchor.pathname.indexOf("/")!=-1)?"/":"\\";var dirs=windowAnchor.pathname.split(splitter);dirs.pop();while((backs>0)&&(dirs.length>0)){dirs.pop();backs--;}
+relStr=dirs.join("/")+"/"+relStr;urlObject.pathname=relStr;}
+if((urlObject.protocol=="file:")||(urlObject.protocol=="")){urlObject.host="localhost";}
+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.Util.getBrowserName=function(){var browserName="";var ua=navigator.userAgent.toLowerCase();if(ua.indexOf("opera")!=-1){browserName="opera";}else if(ua.indexOf("msie")!=-1){browserName="msie";}else if(ua.indexOf("safari")!=-1){browserName="safari";}else if(ua.indexOf("mozilla")!=-1){if(ua.indexOf("firefox")!=-1){browserName="firefox";}else{browserName="mozilla";}}
+return browserName;};OpenLayers.Util.getRenderedDimensions=function(contentHTML,size){var w=h=null;var container=document.createElement("div");container.style.overflow="";container.style.position="absolute";container.style.left="-9999px";if(size){if(size.w){w=container.style.width=size.w;}else if(size.h){h=container.style.height=size.h;}}
+var content=document.createElement("div");content.innerHTML=contentHTML;container.appendChild(content);document.body.appendChild(container);if(!w){w=parseInt(content.scrollWidth);container.style.width=w+"px";}
+if(!h){h=parseInt(content.scrollHeight);}
+container.removeChild(content);document.body.removeChild(container);return new OpenLayers.Size(w,h);};OpenLayers.Util.getScrollbarWidth=function(){var scrollbarWidth=OpenLayers.Util._scrollbarWidth;if(scrollbarWidth==null){var scr=null;var inn=null;var wNoScroll=0;var wScroll=0;scr=document.createElement('div');scr.style.position='absolute';scr.style.top='-1000px';scr.style.left='-1000px';scr.style.width='100px';scr.style.height='50px';scr.style.overflow='hidden';inn=document.createElement('div');inn.style.width='100%';inn.style.height='200px';scr.appendChild(inn);document.body.appendChild(scr);wNoScroll=inn.offsetWidth;scr.style.overflow='scroll';wScroll=inn.offsetWidth;document.body.removeChild(document.body.lastChild);OpenLayers.Util._scrollbarWidth=(wNoScroll-wScroll);scrollbarWidth=OpenLayers.Util._scrollbarWidth;}
+return scrollbarWidth;};OpenLayers.ProxyHost="";OpenLayers.nullHandler=function(request){alert(OpenLayers.i18n("unhandledRequest",{'statusText':request.statusText}));};OpenLayers.loadURL=function(uri,params,caller,onComplete,onFailure){var success=(onComplete)?OpenLayers.Function.bind(onComplete,caller):OpenLayers.nullHandler;var failure=(onFailure)?OpenLayers.Function.bind(onFailure,caller):OpenLayers.nullHandler;var request=new OpenLayers.Ajax.Request(uri,{method:'get',parameters:params,onComplete:success,onFailure:failure});return request.transport;};OpenLayers.parseXMLString=function(text){var index=text.indexOf('<');if(index>0){text=text.substring(index);}
+var ajaxResponse=OpenLayers.Util.Try(function(){var xmldom=new ActiveXObject('Microsoft.XMLDOM');xmldom.loadXML(text);return xmldom;},function(){return new DOMParser().parseFromString(text,'text/xml');},function(){var req=new XMLHttpRequest();req.open("GET","data:"+"text/xml"+";charset=utf-8,"+encodeURIComponent(text),false);if(req.overrideMimeType){req.overrideMimeType("text/xml");}
+req.send(null);return req.responseXML;});return ajaxResponse;};OpenLayers.Ajax={emptyFunction:function(){},getTransport:function(){return OpenLayers.Util.Try(function(){return new XMLHttpRequest();},function(){return new ActiveXObject('Msxml2.XMLHTTP');},function(){return new ActiveXObject('Microsoft.XMLHTTP');})||false;},activeRequestCount:0};OpenLayers.Ajax.Responders={responders:[],register:function(responderToAdd){for(var i=0;i<this.responders.length;i++){if(responderToAdd==this.responders[i]){return;}}
+this.responders.push(responderToAdd);},unregister:function(responderToRemove){OpenLayers.Util.removeItem(this.reponders,responderToRemove);},dispatch:function(callback,request,transport){var responder;for(var i=0;i<this.responders.length;i++){responder=this.responders[i];if(responder[callback]&&typeof responder[callback]=='function'){try{responder[callback].apply(responder,[request,transport]);}catch(e){}}}}};OpenLayers.Ajax.Responders.register({onCreate:function(){OpenLayers.Ajax.activeRequestCount++;},onComplete:function(){OpenLayers.Ajax.activeRequestCount--;}});OpenLayers.Ajax.Base=OpenLayers.Class({initialize:function(options){this.options={method:'post',asynchronous:true,contentType:'application/xml',parameters:''};OpenLayers.Util.extend(this.options,options||{});this.options.method=this.options.method.toLowerCase();if(typeof this.options.parameters=='string'){this.options.parameters=OpenLayers.Util.getParameters(this.options.parameters);}}});OpenLayers.Ajax.Request=OpenLayers.Class(OpenLayers.Ajax.Base,{_complete:false,initialize:function(url,options){OpenLayers.Ajax.Base.prototype.initialize.apply(this,[options]);if(OpenLayers.ProxyHost&&OpenLayers.String.startsWith(url,"http")){url=OpenLayers.ProxyHost+encodeURIComponent(url);}
+this.transport=OpenLayers.Ajax.getTransport();this.request(url);},request:function(url){this.url=url;this.method=this.options.method;var params=OpenLayers.Util.extend({},this.options.parameters);if(this.method!='get'&&this.method!='post'){params['_method']=this.method;this.method='post';}
+this.parameters=params;if(params=OpenLayers.Util.getParameterString(params)){if(this.method=='get'){this.url+=((this.url.indexOf('?')>-1)?'&':'?')+params;}else if(/Konqueror|Safari|KHTML/.test(navigator.userAgent)){params+='&_=';}}
+try{var response=new OpenLayers.Ajax.Response(this);if(this.options.onCreate){this.options.onCreate(response);}
+OpenLayers.Ajax.Responders.dispatch('onCreate',this,response);this.transport.open(this.method.toUpperCase(),this.url,this.options.asynchronous);if(this.options.asynchronous){window.setTimeout(OpenLayers.Function.bind(this.respondToReadyState,this,1),10);}
+this.transport.onreadystatechange=OpenLayers.Function.bind(this.onStateChange,this);this.setRequestHeaders();this.body=this.method=='post'?(this.options.postBody||params):null;this.transport.send(this.body);if(!this.options.asynchronous&&this.transport.overrideMimeType){this.onStateChange();}}catch(e){this.dispatchException(e);}},onStateChange:function(){var readyState=this.transport.readyState;if(readyState>1&&!((readyState==4)&&this._complete)){this.respondToReadyState(this.transport.readyState);}},setRequestHeaders:function(){var headers={'X-Requested-With':'XMLHttpRequest','Accept':'text/javascript, text/html, application/xml, text/xml, */*','OpenLayers':true};if(this.method=='post'){headers['Content-type']=this.options.contentType+
+(this.options.encoding?'; charset='+this.options.encoding:'');if(this.transport.overrideMimeType&&(navigator.userAgent.match(/Gecko\/(\d{4})/)||[0,2005])[1]<2005){headers['Connection']='close';}}
+if(typeof this.options.requestHeaders=='object'){var extras=this.options.requestHeaders;if(typeof extras.push=='function'){for(var i=0,length=extras.length;i<length;i+=2){headers[extras[i]]=extras[i+1];}}else{for(var i in extras){headers[i]=pair[i];}}}
+for(var name in headers){this.transport.setRequestHeader(name,headers[name]);}},success:function(){var status=this.getStatus();return!status||(status>=200&&status<300);},getStatus:function(){try{return this.transport.status||0;}catch(e){return 0;}},respondToReadyState:function(readyState){var state=OpenLayers.Ajax.Request.Events[readyState];var response=new OpenLayers.Ajax.Response(this);if(state=='Complete'){try{this._complete=true;(this.options['on'+response.status]||this.options['on'+(this.success()?'Success':'Failure')]||OpenLayers.Ajax.emptyFunction)(response);}catch(e){this.dispatchException(e);}
+var contentType=response.getHeader('Content-type');}
+try{(this.options['on'+state]||OpenLayers.Ajax.emptyFunction)(response);OpenLayers.Ajax.Responders.dispatch('on'+state,this,response);}catch(e){this.dispatchException(e);}
+if(state=='Complete'){this.transport.onreadystatechange=OpenLayers.Ajax.emptyFunction;}},getHeader:function(name){try{return this.transport.getResponseHeader(name);}catch(e){return null;}},dispatchException:function(exception){var handler=this.options.onException;if(handler){handler(this,exception);OpenLayers.Ajax.Responders.dispatch('onException',this,exception);}else{var listener=false;var responders=OpenLayers.Ajax.Responders.responders;for(var i=0;i<responders.length;i++){if(responders[i].onException){listener=true;break;}}
+if(listener){OpenLayers.Ajax.Responders.dispatch('onException',this,exception);}else{throw exception;}}}});OpenLayers.Ajax.Request.Events=['Uninitialized','Loading','Loaded','Interactive','Complete'];OpenLayers.Ajax.Response=OpenLayers.Class({status:0,statusText:'',initialize:function(request){this.request=request;var transport=this.transport=request.transport,readyState=this.readyState=transport.readyState;if((readyState>2&&!(!!(window.attachEvent&&!window.opera)))||readyState==4){this.status=this.getStatus();this.statusText=this.getStatusText();this.responseText=transport.responseText==null?'':String(transport.responseText);}
+if(readyState==4){var xml=transport.responseXML;this.responseXML=xml===undefined?null:xml;}},getStatus:OpenLayers.Ajax.Request.prototype.getStatus,getStatusText:function(){try{return this.transport.statusText||'';}catch(e){return'';}},getHeader:OpenLayers.Ajax.Request.prototype.getHeader,getResponseHeader:function(name){return this.transport.getResponseHeader(name);}});OpenLayers.Ajax.getElementsByTagNameNS=function(parentnode,nsuri,nsprefix,tagname){var elem=null;if(parentnode.getElementsByTagNameNS){elem=parentnode.getElementsByTagNameNS(nsuri,tagname);}else{elem=parentnode.getElementsByTagName(nsprefix+':'+tagname);}
+return elem;};OpenLayers.Ajax.serializeXMLToString=function(xmldom){var serializer=new XMLSerializer();var data=serializer.serializeToString(xmldom);return data;};OpenLayers.Console={log:function(){},debug:function(){},info:function(){},warn:function(){},error:function(){},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(){if(window.console){var scripts=document.getElementsByTagName("script");for(var i=0;i<scripts.length;++i){if(scripts[i].src.indexOf("firebug.js")!=-1){OpenLayers.Util.extend(OpenLayers.Console,console);break;}}}})();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.Bounds=OpenLayers.Class({left:null,bottom:null,right:null,top:null,initialize:function(left,bottom,right,top){if(left!=null){this.left=parseFloat(left);}
+if(bottom!=null){this.bottom=parseFloat(bottom);}
+if(right!=null){this.right=parseFloat(right);}
+if(top!=null){this.top=parseFloat(top);}},clone:function(){return new OpenLayers.Bounds(this.left,this.bottom,this.right,this.top);},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;},toString:function(){return("left-bottom=("+this.left+","+this.bottom+")"
++" right-top=("+this.right+","+this.top+")");},toArray:function(){return[this.left,this.bottom,this.right,this.top];},toBBOX:function(decimal){if(decimal==null){decimal=6;}
+var mult=Math.pow(10,decimal);var bbox=Math.round(this.left*mult)/mult+","+
+Math.round(this.bottom*mult)/mult+","+
+Math.round(this.right*mult)/mult+","+
+Math.round(this.top*mult)/mult;return bbox;},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)])]);},getWidth:function(){return(this.right-this.left);},getHeight:function(){return(this.top-this.bottom);},getSize:function(){return new OpenLayers.Size(this.getWidth(),this.getHeight());},getCenterPixel:function(){return new OpenLayers.Pixel((this.left+this.right)/2,(this.bottom+this.top)/2);},getCenterLonLat:function(){return new OpenLayers.LonLat((this.left+this.right)/2,(this.bottom+this.top)/2);},add:function(x,y){if((x==null)||(y==null)){var msg=OpenLayers.i18n("boundsAddError");OpenLayers.Console.error(msg);return null;}
+return new OpenLayers.Bounds(this.left+x,this.bottom+y,this.right+x,this.top+y);},extend:function(object){var bounds=null;if(object){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){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;}}}},containsLonLat:function(ll,inclusive){return this.contains(ll.lon,ll.lat,inclusive);},containsPixel:function(px,inclusive){return this.contains(px.x,px.y,inclusive);},contains:function(x,y,inclusive){if(inclusive==null){inclusive=true;}
+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;},intersectsBounds:function(bounds,inclusive){if(inclusive==null){inclusive=true;}
+var inBottom=(bounds.bottom==this.bottom&&bounds.top==this.top)?true:(((bounds.bottom>this.bottom)&&(bounds.bottom<this.top))||((this.bottom>bounds.bottom)&&(this.bottom<bounds.top)));var inTop=(bounds.bottom==this.bottom&&bounds.top==this.top)?true:(((bounds.top>this.bottom)&&(bounds.top<this.top))||((this.top>bounds.bottom)&&(this.top<bounds.top)));var inRight=(bounds.right==this.right&&bounds.left==this.left)?true:(((bounds.right>this.left)&&(bounds.right<this.right))||((this.right>bounds.left)&&(this.right<bounds.right)));var inLeft=(bounds.right==this.right&&bounds.left==this.left)?true:(((bounds.left>this.left)&&(bounds.left<this.right))||((this.left>bounds.left)&&(this.left<bounds.right)));return(this.containsBounds(bounds,true,inclusive)||bounds.containsBounds(this,true,inclusive)||((inTop||inBottom)&&(inLeft||inRight)));},containsBounds:function(bounds,partial,inclusive){if(partial==null){partial=false;}
+if(inclusive==null){inclusive=true;}
+var inLeft;var inTop;var inRight;var inBottom;if(inclusive){inLeft=(bounds.left>=this.left)&&(bounds.left<=this.right);inTop=(bounds.top>=this.bottom)&&(bounds.top<=this.top);inRight=(bounds.right>=this.left)&&(bounds.right<=this.right);inBottom=(bounds.bottom>=this.bottom)&&(bounds.bottom<=this.top);}else{inLeft=(bounds.left>this.left)&&(bounds.left<this.right);inTop=(bounds.top>this.bottom)&&(bounds.top<this.top);inRight=(bounds.right>this.left)&&(bounds.right<this.right);inBottom=(bounds.bottom>this.bottom)&&(bounds.bottom<this.top);}
+return(partial)?(inTop||inBottom)&&(inLeft||inRight):(inTop&&inLeft&&inBottom&&inRight);},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;},transform:function(source,dest){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;},wrapDateLine:function(maxExtent,options){options=options||{};var leftTolerance=options.leftTolerance||0;var rightTolerance=options.rightTolerance||0;var newBounds=this.clone();if(maxExtent){while(newBounds.left<maxExtent.left&&(newBounds.right-rightTolerance)<=maxExtent.left){newBounds=newBounds.add(maxExtent.getWidth(),0);}
+while((newBounds.left+leftTolerance)>=maxExtent.right&&newBounds.right>maxExtent.right){newBounds=newBounds.add(-maxExtent.getWidth(),0);}}
+return newBounds;},CLASS_NAME:"OpenLayers.Bounds"});OpenLayers.Bounds.fromString=function(str){var bounds=str.split(",");return OpenLayers.Bounds.fromArray(bounds);};OpenLayers.Bounds.fromArray=function(bbox){return new OpenLayers.Bounds(parseFloat(bbox[0]),parseFloat(bbox[1]),parseFloat(bbox[2]),parseFloat(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;i<arguments.length;i++){var element=OpenLayers.Util.getElement(arguments[i]);var display=OpenLayers.Element.visible(element)?'hide':'show';OpenLayers.Element[display](element);}},hide:function(){for(var i=0;i<arguments.length;i++){var element=OpenLayers.Util.getElement(arguments[i]);element.style.display='none';}},show:function(){for(var i=0;i<arguments.length;i++){var element=OpenLayers.Util.getElement(arguments[i]);element.style.display='';}},remove:function(element){element=OpenLayers.Util.getElement(element);element.parentNode.removeChild(element);},getHeight:function(element){element=OpenLayers.Util.getElement(element);return element.offsetHeight;},getDimensions:function(element){element=OpenLayers.Util.getElement(element);if(OpenLayers.Element.getStyle(element,'display')!='none'){return{width:element.offsetWidth,height:element.offsetHeight};}
+var els=element.style;var originalVisibility=els.visibility;var originalPosition=els.position;els.visibility='hidden';els.position='absolute';els.display='';var originalWidth=element.clientWidth;var originalHeight=element.clientHeight;els.display='none';els.position=originalPosition;els.visibility=originalVisibility;return{width:originalWidth,height:originalHeight};},getStyle:function(element,style){element=OpenLayers.Util.getElement(element);var value=element.style[OpenLayers.String.camelize(style)];if(!value){if(document.defaultView&&document.defaultView.getComputedStyle){var css=document.defaultView.getComputedStyle(element,null);value=css?css.getPropertyValue(style):null;}else if(element.currentStyle){value=element.currentStyle[OpenLayers.String.camelize(style)];}}
+var positions=['left','top','right','bottom'];if(window.opera&&(OpenLayers.Util.indexOf(positions,style)!=-1)&&(OpenLayers.Element.getStyle(element,'position')=='static')){value='auto';}
+return value=='auto'?null:value;}};OpenLayers.LonLat=OpenLayers.Class({lon:0.0,lat:0.0,initialize:function(lon,lat){this.lon=parseFloat(lon);this.lat=parseFloat(lat);},toString:function(){return("lon="+this.lon+",lat="+this.lat);},toShortString:function(){return(this.lon+", "+this.lat);},clone:function(){return new OpenLayers.LonLat(this.lon,this.lat);},add:function(lon,lat){if((lon==null)||(lat==null)){var msg=OpenLayers.i18n("lonlatAddError");OpenLayers.Console.error(msg);return null;}
+return new OpenLayers.LonLat(this.lon+lon,this.lat+lat);},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;},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;},wrapDateLine:function(maxExtent){var newLonLat=this.clone();if(maxExtent){while(newLonLat.lon<maxExtent.left){newLonLat.lon+=maxExtent.getWidth();}
+while(newLonLat.lon>maxExtent.right){newLonLat.lon-=maxExtent.getWidth();}}
+return newLonLat;},CLASS_NAME:"OpenLayers.LonLat"});OpenLayers.LonLat.fromString=function(str){var pair=str.split(",");return new OpenLayers.LonLat(parseFloat(pair[0]),parseFloat(pair[1]));};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;},add:function(x,y){if((x==null)||(y==null)){var msg=OpenLayers.i18n("pixelAddError");OpenLayers.Console.error(msg);return null;}
+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.Control=OpenLayers.Class({id:null,map:null,div:null,type:null,allowSelection:false,displayClass:"",title:"",active:null,handler:null,eventListeners:null,events:null,EVENT_TYPES:["activate","deactivate"],initialize:function(options){this.displayClass=this.CLASS_NAME.replace("OpenLayers.","ol").replace(/\./g,"");OpenLayers.Util.extend(this,options);this.events=new OpenLayers.Events(this,null,this.EVENT_TYPES);if(this.eventListeners instanceof Object){this.events.on(this.eventListeners);}
+this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){if(this.events){if(this.eventListeners){this.events.un(this.eventListeners);}
+this.events.destroy();this.events=null;}
+this.eventListeners=null;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;}},setMap:function(map){this.map=map;if(this.handler){this.handler.setMap(map);}},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=function(){return(false);};}
+if(this.title!=""){this.div.title=this.title;}}
+if(px!=null){this.position=px.clone();}
+this.moveTo(this.position);return this.div;},moveTo:function(px){if((px!=null)&&(this.div!=null)){this.div.style.left=px.x+"px";this.div.style.top=px.y+"px";}},activate:function(){if(this.active){return false;}
+if(this.handler){this.handler.activate();}
+this.active=true;this.events.triggerEvent("activate");return true;},deactivate:function(){if(this.active){if(this.handler){this.handler.deactivate();}
+this.active=false;this.events.triggerEvent("deactivate");return true;}
+return false;},CLASS_NAME:"OpenLayers.Control"});OpenLayers.Control.TYPE_BUTTON=1;OpenLayers.Control.TYPE_TOGGLE=2;OpenLayers.Control.TYPE_TOOL=3;OpenLayers.Icon=OpenLayers.Class({url:null,size:null,offset:null,calculateOffset:null,imageDiv:null,px:null,initialize:function(url,size,offset,calculateOffset){this.url=url;this.size=(size)?size:new OpenLayers.Size(20,20);this.offset=offset?offset:new OpenLayers.Pixel(-(this.size.w/2),-(this.size.h/2));this.calculateOffset=calculateOffset;var id=OpenLayers.Util.createUniqueID("OL_Icon_");this.imageDiv=OpenLayers.Util.createAlphaImageDiv(id);},destroy:function(){OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);this.imageDiv.innerHTML="";this.imageDiv=null;},clone:function(){return new OpenLayers.Icon(this.url,this.size,this.offset,this.calculateOffset);},setSize:function(size){if(size!=null){this.size=size;}
+this.draw();},setUrl:function(url){if(url!=null){this.url=url;}
+this.draw();},draw:function(px){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,this.size,this.url,"absolute");this.moveTo(px);return this.imageDiv;},setOpacity:function(opacity){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,null,null,null,null,null,opacity);},moveTo:function(px){if(px!=null){this.px=px;}
+if(this.imageDiv!=null){if(this.px==null){this.display(false);}else{if(this.calculateOffset){this.offset=this.calculateOffset(this.size);}
+var offsetPx=this.px.offset(this.offset);OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,offsetPx);}}},display:function(display){this.imageDiv.style.display=(display)?"":"none";},CLASS_NAME:"OpenLayers.Icon"});OpenLayers.Lang={code:null,defaultCode:"en",getCode:function(){if(!OpenLayers.Lang.code){OpenLayers.Lang.setCode();}
+return OpenLayers.Lang.code;},setCode:function(code){var lang;if(!code){code=(OpenLayers.Util.getBrowserName()=="msie")?navigator.userLanguage:navigator.language;}
+var parts=code.split('-');parts[0]=parts[0].toLowerCase();if(typeof OpenLayers.Lang[parts[0]]=="object"){lang=parts[0];}
+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;},translate:function(key,context){var dictionary=OpenLayers.Lang[OpenLayers.Lang.getCode()];var message=dictionary[key];if(!message){message=key;}
+if(context){message=OpenLayers.String.format(message,context);}
+return message;}};OpenLayers.i18n=OpenLayers.Lang.translate;OpenLayers.Tween=OpenLayers.Class({INTERVAL:10,easing:null,begin:null,finish:null,duration:null,callbacks:null,time:null,interval: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;if(this.interval){window.clearInterval(this.interval);this.interval=null;}
+if(this.callbacks&&this.callbacks.start){this.callbacks.start.call(this,this.begin);}
+this.interval=window.setInterval(OpenLayers.Function.bind(this.play,this),this.INTERVAL);},stop:function(){if(!this.playing){return;}
+if(this.callbacks&&this.callbacks.done){this.callbacks.done.call(this,this.finish);}
+window.clearInterval(this.interval);this.interval=null;this.playing=false;},play:function(){var value={};for(var i in this.begin){var b=this.begin[i];var f=this.finish[i];if(b==null||f==null||isNaN(b)||isNaN(f)){OpenLayers.Console.error('invalid value for Tween');}
+var c=f-b;value[i]=this.easing.apply(this,[this.time,b,c,this.duration]);}
+this.time++;if(this.callbacks&&this.callbacks.eachStep){this.callbacks.eachStep.call(this,value);}
+if(this.time>this.duration){if(this.callbacks&&this.callbacks.done){this.callbacks.done.call(this,this.finish);this.playing=false;}
+window.clearInterval(this.interval);this.interval=null;}},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.Control.ArgParser=OpenLayers.Class(OpenLayers.Control,{center:null,zoom:null,layers:null,displayProjection:null,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);},setMap:function(map){OpenLayers.Control.prototype.setMap.apply(this,arguments);for(var i=0;i<this.map.controls.length;i++){var control=this.map.controls[i];if((control!=this)&&(control.CLASS_NAME=="OpenLayers.Control.ArgParser")){if(control.displayProjection!=this.displayProjection){this.displayProjection=control.displayProjection;}
+break;}}
+if(i==this.map.controls.length){var args=OpenLayers.Util.getParameters();if(args.layers){this.layers=args.layers;this.map.events.register('addlayer',this,this.configureLayers);this.configureLayers();}
+if(args.lat&&args.lon){this.center=new OpenLayers.LonLat(parseFloat(args.lon),parseFloat(args.lat));if(args.zoom){this.zoom=parseInt(args.zoom);}
+this.map.events.register('changebaselayer',this,this.setCenter);this.setCenter();}}},setCenter:function(){if(this.map.baseLayer){this.map.events.unregister('changebaselayer',this,this.setCenter);if(this.displayProjection){this.center.transform(this.displayProjection,this.map.getProjectionObject());}
+this.map.setCenter(this.center,this.zoom);}},configureLayers:function(){if(this.layers.length==this.map.layers.length){this.map.events.unregister('addlayer',this,this.configureLayers);for(var i=0;i<this.layers.length;i++){var layer=this.map.layers[i];var c=this.layers.charAt(i);if(c=="B"){this.map.setBaseLayer(layer);}else if((c=="T")||(c=="F")){layer.setVisibility(c=="T");}}}},CLASS_NAME:"OpenLayers.Control.ArgParser"});OpenLayers.Control.MousePosition=OpenLayers.Class(OpenLayers.Control,{element:null,prefix:'',separator:', ',suffix:'',numdigits:5,granularity:10,lastXy:null,displayProjection:null,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){if(this.map){this.map.events.unregister('mousemove',this,this.redraw);}
+OpenLayers.Control.prototype.destroy.apply(this,arguments);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.element){this.div.left="";this.div.top="";this.element=this.div;}
+this.redraw();return this.div;},redraw:function(evt){var lonLat;if(evt==null){lonLat=new OpenLayers.LonLat(0,0);}else{if(this.lastXy==null||Math.abs(evt.xy.x-this.lastXy.x)>this.granularity||Math.abs(evt.xy.y-this.lastXy.y)>this.granularity)
+{this.lastXy=evt.xy;return;}
+lonLat=this.map.getLonLatFromPixel(evt.xy);if(!lonLat){return;}
+if(this.displayProjection){lonLat.transform(this.map.getProjectionObject(),this.displayProjection);}
+this.lastXy=evt.xy;}
+var newHtml=this.formatOutput(lonLat);if(newHtml!=this.element.innerHTML){this.element.innerHTML=newHtml;}},formatOutput:function(lonLat){var digits=parseInt(this.numdigits);var newHtml=this.prefix+
+lonLat.lon.toFixed(digits)+
+this.separator+
+lonLat.lat.toFixed(digits)+
+this.suffix;return newHtml;},setMap:function(){OpenLayers.Control.prototype.setMap.apply(this,arguments);this.map.events.register('mousemove',this,this.redraw);},CLASS_NAME:"OpenLayers.Control.MousePosition"});OpenLayers.Control.PanZoom=OpenLayers.Class(OpenLayers.Control,{slideFactor:50,buttons:null,position:null,initialize:function(options){this.position=new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,OpenLayers.Control.PanZoom.Y);OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){OpenLayers.Control.prototype.destroy.apply(this,arguments);while(this.buttons.length){var btn=this.buttons.shift();btn.map=null;OpenLayers.Event.stopObservingElement(btn);}
+this.buttons=null;this.position=null;},draw:function(px){OpenLayers.Control.prototype.draw.apply(this,arguments);px=this.position;this.buttons=[];var sz=new OpenLayers.Size(18,18);var centered=new OpenLayers.Pixel(px.x+sz.w/2,px.y);this._addButton("panup","north-mini.png",centered,sz);px.y=centered.y+sz.h;this._addButton("panleft","west-mini.png",px,sz);this._addButton("panright","east-mini.png",px.add(sz.w,0),sz);this._addButton("pandown","south-mini.png",centered.add(0,sz.h*2),sz);this._addButton("zoomin","zoom-plus-mini.png",centered.add(0,sz.h*3+5),sz);this._addButton("zoomworld","zoom-world-mini.png",centered.add(0,sz.h*4+5),sz);this._addButton("zoomout","zoom-minus-mini.png",centered.add(0,sz.h*5+5),sz);return this.div;},_addButton:function(id,img,xy,sz){var imgLocation=OpenLayers.Util.getImagesLocation()+img;var btn=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_PanZoom_"+id,xy,sz,imgLocation,"absolute");this.div.appendChild(btn);OpenLayers.Event.observe(btn,"mousedown",OpenLayers.Function.bindAsEventListener(this.buttonDown,btn));OpenLayers.Event.observe(btn,"dblclick",OpenLayers.Function.bindAsEventListener(this.doubleClick,btn));OpenLayers.Event.observe(btn,"click",OpenLayers.Function.bindAsEventListener(this.doubleClick,btn));btn.action=id;btn.map=this.map;btn.slideFactor=this.slideFactor;this.buttons.push(btn);return btn;},doubleClick:function(evt){OpenLayers.Event.stop(evt);return false;},buttonDown:function(evt){if(!OpenLayers.Event.isLeftClick(evt)){return;}
+switch(this.action){case"panup":this.map.pan(0,-this.slideFactor);break;case"pandown":this.map.pan(0,this.slideFactor);break;case"panleft":this.map.pan(-this.slideFactor,0);break;case"panright":this.map.pan(this.slideFactor,0);break;case"zoomin":this.map.zoomIn();break;case"zoomout":this.map.zoomOut();break;case"zoomworld":this.map.zoomToMaxExtent();break;}
+OpenLayers.Event.stop(evt);},CLASS_NAME:"OpenLayers.Control.PanZoom"});OpenLayers.Control.PanZoom.X=4;OpenLayers.Control.PanZoom.Y=4;OpenLayers.Control.ScaleLine=OpenLayers.Class(OpenLayers.Control,{maxWidth:100,topOutUnits:"km",topInUnits:"m",bottomOutUnits:"mi",bottomInUnits:"ft",eTop:null,eBottom:null,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,[options]);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.eTop){this.div.style.display="block";this.div.style.position="absolute";this.eTop=document.createElement("div");this.eTop.className=this.displayClass+"Top";var theLen=this.topInUnits.length;this.div.appendChild(this.eTop);if((this.topOutUnits=="")||(this.topInUnits=="")){this.eTop.style.visibility="hidden";}else{this.eTop.style.visibility="visible";}
+this.eBottom=document.createElement("div");this.eBottom.className=this.displayClass+"Bottom";this.div.appendChild(this.eBottom);if((this.bottomOutUnits=="")||(this.bottomInUnits=="")){this.eBottom.style.visibility="hidden";}else{this.eBottom.style.visibility="visible";}}
+this.map.events.register('moveend',this,this.update);this.update();return this.div;},getBarLen:function(maxLen){var digits=parseInt(Math.log(maxLen)/Math.log(10));var pow10=Math.pow(10,digits);var firstChar=parseInt(maxLen/pow10);var barLen;if(firstChar>5){barLen=5;}else if(firstChar>2){barLen=2;}else{barLen=1;}
+return barLen*pow10;},update:function(){var res=this.map.getResolution();if(!res){return;}
+var curMapUnits=this.map.units;var inches=OpenLayers.INCHES_PER_UNIT;var maxSizeData=this.maxWidth*res*inches[curMapUnits];var topUnits;var bottomUnits;if(maxSizeData>100000){topUnits=this.topOutUnits;bottomUnits=this.bottomOutUnits;}else{topUnits=this.topInUnits;bottomUnits=this.bottomInUnits;}
+var topMax=maxSizeData/inches[topUnits];var bottomMax=maxSizeData/inches[bottomUnits];var topRounded=this.getBarLen(topMax);var bottomRounded=this.getBarLen(bottomMax);topMax=topRounded/inches[curMapUnits]*inches[topUnits];bottomMax=bottomRounded/inches[curMapUnits]*inches[bottomUnits];var topPx=topMax/res;var bottomPx=bottomMax/res;this.eTop.style.width=Math.round(topPx)+"px";this.eBottom.style.width=Math.round(bottomPx)+"px";this.eTop.innerHTML=topRounded+" "+topUnits;this.eBottom.innerHTML=bottomRounded+" "+bottomUnits;},CLASS_NAME:"OpenLayers.Control.ScaleLine"});OpenLayers.Event={observers:false,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;},isLeftClick:function(event){return(((event.which)&&(event.which==1))||((event.button)&&(event.button==1)));},stop:function(event,allowDefault){if(!allowDefault){if(event.preventDefault){event.preventDefault();}else{event.returnValue=false;}}
+if(event.stopPropagation){event.stopPropagation();}else{event.cancelBubble=true;}},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];var args=new Array(entry.element,entry.name,entry.observer,entry.useCapture);var removed=OpenLayers.Event.stopObserving.apply(this,args);}}},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<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++;}}
+if(foundEntry){if(element.removeEventListener){element.removeEventListener(name,observer,useCapture);}else if(element&&element.detachEvent){element.detachEvent('on'+name,observer);}}
+return foundEntry;},unloadCache:function(){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"};OpenLayers.Event.observe(window,'unload',OpenLayers.Event.unloadCache,false);if(window.Event){OpenLayers.Util.applyDefaults(window.Event,OpenLayers.Event);}else{var Event=OpenLayers.Event;}
+OpenLayers.Events=OpenLayers.Class({BROWSER_EVENTS:["mouseover","mouseout","mousedown","mouseup","mousemove","click","dblclick","resize","focus","blur"],listeners:null,object:null,element:null,eventTypes:null,eventHandler:null,fallThrough:null,initialize:function(object,element,eventTypes,fallThrough){this.object=object;this.element=element;this.eventTypes=eventTypes;this.fallThrough=fallThrough;this.listeners={};this.eventHandler=OpenLayers.Function.bindAsEventListener(this.handleBrowserEvent,this);if(this.eventTypes!=null){for(var i=0;i<this.eventTypes.length;i++){this.addEventType(this.eventTypes[i]);}}
+if(this.element!=null){this.attachToElement(element);}},destroy:function(){if(this.element){OpenLayers.Event.stopObservingElement(this.element);}
+this.element=null;this.listeners=null;this.object=null;this.eventTypes=null;this.fallThrough=null;this.eventHandler=null;},addEventType:function(eventName){if(!this.listeners[eventName]){this.listeners[eventName]=[];}},attachToElement:function(element){for(var i=0;i<this.BROWSER_EVENTS.length;i++){var eventType=this.BROWSER_EVENTS[i];this.addEventType(eventType);OpenLayers.Event.observe(element,eventType,this.eventHandler);}
+OpenLayers.Event.observe(element,"dragstart",OpenLayers.Event.stop);},on:function(object){for(var type in object){if(type!="scope"){this.register(type,object.scope,object[type]);}}},register:function(type,obj,func){if(func!=null&&((this.eventTypes&&OpenLayers.Util.indexOf(this.eventTypes,type)!=-1)||OpenLayers.Util.indexOf(this.BROWSER_EVENTS,type)!=-1)){if(obj==null){obj=this.object;}
+var listeners=this.listeners[type];if(listeners!=null){listeners.push({obj:obj,func:func});}}},registerPriority:function(type,obj,func){if(func!=null){if(obj==null){obj=this.object;}
+var listeners=this.listeners[type];if(listeners!=null){listeners.unshift({obj:obj,func:func});}}},un:function(object){for(var type in object){if(type!="scope"){this.unregister(type,object.scope,object[type]);}}},unregister:function(type,obj,func){if(obj==null){obj=this.object;}
+var listeners=this.listeners[type];if(listeners!=null){for(var i=0;i<listeners.length;i++){if(listeners[i].obj==obj&&listeners[i].func==func){listeners.splice(i,1);break;}}}},remove:function(type){if(this.listeners[type]!=null){this.listeners[type]=[];}},triggerEvent:function(type,evt){if(evt==null){evt={};}
+evt.object=this.object;evt.element=this.element;if(!evt.type){evt.type=type;}
+var listeners=(this.listeners[type])?this.listeners[type].slice():null;if((listeners!=null)&&(listeners.length>0)){var continueChain;for(var i=0;i<listeners.length;i++){var callback=listeners[i];continueChain=callback.func.apply(callback.obj,[evt]);if((continueChain!=undefined)&&(continueChain==false)){break;}}
+if(!this.fallThrough){OpenLayers.Event.stop(evt,true);}}
+return continueChain;},handleBrowserEvent:function(evt){evt.xy=this.getMousePosition(evt);this.triggerEvent(evt.type,evt);},getMousePosition:function(evt){if(!this.element.offsets){this.element.offsets=OpenLayers.Util.pagePosition(this.element);this.element.offsets[0]+=(document.documentElement.scrollLeft||document.body.scrollLeft);this.element.offsets[1]+=(document.documentElement.scrollTop||document.body.scrollTop);}
+return new OpenLayers.Pixel((evt.clientX+(document.documentElement.scrollLeft||document.body.scrollLeft))-this.element.offsets[0]
+-(document.documentElement.clientLeft||0),(evt.clientY+(document.documentElement.scrollTop||document.body.scrollTop))-this.element.offsets[1]
+-(document.documentElement.clientTop||0));},CLASS_NAME:"OpenLayers.Events"});OpenLayers.Lang.en={'unhandledRequest':"Unhandled request return ${statusText}",'permalink':"Permalink",'overlays':"Overlays",'baseLayer':"Base Layer",'sameProjection':"The overview map only works when it is in the same projection as the main map",'readNotImplemented':"Read not implemented.",'writeNotImplemented':"Write not implemented.",'noFID':"Can't update a feature for which there is no FID.",'errorLoadingGML':"Error in loading GML file ${url}",'browserNotSupported':"Your browser does not support vector rendering. Currently supported renderers are:\n${renderers}",'componentShouldBe':"addFeatures : component should be an ${geomType}",'getFeatureError':"getFeatureFromEvent called on layer with no renderer. This usually means you "+"destroyed a layer, but not some handler which is associated with it.",'minZoomLevelError':"The minZoomLevel property is only intended for use "+"with the FixedZoomLevels-descendent layers. That this "+"wfs layer checks for minZoomLevel is a relic of the"+"past. We cannot, however, remove it without possibly "+"breaking OL based applications that may depend on it."+" Therefore we are deprecating it -- the minZoomLevel "+"check below will be removed at 3.0. Please instead "+"use min/max resolution setting as described here: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS Transaction: SUCCESS ${response}",'commitFailed':"WFS Transaction: FAILED ${response}",'googleWarning':"The Google Layer was unable to load correctly.<br><br>"+"To get rid of this message, select a new BaseLayer "+"in the layer switcher in the upper-right corner.<br><br>"+"Most likely, this is because the Google Maps library "+"script was either not included, or does not contain the "+"correct API key for your site.<br><br>"+"Developers: For help getting this working correctly, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>click here</a>",'getLayerWarning':"The ${layerType} Layer was unable to load correctly.<br><br>"+"To get rid of this message, select a new BaseLayer "+"in the layer switcher in the upper-right corner.<br><br>"+"Most likely, this is because the ${layerLib} library "+"script was either not correctly included.<br><br>"+"Developers: For help getting this working correctly, "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>click here</a>",'scale':"Scale = 1 : ${scaleDenom}",'layerAlreadyAdded':"You tried to add the layer: ${layerName} to the map, but it has already been added",'reprojectDeprecated':"You are using the 'reproject' option "+"on the ${layerName} layer. This option is deprecated: "+"its use was designed to support displaying data over commercial "+"basemaps, but that functionality should now be achieved by using "+"Spherical Mercator support. More information is available from "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"This method has been deprecated and will be removed in 3.0. "+"Please use ${newMethod} instead.",'boundsAddError':"You must pass both x and y values to the add function.",'lonlatAddError':"You must pass both lon and lat values to the add function.",'pixelAddError':"You must pass both x and y values to the add function.",'unsupportedGeometryType':"Unsupported geometry type: ${geomType}",'pagePositionFailed':"OpenLayers.Util.pagePosition failed: element with id ${elemId} may be misplaced.",'end':''};OpenLayers.Projection=OpenLayers.Class({proj:null,projCode:null,initialize:function(projCode,options){OpenLayers.Util.extend(this,options);this.projCode=projCode;if(window.Proj4js){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){if(projection&&projection.getCode){return this.getCode()==projection.getCode();}else{return false;}},destroy:function(){delete this.proj;delete this.projCode;},CLASS_NAME:"OpenLayers.Projection"});OpenLayers.Projection.transforms={};OpenLayers.Projection.addTransform=function(from,to,method){if(!OpenLayers.Projection.transforms[from]){OpenLayers.Projection.transforms[from]={};}
+OpenLayers.Projection.transforms[from][to]=method;};OpenLayers.Projection.transform=function(point,source,dest){if(source.proj&&dest.proj){point=Proj4js.transform(source.proj,dest.proj,point);}else if(source&&dest&&OpenLayers.Projection.transforms[source.getCode()]&&OpenLayers.Projection.transforms[source.getCode()][dest.getCode()]){OpenLayers.Projection.transforms[source.getCode()][dest.getCode()](point);}
+return point;};OpenLayers.Tile=OpenLayers.Class({EVENT_TYPES:["loadstart","loadend","reload","unload"],events:null,id:null,layer:null,url:null,bounds:null,size:null,position:null,isLoading:false,isBackBuffer:false,lastRatio:1,isFirstDraw:true,backBufferTile:null,initialize:function(layer,position,bounds,url,size){this.layer=layer;this.position=position.clone();this.bounds=bounds.clone();this.url=url;this.size=size.clone();this.id=OpenLayers.Util.createUniqueID("Tile_");this.events=new OpenLayers.Events(this,null,this.EVENT_TYPES);},unload:function(){if(this.isLoading){this.isLoading=false;this.events.triggerEvent("unload");}},destroy:function(){if(OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS,this.layer.transitionEffect)!=-1){this.layer.events.unregister("loadend",this,this.resetBackBuffer);this.events.unregister('loadend',this,this.resetBackBuffer);}else{this.events.unregister('loadend',this,this.showTile);}
+this.layer=null;this.bounds=null;this.size=null;this.position=null;this.events.destroy();this.events=null;if(this.backBufferTile){this.backBufferTile.destroy();this.backBufferTile=null;}},clone:function(obj){if(obj==null){obj=new OpenLayers.Tile(this.layer,this.position,this.bounds,this.url,this.size);}
+OpenLayers.Util.applyDefaults(obj,this);return obj;},draw:function(){var maxExtent=this.layer.maxExtent;var withinMaxExtent=(maxExtent&&this.bounds.intersectsBounds(maxExtent,false));var drawTile=(withinMaxExtent||this.layer.displayOutsideMaxExtent);if(OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS,this.layer.transitionEffect)!=-1){if(drawTile){if(!this.backBufferTile){this.backBufferTile=this.clone();this.backBufferTile.hide();this.backBufferTile.isBackBuffer=true;this.events.register('loadend',this,this.resetBackBuffer);this.layer.events.register("loadend",this,this.resetBackBuffer);}
+this.startTransition();}else{if(this.backBufferTile){this.backBufferTile.clear();}}}else{if(drawTile&&this.isFirstDraw){this.events.register('loadend',this,this.showTile);this.isFirstDraw=false;}}
+this.shouldDraw=drawTile;this.clear();return drawTile;},moveTo:function(bounds,position,redraw){if(redraw==null){redraw=true;}
+this.bounds=bounds.clone();this.position=position.clone();if(redraw){this.draw();}},clear:function(){},getBoundsFromBaseLayer:function(position){var msg=OpenLayers.i18n('reprojectDeprecated',{'layerName':this.layer.name});OpenLayers.Console.warn(msg);var topLeft=this.layer.map.getLonLatFromLayerPx(position);var bottomRightPx=position.clone();bottomRightPx.x+=this.size.w;bottomRightPx.y+=this.size.h;var bottomRight=this.layer.map.getLonLatFromLayerPx(bottomRightPx);if(topLeft.lon>bottomRight.lon){if(topLeft.lon<0){topLeft.lon=-180-(topLeft.lon+180);}else{bottomRight.lon=180+bottomRight.lon+180;}}
+var bounds=new OpenLayers.Bounds(topLeft.lon,bottomRight.lat,bottomRight.lon,topLeft.lat);return bounds;},startTransition:function(){},resetBackBuffer:function(){this.showTile();if(this.backBufferTile&&(this.isFirstDraw||!this.layer.numLoadingTiles)){this.isFirstDraw=false;var maxExtent=this.layer.maxExtent;var withinMaxExtent=(maxExtent&&this.bounds.intersectsBounds(maxExtent,false));if(withinMaxExtent){this.backBufferTile.position=this.position;this.backBufferTile.bounds=this.bounds;this.backBufferTile.size=this.size;this.backBufferTile.imageSize=this.layer.imageSize||this.size;this.backBufferTile.imageOffset=this.layer.imageOffset;this.backBufferTile.resolution=this.layer.getResolution();this.backBufferTile.renderTile();}}},showTile:function(){if(this.shouldDraw){this.show();}},show:function(){},hide:function(){},CLASS_NAME:"OpenLayers.Tile"});OpenLayers.Handler=OpenLayers.Class({id:null,control:null,map:null,keyMask:null,active:false,evt:null,initialize:function(control,callbacks,options){OpenLayers.Util.extend(this,options);this.control=control;this.callbacks=callbacks;if(control.map){this.setMap(control.map);}
+OpenLayers.Util.extend(this,options);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},setMap:function(map){this.map=map;},checkModifiers:function(evt){if(this.keyMask==null){return true;}
+var keyModifiers=(evt.shiftKey?OpenLayers.Handler.MOD_SHIFT:0)|(evt.ctrlKey?OpenLayers.Handler.MOD_CTRL:0)|(evt.altKey?OpenLayers.Handler.MOD_ALT:0);return(keyModifiers==this.keyMask);},activate:function(){if(this.active){return false;}
+var events=OpenLayers.Events.prototype.BROWSER_EVENTS;for(var i=0;i<events.length;i++){if(this[events[i]]){this.register(events[i],this[events[i]]);}}
+this.active=true;return true;},deactivate:function(){if(!this.active){return false;}
+var events=OpenLayers.Events.prototype.BROWSER_EVENTS;for(var i=0;i<events.length;i++){if(this[events[i]]){this.unregister(events[i],this[events[i]]);}}
+this.active=false;return true;},callback:function(name,args){if(name&&this.callbacks[name]){this.callbacks[name].apply(this.control,args);}},register:function(name,method){this.map.events.registerPriority(name,this,method);this.map.events.registerPriority(name,this,this.setEvent);},unregister:function(name,method){this.map.events.unregister(name,this,method);this.map.events.unregister(name,this,this.setEvent);},setEvent:function(evt){this.evt=evt;return true;},destroy:function(){this.deactivate();this.control=this.map=null;},CLASS_NAME:"OpenLayers.Handler"});OpenLayers.Handler.MOD_NONE=0;OpenLayers.Handler.MOD_SHIFT=1;OpenLayers.Handler.MOD_CTRL=2;OpenLayers.Handler.MOD_ALT=4;OpenLayers.Map=OpenLayers.Class({Z_INDEX_BASE:{BaseLayer:100,Overlay:325,Popup:750,Control:1000},EVENT_TYPES:["preaddlayer","addlayer","removelayer","changelayer","movestart","move","moveend","zoomend","popupopen","popupclose","addmarker","removemarker","clearmarkers","mouseover","mouseout","mousemove","dragstart","drag","dragend","changebaselayer"],id:null,fractionalZoom:false,events:null,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,viewRequestID:0,tileSize:null,projection:"EPSG:4326",units:'degrees',resolutions:null,maxResolution:1.40625,minResolution:null,maxScale:null,minScale:null,maxExtent:null,minExtent:null,restrictedExtent:null,numZoomLevels:16,theme:null,displayProjection:null,fallThrough:true,panTween:null,eventListeners:null,panMethod:OpenLayers.Easing.Expo.easeOut,paddingForPopups:null,initialize:function(div,options){this.tileSize=new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,OpenLayers.Map.TILE_HEIGHT);this.maxExtent=new OpenLayers.Bounds(-180,-90,180,90);this.paddingForPopups=new OpenLayers.Bounds(15,15,15,15);this.theme=OpenLayers._getScriptLocation()+'theme/default/style.css';OpenLayers.Util.extend(this,options);this.id=OpenLayers.Util.createUniqueID("OpenLayers.Map_");this.div=OpenLayers.Util.getElement(div);var id=this.div.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);id=this.div.id+"_OpenLayers_Container";this.layerContainerDiv=OpenLayers.Util.createDiv(id);this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;this.viewPortDiv.appendChild(this.layerContainerDiv);this.events=new OpenLayers.Events(this,this.div,this.EVENT_TYPES,this.fallThrough);this.updateSize();if(this.eventListeners instanceof Object){this.events.on(this.eventListeners);}
+this.events.register("movestart",this,this.updateSize);if(OpenLayers.String.contains(navigator.appName,"Microsoft")){this.events.register("resize",this,this.updateSize);}else{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;i<nodes.length;++i){if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,this.theme)){addNode=false;break;}}
+if(addNode){var cssNode=document.createElement('link');cssNode.setAttribute('rel','stylesheet');cssNode.setAttribute('type','text/css');cssNode.setAttribute('href',this.theme);document.getElementsByTagName('head')[0].appendChild(cssNode);}}
+this.layers=[];if(this.controls==null){if(OpenLayers.Control!=null){this.controls=[new OpenLayers.Control.Navigation(),new OpenLayers.Control.PanZoom(),new OpenLayers.Control.ArgParser(),new OpenLayers.Control.Attribution()];}else{this.controls=[];}}
+for(var i=0;i<this.controls.length;i++){this.addControlToMap(this.controls[i]);}
+this.popups=[];this.unloadDestroy=OpenLayers.Function.bind(this.destroy,this);OpenLayers.Event.observe(window,'unload',this.unloadDestroy);},unloadDestroy:null,updateSizeDestroy:null,destroy:function(){if(!this.unloadDestroy){return false;}
+OpenLayers.Event.stopObserving(window,'unload',this.unloadDestroy);this.unloadDestroy=null;if(this.updateSizeDestroy){OpenLayers.Event.stopObserving(window,'resize',this.updateSizeDestroy);}else{this.events.unregister("resize",this,this.updateSize);}
+this.paddingForPopups=null;if(this.controls!=null){for(var i=this.controls.length-1;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;},setOptions:function(options){OpenLayers.Util.extend(this,options);},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;i<this.layers.length;i++){var layer=this.layers[i];if(layer.id==id){foundLayer=layer;break;}}
+return foundLayer;},setLayerZIndex:function(layer,zIdx){layer.setZIndex(this.Z_INDEX_BASE[layer.isBaseLayer?'BaseLayer':'Overlay']
++zIdx*5);},resetLayersZIndex:function(){for(var i=0;i<this.layers.length;i++){var layer=this.layers[i];this.setLayerZIndex(layer,i);}},addLayer:function(layer){for(var i=0;i<this.layers.length;i++){if(this.layers[i]==layer){var msg=OpenLayers.i18n('layerAlreadyAdded',{'layerName':layer.name});OpenLayers.Console.warn(msg);return false;}}
+this.events.triggerEvent("preaddlayer",{layer:layer});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){if(this.baseLayer==null){this.setBaseLayer(layer);}else{layer.setVisibility(false);}}else{layer.redraw();}
+this.events.triggerEvent("addlayer",{layer:layer});},addLayers:function(layers){for(var i=0;i<layers.length;i++){this.addLayer(layers[i]);}},removeLayer:function(layer,setNewBaseLayer){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(this.baseLayer==layer){this.baseLayer=null;if(setNewBaseLayer){for(var i=0;i<this.layers.length;i++){var iLayer=this.layers[i];if(iLayer.isBaseLayer){this.setBaseLayer(iLayer);break;}}}}
+this.resetLayersZIndex();this.events.triggerEvent("removelayer",{layer:layer});},getNumLayers:function(){return this.layers.length;},getLayerIndex:function(layer){return OpenLayers.Util.indexOf(this.layers,layer);},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;i<this.layers.length;i++){this.setLayerZIndex(this.layers[i],i);}
+this.events.triggerEvent("changelayer",{layer:layer,property:"order"});}},raiseLayer:function(layer,delta){var idx=this.getLayerIndex(layer)+delta;this.setLayerIndex(layer,idx);},setBaseLayer:function(newBaseLayer){var oldExtent=null;if(this.baseLayer){oldExtent=this.baseLayer.getExtent();}
+if(newBaseLayer!=this.baseLayer){if(OpenLayers.Util.indexOf(this.layers,newBaseLayer)!=-1){if(this.baseLayer!=null){this.baseLayer.setVisibility(false);}
+this.baseLayer=newBaseLayer;this.viewRequestID++;this.baseLayer.visibility=true;var center=this.getCenter();if(center!=null){var newCenter=(oldExtent)?oldExtent.getCenterLonLat():center;var newZoom=(oldExtent)?this.getZoomForExtent(oldExtent,true):this.getZoomForResolution(this.resolution,true);this.setCenter(newCenter,newZoom,false,true);}
+this.events.triggerEvent("changebaselayer",{layer:this.baseLayer});}}},addControl:function(control,px){this.controls.push(control);this.addControlToMap(control,px);},addControlToMap:function(control,px){control.outsideViewport=(control.div!=null);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);}}},getControl:function(id){var returnControl=null;for(var i=0;i<this.controls.length;i++){var control=this.controls[i];if(control.id==id){returnControl=control;break;}}
+return returnControl;},removeControl:function(control){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);}},addPopup:function(popup,exclusive){if(exclusive){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);}},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(){this.events.element.offsets=null;var newSize=this.getCurrentSize();var oldSize=this.getSize();if(oldSize==null){this.size=oldSize=newSize;}
+if(!newSize.equals(oldSize)){this.size=newSize;for(var i=0;i<this.layers.length;i++){this.layers[i].onMapResize();}
+if(this.baseLayer!=null){var center=new OpenLayers.Pixel(newSize.w/2,newSize.h/2);var centerLL=this.getLonLatFromViewPortPx(center);var zoom=this.getZoom();this.zoom=null;this.setCenter(this.getCenter(),zoom);}}},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)){var dim=OpenLayers.Element.getDimensions(this.div);size.w=dim.width;size.h=dim.height;}
+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;},calculateBounds:function(center,resolution){var extent=null;if(center==null){center=this.getCenter();}
+if(resolution==null){resolution=this.getResolution();}
+if((center!=null)&&(resolution!=null)){var size=this.getSize();var w_deg=size.w*resolution;var h_deg=size.h*resolution;extent=new OpenLayers.Bounds(center.lon-w_deg/2,center.lat-h_deg/2,center.lon+w_deg/2,center.lat+h_deg/2);}
+return extent;},getCenter:function(){return this.center;},getZoom:function(){return this.zoom;},pan:function(dx,dy,options){if(!options){options={};}
+OpenLayers.Util.applyDefaults(options,{animate:true,dragging:false});var centerPx=this.getViewPortPxFromLonLat(this.getCenter());var newCenterPx=centerPx.add(dx,dy);if(!options.dragging||!newCenterPx.equals(centerPx)){var newCenterLonLat=this.getLonLatFromViewPortPx(newCenterPx);if(options.animate){this.panTo(newCenterLonLat);}else{this.setCenter(newCenterLonLat,null,options.dragging);}}},panTo:function(lonlat){if(this.panMethod&&this.getExtent().containsLonLat(lonlat)){if(!this.panTween){this.panTween=new OpenLayers.Tween(this.panMethod);}
+var center=this.getCenter();var from={lon:center.lon,lat:center.lat};var to={lon:lonlat.lon,lat:lonlat.lat};this.panTween.start(from,to,50,{callbacks:{start:OpenLayers.Function.bind(function(lonlat){this.events.triggerEvent("movestart");},this),eachStep:OpenLayers.Function.bind(function(lonlat){lonlat=new OpenLayers.LonLat(lonlat.lon,lonlat.lat);this.moveTo(lonlat,this.zoom,{'dragging':true,'noEvent':true});},this),done:OpenLayers.Function.bind(function(lonlat){lonlat=new OpenLayers.LonLat(lonlat.lon,lonlat.lat);this.moveTo(lonlat,this.zoom,{'noEvent':true});this.events.triggerEvent("moveend");},this)}});}else{this.setCenter(lonlat);}},setCenter:function(lonlat,zoom,dragging,forceZoomChange){this.moveTo(lonlat,zoom,{'dragging':dragging,'forceZoomChange':forceZoomChange,'caller':'setCenter'});},moveTo:function(lonlat,zoom,options){if(!options){options={};}
+var dragging=options.dragging;var forceZoomChange=options.forceZoomChange;var noEvent=options.noEvent;if(this.panTween&&options.caller=="setCenter"){this.panTween.stop();}
+if(!this.center&&!this.isValidLonLat(lonlat)){lonlat=this.maxExtent.getCenterLonLat();}
+if(this.restrictedExtent!=null){if(lonlat==null){lonlat=this.getCenter();}
+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(zoomChanged||centerChanged||!dragging){if(!this.dragging&&!noEvent){this.events.triggerEvent("movestart");}
+if(centerChanged){if((!zoomChanged)&&(this.center)){this.centerLayerContainer(lonlat);}
+this.center=lonlat.clone();}
+if((zoomChanged)||(this.layerContainerOrigin==null)){this.layerContainerOrigin=this.center.clone();this.layerContainerDiv.style.left="0px";this.layerContainerDiv.style.top="0px";}
+if(zoomChanged){this.zoom=zoom;this.resolution=this.getResolutionForZoom(zoom);this.viewRequestID++;}
+var bounds=this.getExtent();this.baseLayer.moveTo(bounds,zoomChanged,dragging);bounds=this.baseLayer.getExtent();for(var i=0;i<this.layers.length;i++){var layer=this.layers[i];if(!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,dragging);}}}
+if(zoomChanged){for(var i=0;i<this.popups.length;i++){this.popups[i].updatePosition();}}
+this.events.triggerEvent("move");if(zoomChanged){this.events.triggerEvent("zoomend");}}
+if(!dragging&&!noEvent){this.events.triggerEvent("moveend");}
+this.dragging=!!dragging;},centerLayerContainer:function(lonlat){var originPx=this.getViewPortPxFromLonLat(this.layerContainerOrigin);var newPx=this.getViewPortPxFromLonLat(lonlat);if((originPx!=null)&&(newPx!=null)){this.layerContainerDiv.style.left=Math.round(originPx.x-newPx.x)+"px";this.layerContainerDiv.style.top=Math.round(originPx.y-newPx.y)+"px";}},isValidZoomLevel:function(zoomLevel){return((zoomLevel!=null)&&(zoomLevel>=0)&&(zoomLevel<this.getNumZoomLevels()));},isValidLonLat:function(lonlat){var valid=false;if(lonlat!=null){var maxExtent=this.getMaxExtent();valid=maxExtent.containsLonLat(lonlat);}
+return valid;},getProjection:function(){var projection=this.getProjectionObject();return projection?projection.getCode():null;},getProjectionObject:function(){var projection=null;if(this.baseLayer!=null){projection=this.baseLayer.projection;}
+return projection;},getMaxResolution:function(){var maxResolution=null;if(this.baseLayer!=null){maxResolution=this.baseLayer.maxResolution;}
+return maxResolution;},getMaxExtent:function(){var maxExtent=null;if(this.baseLayer!=null){maxExtent=this.baseLayer.maxExtent;}
+return maxExtent;},getNumZoomLevels:function(){var numZoomLevels=null;if(this.baseLayer!=null){numZoomLevels=this.baseLayer.numZoomLevels;}
+return numZoomLevels;},getExtent:function(){var extent=null;if(this.baseLayer!=null){extent=this.baseLayer.getExtent();}
+return extent;},getResolution:function(){var resolution=null;if(this.baseLayer!=null){resolution=this.baseLayer.getResolution();}
+return resolution;},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){var center=bounds.getCenterLonLat();if(this.baseLayer.wrapDateLine){var maxExtent=this.getMaxExtent();bounds=bounds.clone();while(bounds.right<bounds.left){bounds.right+=maxExtent.getWidth();}
+center=bounds.getCenterLonLat().wrapDateLine(maxExtent);}
+this.setCenter(center,this.getZoomForExtent(bounds));},zoomToMaxExtent:function(){this.zoomToExtent(this.getMaxExtent());},zoomToScale:function(scale){var res=OpenLayers.Util.getResolutionFromScale(scale,this.baseLayer.units);var size=this.getSize();var w_deg=size.w*res;var h_deg=size.h*res;var center=this.getCenter();var extent=new OpenLayers.Bounds(center.lon-w_deg/2,center.lat-h_deg/2,center.lon+w_deg/2,center.lat+h_deg/2);this.zoomToExtent(extent);},getLonLatFromViewPortPx:function(viewPortPx){var lonlat=null;if(this.baseLayer!=null){lonlat=this.baseLayer.getLonLatFromViewPortPx(viewPortPx);}
+return lonlat;},getViewPortPxFromLonLat:function(lonlat){var px=null;if(this.baseLayer!=null){px=this.baseLayer.getViewPortPxFromLonLat(lonlat);}
+return px;},getLonLatFromPixel:function(px){return this.getLonLatFromViewPortPx(px);},getPixelFromLonLat:function(lonlat){var px=this.getViewPortPxFromLonLat(lonlat);px.x=Math.round(px.x);px.y=Math.round(px.y);return px;},getViewPortPxFromLayerPx:function(layerPx){var viewPortPx=null;if(layerPx!=null){var dX=parseInt(this.layerContainerDiv.style.left);var dY=parseInt(this.layerContainerDiv.style.top);viewPortPx=layerPx.add(dX,dY);}
+return viewPortPx;},getLayerPxFromViewPortPx:function(viewPortPx){var layerPx=null;if(viewPortPx!=null){var dX=-parseInt(this.layerContainerDiv.style.left);var dY=-parseInt(this.layerContainerDiv.style.top);layerPx=viewPortPx.add(dX,dY);if(isNaN(layerPx.x)||isNaN(layerPx.y)){layerPx=null;}}
+return layerPx;},getLonLatFromLayerPx:function(px){px=this.getViewPortPxFromLayerPx(px);return this.getLonLatFromViewPortPx(px);},getLayerPxFromLonLat:function(lonlat){var px=this.getPixelFromLonLat(lonlat);return this.getLayerPxFromViewPortPx(px);},CLASS_NAME:"OpenLayers.Map"});OpenLayers.Map.TILE_WIDTH=256;OpenLayers.Map.TILE_HEIGHT=256;OpenLayers.Marker=OpenLayers.Class({icon:null,lonlat:null,events:null,map:null,initialize:function(lonlat,icon){this.lonlat=lonlat;var newIcon=(icon)?icon:OpenLayers.Marker.defaultIcon();if(this.icon==null){this.icon=newIcon;}else{this.icon.url=newIcon.url;this.icon.size=newIcon.size;this.icon.offset=newIcon.offset;this.icon.calculateOffset=newIcon.calculateOffset;}
+this.events=new OpenLayers.Events(this,this.icon.imageDiv,null);},destroy:function(){this.map=null;this.events.destroy();this.events=null;if(this.icon!=null){this.icon.destroy();this.icon=null;}},draw:function(px){return this.icon.draw(px);},moveTo:function(px){if((px!=null)&&(this.icon!=null)){this.icon.moveTo(px);}
+this.lonlat=this.map.getLonLatFromLayerPx(px);},onScreen:function(){var onScreen=false;if(this.map){var screenBounds=this.map.getExtent();onScreen=screenBounds.containsLonLat(this.lonlat);}
+return onScreen;},inflate:function(inflate){if(this.icon){var newSize=new OpenLayers.Size(this.icon.size.w*inflate,this.icon.size.h*inflate);this.icon.setSize(newSize);}},setOpacity:function(opacity){this.icon.setOpacity(opacity);},setUrl:function(url){this.icon.setUrl(url);},display:function(display){this.icon.display(display);},CLASS_NAME:"OpenLayers.Marker"});OpenLayers.Marker.defaultIcon=function(){var url=OpenLayers.Util.getImagesLocation()+"marker.png";var size=new OpenLayers.Size(21,25);var calculateOffset=function(size){return new OpenLayers.Pixel(-(size.w/2),-size.h);};return new OpenLayers.Icon(url,size,null,calculateOffset);};OpenLayers.Tile.Image=OpenLayers.Class(OpenLayers.Tile,{url:null,imgDiv:null,frame:null,layerAlphaHack:null,initialize:function(layer,position,bounds,url,size){OpenLayers.Tile.prototype.initialize.apply(this,arguments);this.url=url;this.frame=document.createElement('div');this.frame.style.overflow='hidden';this.frame.style.position='absolute';this.layerAlphaHack=this.layer.alpha&&OpenLayers.Util.alphaHack();},destroy:function(){if(this.imgDiv!=null){if(this.layerAlphaHack){OpenLayers.Event.stopObservingElement(this.imgDiv.childNodes[0].id);}else{OpenLayers.Event.stopObservingElement(this.imgDiv.id);}
+if(this.imgDiv.parentNode==this.frame){this.frame.removeChild(this.imgDiv);this.imgDiv.map=null;}}
+this.imgDiv=null;if((this.frame!=null)&&(this.frame.parentNode==this.layer.div)){this.layer.div.removeChild(this.frame);}
+this.frame=null;OpenLayers.Tile.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Tile.Image(this.layer,this.position,this.bounds,this.url,this.size);}
+obj=OpenLayers.Tile.prototype.clone.apply(this,[obj]);obj.imgDiv=null;return obj;},draw:function(){if(this.layer!=this.layer.map.baseLayer&&this.layer.reproject){this.bounds=this.getBoundsFromBaseLayer(this.position);}
+if(!OpenLayers.Tile.prototype.draw.apply(this,arguments)){return false;}
+if(this.isLoading){this.events.triggerEvent("reload");}else{this.isLoading=true;this.events.triggerEvent("loadstart");}
+return this.renderTile();},renderTile:function(){if(this.imgDiv==null){this.initImgDiv();}
+this.imgDiv.viewRequestID=this.layer.map.viewRequestID;this.url=this.layer.getURL(this.bounds);OpenLayers.Util.modifyDOMElement(this.frame,null,this.position,this.size);var imageSize=this.layer.getImageSize();if(this.layerAlphaHack){OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,null,null,imageSize,this.url);}else{OpenLayers.Util.modifyDOMElement(this.imgDiv,null,null,imageSize);this.imgDiv.src=this.url;}
+return true;},clear:function(){if(this.imgDiv){this.hide();if(OpenLayers.Tile.Image.useBlankTile){this.imgDiv.src=OpenLayers.Util.getImagesLocation()+"blank.gif";}}},initImgDiv:function(){var offset=this.layer.imageOffset;var size=this.layer.getImageSize();if(this.layerAlphaHack){this.imgDiv=OpenLayers.Util.createAlphaImageDiv(null,offset,size,null,"relative",null,null,null,true);}else{this.imgDiv=OpenLayers.Util.createImage(null,offset,size,null,"relative",null,null,true);}
+this.imgDiv.className='olTileImage';this.frame.style.zIndex=this.isBackBuffer?0:1;this.frame.appendChild(this.imgDiv);this.layer.div.appendChild(this.frame);if(this.layer.opacity!=null){OpenLayers.Util.modifyDOMElement(this.imgDiv,null,null,null,null,null,null,this.layer.opacity);}
+this.imgDiv.map=this.layer.map;var onload=function(){if(this.isLoading){this.isLoading=false;this.events.triggerEvent("loadend");}};if(this.layerAlphaHack){OpenLayers.Event.observe(this.imgDiv.childNodes[0],'load',OpenLayers.Function.bind(onload,this));}else{OpenLayers.Event.observe(this.imgDiv,'load',OpenLayers.Function.bind(onload,this));}
+var onerror=function(){if(this.imgDiv._attempts>OpenLayers.IMAGE_RELOAD_ATTEMPTS){onload.call(this);}};OpenLayers.Event.observe(this.imgDiv,"error",OpenLayers.Function.bind(onerror,this));},checkImgURL:function(){if(this.layer){var loaded=this.layerAlphaHack?this.imgDiv.firstChild.src:this.imgDiv.src;if(!OpenLayers.Util.isEquivalentUrl(loaded,this.url)){this.hide();}}},startTransition:function(){if(!this.backBufferTile||!this.backBufferTile.imgDiv){return;}
+var ratio=1;if(this.backBufferTile.resolution){ratio=this.backBufferTile.resolution/this.layer.getResolution();}
+if(ratio!=this.lastRatio){if(this.layer.transitionEffect=='resize'){var upperLeft=new OpenLayers.LonLat(this.backBufferTile.bounds.left,this.backBufferTile.bounds.top);var size=new OpenLayers.Size(this.backBufferTile.size.w*ratio,this.backBufferTile.size.h*ratio);var px=this.layer.map.getLayerPxFromLonLat(upperLeft);OpenLayers.Util.modifyDOMElement(this.backBufferTile.frame,null,px,size);var imageSize=this.backBufferTile.imageSize;imageSize=new OpenLayers.Size(imageSize.w*ratio,imageSize.h*ratio);var imageOffset=this.backBufferTile.imageOffset;if(imageOffset){imageOffset=new OpenLayers.Pixel(imageOffset.x*ratio,imageOffset.y*ratio);}
+OpenLayers.Util.modifyDOMElement(this.backBufferTile.imgDiv,null,imageOffset,imageSize);this.backBufferTile.show();}}else{if(this.layer.singleTile){this.backBufferTile.show();}else{this.backBufferTile.hide();}}
+this.lastRatio=ratio;},show:function(){this.frame.style.display='';if(OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS,this.layer.transitionEffect)!=-1){if(navigator.userAgent.toLowerCase().indexOf("gecko")!=-1){this.frame.scrollLeft=this.frame.scrollLeft;}}},hide:function(){this.frame.style.display='none';},CLASS_NAME:"OpenLayers.Tile.Image"});OpenLayers.Tile.Image.useBlankTile=(OpenLayers.Util.getBrowserName()=="safari"||OpenLayers.Util.getBrowserName()=="opera");OpenLayers.Control.OverviewMap=OpenLayers.Class(OpenLayers.Control,{element:null,ovmap:null,size:new OpenLayers.Size(180,90),layers:null,minRectSize:15,minRectDisplayClass:"RectReplacement",minRatio:8,maxRatio:32,mapOptions:null,handlers:null,initialize:function(options){this.layers=[];this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,[options]);},destroy:function(){if(!this.mapDiv){return;}
+this.handlers.click.destroy();this.mapDiv.removeChild(this.extentRectangle);this.extentRectangle=null;this.rectEvents.destroy();this.rectEvents=null;this.ovmap.destroy();this.ovmap=null;this.element.removeChild(this.mapDiv);this.mapDiv=null;this.div.removeChild(this.element);this.element=null;if(this.maximizeDiv){OpenLayers.Event.stopObservingElement(this.maximizeDiv);this.div.removeChild(this.maximizeDiv);this.maximizeDiv=null;}
+if(this.minimizeDiv){OpenLayers.Event.stopObservingElement(this.minimizeDiv);this.div.removeChild(this.minimizeDiv);this.minimizeDiv=null;}
+this.map.events.un({"moveend":this.update,"changebaselayer":this.baseLayerDraw,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!(this.layers.length>0)){if(this.map.baseLayer){var layer=this.map.baseLayer.clone();this.layers=[layer];}else{this.map.events.register("changebaselayer",this,this.baseLayerDraw);return this.div;}}
+this.element=document.createElement('div');this.element.className=this.displayClass+'Element';this.element.style.display='none';this.mapDiv=document.createElement('div');this.mapDiv.style.width=this.size.w+'px';this.mapDiv.style.height=this.size.h+'px';this.mapDiv.style.position='relative';this.mapDiv.style.overflow='hidden';this.mapDiv.id=OpenLayers.Util.createUniqueID('overviewMap');this.extentRectangle=document.createElement('div');this.extentRectangle.style.position='absolute';this.extentRectangle.style.zIndex=1000;this.extentRectangle.className=this.displayClass+'ExtentRectangle';this.mapDiv.appendChild(this.extentRectangle);this.element.appendChild(this.mapDiv);this.div.appendChild(this.element);if(!this.outsideViewport){this.div.className+=" "+this.displayClass+'Container';var imgLocation=OpenLayers.Util.getImagesLocation();var img=imgLocation+'layer-switcher-maximize.png';this.maximizeDiv=OpenLayers.Util.createAlphaImageDiv(this.displayClass+'MaximizeButton',null,new OpenLayers.Size(18,18),img,'absolute');this.maximizeDiv.style.display='none';this.maximizeDiv.className=this.displayClass+'MaximizeButton';OpenLayers.Event.observe(this.maximizeDiv,'click',OpenLayers.Function.bindAsEventListener(this.maximizeControl,this));this.div.appendChild(this.maximizeDiv);var img=imgLocation+'layer-switcher-minimize.png';this.minimizeDiv=OpenLayers.Util.createAlphaImageDiv('OpenLayers_Control_minimizeDiv',null,new OpenLayers.Size(18,18),img,'absolute');this.minimizeDiv.style.display='none';this.minimizeDiv.className=this.displayClass+'MinimizeButton';OpenLayers.Event.observe(this.minimizeDiv,'click',OpenLayers.Function.bindAsEventListener(this.minimizeControl,this));this.div.appendChild(this.minimizeDiv);var eventsToStop=['dblclick','mousedown'];for(var i=0;i<eventsToStop.length;i++){OpenLayers.Event.observe(this.maximizeDiv,eventsToStop[i],OpenLayers.Event.stop);OpenLayers.Event.observe(this.minimizeDiv,eventsToStop[i],OpenLayers.Event.stop);}
+this.minimizeControl();}else{this.element.style.display='';}
+if(this.map.getExtent()){this.update();}
+this.map.events.register('moveend',this,this.update);return this.div;},baseLayerDraw:function(){this.draw();this.map.events.unregister("changebaselayer",this,this.baseLayerDraw);},rectDrag:function(px){var deltaX=this.handlers.drag.last.x-px.x;var deltaY=this.handlers.drag.last.y-px.y;if(deltaX!=0||deltaY!=0){var rectTop=this.rectPxBounds.top;var rectLeft=this.rectPxBounds.left;var rectHeight=Math.abs(this.rectPxBounds.getHeight());var rectWidth=this.rectPxBounds.getWidth();var newTop=Math.max(0,(rectTop-deltaY));newTop=Math.min(newTop,this.ovmap.size.h-this.hComp-rectHeight);var newLeft=Math.max(0,(rectLeft-deltaX));newLeft=Math.min(newLeft,this.ovmap.size.w-this.wComp-rectWidth);this.setRectPxBounds(new OpenLayers.Bounds(newLeft,newTop+rectHeight,newLeft+rectWidth,newTop));}},mapDivClick:function(evt){var pxCenter=this.rectPxBounds.getCenterPixel();var deltaX=evt.xy.x-pxCenter.x;var deltaY=evt.xy.y-pxCenter.y;var top=this.rectPxBounds.top;var left=this.rectPxBounds.left;var height=Math.abs(this.rectPxBounds.getHeight());var width=this.rectPxBounds.getWidth();var newTop=Math.max(0,(top+deltaY));newTop=Math.min(newTop,this.ovmap.size.h-height);var newLeft=Math.max(0,(left+deltaX));newLeft=Math.min(newLeft,this.ovmap.size.w-width);this.setRectPxBounds(new OpenLayers.Bounds(newLeft,newTop+height,newLeft+width,newTop));this.updateMapToRect();},maximizeControl:function(e){this.element.style.display='';this.showToggle(false);if(e!=null){OpenLayers.Event.stop(e);}},minimizeControl:function(e){this.element.style.display='none';this.showToggle(true);if(e!=null){OpenLayers.Event.stop(e);}},showToggle:function(minimize){this.maximizeDiv.style.display=minimize?'':'none';this.minimizeDiv.style.display=minimize?'none':'';},update:function(){if(this.ovmap==null){this.createMap();}
+if(!this.isSuitableOverview()){this.updateOverview();}
+this.updateRectToMap();},isSuitableOverview:function(){var mapExtent=this.map.getExtent();var maxExtent=this.map.maxExtent;var testExtent=new OpenLayers.Bounds(Math.max(mapExtent.left,maxExtent.left),Math.max(mapExtent.bottom,maxExtent.bottom),Math.min(mapExtent.right,maxExtent.right),Math.min(mapExtent.top,maxExtent.top));var resRatio=this.ovmap.getResolution()/this.map.getResolution();return((resRatio>this.minRatio)&&(resRatio<=this.maxRatio)&&(this.ovmap.getExtent().containsBounds(testExtent)));},updateOverview:function(){var mapRes=this.map.getResolution();var targetRes=this.ovmap.getResolution();var resRatio=targetRes/mapRes;if(resRatio>this.maxRatio){targetRes=this.minRatio*mapRes;}else if(resRatio<=this.minRatio){targetRes=this.maxRatio*mapRes;}
+this.ovmap.setCenter(this.map.center,this.ovmap.getZoomForResolution(targetRes));this.updateRectToMap();},createMap:function(){var options=OpenLayers.Util.extend({controls:[],maxResolution:'auto',fallThrough:false},this.mapOptions);this.ovmap=new OpenLayers.Map(this.mapDiv,options);OpenLayers.Event.stopObserving(window,'unload',this.ovmap.unloadDestroy);this.ovmap.addLayers(this.layers);this.ovmap.zoomToMaxExtent();this.wComp=parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-left-width'))+
+parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-right-width'));this.wComp=(this.wComp)?this.wComp:2;this.hComp=parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-top-width'))+
+parseInt(OpenLayers.Element.getStyle(this.extentRectangle,'border-bottom-width'));this.hComp=(this.hComp)?this.hComp:2;this.handlers.drag=new OpenLayers.Handler.Drag(this,{move:this.rectDrag,done:this.updateMapToRect},{map:this.ovmap});this.handlers.click=new OpenLayers.Handler.Click(this,{"click":this.mapDivClick},{"single":true,"double":false,"stopSingle":true,"stopDouble":true,"pixelTolerance":1,map:this.ovmap});this.handlers.click.activate();this.rectEvents=new OpenLayers.Events(this,this.extentRectangle,null,true);this.rectEvents.register("mouseover",this,function(e){if(!this.handlers.drag.active&&!this.map.dragging){this.handlers.drag.activate();}});this.rectEvents.register("mouseout",this,function(e){if(!this.handlers.drag.dragging){this.handlers.drag.deactivate();}});},updateRectToMap:function(){if(this.map.units!='degrees'){if(this.ovmap.getProjection()&&(this.map.getProjection()!=this.ovmap.getProjection())){alert(OpenLayers.i18n("sameProjection"));}}
+var pxBounds=this.getRectBoundsFromMapBounds(this.map.getExtent());if(pxBounds){this.setRectPxBounds(pxBounds);}},updateMapToRect:function(){var lonLatBounds=this.getMapBoundsFromRectBounds(this.rectPxBounds);this.map.panTo(lonLatBounds.getCenterLonLat());},setRectPxBounds:function(pxBounds){var top=Math.max(pxBounds.top,0);var left=Math.max(pxBounds.left,0);var bottom=Math.min(pxBounds.top+Math.abs(pxBounds.getHeight()),this.ovmap.size.h-this.hComp);var right=Math.min(pxBounds.left+pxBounds.getWidth(),this.ovmap.size.w-this.wComp);var width=Math.max(right-left,0);var height=Math.max(bottom-top,0);if(width<this.minRectSize||height<this.minRectSize){this.extentRectangle.className=this.displayClass+
+this.minRectDisplayClass;var rLeft=left+(width/2)-(this.minRectSize/2);var rTop=top+(height/2)-(this.minRectSize/2);this.extentRectangle.style.top=Math.round(rTop)+'px';this.extentRectangle.style.left=Math.round(rLeft)+'px';this.extentRectangle.style.height=this.minRectSize+'px';this.extentRectangle.style.width=this.minRectSize+'px';}else{this.extentRectangle.className=this.displayClass+'ExtentRectangle';this.extentRectangle.style.top=Math.round(top)+'px';this.extentRectangle.style.left=Math.round(left)+'px';this.extentRectangle.style.height=Math.round(height)+'px';this.extentRectangle.style.width=Math.round(width)+'px';}
+this.rectPxBounds=new OpenLayers.Bounds(Math.round(left),Math.round(bottom),Math.round(right),Math.round(top));},getRectBoundsFromMapBounds:function(lonLatBounds){var leftBottomLonLat=new OpenLayers.LonLat(lonLatBounds.left,lonLatBounds.bottom);var rightTopLonLat=new OpenLayers.LonLat(lonLatBounds.right,lonLatBounds.top);var leftBottomPx=this.getOverviewPxFromLonLat(leftBottomLonLat);var rightTopPx=this.getOverviewPxFromLonLat(rightTopLonLat);var bounds=null;if(leftBottomPx&&rightTopPx){bounds=new OpenLayers.Bounds(leftBottomPx.x,leftBottomPx.y,rightTopPx.x,rightTopPx.y);}
+return bounds;},getMapBoundsFromRectBounds:function(pxBounds){var leftBottomPx=new OpenLayers.Pixel(pxBounds.left,pxBounds.bottom);var rightTopPx=new OpenLayers.Pixel(pxBounds.right,pxBounds.top);var leftBottomLonLat=this.getLonLatFromOverviewPx(leftBottomPx);var rightTopLonLat=this.getLonLatFromOverviewPx(rightTopPx);return new OpenLayers.Bounds(leftBottomLonLat.lon,leftBottomLonLat.lat,rightTopLonLat.lon,rightTopLonLat.lat);},getLonLatFromOverviewPx:function(overviewMapPx){var size=this.ovmap.size;var res=this.ovmap.getResolution();var center=this.ovmap.getExtent().getCenterLonLat();var delta_x=overviewMapPx.x-(size.w/2);var delta_y=overviewMapPx.y-(size.h/2);return new OpenLayers.LonLat(center.lon+delta_x*res,center.lat-delta_y*res);},getOverviewPxFromLonLat:function(lonlat){var res=this.ovmap.getResolution();var extent=this.ovmap.getExtent();var px=null;if(extent){px=new OpenLayers.Pixel(Math.round(1/res*(lonlat.lon-extent.left)),Math.round(1/res*(extent.top-lonlat.lat)));}
+return px;},CLASS_NAME:'OpenLayers.Control.OverviewMap'});OpenLayers.Handler.Click=OpenLayers.Class(OpenLayers.Handler,{delay:300,single:true,'double':false,pixelTolerance:0,stopSingle:false,stopDouble:false,timerId:null,down:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);if(this.pixelTolerance!=null){this.mousedown=function(evt){this.down=evt.xy;return true;};}},mousedown:null,dblclick:function(evt){if(this.passesTolerance(evt)){if(this["double"]){this.callback('dblclick',[evt]);}
+this.clearTimer();}
+return!this.stopDouble;},click:function(evt){if(this.passesTolerance(evt)){if(this.timerId!=null){this.clearTimer();}else{var clickEvent=this.single?OpenLayers.Util.extend({},evt):null;this.timerId=window.setTimeout(OpenLayers.Function.bind(this.delayedCall,this,clickEvent),this.delay);}}
+return!this.stopSingle;},passesTolerance:function(evt){var passes=true;if(this.pixelTolerance!=null&&this.down){var dpx=Math.sqrt(Math.pow(this.down.x-evt.xy.x,2)+
+Math.pow(this.down.y-evt.xy.y,2));if(dpx>this.pixelTolerance){passes=false;}}
+return passes;},clearTimer:function(){if(this.timerId!=null){window.clearTimeout(this.timerId);this.timerId=null;}},delayedCall:function(evt){this.timerId=null;if(evt){this.callback('click',[evt]);}},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.clearTimer();this.down=null;deactivated=true;}
+return deactivated;},CLASS_NAME:"OpenLayers.Handler.Click"});OpenLayers.Handler.Drag=OpenLayers.Class(OpenLayers.Handler,{started:false,stopDown:true,dragging:false,last:null,start:null,oldOnselectstart:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);},down:function(evt){},move:function(evt){},up:function(evt){},out:function(evt){},mousedown:function(evt){var propagate=true;this.dragging=false;if(this.checkModifiers(evt)&&OpenLayers.Event.isLeftClick(evt)){this.started=true;this.start=evt.xy;this.last=evt.xy;this.map.div.style.cursor="move";this.down(evt);this.callback("down",[evt.xy]);OpenLayers.Event.stop(evt);if(!this.oldOnselectstart){this.oldOnselectstart=(document.onselectstart)?document.onselectstart:function(){return true;};document.onselectstart=function(){return false;};}
+propagate=!this.stopDown;}else{this.started=false;this.start=null;this.last=null;}
+return propagate;},mousemove:function(evt){if(this.started){if(evt.xy.x!=this.last.x||evt.xy.y!=this.last.y){this.dragging=true;this.move(evt);this.callback("move",[evt.xy]);if(!this.oldOnselectstart){this.oldOnselectstart=document.onselectstart;document.onselectstart=function(){return false;};}
+this.last=evt.xy;}}
+return true;},mouseup:function(evt){if(this.started){var dragged=(this.start!=this.last);this.started=false;this.dragging=false;this.map.div.style.cursor="";this.up(evt);this.callback("up",[evt.xy]);if(dragged){this.callback("done",[evt.xy]);}
+document.onselectstart=this.oldOnselectstart;}
+return true;},mouseout:function(evt){if(this.started&&OpenLayers.Util.mouseLeft(evt,this.map.div)){var dragged=(this.start!=this.last);this.started=false;this.dragging=false;this.map.div.style.cursor="";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.started=false;this.dragging=false;this.start=null;this.last=null;deactivated=true;}
+return deactivated;},CLASS_NAME:"OpenLayers.Handler.Drag"});OpenLayers.Handler.MouseWheel=OpenLayers.Class(OpenLayers.Handler,{wheelListener:null,mousePosition:null,initialize:function(control,callbacks,options){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(e){if(!this.map||!this.checkModifiers(e)){return;}
+var overScrollableDiv=false;var overLayerDiv=false;var overMapDiv=false;var elem=OpenLayers.Event.element(e);while((elem!=null)&&!overMapDiv&&!overScrollableDiv){if(!overScrollableDiv){try{if(elem.currentStyle){overflow=elem.currentStyle["overflow"];}else{var style=document.defaultView.getComputedStyle(elem,null);var overflow=style.getPropertyValue("overflow");}
+overScrollableDiv=(overflow&&(overflow=="auto")||(overflow=="scroll"));}catch(err){}}
+if(!overLayerDiv){for(var i=0;i<this.map.layers.length;i++){if(elem==this.map.layers[i].div||elem==this.map.layers[i].pane){overLayerDiv=true;break;}}}
+overMapDiv=(elem==this.map.div);elem=elem.parentNode;}
+if(!overScrollableDiv&&overMapDiv){if(overLayerDiv){this.wheelZoom(e);}
+OpenLayers.Event.stop(e);}},wheelZoom:function(e){var delta=0;if(!e){e=window.event;}
+if(e.wheelDelta){delta=e.wheelDelta/120;if(window.opera&&window.opera.version()<9.2){delta=-delta;}}else if(e.detail){delta=-e.detail/3;}
+if(delta){if(this.mousePosition){e.xy=this.mousePosition;}
+if(!e.xy){e.xy=this.map.getPixelFromLonLat(this.map.getCenter());}
+if(delta<0){this.callback("down",[e,delta]);}else{this.callback("up",[e,delta]);}}},mousemove:function(evt){this.mousePosition=evt.xy;},activate:function(evt){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){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;}},deactivate:function(evt){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){var wheelListener=this.wheelListener;OpenLayers.Event.stopObserving(window,"DOMMouseScroll",wheelListener);OpenLayers.Event.stopObserving(window,"mousewheel",wheelListener);OpenLayers.Event.stopObserving(document,"mousewheel",wheelListener);return true;}else{return false;}},CLASS_NAME:"OpenLayers.Handler.MouseWheel"});OpenLayers.Layer=OpenLayers.Class({id:null,name:null,div:null,opacity:null,EVENT_TYPES:["loadstart","loadend","loadcancel","visibilitychanged"],events:null,map:null,isBaseLayer:false,alpha:false,displayInLayerSwitcher:true,visibility:true,attribution:null,inRange:false,imageSize:null,imageOffset: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:false,wrapDateLine:false,transitionEffect:null,SUPPORTED_TRANSITIONS:['resize'],initialize:function(name,options){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.events=new OpenLayers.Events(this,this.div,this.EVENT_TYPES);if(this.eventListeners instanceof Object){this.events.on(this.eventListeners);}}
+if(this.wrapDateLine){this.displayOutsideMaxExtent=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;},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer(this.name,this.options);}
+OpenLayers.Util.applyDefaults(obj,this);obj.map=null;return obj;},setName:function(newName){if(newName!=this.name){this.name=newName;if(this.map!=null){this.map.events.triggerEvent("changelayer",{layer:this,property:"name"});}}},addOptions:function(newOptions){if(this.options==null){this.options={};}
+OpenLayers.Util.extend(this.options,newOptions);OpenLayers.Util.extend(this,newOptions);},onMapResize:function(){},redraw:function(){var redrawn=false;if(this.map){this.inRange=this.calculateInRange();var extent=this.getExtent();if(extent&&this.inRange&&this.visibility){this.moveTo(extent,true,false);redrawn=true;}}
+return redrawn;},moveTo:function(bounds,zoomChanged,dragging){var display=this.visibility;if(!this.isBaseLayer){display=display&&this.inRange;}
+this.display(display);},setMap:function(map){if(this.map==null){this.map=map;this.maxExtent=this.maxExtent||this.map.maxExtent;this.projection=this.projection||this.map.projection;if(this.projection&&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();}},removeMap:function(map){},getImageSize:function(){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.imageOffset=new OpenLayers.Pixel(-this.gutter,-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){var inRange=this.calculateInRange();if(display!=(this.div.style.display!="none")){this.div.style.display=(display&&inRange)?"block":"none";}},calculateInRange:function(){var inRange=false;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 props=new Array('projection','units','scales','resolutions','maxScale','minScale','maxResolution','minResolution','minExtent','maxExtent','numZoomLevels','maxZoomLevel');var confProps={};for(var i=0;i<props.length;i++){var property=props[i];confProps[property]=this.options[property]||this.map[property];}
+if(this.options.minScale!=null&&this.options.maxScale!=null&&this.options.scales==null){confProps.scales=null;}
+if(this.options.minResolution!=null&&this.options.maxResolution!=null&&this.options.resolutions==null){confProps.resolutions=null;}
+if((!confProps.numZoomLevels)&&(confProps.maxZoomLevel)){confProps.numZoomLevels=confProps.maxZoomLevel+1;}
+if((confProps.scales!=null)||(confProps.resolutions!=null)){if(confProps.scales!=null){confProps.resolutions=[];for(var i=0;i<confProps.scales.length;i++){var scale=confProps.scales[i];confProps.resolutions[i]=OpenLayers.Util.getResolutionFromScale(scale,confProps.units);}}
+confProps.numZoomLevels=confProps.resolutions.length;}else{if(confProps.minScale){confProps.maxResolution=OpenLayers.Util.getResolutionFromScale(confProps.minScale,confProps.units);}else if(confProps.maxResolution=="auto"){var viewSize=this.map.getSize();var wRes=confProps.maxExtent.getWidth()/viewSize.w;var hRes=confProps.maxExtent.getHeight()/viewSize.h;confProps.maxResolution=Math.max(wRes,hRes);}
+if(confProps.maxScale!=null){confProps.minResolution=OpenLayers.Util.getResolutionFromScale(confProps.maxScale,confProps.units);}else if((confProps.minResolution=="auto")&&(confProps.minExtent!=null)){var viewSize=this.map.getSize();var wRes=confProps.minExtent.getWidth()/viewSize.w;var hRes=confProps.minExtent.getHeight()/viewSize.h;confProps.minResolution=Math.max(wRes,hRes);}
+if(confProps.minResolution!=null&&this.options.numZoomLevels==undefined){var ratio=confProps.maxResolution/confProps.minResolution;confProps.numZoomLevels=Math.floor(Math.log(ratio)/Math.log(2))+1;}
+confProps.resolutions=new Array(confProps.numZoomLevels);var base=2;if(typeof confProps.minResolution=="number"&&confProps.numZoomLevels>1){base=Math.pow((confProps.maxResolution/confProps.minResolution),(1/(confProps.numZoomLevels-1)));}
+for(var i=0;i<confProps.numZoomLevels;i++){var res=confProps.maxResolution/Math.pow(base,i);confProps.resolutions[i]=res;}}
+confProps.resolutions.sort(function(a,b){return(b-a);});this.resolutions=confProps.resolutions;this.maxResolution=confProps.resolutions[0];var lastIndex=confProps.resolutions.length-1;this.minResolution=confProps.resolutions[lastIndex];this.scales=[];for(var i=0;i<confProps.resolutions.length;i++){this.scales[i]=OpenLayers.Util.getScaleFromResolution(confProps.resolutions[i],confProps.units);}
+this.minScale=this.scales[0];this.maxScale=this.scales[this.scales.length-1];this.numZoomLevels=confProps.numZoomLevels;},getResolution:function(){var zoom=this.map.getZoom();return this.getResolutionForZoom(zoom);},getExtent:function(){return this.map.calculateBounds();},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);},getDataExtent:function(){},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[high]+
+((zoom-low)*(this.resolutions[low]-this.resolutions[high]));}else{resolution=this.resolutions[Math.round(zoom)];}
+return resolution;},getZoomForResolution:function(resolution,closest){var zoom;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(var i=0;i<this.resolutions.length;++i){res=this.resolutions[i];if(res>=resolution){highRes=res;lowZoom=i;}
+if(res<=resolution){lowRes=res;highZoom=i;break;}}
+var dRes=highRes-lowRes;if(dRes>0){zoom=lowZoom+((resolution-lowRes)/dRes);}else{zoom=lowZoom;}}else{var diff;var minDiff=Number.POSITIVE_INFINITY;for(var i=0;i<this.resolutions.length;i++){if(closest){diff=Math.abs(this.resolutions[i]-resolution);if(diff>minDiff){break;}
+minDiff=diff;}else{if(this.resolutions[i]<resolution){break;}}}
+zoom=Math.max(0,i-1);}
+return zoom;},getLonLatFromViewPortPx:function(viewPortPx){var lonlat=null;if(viewPortPx!=null){var size=this.map.getSize();var center=this.map.getCenter();if(center){var res=this.map.getResolution();var delta_x=viewPortPx.x-(size.w/2);var delta_y=viewPortPx.y-(size.h/2);lonlat=new OpenLayers.LonLat(center.lon+delta_x*res,center.lat-delta_y*res);if(this.wrapDateLine){lonlat=lonlat.wrapDateLine(this.maxExtent);}}}
+return lonlat;},getViewPortPxFromLonLat:function(lonlat){var px=null;if(lonlat!=null){var resolution=this.map.getResolution();var extent=this.map.getExtent();px=new OpenLayers.Pixel((1/resolution*(lonlat.lon-extent.left)),(1/resolution*(extent.top-lonlat.lat)));}
+return px;},setOpacity:function(opacity){if(opacity!=this.opacity){this.opacity=opacity;for(var i=0;i<this.div.childNodes.length;++i){var element=this.div.childNodes[i].firstChild;OpenLayers.Util.modifyDOMElement(element,null,null,null,null,null,null,opacity);}}},setZIndex:function(zIndex){this.div.style.zIndex=zIndex;},adjustBounds:function(bounds){if(this.gutter){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){var wrappingOptions={'rightTolerance':this.getResolution()};bounds=bounds.wrapDateLine(this.maxExtent,wrappingOptions);}
+return bounds;},CLASS_NAME:"OpenLayers.Layer"});OpenLayers.Marker.Box=OpenLayers.Class(OpenLayers.Marker,{bounds:null,div:null,initialize:function(bounds,borderColor,borderWidth){this.bounds=bounds;this.div=OpenLayers.Util.createDiv();this.div.style.overflow='hidden';this.events=new OpenLayers.Events(this,this.div,null);this.setBorder(borderColor,borderWidth);},destroy:function(){this.bounds=null;this.div=null;OpenLayers.Marker.prototype.destroy.apply(this,arguments);},setBorder:function(color,width){if(!color){color="red";}
+if(!width){width=2;}
+this.div.style.border=width+"px solid "+color;},draw:function(px,sz){OpenLayers.Util.modifyDOMElement(this.div,null,px,sz);return this.div;},onScreen:function(){var onScreen=false;if(this.map){var screenBounds=this.map.getExtent();onScreen=screenBounds.containsBounds(this.bounds,true,true);}
+return onScreen;},display:function(display){this.div.style.display=(display)?"":"none";},CLASS_NAME:"OpenLayers.Marker.Box"});OpenLayers.Control.DragPan=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:false,draw:function(){this.handler=new OpenLayers.Handler.Drag(this,{"move":this.panMap,"done":this.panMapDone});},panMap:function(xy){this.panned=true;this.map.pan(this.handler.last.x-xy.x,this.handler.last.y-xy.y,{dragging:this.handler.dragging,animate:false});},panMapDone:function(xy){if(this.panned){this.panMap(xy);this.panned=false;}},CLASS_NAME:"OpenLayers.Control.DragPan"});OpenLayers.Handler.Box=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,boxDivClassName:'olHandlerBoxZoomBox',initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);var callbacks={"down":this.startBox,"move":this.moveBox,"out":this.removeBox,"up":this.endBox};this.dragHandler=new OpenLayers.Handler.Drag(this,callbacks,{keyMask:this.keyMask});},setMap:function(map){OpenLayers.Handler.prototype.setMap.apply(this,arguments);if(this.dragHandler){this.dragHandler.setMap(map);}},startBox:function(xy){this.zoomBox=OpenLayers.Util.createDiv('zoomBox',this.dragHandler.start);this.zoomBox.className=this.boxDivClassName;this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE["Popup"]-1;this.map.viewPortDiv.appendChild(this.zoomBox);this.map.div.style.cursor="crosshair";},moveBox:function(xy){var deltaX=Math.abs(this.dragHandler.start.x-xy.x);var deltaY=Math.abs(this.dragHandler.start.y-xy.y);this.zoomBox.style.width=Math.max(1,deltaX)+"px";this.zoomBox.style.height=Math.max(1,deltaY)+"px";if(xy.x<this.dragHandler.start.x){this.zoomBox.style.left=xy.x+"px";}
+if(xy.y<this.dragHandler.start.y){this.zoomBox.style.top=xy.y+"px";}},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();}
+this.removeBox();this.map.div.style.cursor="";this.callback("done",[result]);},removeBox:function(){this.map.viewPortDiv.removeChild(this.zoomBox);this.zoomBox=null;},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();return true;}else{return false;}},CLASS_NAME:"OpenLayers.Handler.Box"});OpenLayers.Layer.HTTPRequest=OpenLayers.Class(OpenLayers.Layer,{URL_HASH_FACTOR:(Math.sqrt(5)-1)/2,url:null,params:null,reproject:false,initialize:function(name,url,params,options){var newArguments=arguments;newArguments=[name,options];OpenLayers.Layer.prototype.initialize.apply(this,newArguments);this.url=url;this.params=OpenLayers.Util.extend({},params);},destroy:function(){this.url=null;this.params=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.HTTPRequest(this.name,this.url,this.params,this.options);}
+obj=OpenLayers.Layer.prototype.clone.apply(this,[obj]);return obj;},setUrl:function(newUrl){this.url=newUrl;},mergeNewParams:function(newParams){this.params=OpenLayers.Util.extend(this.params,newParams);return this.redraw();},redraw:function(force){if(force){return this.mergeNewParams({"_olSalt":Math.random()});}else{return OpenLayers.Layer.prototype.redraw.apply(this,[]);}},selectUrl:function(paramString,urls){var product=1;for(var i=0;i<paramString.length;i++){product*=paramString.charCodeAt(i)*this.URL_HASH_FACTOR;product-=Math.floor(product);}
+return urls[Math.floor(product*urls.length)];},getFullRequestString:function(newParams,altUrl){var url=altUrl||this.url;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var paramsString=OpenLayers.Util.getParameterString(allParams);if(url instanceof Array){url=this.selectUrl(paramsString,url);}
+var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
+paramsString=OpenLayers.Util.getParameterString(allParams);var requestString=url;if(paramsString!=""){var lastServerChar=url.charAt(url.length-1);if((lastServerChar=="&")||(lastServerChar=="?")){requestString+=paramsString;}else{if(url.indexOf('?')==-1){requestString+='?'+paramsString;}else{requestString+='&'+paramsString;}}}
+return requestString;},CLASS_NAME:"OpenLayers.Layer.HTTPRequest"});OpenLayers.Control.ZoomBox=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,out:false,draw:function(){this.handler=new OpenLayers.Handler.Box(this,{done:this.zoomBox},{keyMask:this.keyMask});},zoomBox:function(position){if(position instanceof OpenLayers.Bounds){if(!this.out){var minXY=this.map.getLonLatFromPixel(new OpenLayers.Pixel(position.left,position.bottom));var maxXY=this.map.getLonLatFromPixel(new OpenLayers.Pixel(position.right,position.top));var 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;var bounds=new OpenLayers.Bounds(xmin,ymin,xmax,ymax);}
+this.map.zoomToExtent(bounds);}else{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.Layer.Grid=OpenLayers.Class(OpenLayers.Layer.HTTPRequest,{tileSize:null,grid:null,singleTile:false,ratio:1.5,buffer:2,numLoadingTiles:0,initialize:function(name,url,params,options){OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,arguments);this.events.addEventType("tileloaded");this.grid=[];},destroy:function(){this.clearGrid();this.grid=null;this.tileSize=null;OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this,arguments);},clearGrid:function(){if(this.grid){for(var iRow=0;iRow<this.grid.length;iRow++){var row=this.grid[iRow];for(var iCol=0;iCol<row.length;iCol++){var tile=row[iCol];this.removeTileMonitoringHooks(tile);tile.destroy();}}
+this.grid=[];}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.Grid(this.name,this.url,this.params,this.options);}
+obj=OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this,[obj]);if(this.tileSize!=null){obj.tileSize=this.tileSize.clone();}
+obj.grid=[];return obj;},moveTo:function(bounds,zoomChanged,dragging){OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this,arguments);bounds=bounds||this.map.getExtent();if(bounds!=null){var forceReTile=!this.grid.length||zoomChanged;var tilesBounds=this.getTilesBounds();if(this.singleTile){if(forceReTile||(!dragging&&!tilesBounds.containsBounds(bounds))){this.initSingleTile(bounds);}}else{if(forceReTile||!tilesBounds.containsBounds(bounds,true)){this.initGriddedTiles(bounds);}else{this.moveGriddedTiles(bounds);}}}},setTileSize:function(size){if(this.singleTile){size=this.map.getSize().clone();size.h=parseInt(size.h*this.ratio);size.w=parseInt(size.w*this.ratio);}
+OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this,[size]);},getGridBounds:function(){var msg="The getGridBounds() function is deprecated. It will be "+"removed in 3.0. Please use getTilesBounds() instead.";OpenLayers.Console.warn(msg);return this.getTilesBounds();},getTilesBounds:function(){var bounds=null;if(this.grid.length){var bottom=this.grid.length-1;var bottomLeftTile=this.grid[bottom][0];var right=this.grid[0].length-1;var topRightTile=this.grid[0][right];bounds=new OpenLayers.Bounds(bottomLeftTile.bounds.left,bottomLeftTile.bounds.bottom,topRightTile.bounds.right,topRightTile.bounds.top);}
+return bounds;},initSingleTile:function(bounds){var center=bounds.getCenterLonLat();var tileWidth=bounds.getWidth()*this.ratio;var tileHeight=bounds.getHeight()*this.ratio;var tileBounds=new OpenLayers.Bounds(center.lon-(tileWidth/2),center.lat-(tileHeight/2),center.lon+(tileWidth/2),center.lat+(tileHeight/2));var ul=new OpenLayers.LonLat(tileBounds.left,tileBounds.top);var px=this.map.getLayerPxFromLonLat(ul);if(!this.grid.length){this.grid[0]=[];}
+var tile=this.grid[0][0];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);tile.draw();this.grid[0][0]=tile;}else{tile.moveTo(tileBounds,px);}
+this.removeExcessTiles(1,1);},calculateGridLayout:function(bounds,extent,resolution){var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left-extent.left;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var tilecolremain=offsetlon/tilelon-tilecol;var tileoffsetx=-tilecolremain*this.tileSize.w;var tileoffsetlon=extent.left+tilecol*tilelon;var offsetlat=bounds.top-(extent.bottom+tilelat);var tilerow=Math.ceil(offsetlat/tilelat)+this.buffer;var tilerowremain=tilerow-offsetlat/tilelat;var tileoffsety=-tilerowremain*this.tileSize.h;var tileoffsetlat=extent.bottom+tilerow*tilelat;return{tilelon:tilelon,tilelat:tilelat,tileoffsetlon:tileoffsetlon,tileoffsetlat:tileoffsetlat,tileoffsetx:tileoffsetx,tileoffsety:tileoffsety};},initGriddedTiles:function(bounds){var viewSize=this.map.getSize();var minRows=Math.ceil(viewSize.h/this.tileSize.h)+
+Math.max(1,2*this.buffer);var minCols=Math.ceil(viewSize.w/this.tileSize.w)+
+Math.max(1,2*this.buffer);var extent=this.map.getMaxExtent();var resolution=this.map.getResolution();var tileLayout=this.calculateGridLayout(bounds,extent,resolution);var tileoffsetx=Math.round(tileLayout.tileoffsetx);var tileoffsety=Math.round(tileLayout.tileoffsety);var tileoffsetlon=tileLayout.tileoffsetlon;var tileoffsetlat=tileLayout.tileoffsetlat;var tilelon=tileLayout.tilelon;var tilelat=tileLayout.tilelat;this.origin=new OpenLayers.Pixel(tileoffsetx,tileoffsety);var startX=tileoffsetx;var startLon=tileoffsetlon;var rowidx=0;var layerContainerDivLeft=parseInt(this.map.layerContainerDiv.style.left);var layerContainerDivTop=parseInt(this.map.layerContainerDiv.style.top);do{var row=this.grid[rowidx++];if(!row){row=[];this.grid.push(row);}
+tileoffsetlon=startLon;tileoffsetx=startX;var colidx=0;do{var tileBounds=new OpenLayers.Bounds(tileoffsetlon,tileoffsetlat,tileoffsetlon+tilelon,tileoffsetlat+tilelat);var x=tileoffsetx;x-=layerContainerDivLeft;var y=tileoffsety;y-=layerContainerDivTop;var px=new OpenLayers.Pixel(x,y);var tile=row[colidx++];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);row.push(tile);}else{tile.moveTo(tileBounds,px,false);}
+tileoffsetlon+=tilelon;tileoffsetx+=this.tileSize.w;}while((tileoffsetlon<=bounds.right+tilelon*this.buffer)||colidx<minCols)
+tileoffsetlat-=tilelat;tileoffsety+=this.tileSize.h;}while((tileoffsetlat>=bounds.bottom-tilelat*this.buffer)||rowidx<minRows)
+this.removeExcessTiles(rowidx,colidx);this.spiralTileLoad();},spiralTileLoad:function(){var tileQueue=[];var directions=["right","down","left","up"];var iRow=0;var iCell=-1;var direction=OpenLayers.Util.indexOf(directions,"right");var directionsTried=0;while(directionsTried<directions.length){var testRow=iRow;var testCell=iCell;switch(directions[direction]){case"right":testCell++;break;case"down":testRow++;break;case"left":testCell--;break;case"up":testRow--;break;}
+var tile=null;if((testRow<this.grid.length)&&(testRow>=0)&&(testCell<this.grid[0].length)&&(testCell>=0)){tile=this.grid[testRow][testCell];}
+if((tile!=null)&&(!tile.queued)){tileQueue.unshift(tile);tile.queued=true;directionsTried=0;iRow=testRow;iCell=testCell;}else{direction=(direction+1)%4;directionsTried++;}}
+for(var i=0;i<tileQueue.length;i++){var tile=tileQueue[i];tile.draw();tile.queued=false;}},addTile:function(bounds,position){},addTileMonitoringHooks:function(tile){tile.onLoadStart=function(){if(this.numLoadingTiles==0){this.events.triggerEvent("loadstart");}
+this.numLoadingTiles++;};tile.events.register("loadstart",this,tile.onLoadStart);tile.onLoadEnd=function(){this.numLoadingTiles--;this.events.triggerEvent("tileloaded");if(this.numLoadingTiles==0){this.events.triggerEvent("loadend");}};tile.events.register("loadend",this,tile.onLoadEnd);tile.events.register("unload",this,tile.onLoadEnd);},removeTileMonitoringHooks:function(tile){tile.unload();tile.events.un({"loadstart":tile.onLoadStart,"loadend":tile.onLoadEnd,"unload":tile.onLoadEnd,scope:this});},moveGriddedTiles:function(bounds){var buffer=this.buffer||1;while(true){var tlLayer=this.grid[0][0].position;var tlViewPort=this.map.getViewPortPxFromLayerPx(tlLayer);if(tlViewPort.x>-this.tileSize.w*(buffer-1)){this.shiftColumn(true);}else if(tlViewPort.x<-this.tileSize.w*buffer){this.shiftColumn(false);}else if(tlViewPort.y>-this.tileSize.h*(buffer-1)){this.shiftRow(true);}else if(tlViewPort.y<-this.tileSize.h*buffer){this.shiftRow(false);}else{break;}};},shiftRow:function(prepend){var modelRowIndex=(prepend)?0:(this.grid.length-1);var grid=this.grid;var modelRow=grid[modelRowIndex];var resolution=this.map.getResolution();var deltaY=(prepend)?-this.tileSize.h:this.tileSize.h;var deltaLat=resolution*-deltaY;var row=(prepend)?grid.pop():grid.shift();for(var i=0;i<modelRow.length;i++){var modelTile=modelRow[i];var bounds=modelTile.bounds.clone();var position=modelTile.position.clone();bounds.bottom=bounds.bottom+deltaLat;bounds.top=bounds.top+deltaLat;position.y=position.y+deltaY;row[i].moveTo(bounds,position);}
+if(prepend){grid.unshift(row);}else{grid.push(row);}},shiftColumn:function(prepend){var deltaX=(prepend)?-this.tileSize.w:this.tileSize.w;var resolution=this.map.getResolution();var deltaLon=resolution*deltaX;for(var i=0;i<this.grid.length;i++){var row=this.grid[i];var modelTileIndex=(prepend)?0:(row.length-1);var modelTile=row[modelTileIndex];var bounds=modelTile.bounds.clone();var position=modelTile.position.clone();bounds.left=bounds.left+deltaLon;bounds.right=bounds.right+deltaLon;position.x=position.x+deltaX;var tile=prepend?this.grid[i].pop():this.grid[i].shift();tile.moveTo(bounds,position);if(prepend){row.unshift(tile);}else{row.push(tile);}}},removeExcessTiles:function(rows,columns){while(this.grid.length>rows){var row=this.grid.pop();for(var i=0,l=row.length;i<l;i++){var tile=row[i];this.removeTileMonitoringHooks(tile);tile.destroy();}}
+while(this.grid[0].length>columns){for(var i=0,l=this.grid.length;i<l;i++){var row=this.grid[i];var tile=row.pop();this.removeTileMonitoringHooks(tile);tile.destroy();}}},onMapResize:function(){if(this.singleTile){this.clearGrid();this.setTileSize();}},getTileBounds:function(viewPortPx){var maxExtent=this.map.getMaxExtent();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.Control.Navigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,zoomBox:null,zoomWheelEnabled:true,initialize:function(options){this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){this.deactivate();if(this.dragPan){this.dragPan.destroy();}
+this.dragPan=null;if(this.zoomBox){this.zoomBox.destroy();}
+this.zoomBox=null;OpenLayers.Control.prototype.destroy.apply(this,arguments);},activate:function(){this.dragPan.activate();if(this.zoomWheelEnabled){this.handlers.wheel.activate();}
+this.handlers.click.activate();this.zoomBox.activate();return OpenLayers.Control.prototype.activate.apply(this,arguments);},deactivate:function(){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.handlers.click=new OpenLayers.Handler.Click(this,{'dblclick':this.defaultDblClick},{'double':true,'stopDouble':true});this.dragPan=new OpenLayers.Control.DragPan({map:this.map});this.zoomBox=new OpenLayers.Control.ZoomBox({map:this.map,keyMask:OpenLayers.Handler.MOD_SHIFT});this.dragPan.draw();this.zoomBox.draw();this.handlers.wheel=new OpenLayers.Handler.MouseWheel(this,{"up":this.wheelUp,"down":this.wheelDown});this.activate();},defaultDblClick:function(evt){var newCenter=this.map.getLonLatFromViewPortPx(evt.xy);this.map.setCenter(newCenter,this.map.zoom+1);},wheelChange:function(evt,deltaZ){var newZoom=this.map.getZoom()+deltaZ;if(!this.map.isValidZoomLevel(newZoom)){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);},wheelUp:function(evt){this.wheelChange(evt,1);},wheelDown:function(evt){this.wheelChange(evt,-1);},disableZoomWheel:function(){this.zoomWheelEnabled=false;this.handlers.wheel.deactivate();},enableZoomWheel:function(){this.zoomWheelEnabled=true;if(this.active){this.handlers.wheel.activate();}},CLASS_NAME:"OpenLayers.Control.Navigation"});OpenLayers.Layer.MapGuide=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:true,singleTile:false,TILE_PARAMS:{operation:'GETTILEIMAGE',version:'1.2.0'},SINGLE_TILE_PARAMS:{operation:'GETMAPIMAGE',format:'PNG',locale:'en',clip:'1',version:'1.0.0'},defaultSize:new OpenLayers.Size(300,300),initialize:function(name,url,params,options){OpenLayers.Layer.Grid.prototype.initialize.apply(this,arguments);if(options==null||options.isBaseLayer==null){this.isBaseLayer=((this.transparent!="true")&&(this.transparent!=true));}
+if(this.singleTile){OpenLayers.Util.applyDefaults(this.params,this.SINGLE_TILE_PARAMS);}else{OpenLayers.Util.applyDefaults(this.params,this.TILE_PARAMS);this.setTileSize(this.defaultSize);}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.MapGuide(this.name,this.url,this.params,this.options);}
+obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},getURL:function(bounds){var url;var center=bounds.getCenterLonLat();var mapSize=this.map.getCurrentSize();if(this.singleTile){var params={};params.setdisplaydpi=OpenLayers.DOTS_PER_INCH;params.setdisplayheight=mapSize.h*this.ratio;params.setdisplaywidth=mapSize.w*this.ratio;params.setviewcenterx=center.lon;params.setviewcentery=center.lat;params.setviewscale=this.map.getScale();if(!this.isBaseLayer){this.params.operation="GETDYNAMICMAPOVERLAYIMAGE";var getVisParams={};getVisParams.operation="GETVISIBLEMAPEXTENT";getVisParams.version="1.0.0";getVisParams.session=this.params.session;getVisParams.mapName=this.params.mapName;getVisParams.format='text/xml';getVisParams=OpenLayers.Util.extend(getVisParams,params);new OpenLayers.Ajax.Request(this.url,{parameters:getVisParams,method:'get',asynchronous:false});}
+url=this.getFullRequestString(params);}else{var currentRes=this.map.getResolution();var colidx=Math.floor((bounds.left-this.maxExtent.left)/currentRes);colidx=Math.round(colidx/this.tileSize.w);var rowidx=Math.floor((this.maxExtent.top-bounds.top)/currentRes);rowidx=Math.round(rowidx/this.tileSize.h);url=this.getFullRequestString({tilecol:colidx,tilerow:rowidx,scaleindex:this.resolutions.length-this.map.zoom-1});}
+return url;},getFullRequestString:function(newParams,altUrl){var url=(altUrl==null)?this.url:altUrl;if(typeof url=="object"){url=url[Math.floor(Math.random()*url.length)];}
+var requestString=url;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getArgs(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
+var paramsString=OpenLayers.Util.getParameterString(allParams);paramsString=paramsString.replace(/,/g,"+");if(paramsString!=""){var lastServerChar=url.charAt(url.length-1);if((lastServerChar=="&")||(lastServerChar=="?")){requestString+=paramsString;}else{if(url.indexOf('?')==-1){requestString+='?'+paramsString;}else{requestString+='&'+paramsString;}}}
+return requestString;},calculateGridLayout:function(bounds,extent,resolution){var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left-extent.left;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var tilecolremain=offsetlon/tilelon-tilecol;var tileoffsetx=-tilecolremain*this.tileSize.w;var tileoffsetlon=extent.left+tilecol*tilelon;var offsetlat=extent.top-bounds.top+tilelat;var tilerow=Math.floor(offsetlat/tilelat)-this.buffer;var tilerowremain=tilerow-offsetlat/tilelat;var tileoffsety=tilerowremain*this.tileSize.h;var tileoffsetlat=extent.top-tilelat*tilerow;return{tilelon:tilelon,tilelat:tilelat,tileoffsetlon:tileoffsetlon,tileoffsetlat:tileoffsetlat,tileoffsetx:tileoffsetx,tileoffsety:tileoffsety};},CLASS_NAME:"OpenLayers.Layer.MapGuide"});OpenLayers.Layer.MapServer=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{mode:"map",map_imagetype:"png"},initialize:function(name,url,params,options){var newArguments=[];newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);if(arguments.length>0){OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS);}
+if(options==null||options.isBaseLayer==null){this.isBaseLayer=((this.params.transparent!="true")&&(this.params.transparent!=true));}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.MapServer(this.name,this.url,this.params,this.options);}
+obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},getURL:function(bounds){bounds=this.adjustBounds(bounds);var extent=[bounds.left,bounds.bottom,bounds.right,bounds.top];var imageSize=this.getImageSize();var url=this.getFullRequestString({mapext:extent,imgext:extent,map_size:[imageSize.w,imageSize.h],imgx:imageSize.w/2,imgy:imageSize.h/2,imgxy:[imageSize.w,imageSize.h]});return url;},getFullRequestString:function(newParams,altUrl){var url=(altUrl==null)?this.url:altUrl;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var paramsString=OpenLayers.Util.getParameterString(allParams);if(url instanceof Array){url=this.selectUrl(paramsString,url);}
+var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
+paramsString=OpenLayers.Util.getParameterString(allParams);var requestString=url;paramsString=paramsString.replace(/,/g,"+");if(paramsString!=""){var lastServerChar=url.charAt(url.length-1);if((lastServerChar=="&")||(lastServerChar=="?")){requestString+=paramsString;}else{if(url.indexOf('?')==-1){requestString+='?'+paramsString;}else{requestString+='&'+paramsString;}}}
+return requestString;},CLASS_NAME:"OpenLayers.Layer.MapServer"});OpenLayers.Layer.WMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{service:"WMS",version:"1.1.1",request:"GetMap",styles:"",exceptions:"application/vnd.ogc.se_inimage",format:"image/jpeg"},reproject:false,isBaseLayer:true,encodeBBOX:false,initialize:function(name,url,params,options){var newArguments=[];params=OpenLayers.Util.upperCaseObject(params);newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS));if(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";}}},destroy:function(){OpenLayers.Layer.Grid.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.options);}
+obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},getURL:function(bounds){bounds=this.adjustBounds(bounds);var imageSize=this.getImageSize();var newParams={'BBOX':this.encodeBBOX?bounds.toBBOX():bounds.toArray(),'WIDTH':imageSize.w,'HEIGHT':imageSize.h};var requestString=this.getFullRequestString(newParams);return requestString;},addTile:function(bounds,position){return new OpenLayers.Tile.Image(this,position,bounds,null,this.tileSize);},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 projectionCode=this.map.getProjection();this.params.SRS=(projectionCode=="none")?null:projectionCode;return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments);},CLASS_NAME:"OpenLayers.Layer.WMS"});
\ No newline at end of file
Copied: sandbox/aboudreault/lib/OpenLayers/OpenLayersUncompressed.js (from rev 1412, trunk/lib/OpenLayers/OpenLayersUncompressed.js)
===================================================================
--- sandbox/aboudreault/lib/OpenLayers/OpenLayersUncompressed.js (rev 0)
+++ sandbox/aboudreault/lib/OpenLayers/OpenLayersUncompressed.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -0,0 +1,15655 @@
+/*
+
+ OpenLayers.js -- OpenLayers Map Viewer Library
+
+ Copyright 2005-2008 MetaCarta, Inc., released under the Clear BSD 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: <http://openlayers.org/>)
+
+*/
+
+/* Contains portions of Prototype.js:
+ *
+ * Prototype JavaScript framework, version 1.4.0
+ * (c) 2005 Sam Stephenson <sam at conio.net>
+ *
+ * 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 <http://openrico.org/>
+*
+* Copyright 2005 Sabre Airline Solutions
+*
+* Licensed under the Apache License, Version 2.0 (the "License"); you
+* may not use this file except in compliance with the License. You
+* may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* permissions and limitations under the License.
+*
+**/
+
+/* ======================================================================
+ OpenLayers/SingleFile.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+var OpenLayers = {
+ singleFile: true
+};
+
+
+/* ======================================================================
+ OpenLayers.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/*
+ * @requires OpenLayers/BaseTypes.js
+ * @requires OpenLayers/Lang/en.js
+ */
+
+(function() {
+ /**
+ * Before creating the OpenLayers namespace, check to see if
+ * OpenLayers.singleFile is true. This occurs if the
+ * OpenLayers/SingleFile.js script is included before this one - as is the
+ * case with single file builds.
+ */
+ var singleFile = (typeof OpenLayers == "object" && OpenLayers.singleFile);
+
+ /**
+ * Namespace: OpenLayers
+ * The OpenLayers object provides a namespace for all things OpenLayers
+ */
+ window.OpenLayers = {
+
+ /**
+ * Property: _scriptName
+ * {String} Relative path of this script.
+ */
+ _scriptName: (!singleFile) ? "lib/OpenLayers.js" : "OpenLayers.js",
+
+ /**
+ * Function: _getScriptLocation
+ * Return the path to this script.
+ *
+ * Returns:
+ * {String} Path to this script
+ */
+ _getScriptLocation: function () {
+ var scriptLocation = "";
+ var scriptName = OpenLayers._scriptName;
+
+ var scripts = document.getElementsByTagName('script');
+ for (var i = 0; i < scripts.length; i++) {
+ var src = scripts[i].getAttribute('src');
+ if (src) {
+ var index = src.lastIndexOf(scriptName);
+ // set path length for src up to a query string
+ var pathLength = src.lastIndexOf('?');
+ if (pathLength < 0) {
+ pathLength = src.length;
+ }
+ // is it found, at the end of the URL?
+ if ((index > -1) && (index + scriptName.length == pathLength)) {
+ scriptLocation = src.slice(0, pathLength - scriptName.length);
+ break;
+ }
+ }
+ }
+ return scriptLocation;
+ }
+ };
+ /**
+ * OpenLayers.singleFile is a flag indicating this file is being included
+ * in a Single File Library build of the OpenLayers Library.
+ *
+ * When we are *not* part of a SFL build we dynamically include the
+ * OpenLayers library code.
+ *
+ * When we *are* part of a SFL build we do not dynamically include the
+ * OpenLayers library code as it will be appended at the end of this file.
+ */
+ if(!singleFile) {
+ var jsfiles = new Array(
+ "OpenLayers/Util.js",
+ "OpenLayers/BaseTypes.js",
+ "OpenLayers/BaseTypes/Class.js",
+ "OpenLayers/BaseTypes/Bounds.js",
+ "OpenLayers/BaseTypes/Element.js",
+ "OpenLayers/BaseTypes/LonLat.js",
+ "OpenLayers/BaseTypes/Pixel.js",
+ "OpenLayers/BaseTypes/Size.js",
+ "OpenLayers/Console.js",
+ "OpenLayers/Tween.js",
+ "Rico/Corner.js",
+ "Rico/Color.js",
+ "OpenLayers/Ajax.js",
+ "OpenLayers/Events.js",
+ "OpenLayers/Projection.js",
+ "OpenLayers/Map.js",
+ "OpenLayers/Layer.js",
+ "OpenLayers/Icon.js",
+ "OpenLayers/Marker.js",
+ "OpenLayers/Marker/Box.js",
+ "OpenLayers/Popup.js",
+ "OpenLayers/Tile.js",
+ "OpenLayers/Tile/Image.js",
+ "OpenLayers/Tile/WFS.js",
+ "OpenLayers/Layer/Image.js",
+ "OpenLayers/Layer/SphericalMercator.js",
+ "OpenLayers/Layer/EventPane.js",
+ "OpenLayers/Layer/FixedZoomLevels.js",
+ "OpenLayers/Layer/Google.js",
+ "OpenLayers/Layer/VirtualEarth.js",
+ "OpenLayers/Layer/Yahoo.js",
+ "OpenLayers/Layer/HTTPRequest.js",
+ "OpenLayers/Layer/Grid.js",
+ "OpenLayers/Layer/MapGuide.js",
+ "OpenLayers/Layer/MapServer.js",
+ "OpenLayers/Layer/MapServer/Untiled.js",
+ "OpenLayers/Layer/KaMap.js",
+ "OpenLayers/Layer/MultiMap.js",
+ "OpenLayers/Layer/Markers.js",
+ "OpenLayers/Layer/Text.js",
+ "OpenLayers/Layer/WorldWind.js",
+ "OpenLayers/Layer/WMS.js",
+ "OpenLayers/Layer/WMS/Untiled.js",
+ "OpenLayers/Layer/GeoRSS.js",
+ "OpenLayers/Layer/Boxes.js",
+ "OpenLayers/Layer/TMS.js",
+ "OpenLayers/Layer/TileCache.js",
+ "OpenLayers/Popup/Anchored.js",
+ "OpenLayers/Popup/AnchoredBubble.js",
+ "OpenLayers/Popup/Framed.js",
+ "OpenLayers/Popup/FramedCloud.js",
+ "OpenLayers/Feature.js",
+ "OpenLayers/Feature/Vector.js",
+ "OpenLayers/Feature/WFS.js",
+ "OpenLayers/Handler.js",
+ "OpenLayers/Handler/Click.js",
+ "OpenLayers/Handler/Hover.js",
+ "OpenLayers/Handler/Point.js",
+ "OpenLayers/Handler/Path.js",
+ "OpenLayers/Handler/Polygon.js",
+ "OpenLayers/Handler/Feature.js",
+ "OpenLayers/Handler/Drag.js",
+ "OpenLayers/Handler/RegularPolygon.js",
+ "OpenLayers/Handler/Box.js",
+ "OpenLayers/Handler/MouseWheel.js",
+ "OpenLayers/Handler/Keyboard.js",
+ "OpenLayers/Control.js",
+ "OpenLayers/Control/Attribution.js",
+ "OpenLayers/Control/Button.js",
+ "OpenLayers/Control/ZoomBox.js",
+ "OpenLayers/Control/ZoomToMaxExtent.js",
+ "OpenLayers/Control/DragPan.js",
+ "OpenLayers/Control/Navigation.js",
+ "OpenLayers/Control/MouseDefaults.js",
+ "OpenLayers/Control/MousePosition.js",
+ "OpenLayers/Control/OverviewMap.js",
+ "OpenLayers/Control/KeyboardDefaults.js",
+ "OpenLayers/Control/PanZoom.js",
+ "OpenLayers/Control/PanZoomBar.js",
+ "OpenLayers/Control/ArgParser.js",
+ "OpenLayers/Control/Permalink.js",
+ "OpenLayers/Control/Scale.js",
+ "OpenLayers/Control/ScaleLine.js",
+ "OpenLayers/Control/LayerSwitcher.js",
+ "OpenLayers/Control/DrawFeature.js",
+ "OpenLayers/Control/DragFeature.js",
+ "OpenLayers/Control/ModifyFeature.js",
+ "OpenLayers/Control/Panel.js",
+ "OpenLayers/Control/SelectFeature.js",
+ "OpenLayers/Control/NavigationHistory.js",
+ "OpenLayers/Geometry.js",
+ "OpenLayers/Geometry/Rectangle.js",
+ "OpenLayers/Geometry/Collection.js",
+ "OpenLayers/Geometry/Point.js",
+ "OpenLayers/Geometry/MultiPoint.js",
+ "OpenLayers/Geometry/Curve.js",
+ "OpenLayers/Geometry/LineString.js",
+ "OpenLayers/Geometry/LinearRing.js",
+ "OpenLayers/Geometry/Polygon.js",
+ "OpenLayers/Geometry/MultiLineString.js",
+ "OpenLayers/Geometry/MultiPolygon.js",
+ "OpenLayers/Geometry/Surface.js",
+ "OpenLayers/Renderer.js",
+ "OpenLayers/Renderer/Elements.js",
+ "OpenLayers/Renderer/SVG.js",
+ "OpenLayers/Renderer/VML.js",
+ "OpenLayers/Layer/Vector.js",
+ "OpenLayers/Layer/PointTrack.js",
+ "OpenLayers/Layer/GML.js",
+ "OpenLayers/Style.js",
+ "OpenLayers/StyleMap.js",
+ "OpenLayers/Rule.js",
+ "OpenLayers/Filter.js",
+ "OpenLayers/Filter/FeatureId.js",
+ "OpenLayers/Filter/Logical.js",
+ "OpenLayers/Filter/Comparison.js",
+ "OpenLayers/Format.js",
+ "OpenLayers/Format/XML.js",
+ "OpenLayers/Format/GML.js",
+ "OpenLayers/Format/KML.js",
+ "OpenLayers/Format/GeoRSS.js",
+ "OpenLayers/Format/WFS.js",
+ "OpenLayers/Format/WKT.js",
+ "OpenLayers/Format/OSM.js",
+ "OpenLayers/Format/SLD.js",
+ "OpenLayers/Format/SLD/v1.js",
+ "OpenLayers/Format/SLD/v1_0_0.js",
+ "OpenLayers/Format/Text.js",
+ "OpenLayers/Format/JSON.js",
+ "OpenLayers/Format/GeoJSON.js",
+ "OpenLayers/Format/WMC.js",
+ "OpenLayers/Format/WMC/v1.js",
+ "OpenLayers/Format/WMC/v1_0_0.js",
+ "OpenLayers/Format/WMC/v1_1_0.js",
+ "OpenLayers/Layer/WFS.js",
+ "OpenLayers/Control/MouseToolbar.js",
+ "OpenLayers/Control/NavToolbar.js",
+ "OpenLayers/Control/EditingToolbar.js",
+ "OpenLayers/Lang.js",
+ "OpenLayers/Lang/en.js"
+ ); // etc.
+
+ var agent = navigator.userAgent;
+ var docWrite = (agent.match("MSIE") || agent.match("Safari"));
+ if(docWrite) {
+ var allScriptTags = new Array(jsfiles.length);
+ }
+ var host = OpenLayers._getScriptLocation() + "lib/";
+ for (var i = 0; i < jsfiles.length; i++) {
+ if (docWrite) {
+ allScriptTags[i] = "<script src='" + host + jsfiles[i] +
+ "'></script>";
+ } else {
+ var s = document.createElement("script");
+ s.src = host + jsfiles[i];
+ var h = document.getElementsByTagName("head").length ?
+ document.getElementsByTagName("head")[0] :
+ document.body;
+ h.appendChild(s);
+ }
+ }
+ if (docWrite) {
+ document.write(allScriptTags.join(""));
+ }
+ }
+})();
+
+/**
+ * Constant: VERSION_NUMBER
+ */
+OpenLayers.VERSION_NUMBER="$Revision: 6818 $";
+/* ======================================================================
+ OpenLayers/BaseTypes.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @requires OpenLayers/BaseTypes/LonLat.js
+ * @requires OpenLayers/BaseTypes/Size.js
+ * @requires OpenLayers/BaseTypes/Pixel.js
+ * @requires OpenLayers/BaseTypes/Bounds.js
+ * @requires OpenLayers/BaseTypes/Element.js
+ * @requires OpenLayers/Lang/en.js
+ */
+
+/**
+ * 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 - {Sring} 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*$/, "$1");
+ },
+
+ /**
+ * 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; i < oStringList.length; i++) {
+ var s = oStringList[i];
+ camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
+ }
+ return camelizedString;
+ },
+
+ /**
+ * APIFunction: format
+ * Given a string with tokens in the form ${token}, return a string
+ * with tokens replaced with properties from the given context
+ * object. Represent a literal "${" by doubling it, e.g. "${${".
+ *
+ * Parameters:
+ * template - {String} A string with tokens to be replaced. A template
+ * has the form "literal ${token}" where the token will be replaced
+ * by the value of context["token"].
+ * context - {Object} An optional object with properties corresponding
+ * to the tokens in the format string. If no context is sent, the
+ * window object will be used.
+ * args - {Array} Optional arguments to pass to any functions found in
+ * the context. If a context property is a function, the token
+ * will be replaced by the return from the function called with
+ * these arguments.
+ *
+ * Returns:
+ * {String} A string with tokens replaced from the context object.
+ */
+ format: function(template, context, args) {
+ if(!context) {
+ context = window;
+ }
+ var tokens = template.split("${");
+ var item, last, replacement;
+ for(var i=1; i<tokens.length; i++) {
+ item = tokens[i];
+ last = item.indexOf("}");
+ if(last > 0) {
+ replacement = context[item.substring(0, last)];
+ if(typeof replacement == "function") {
+ replacement = args ?
+ replacement.apply(null, args) :
+ replacement();
+ }
+ tokens[i] = replacement + item.substring(++last);
+ } else {
+ tokens[i] = "${" + item;
+ }
+ }
+ return tokens.join("");
+ }
+
+};
+
+if (!String.prototype.startsWith) {
+ /**
+ * APIMethod: String.startsWith
+ * *Deprecated*. Whether or not a string starts with another string.
+ *
+ * Parameters:
+ * sStart - {Sring} The string we're testing for.
+ *
+ * Returns:
+ * {Boolean} Whether or not this string starts with the string passed in.
+ */
+ String.prototype.startsWith = function(sStart) {
+ OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+ {'newMethod':'OpenLayers.String.startsWith'}));
+ return OpenLayers.String.startsWith(this, sStart);
+ };
+}
+
+if (!String.prototype.contains) {
+ /**
+ * APIMethod: String.contains
+ * *Deprecated*. Whether or not a string contains another string.
+ *
+ * Parameters:
+ * str - {String} The string that we're testing for.
+ *
+ * Returns:
+ * {Boolean} Whether or not this string contains with the string passed in.
+ */
+ String.prototype.contains = function(str) {
+ OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+ {'newMethod':'OpenLayers.String.contains'}));
+ return OpenLayers.String.contains(this, str);
+ };
+}
+
+if (!String.prototype.trim) {
+ /**
+ * APIMethod: String.trim
+ * *Deprecated*. Removes leading and trailing whitespace characters from a string.
+ *
+ * Returns:
+ * {String} A trimmed version of the string - all leading and
+ * trailing spaces removed
+ */
+ String.prototype.trim = function() {
+ OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+ {'newMethod':'OpenLayers.String.trim'}));
+ return OpenLayers.String.trim(this);
+ };
+}
+
+if (!String.prototype.camelize) {
+ /**
+ * APIMethod: String.camelize
+ * *Deprecated*. Camel-case a hyphenated string.
+ * Ex. "chicken-head" becomes "chickenHead", and
+ * "-chicken-head" becomes "ChickenHead".
+ *
+ * Returns:
+ * {String} The string, camelized
+ */
+ String.prototype.camelize = function() {
+ OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+ {'newMethod':'OpenLayers.String.camelize'}));
+ return OpenLayers.String.camelize(this);
+ };
+}
+
+/**
+ * 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;
+ }
+};
+
+if (!Number.prototype.limitSigDigs) {
+ /**
+ * APIMethod: Number.limitSigDigs
+ * *Deprecated*. Limit the number of significant digits on an integer. Does *not*
+ * work with floats!
+ *
+ * Parameters:
+ * sig - {Integer}
+ *
+ * Returns:
+ * {Integer} The number, rounded to the specified number of significant digits.
+ * If null, 0, or negative value passed in, returns 0
+ */
+ Number.prototype.limitSigDigs = function(sig) {
+ OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+ {'newMethod':'OpenLayers.String.limitSigDigs'}));
+ return OpenLayers.Number.limitSigDigs(this, sig);
+ };
+}
+
+/**
+ * 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);
+ };
+ }
+};
+
+if (!Function.prototype.bind) {
+ /**
+ * APIMethod: Function.bind
+ * *Deprecated*. Bind a function to an object.
+ * Method to easily create closures with 'this' altered.
+ *
+ * Parameters:
+ * object - {Object} the this parameter
+ *
+ * Returns:
+ * {Function} A closure with 'this' altered to the first
+ * argument.
+ */
+ Function.prototype.bind = function() {
+ OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+ {'newMethod':'OpenLayers.String.bind'}));
+ // new function takes the same arguments with this function up front
+ Array.prototype.unshift.apply(arguments, [this]);
+ return OpenLayers.Function.bind.apply(null, arguments);
+ };
+}
+
+if (!Function.prototype.bindAsEventListener) {
+ /**
+ * APIMethod: Function.bindAsEventListener
+ * *Deprecated*. Bind a function to an object, and configure it to receive the
+ * event object as first parameter when called.
+ *
+ * Parameters:
+ * object - {Object} A reference to this.
+ *
+ * Returns:
+ * {Function}
+ */
+ Function.prototype.bindAsEventListener = function(object) {
+ OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
+ {'newMethod':'OpenLayers.String.bindAsEventListener'}));
+ return OpenLayers.Function.bindAsEventListener(this, object);
+ };
+}
+
+/**
+ * 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/docs/Core_JavaScript_1.5_Reference: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<len; i++) {
+ if (i in array) {
+ var val = array[i];
+ if (callback.call(caller, val, i, array)) {
+ selected.push(val);
+ }
+ }
+ }
+ }
+ return selected;
+ }
+
+};
+/* ======================================================================
+ OpenLayers/BaseTypes/Class.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Constructor: OpenLayers.Class
+ * Base class used to construct all other classes. Includes support for
+ * multiple inheritance.
+ *
+ * This constructor is new in OpenLayers 2.5. At OpenLayers 3.0, the old
+ * syntax for creating classes and dealing with inheritance
+ * will be removed.
+ *
+ * To create a new OpenLayers-style class, use the following syntax:
+ * > var MyClass = OpenLayers.Class(prototype);
+ *
+ * To create a new OpenLayers-style class with multiple inheritance, use the
+ * following syntax:
+ * > var MyClass = OpenLayers.Class(Class1, Class2, prototype);
+ *
+ */
+OpenLayers.Class = function() {
+ var Class = function() {
+ /**
+ * This following condition can be removed at 3.0 - this is only for
+ * backwards compatibility while the Class.inherit method is still
+ * in use. So at 3.0, the following three lines would be replaced with
+ * simply:
+ * this.initialize.apply(this, arguments);
+ */
+ if (arguments && arguments[0] != OpenLayers.Class.isPrototype) {
+ this.initialize.apply(this, arguments);
+ }
+ };
+ var extended = {};
+ var parent;
+ for(var i=0; i<arguments.length; ++i) {
+ if(typeof arguments[i] == "function") {
+ // get the prototype of the superclass
+ parent = arguments[i].prototype;
+ } else {
+ // in this case we're extending with the prototype
+ parent = arguments[i];
+ }
+ OpenLayers.Util.extend(extended, parent);
+ }
+ Class.prototype = extended;
+ return Class;
+};
+
+/**
+ * Property: isPrototype
+ * *Deprecated*. This is no longer needed and will be removed at 3.0.
+ */
+OpenLayers.Class.isPrototype = function () {};
+
+/**
+ * APIFunction: OpenLayers.create
+ * *Deprecated*. Old method to create an OpenLayers style class. Use the
+ * <OpenLayers.Class> constructor instead.
+ *
+ * Returns:
+ * An OpenLayers class
+ */
+OpenLayers.Class.create = function() {
+ return function() {
+ if (arguments && arguments[0] != OpenLayers.Class.isPrototype) {
+ this.initialize.apply(this, arguments);
+ }
+ };
+};
+
+
+/**
+ * APIFunction: inherit
+ * *Deprecated*. Old method to inherit from one or more OpenLayers style
+ * classes. Use the <OpenLayers.Class> constructor instead.
+ *
+ * Parameters:
+ * class - One or more classes can be provided as arguments
+ *
+ * Returns:
+ * An object prototype
+ */
+OpenLayers.Class.inherit = function () {
+ var superClass = arguments[0];
+ var proto = new superClass(OpenLayers.Class.isPrototype);
+ for (var i = 1; i < arguments.length; i++) {
+ if (typeof arguments[i] == "function") {
+ var mixin = arguments[i];
+ arguments[i] = new mixin(OpenLayers.Class.isPrototype);
+ }
+ OpenLayers.Util.extend(proto, arguments[i]);
+ }
+ return proto;
+};
+/* ======================================================================
+ OpenLayers/Util.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * Namespace: Util
+ */
+OpenLayers.Util = {};
+
+/**
+ * Function: getElement
+ * This is the old $() from prototype
+ */
+OpenLayers.Util.getElement = function() {
+ var elements = [];
+
+ for (var i = 0; i < arguments.length; i++) {
+ var element = arguments[i];
+ if (typeof element == 'string') {
+ element = document.getElementById(element);
+ }
+ if (arguments.length == 1) {
+ return element;
+ }
+ elements.push(element);
+ }
+ return elements;
+};
+
+/**
+ * Maintain $() from prototype
+ */
+if ($ == null) {
+ var $ = OpenLayers.Util.getElement;
+}
+
+/**
+ * APIFunction: extend
+ * Copy all properties of a source object to a destination object. Modifies
+ * the passed in destination object. Any properties on the source object
+ * that are set to undefined will not be (re)set on the destination object.
+ *
+ * Parameters:
+ * destination - {Object} The object that will be modified
+ * source - {Object} The object with properties to be set on the destination
+ *
+ * Returns:
+ * {Object} The destination object.
+ */
+OpenLayers.Util.extend = function(destination, source) {
+ if(destination && source) {
+ for(var property in source) {
+ var value = source[property];
+ if(value !== undefined) {
+ destination[property] = value;
+ }
+ }
+
+ /**
+ * IE doesn't include the toString property when iterating over an object's
+ * properties with the for(property in object) syntax. Explicitly check if
+ * the source has its own toString property.
+ */
+
+ /*
+ * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative
+ * prototype object" when calling hawOwnProperty if the source object
+ * is an instance of window.Event.
+ */
+
+ var sourceIsEvt = typeof window.Event == "function"
+ && source instanceof window.Event;
+
+ if(!sourceIsEvt
+ && source.hasOwnProperty && source.hasOwnProperty('toString')) {
+ destination.toString = source.toString;
+ }
+ }
+ return destination;
+};
+
+
+/**
+ * Function: removeItem
+ * Remove an object from an array. Iterates through the array
+ * to find the item, then removes it.
+ *
+ * Parameters:
+ * array - {Array}
+ * item - {Object}
+ *
+ * Return
+ * {Array} A reference to the array
+ */
+OpenLayers.Util.removeItem = function(array, item) {
+ for(var i = array.length - 1; i >= 0; i--) {
+ if(array[i] == item) {
+ array.splice(i,1);
+ //break;more than once??
+ }
+ }
+ return array;
+};
+
+/**
+ * Function: clearArray
+ * *Deprecated*. This function will disappear in 3.0.
+ * Please use "array.length = 0" instead.
+ *
+ * Parameters:
+ * array - {Array}
+ */
+OpenLayers.Util.clearArray = function(array) {
+ OpenLayers.Console.warn(
+ OpenLayers.i18n(
+ "methodDeprecated", {'newMethod': 'array = []'}
+ )
+ );
+ array.length = 0;
+};
+
+/**
+ * Function: indexOf
+ * Seems to exist already in FF, but not in MOZ.
+ *
+ * Parameters:
+ * array - {Array}
+ * obj - {Object}
+ *
+ * Returns:
+ * {Integer} The index at, which the object was found in the array.
+ * If not found, returns -1.
+ */
+OpenLayers.Util.indexOf = function(array, obj) {
+
+ for(var i=0; i < array.length; i++) {
+ if (array[i] == obj) {
+ return i;
+ }
+ }
+ return -1;
+};
+
+
+
+/**
+ * Function: modifyDOMElement
+ *
+ * Modifies many properties of a DOM element all at once. Passing in
+ * null to an individual parameter will avoid setting the attribute.
+ *
+ * Parameters:
+ * id - {String} The element id attribute to set.
+ * px - {<OpenLayers.Pixel>} The left and top style position.
+ * sz - {<OpenLayers.Size>} The width and height style attributes.
+ * position - {String} The position attribute. eg: absolute,
+ * relative, etc.
+ * border - {String} The style.border attribute. eg:
+ * solid black 2px
+ * overflow - {String} The style.overview attribute.
+ * opacity - {Float} Fractional value (0.0 - 1.0)
+ */
+OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position,
+ border, overflow, opacity) {
+
+ if (id) {
+ element.id = id;
+ }
+ if (px) {
+ element.style.left = px.x + "px";
+ element.style.top = px.y + "px";
+ }
+ if (sz) {
+ element.style.width = sz.w + "px";
+ element.style.height = sz.h + "px";
+ }
+ if (position) {
+ element.style.position = position;
+ }
+ if (border) {
+ element.style.border = border;
+ }
+ if (overflow) {
+ element.style.overflow = overflow;
+ }
+ if (parseFloat(opacity) >= 0.0 && parseFloat(opacity) < 1.0) {
+ element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
+ element.style.opacity = opacity;
+ } else if (parseFloat(opacity) == 1.0) {
+ element.style.filter = '';
+ element.style.opacity = '';
+ }
+};
+
+/**
+ * Function: createDiv
+ * Creates a new div and optionally set some standard attributes.
+ * Null may be passed to each parameter if you do not wish to
+ * set a particular attribute.
+ * Note - zIndex is NOT set on the resulting div.
+ *
+ * Parameters:
+ * id - {String} An identifier for this element. If no id is
+ * passed an identifier will be created
+ * automatically.
+ * px - {<OpenLayers.Pixel>} The element left and top position.
+ * sz - {<OpenLayers.Size>} The element width and height.
+ * imgURL - {String} A url pointing to an image to use as a
+ * background image.
+ * position - {String} The style.position value. eg: absolute,
+ * relative etc.
+ * border - {String} The the style.border value.
+ * eg: 2px solid black
+ * overflow - {String} The style.overflow value. Eg. hidden
+ * opacity - {Float} Fractional value (0.0 - 1.0)
+ *
+ * Returns:
+ * {DOMElement} A DOM Div created with the specified attributes.
+ */
+OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position,
+ border, overflow, opacity) {
+
+ var dom = document.createElement('div');
+
+ if (imgURL) {
+ dom.style.backgroundImage = 'url(' + imgURL + ')';
+ }
+
+ //set generic properties
+ if (!id) {
+ id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
+ }
+ if (!position) {
+ position = "absolute";
+ }
+ OpenLayers.Util.modifyDOMElement(dom, id, px, sz, position,
+ border, overflow, opacity);
+
+ return dom;
+};
+
+/**
+ * Function: createImage
+ * Creates an img element with specific attribute values.
+ *
+ * Parameters:
+ * id - {String} The id field for the img. If none assigned one will be
+ * automatically generated.
+ * px - {<OpenLayers.Pixel>} The left and top positions.
+ * sz - {<OpenLayers.Size>} The style.width and style.height values.
+ * imgURL - {String} The url to use as the image source.
+ * position - {String} The style.position value.
+ * border - {String} The border to place around the image.
+ * delayDisplay - {Boolean} If true waits until the image has been
+ * loaded.
+ * opacity - {Float} Fractional value (0.0 - 1.0)
+ *
+ * Returns:
+ * {DOMElement} A DOM Image created with the specified attributes.
+ */
+OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border,
+ opacity, delayDisplay) {
+
+ var image = document.createElement("img");
+
+ //set generic properties
+ if (!id) {
+ id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
+ }
+ if (!position) {
+ position = "relative";
+ }
+ OpenLayers.Util.modifyDOMElement(image, id, px, sz, position,
+ border, null, opacity);
+
+ if(delayDisplay) {
+ image.style.display = "none";
+ OpenLayers.Event.observe(image, "load",
+ OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, image));
+ OpenLayers.Event.observe(image, "error",
+ OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, image));
+
+ }
+
+ //set special properties
+ image.style.alt = id;
+ image.galleryImg = "no";
+ if (imgURL) {
+ image.src = imgURL;
+ }
+
+
+
+ return image;
+};
+
+/**
+ * Function: setOpacity
+ * *Deprecated*. This function has been deprecated. Instead, please use
+ * <OpenLayers.Util.modifyDOMElement>
+ * or
+ * <OpenLayers.Util.modifyAlphaImageDiv>
+ *
+ * Set the opacity of a DOM Element
+ * Note that for this function to work in IE, elements must "have layout"
+ * according to:
+ * http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp
+ *
+ * Parameters:
+ * element - {DOMElement} Set the opacity on this DOM element
+ * opacity - {Float} Opacity value (0.0 - 1.0)
+ */
+OpenLayers.Util.setOpacity = function(element, opacity) {
+ OpenLayers.Util.modifyDOMElement(element, null, null, null,
+ null, null, null, opacity);
+};
+
+/**
+ * Function: onImageLoad
+ * Bound to image load events. For all images created with <createImage> or
+ * <createAlphaImageDiv>, this function will be bound to the load event.
+ */
+OpenLayers.Util.onImageLoad = function() {
+ // The complex check here is to solve issues described in #480.
+ // Every time a map view changes, it increments the 'viewRequestID'
+ // property. As the requests for the images for the new map view are sent
+ // out, they are tagged with this unique viewRequestID.
+ //
+ // If an image has no viewRequestID property set, we display it regardless,
+ // but if it does have a viewRequestID property, we check that it matches
+ // the viewRequestID set on the map.
+ //
+ // If the viewRequestID on the map has changed, that means that the user
+ // has changed the map view since this specific request was sent out, and
+ // therefore this tile does not need to be displayed (so we do not execute
+ // this code that turns its display on).
+ //
+ if (!this.viewRequestID ||
+ (this.map && this.viewRequestID == this.map.viewRequestID)) {
+ this.style.backgroundColor = null;
+ this.style.display = "";
+ }
+};
+
+/**
+ * Property: onImageLoadErrorColor
+ * {String} The color tiles with load errors will turn.
+ * Default is "pink"
+ */
+OpenLayers.Util.onImageLoadErrorColor = "pink";
+
+/**
+ * Property: IMAGE_RELOAD_ATTEMPTS
+ * {Integer} How many times should we try to reload an image before giving up?
+ * Default is 0
+ */
+OpenLayers.IMAGE_RELOAD_ATTEMPTS = 0;
+
+/**
+ * Function: onImageLoadError
+ */
+OpenLayers.Util.onImageLoadError = function() {
+ this._attempts = (this._attempts) ? (this._attempts + 1) : 1;
+ if(this._attempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
+ this.src = this.src;
+ } else {
+ this.style.backgroundColor = OpenLayers.Util.onImageLoadErrorColor;
+ }
+ this.style.display = "";
+};
+
+/**
+ * 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 alpha has is necessary and possible, false otherwise.
+ */
+OpenLayers.Util.alphaHack = function() {
+ 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) {
+ }
+
+ return ( filter &&
+ (version >= 5.5) && (version < 7) );
+};
+
+/**
+ * Function: modifyAlphaImageDiv
+ *
+ * div - {DOMElement} Div containing Alpha-adjusted Image
+ * id - {String}
+ * px - {<OpenLayers.Pixel>}
+ * sz - {<OpenLayers.Size>}
+ * imgURL - {String}
+ * position - {String}
+ * border - {String}
+ * sizing {String} 'crop', 'scale', or 'image'. Default is "scale"
+ * opacity - {Float} Fractional value (0.0 - 1.0)
+ */
+OpenLayers.Util.modifyAlphaImageDiv = function(div, id, px, sz, imgURL,
+ position, border, sizing,
+ opacity) {
+
+ OpenLayers.Util.modifyDOMElement(div, id, px, sz,
+ null, 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()) {
+
+ div.style.display = "inline-block";
+ if (sizing == null) {
+ sizing = "scale";
+ }
+
+ div.style.filter = "progid:DXImageTransform.Microsoft" +
+ ".AlphaImageLoader(src='" + img.src + "', " +
+ "sizingMethod='" + sizing + "')";
+ if (parseFloat(div.style.opacity) >= 0.0 &&
+ parseFloat(div.style.opacity) < 1.0) {
+ div.style.filter += " alpha(opacity=" + div.style.opacity * 100 + ")";
+ }
+
+ img.style.filter = "alpha(opacity=0)";
+ }
+};
+
+/**
+ * Function: createAlphaImageDiv
+ *
+ * id - {String}
+ * px - {<OpenLayers.Pixel>}
+ * sz - {<OpenLayers.Size>}
+ * imgURL - {String}
+ * position - {String}
+ * border - {String}
+ * sizing {String} 'crop', 'scale', or 'image'. Default is "scale"
+ * delayDisplay{Boolean}
+ *
+ * Returns:
+ * {DOMElement} A DOM Div created with a DOM Image inside it. If the hack is
+ * needed for transparency in IE, it is added.
+ */
+OpenLayers.Util.createAlphaImageDiv = function(id, px, sz, imgURL,
+ position, border, sizing,
+ opacity, delayDisplay) {
+
+ var div = OpenLayers.Util.createDiv();
+ var img = OpenLayers.Util.createImage(null, null, null, null, null, null,
+ null, false);
+ div.appendChild(img);
+
+ if (delayDisplay) {
+ img.style.display = "none";
+ OpenLayers.Event.observe(img, "load",
+ OpenLayers.Function.bind(OpenLayers.Util.onImageLoad, div));
+ OpenLayers.Event.observe(img, "error",
+ OpenLayers.Function.bind(OpenLayers.Util.onImageLoadError, div));
+ }
+
+ OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL, position,
+ border, sizing, opacity);
+
+ return div;
+};
+
+
+/**
+ * Function: upperCaseObject
+ * Creates a new hashtable and copies over all the keys from the
+ * passed-in object, but storing them under an uppercased
+ * version of the key at which they were stored.
+ *
+ * Parameters:
+ * object - {Object}
+ *
+ * Returns:
+ * {Object} A new Object with all the same keys but uppercased
+ */
+OpenLayers.Util.upperCaseObject = function (object) {
+ var uObject = {};
+ for (var key in object) {
+ uObject[key.toUpperCase()] = object[key];
+ }
+ return uObject;
+};
+
+/**
+ * Function: applyDefaults
+ * Takes an object and copies any properties that don't exist from
+ * another properties, by analogy with OpenLayers.Util.extend() from
+ * Prototype.js.
+ *
+ * Parameters:
+ * to - {Object} The destination object.
+ * from - {Object} The source object. Any properties of this object that
+ * are undefined in the to object will be set on the to object.
+ *
+ * Returns:
+ * {Object} A reference to the to object. Note that the to argument is modified
+ * in place and returned by this function.
+ */
+OpenLayers.Util.applyDefaults = function (to, from) {
+
+ /*
+ * 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.hasOwnProperty
+ && from.hasOwnProperty('toString') && !to.hasOwnProperty('toString')) {
+ to.toString = from.toString;
+ }
+
+ return to;
+};
+
+/**
+ * Function: getParameterString
+ *
+ * Parameters:
+ * params - {Object}
+ *
+ * Returns:
+ * {String} A concatenation of the properties of an object in
+ * http parameter notation.
+ * (ex. <i>"key1=value1&key2=value2&key3=value3"</i>)
+ * If a parameter is actually a list, that parameter will then
+ * be set to a comma-seperated list of values (foo,bar) instead
+ * of being URL escaped (foo%3Abar).
+ */
+OpenLayers.Util.getParameterString = function(params) {
+ var paramsArray = [];
+
+ for (var key in params) {
+ var value = params[key];
+ if ((value != null) && (typeof value != 'function')) {
+ var encodedValue;
+ if (typeof value == 'object' && value.constructor == Array) {
+ /* value is an array; encode items and separate with "," */
+ var encodedItemArray = [];
+ for (var itemIndex=0; itemIndex<value.length; itemIndex++) {
+ encodedItemArray.push(encodeURIComponent(value[itemIndex]));
+ }
+ encodedValue = encodedItemArray.join(",");
+ }
+ else {
+ /* value is a string; simply encode */
+ encodedValue = encodeURIComponent(value);
+ }
+ paramsArray.push(encodeURIComponent(key) + "=" + encodedValue);
+ }
+ }
+
+ return paramsArray.join("&");
+};
+
+/**
+ * Property: ImgPath
+ * {String} Default is ''.
+ */
+OpenLayers.ImgPath = '';
+
+/**
+ * Function: getImagesLocation
+ *
+ * Returns:
+ * {String} The fully formatted image location string
+ */
+OpenLayers.Util.getImagesLocation = function() {
+ return OpenLayers.ImgPath || (OpenLayers._getScriptLocation() + "img/");
+};
+
+
+/**
+ * Function: Try
+ * Execute functions until one of them doesn't throw an error.
+ * Capitalized because "try" is a reserved word in JavaScript.
+ * Taken directly from OpenLayers.Util.Try()
+ *
+ * Parameters:
+ * [*] - {Function} Any number of parameters may be passed to Try()
+ * It will attempt to execute each of them until one of them
+ * successfully executes.
+ * If none executes successfully, returns null.
+ *
+ * Returns:
+ * {*} The value returned by the first successfully executed function.
+ */
+OpenLayers.Util.Try = function() {
+ var returnValue = null;
+
+ for (var i = 0; i < arguments.length; i++) {
+ var lambda = arguments[i];
+ try {
+ returnValue = lambda();
+ break;
+ } catch (e) {}
+ }
+
+ return returnValue;
+};
+
+
+/**
+ * Function: getNodes
+ *
+ * These could/should be made namespace aware?
+ *
+ * Parameters:
+ * p - {}
+ * tagName - {String}
+ *
+ * Returns:
+ * {Array}
+ */
+OpenLayers.Util.getNodes=function(p, tagName) {
+ var nodes = OpenLayers.Util.Try(
+ function () {
+ return OpenLayers.Util._getNodes(p.documentElement.childNodes,
+ tagName);
+ },
+ function () {
+ return OpenLayers.Util._getNodes(p.childNodes, tagName);
+ }
+ );
+ return nodes;
+};
+
+/**
+ * Function: _getNodes
+ *
+ * Parameters:
+ * nodes - {Array}
+ * tagName - {String}
+ *
+ * Returns:
+ * {Array}
+ */
+OpenLayers.Util._getNodes=function(nodes, tagName) {
+ var retArray = [];
+ for (var i=0;i<nodes.length;i++) {
+ if (nodes[i].nodeName==tagName) {
+ retArray.push(nodes[i]);
+ }
+ }
+
+ return retArray;
+};
+
+
+
+/**
+ * Function: getTagText
+ *
+ * Parameters:
+ * parent - {}
+ * item - {String}
+ * index - {Integer}
+ *
+ * Returns:
+ * {String}
+ */
+OpenLayers.Util.getTagText = function (parent, item, index) {
+ var result = OpenLayers.Util.getNodes(parent, item);
+ if (result && (result.length > 0))
+ {
+ if (!index) {
+ index=0;
+ }
+ if (result[index].childNodes.length > 1) {
+ return result.childNodes[1].nodeValue;
+ }
+ else if (result[index].childNodes.length == 1) {
+ return result[index].firstChild.nodeValue;
+ }
+ } else {
+ return "";
+ }
+};
+
+/**
+ * Function: getXmlNodeValue
+ *
+ * Parameters:
+ * node - {XMLNode}
+ *
+ * Returns:
+ * {String} The text value of the given node, without breaking in firefox or IE
+ */
+OpenLayers.Util.getXmlNodeValue = function(node) {
+ var val = null;
+ OpenLayers.Util.Try(
+ function() {
+ val = node.text;
+ if (!val) {
+ val = node.textContent;
+ }
+ if (!val) {
+ val = node.firstChild.nodeValue;
+ }
+ },
+ function() {
+ val = node.textContent;
+ });
+ return val;
+};
+
+/**
+ * Function: mouseLeft
+ *
+ * Parameters:
+ * evt - {Event}
+ * div - {HTMLDivElement}
+ *
+ * Returns:
+ * {Boolean}
+ */
+OpenLayers.Util.mouseLeft = function (evt, div) {
+ // start with the element to which the mouse has moved
+ var target = (evt.relatedTarget) ? evt.relatedTarget : evt.toElement;
+ // walk up the DOM tree.
+ while (target != div && target != null) {
+ target = target.parentNode;
+ }
+ // if the target we stop at isn't the div, then we've left the div.
+ return (target != div);
+};
+
+/**
+ * Function: rad
+ *
+ * Parameters:
+ * x - {Float}
+ *
+ * Returns:
+ * {Float}
+ */
+OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
+
+/**
+ * Function: distVincenty
+ *
+ * Parameters:
+ * p1 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
+ * p2 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
+ *
+ * Returns:
+ * {Float}
+ */
+OpenLayers.Util.distVincenty=function(p1, p2) {
+ var a = 6378137, b = 6356752.3142, f = 1/298.257223563;
+ 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;
+};
+
+/**
+ * Function: getParameters
+ * Parse the parameters from a URL or from the current page itself into a
+ * JavaScript Object. Note that parameter values with commas are separated
+ * out into an Array.
+ *
+ * Parameters:
+ * url - {String} Optional url used to extract the query string.
+ * If null, query string is taken from page location.
+ *
+ * Returns:
+ * {Object} An object of key/value pairs from the query string.
+ */
+OpenLayers.Util.getParameters = function(url) {
+ // if no url specified, take it from the location bar
+ url = url || window.location.href;
+
+ //parse out parameters portion of url string
+ var paramsString = "";
+ if (OpenLayers.String.contains(url, '?')) {
+ var start = url.indexOf('?') + 1;
+ var end = OpenLayers.String.contains(url, "#") ?
+ url.indexOf('#') : url.length;
+ paramsString = url.substring(start, end);
+ }
+
+ var parameters = {};
+ var pairs = paramsString.split(/[&;]/);
+ for(var i = 0; i < pairs.length; ++i) {
+ var keyValue = pairs[i].split('=');
+ if (keyValue[0]) {
+ var key = decodeURIComponent(keyValue[0]);
+ var value = keyValue[1] || ''; //empty string if no value
+
+ //decode individual values
+ value = value.split(",");
+ for(var j=0; j < value.length; j++) {
+ value[j] = decodeURIComponent(value[j]);
+ }
+
+ //if there's only one value, do not return as array
+ if (value.length == 1) {
+ value = value[0];
+ }
+
+ parameters[key] = value;
+ }
+ }
+ return parameters;
+};
+
+/**
+ * Function: getArgs
+ * *Deprecated*. Will be removed in 3.0. Please use instead
+ * <OpenLayers.Util.getParameters>
+ *
+ * Parameters:
+ * url - {String} Optional url used to extract the query string.
+ * If null, query string is taken from page location.
+ *
+ * Returns:
+ * {Object} An object of key/value pairs from the query string.
+ */
+OpenLayers.Util.getArgs = function(url) {
+ OpenLayers.Console.warn(
+ OpenLayers.i18n(
+ "methodDeprecated", {'newMethod': 'OpenLayers.Util.getParameters'}
+ )
+ );
+ return OpenLayers.Util.getParameters(url);
+};
+
+/**
+ * Property: lastSeqID
+ * {Integer} The ever-incrementing count variable.
+ * Used for generating unique ids.
+ */
+OpenLayers.Util.lastSeqID = 0;
+
+/**
+ * Function: createUniqueID
+ * Create a unique identifier for this session. Each time this function
+ * is called, a counter is incremented. The return will be the optional
+ * prefix (defaults to "id_") appended with the counter value.
+ *
+ * Parameters:
+ * prefix {String} Optionsal string to prefix unique id. Default is "id_".
+ *
+ * Returns:
+ * {String} A unique id string, built on the passed in prefix.
+ */
+OpenLayers.Util.createUniqueID = function(prefix) {
+ if (prefix == null) {
+ prefix = "id_";
+ }
+ OpenLayers.Util.lastSeqID += 1;
+ return prefix + OpenLayers.Util.lastSeqID;
+};
+
+/**
+ * Constant: INCHES_PER_UNIT
+ * {Object} Constant inches per unit -- borrowed from MapServer mapscale.c
+ * derivation of nautical miles from http://en.wikipedia.org/wiki/Nautical_mile
+ */
+OpenLayers.INCHES_PER_UNIT = {
+ 'inches': 1.0,
+ 'ft': 12.0,
+ 'mi': 63360.0,
+ 'm': 39.3701,
+ 'km': 39370.1,
+ 'dd': 4374754,
+ 'yd': 36
+};
+OpenLayers.INCHES_PER_UNIT["in"]= OpenLayers.INCHES_PER_UNIT.inches;
+OpenLayers.INCHES_PER_UNIT["degrees"] = OpenLayers.INCHES_PER_UNIT.dd;
+OpenLayers.INCHES_PER_UNIT["nmi"] = 1852 * OpenLayers.INCHES_PER_UNIT.m;
+
+/**
+ * Constant: DOTS_PER_INCH
+ * {Integer} 72 (A sensible default)
+ */
+OpenLayers.DOTS_PER_INCH = 72;
+
+/**
+ * Function: normalzeScale
+ *
+ * Parameters:
+ * scale - {float}
+ *
+ * Returns:
+ * {Float} A normalized scale value, in 1 / X format.
+ * This means that if a value less than one ( already 1/x) is passed
+ * in, it just returns scale directly. Otherwise, it returns
+ * 1 / scale
+ */
+OpenLayers.Util.normalizeScale = function (scale) {
+ var normScale = (scale > 1.0) ? (1.0 / scale)
+ : scale;
+ return normScale;
+};
+
+/**
+ * Function: getResolutionFromScale
+ *
+ * Parameters:
+ * scale - {Float}
+ * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
+ * Default is degrees
+ *
+ * Returns:
+ * {Float} The corresponding resolution given passed-in scale and unit
+ * parameters.
+ */
+OpenLayers.Util.getResolutionFromScale = function (scale, units) {
+
+ if (units == null) {
+ units = "degrees";
+ }
+
+ var normScale = OpenLayers.Util.normalizeScale(scale);
+
+ var resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units]
+ * OpenLayers.DOTS_PER_INCH);
+ return resolution;
+};
+
+/**
+ * Function: getScaleFromResolution
+ *
+ * Parameters:
+ * resolution - {Float}
+ * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
+ * Default is degrees
+ *
+ * Returns:
+ * {Float} The corresponding scale given passed-in resolution and unit
+ * parameters.
+ */
+OpenLayers.Util.getScaleFromResolution = function (resolution, units) {
+
+ if (units == null) {
+ units = "degrees";
+ }
+
+ var scale = resolution * OpenLayers.INCHES_PER_UNIT[units] *
+ OpenLayers.DOTS_PER_INCH;
+ return scale;
+};
+
+/**
+ * Function: safeStopPropagation
+ * *Deprecated*. This function has been deprecated. Please use directly
+ * <OpenLayers.Event.stop> passing 'true' as the 2nd
+ * argument (preventDefault)
+ *
+ * Safely stop the propagation of an event *without* preventing
+ * the default browser action from occurring.
+ *
+ * Parameter:
+ * evt - {Event}
+ */
+OpenLayers.Util.safeStopPropagation = function(evt) {
+ OpenLayers.Event.stop(evt, true);
+};
+
+/**
+ * Function: pagePositon
+ * Calculates the position of an element on the page.
+ *
+ * Parameters:
+ * forElement - {DOMElement}
+ *
+ * Returns:
+ * {Array} two item array, L value then T value.
+ */
+OpenLayers.Util.pagePosition = function(forElement) {
+ var valueT = 0, valueL = 0;
+
+ var element = forElement;
+ var child = forElement;
+ while(element) {
+
+ if(element == document.body) {
+ // FIXME: IE, when passed 'window' as the forElement, treats it as
+ // equal to document.body, but window.style fails, so getStyle
+ // fails, so we are paranoid and check this here. This check should
+ // probably move into element.getStyle in 2.6.
+ if(child && child.style &&
+ OpenLayers.Element.getStyle(child, 'position') == 'absolute') {
+ break;
+ }
+ }
+
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+
+ child = element;
+ try {
+ // wrapping this in a try/catch because IE chokes on the offsetParent
+ element = element.offsetParent;
+ } catch(e) {
+ OpenLayers.Console.error(OpenLayers.i18n(
+ "pagePositionFailed",{'elemId':element.id}));
+ break;
+ }
+ }
+
+ element = forElement;
+ while(element) {
+ valueT -= element.scrollTop || 0;
+ valueL -= element.scrollLeft || 0;
+ element = element.parentNode;
+ }
+
+ return [valueL, valueT];
+};
+
+
+/**
+ * Function: isEquivalentUrl
+ * Test two URLs for equivalence.
+ *
+ * Setting 'ignoreCase' allows for case-independent comparison.
+ *
+ * Comparison is based on:
+ * - Protocol
+ * - Host (evaluated without the port)
+ * - Port (set 'ignorePort80' to ignore "80" values)
+ * - Hash ( set 'ignoreHash' to disable)
+ * - Pathname (for relative <-> absolute comparison)
+ * - Arguments (so they can be out of order)
+ *
+ * Parameters:
+ * url1 - {String}
+ * url2 - {String}
+ * options - {Object} Allows for customization of comparison:
+ * 'ignoreCase' - Default is True
+ * 'ignorePort80' - Default is True
+ * 'ignoreHash' - Default is True
+ *
+ * Returns:
+ * {Boolean} Whether or not the two URLs are equivalent
+ */
+OpenLayers.Util.isEquivalentUrl = function(url1, url2, options) {
+ options = options || {};
+
+ OpenLayers.Util.applyDefaults(options, {
+ ignoreCase: true,
+ ignorePort80: true,
+ ignoreHash: true
+ });
+
+ var urlObj1 = OpenLayers.Util.createUrlObject(url1, options);
+ var urlObj2 = OpenLayers.Util.createUrlObject(url2, options);
+
+ //compare all keys (host, port, etc)
+ for(var key in urlObj1) {
+ if (options.test) {
+ alert(key + "\n1:" + urlObj1[key] + "\n2:" + urlObj2[key]);
+ }
+ var val1 = urlObj1[key];
+ var val2 = urlObj2[key];
+
+ switch(key) {
+ case "args":
+ //do nothing, they'll be treated below
+ break;
+ case "host":
+ case "port":
+ case "protocol":
+ if ((val1 == "") || (val2 == "")) {
+ //these will be blank for relative urls, so no need to
+ // compare them here -- call break.
+ //
+ break;
+ }
+ // otherwise continue with default compare
+ //
+ default:
+ if ( (key != "args") && (urlObj1[key] != urlObj2[key]) ) {
+ return false;
+ }
+ break;
+ }
+
+ }
+
+ // compare search args - irrespective of order
+ for(var key in urlObj1.args) {
+ if(urlObj1.args[key] != urlObj2.args[key]) {
+ return false;
+ }
+ delete urlObj2.args[key];
+ }
+ // urlObj2 shouldn't have any args left
+ for(var key in urlObj2.args) {
+ return false;
+ }
+
+ return true;
+};
+
+/**
+ * Function: createUrlObject
+ *
+ * Parameters:
+ * url - {String}
+ * options - {Object} A hash of options. Can be one of:
+ * ignoreCase: lowercase url,
+ * ignorePort80: don't include explicit port if port is 80,
+ * ignoreHash: Don't include part of url after the hash (#).
+ *
+ * Returns:
+ * {Object} An object with separate url, a, port, host, and args parsed out
+ * and ready for comparison
+ */
+OpenLayers.Util.createUrlObject = function(url, options) {
+ options = options || {};
+
+ var urlObject = {};
+
+ if (options.ignoreCase) {
+ url = url.toLowerCase();
+ }
+
+ var a = document.createElement('a');
+ a.href = url;
+
+ //host (without port)
+ urlObject.host = a.host;
+ var port = a.port;
+ if (port.length <= 0) {
+ var newHostLength = urlObject.host.length - (port.length);
+ urlObject.host = urlObject.host.substring(0, newHostLength);
+ }
+
+ //protocol
+ urlObject.protocol = a.protocol;
+
+ //port
+ urlObject.port = ((port == "80") && (options.ignorePort80)) ? "" : port;
+
+ //hash
+ urlObject.hash = (options.ignoreHash) ? "" : 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 part allows for relative <-> absolute comparison)
+ if ( ((urlObject.protocol == "file:") && (url.indexOf("file:") != -1)) ||
+ ((urlObject.protocol != "file:") && (urlObject.host != "")) ) {
+
+ urlObject.pathname = a.pathname;
+
+ //Test to see if the pathname includes the arguments (Opera)
+ var qIndex = urlObject.pathname.indexOf("?");
+ if (qIndex != -1) {
+ urlObject.pathname = urlObject.pathname.substring(0, qIndex);
+ }
+
+ } else {
+ var relStr = OpenLayers.Util.removeTail(url);
+
+ var backs = 0;
+ do {
+ var index = relStr.indexOf("../");
+
+ if (index == 0) {
+ backs++;
+ relStr = relStr.substr(3);
+ } else if (index >= 0) {
+ var prevChunk = relStr.substr(0,index - 1);
+
+ var slash = prevChunk.indexOf("/");
+ prevChunk = (slash != -1) ? prevChunk.substr(0, slash +1)
+ : "";
+
+ var postChunk = relStr.substr(index + 3);
+ relStr = prevChunk + postChunk;
+ }
+ } while(index != -1)
+
+ var windowAnchor = document.createElement("a");
+ var windowUrl = window.location.href;
+ if (options.ignoreCase) {
+ windowUrl = windowUrl.toLowerCase();
+ }
+ windowAnchor.href = windowUrl;
+
+ //set protocol of window
+ urlObject.protocol = windowAnchor.protocol;
+
+ var splitter = (windowAnchor.pathname.indexOf("/") != -1) ? "/" : "\\";
+ var dirs = windowAnchor.pathname.split(splitter);
+ dirs.pop(); //remove filename
+ while ((backs > 0) && (dirs.length > 0)) {
+ dirs.pop();
+ backs--;
+ }
+ relStr = dirs.join("/") + "/"+ relStr;
+ urlObject.pathname = relStr;
+ }
+
+ if ((urlObject.protocol == "file:") || (urlObject.protocol == "")) {
+ urlObject.host = "localhost";
+ }
+
+ return urlObject;
+};
+
+/**
+ * Function: removeTail
+ * Takes a url and removes everything after the ? and #
+ *
+ * Parameters:
+ * url - {String} The url to process
+ *
+ * Returns:
+ * {String} The string with all queryString and Hash removed
+ */
+OpenLayers.Util.removeTail = function(url) {
+ var head = null;
+
+ var qMark = url.indexOf("?");
+ var hashMark = url.indexOf("#");
+
+ if (qMark == -1) {
+ head = (hashMark != -1) ? url.substr(0,hashMark) : url;
+ } else {
+ head = (hashMark != -1) ? url.substr(0,Math.min(qMark, hashMark))
+ : url.substr(0, qMark);
+ }
+ return head;
+};
+
+
+/**
+ * Function: getBrowserName
+ *
+ * Returns:
+ * {String} A string which specifies which is the current
+ * browser in which we are running.
+ *
+ * Currently-supported browser detection and codes:
+ * * 'opera' -- Opera
+ * * 'msie' -- Internet Explorer
+ * * 'safari' -- Safari
+ * * 'firefox' -- FireFox
+ * * 'mozilla' -- Mozilla
+ *
+ * If we are unable to property identify the browser, we
+ * return an empty string.
+ */
+OpenLayers.Util.getBrowserName = function() {
+ var browserName = "";
+
+ var ua = navigator.userAgent.toLowerCase();
+ if ( ua.indexOf( "opera" ) != -1 ) {
+ browserName = "opera";
+ } else if ( ua.indexOf( "msie" ) != -1 ) {
+ browserName = "msie";
+ } else if ( ua.indexOf( "safari" ) != -1 ) {
+ browserName = "safari";
+ } else if ( ua.indexOf( "mozilla" ) != -1 ) {
+ if ( ua.indexOf( "firefox" ) != -1 ) {
+ browserName = "firefox";
+ } else {
+ browserName = "mozilla";
+ }
+ }
+
+ return browserName;
+};
+
+
+
+
+/**
+ * Method: getRenderedDimensions
+ * Renders the contentHTML offscreen to determine actual dimensions for
+ * popup sizing. As we need layout to determine dimensions the content
+ * is rendered -9999px to the left and absolute to ensure the
+ * scrollbars do not flicker
+ *
+ * Parameters:
+ * size - {<OpenLayers.Size>} If either the 'w' or 'h' properties is
+ * specified, we fix that dimension of the div to be measured. This is
+ * useful in the case where we have a limit in one dimension and must
+ * therefore meaure the flow in the other dimension.
+ *
+ * Returns:
+ * {OpenLayers.Size}
+ */
+OpenLayers.Util.getRenderedDimensions = function(contentHTML, size) {
+
+ var w = h = null;
+
+ // create temp container div with restricted size
+ var container = document.createElement("div");
+ container.style.overflow= "";
+ container.style.position = "absolute";
+ container.style.left = "-9999px";
+
+ //fix a dimension, if specified.
+ if (size) {
+ if (size.w) {
+ w = container.style.width = size.w;
+ } else if (size.h) {
+ h = container.style.height = size.h;
+ }
+ }
+
+ // create temp content div and assign content
+ var content = document.createElement("div");
+ content.innerHTML = contentHTML;
+
+ // add content to restricted container
+ container.appendChild(content);
+
+ // append container to body for rendering
+ document.body.appendChild(container);
+
+ // calculate scroll width of content and add corners and shadow width
+ if (!w) {
+ w = parseInt(content.scrollWidth);
+
+ // update container width to allow height to adjust
+ container.style.width = w + "px";
+ }
+ // capture height and add shadow and corner image widths
+ if (!h) {
+ h = parseInt(content.scrollHeight);
+ }
+
+ // remove elements
+ container.removeChild(content);
+ document.body.removeChild(container);
+
+ return new OpenLayers.Size(w, h);
+};
+
+/**
+ * APIFunction: getScrollbarWidth
+ * This function has been modified by the OpenLayers from the original version,
+ * written by Matthew Eernisse and released under the Apache 2
+ * license here:
+ *
+ * http://www.fleegix.org/articles/2006/05/30/getting-the-scrollbar-width-in-pixels
+ *
+ * It has been modified simply to cache its value, since it is physically
+ * impossible that this code could ever run in more than one browser at
+ * once.
+ *
+ * Returns:
+ * {Integer}
+ */
+OpenLayers.Util.getScrollbarWidth = function() {
+
+ var scrollbarWidth = OpenLayers.Util._scrollbarWidth;
+
+ if (scrollbarWidth == null) {
+ var scr = null;
+ var inn = null;
+ var wNoScroll = 0;
+ var wScroll = 0;
+
+ // Outer scrolling div
+ scr = document.createElement('div');
+ scr.style.position = 'absolute';
+ scr.style.top = '-1000px';
+ scr.style.left = '-1000px';
+ scr.style.width = '100px';
+ scr.style.height = '50px';
+ // Start with no scrollbar
+ scr.style.overflow = 'hidden';
+
+ // Inner content div
+ inn = document.createElement('div');
+ inn.style.width = '100%';
+ inn.style.height = '200px';
+
+ // Put the inner div in the scrolling div
+ scr.appendChild(inn);
+ // Append the scrolling div to the doc
+ document.body.appendChild(scr);
+
+ // Width of the inner div sans scrollbar
+ wNoScroll = inn.offsetWidth;
+
+ // Add the scrollbar
+ scr.style.overflow = 'scroll';
+ // Width of the inner div width scrollbar
+ wScroll = inn.offsetWidth;
+
+ // Remove the scrolling div from the doc
+ document.body.removeChild(document.body.lastChild);
+
+ // Pixel width of the scroller
+ OpenLayers.Util._scrollbarWidth = (wNoScroll - wScroll);
+ scrollbarWidth = OpenLayers.Util._scrollbarWidth;
+ }
+
+ return scrollbarWidth;
+};
+/* ======================================================================
+ OpenLayers/Ajax.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+OpenLayers.ProxyHost = "";
+//OpenLayers.ProxyHost = "examples/proxy.cgi?url=";
+
+/**
+ * Ajax reader for OpenLayers
+ *
+ * @uri url to do remote XML http get
+ * @param {String} 'get' format params (x=y&a=b...)
+ * @who object to handle callbacks for this request
+ * @complete the function to be called on success
+ * @failure the function to be called on failure
+ *
+ * example usage from a caller:
+ *
+ * caps: function(request) {
+ * -blah-
+ * },
+ *
+ * OpenLayers.loadURL(url,params,this,caps);
+ *
+ * Notice the above example does not provide an error handler; a default empty
+ * handler is provided which merely logs the error if a failure handler is not
+ * supplied
+ *
+ */
+
+
+/**
+* @param {} request
+*/
+OpenLayers.nullHandler = function(request) {
+ alert(OpenLayers.i18n("unhandledRequest", {'statusText':request.statusText}));
+};
+
+/**
+ * Function: loadURL
+ * Background load a document.
+ *
+ * Parameters:
+ * uri - {String} URI of source doc
+ * params - {String} Params on get (doesnt seem to work)
+ * caller - {Object} object which gets callbacks
+ * onComplete - {Function} Optional callback for success. The callback
+ * will be called with this set to caller and will receive the request
+ * object as an argument.
+ * onFailure - {Function} Optional callback for failure. In the event of
+ * a failure, the callback will be called with this set to caller and will
+ * receive the request object as an argument.
+ *
+ * Returns:
+ * {XMLHttpRequest} The request object. To abort loading, call
+ * request.abort().
+ */
+OpenLayers.loadURL = function(uri, params, caller,
+ onComplete, onFailure) {
+
+ var success = (onComplete) ? OpenLayers.Function.bind(onComplete, caller)
+ : OpenLayers.nullHandler;
+
+ var failure = (onFailure) ? OpenLayers.Function.bind(onFailure, caller)
+ : OpenLayers.nullHandler;
+
+ // from prototype.js
+ var request = new OpenLayers.Ajax.Request(
+ uri,
+ {
+ method: 'get',
+ parameters: params,
+ onComplete: success,
+ onFailure: failure
+ }
+ );
+ return request.transport;
+};
+
+/**
+ * Function: parseXMLString
+ * Parse XML into a doc structure
+ *
+ * Parameters:
+ * text - {String}
+ *
+ * Returns:
+ * {?} Parsed AJAX Responsev
+ */
+OpenLayers.parseXMLString = function(text) {
+
+ //MS sucks, if the server is bad it dies
+ var index = text.indexOf('<');
+ if (index > 0) {
+ text = text.substring(index);
+ }
+
+ var ajaxResponse = OpenLayers.Util.Try(
+ function() {
+ var xmldom = new ActiveXObject('Microsoft.XMLDOM');
+ xmldom.loadXML(text);
+ return xmldom;
+ },
+ function() {
+ return new DOMParser().parseFromString(text, 'text/xml');
+ },
+ function() {
+ var req = new XMLHttpRequest();
+ req.open("GET", "data:" + "text/xml" +
+ ";charset=utf-8," + encodeURIComponent(text), false);
+ if (req.overrideMimeType) {
+ req.overrideMimeType("text/xml");
+ }
+ req.send(null);
+ return req.responseXML;
+ }
+ );
+
+ return ajaxResponse;
+};
+
+
+/**
+ * Namespace: OpenLayers.Ajax
+ */
+OpenLayers.Ajax = {
+
+ /**
+ * Method: emptyFunction
+ */
+ emptyFunction: function () {},
+
+ /**
+ * Method: getTransport
+ *
+ * Returns:
+ * {Object} Transport mechanism for whichever browser we're in, or false if
+ * none available.
+ */
+ getTransport: function() {
+ return OpenLayers.Util.Try(
+ function() {return new XMLHttpRequest();},
+ function() {return new ActiveXObject('Msxml2.XMLHTTP');},
+ function() {return new ActiveXObject('Microsoft.XMLHTTP');}
+ ) || false;
+ },
+
+ /**
+ * Property: activeRequestCount
+ * {Integer}
+ */
+ activeRequestCount: 0
+};
+
+/**
+ * Namespace: OpenLayers.Ajax.Responders
+ * {Object}
+ */
+OpenLayers.Ajax.Responders = {
+
+ /**
+ * Property: responders
+ * {Array}
+ */
+ responders: [],
+
+ /**
+ * Method: register
+ *
+ * Parameters:
+ * responderToAdd - {?}
+ */
+ register: function(responderToAdd) {
+ for (var i = 0; i < this.responders.length; i++){
+ if (responderToAdd == this.responders[i]){
+ return;
+ }
+ }
+ this.responders.push(responderToAdd);
+ },
+
+ /**
+ * Method: unregister
+ *
+ * Parameters:
+ * responderToRemove - {?}
+ */
+ unregister: function(responderToRemove) {
+ OpenLayers.Util.removeItem(this.reponders, responderToRemove);
+ },
+
+ /**
+ * Method: dispatch
+ *
+ * Parameters:
+ * callback - {?}
+ * request - {?}
+ * transport - {?}
+ */
+ dispatch: function(callback, request, transport) {
+ var responder;
+ for (var i = 0; i < this.responders.length; i++) {
+ responder = this.responders[i];
+
+ if (responder[callback] &&
+ typeof responder[callback] == 'function') {
+ try {
+ responder[callback].apply(responder,
+ [request, transport]);
+ } catch (e) {}
+ }
+ }
+ }
+};
+
+OpenLayers.Ajax.Responders.register({
+ /**
+ * Function: onCreate
+ */
+ onCreate: function() {
+ OpenLayers.Ajax.activeRequestCount++;
+ },
+
+ /**
+ * Function: onComplete
+ */
+ onComplete: function() {
+ OpenLayers.Ajax.activeRequestCount--;
+ }
+});
+
+/**
+ * Class: OpenLayers.Ajax.Base
+ */
+OpenLayers.Ajax.Base = OpenLayers.Class({
+
+ /**
+ * Constructor: OpenLayers.Ajax.Base
+ *
+ * Parameters:
+ * options - {Object}
+ */
+ initialize: function(options) {
+ this.options = {
+ method: 'post',
+ asynchronous: true,
+ contentType: 'application/xml',
+ parameters: ''
+ };
+ OpenLayers.Util.extend(this.options, options || {});
+
+ this.options.method = this.options.method.toLowerCase();
+
+ if (typeof this.options.parameters == 'string') {
+ this.options.parameters =
+ OpenLayers.Util.getParameters(this.options.parameters);
+ }
+ }
+});
+
+/**
+ * Class: OpenLayers.Ajax.Request
+ *
+ * Inherit:
+ * - <OpenLayers.Ajax.Base>
+ */
+OpenLayers.Ajax.Request = OpenLayers.Class(OpenLayers.Ajax.Base, {
+
+ /**
+ * Property: _complete
+ *
+ * {Boolean}
+ */
+ _complete: false,
+
+ /**
+ * Constructor: OpenLayers.Ajax.Request
+ *
+ * Parameters:
+ * url - {String}
+ * options - {Object}
+ */
+ initialize: function(url, options) {
+ OpenLayers.Ajax.Base.prototype.initialize.apply(this, [options]);
+
+ if (OpenLayers.ProxyHost && OpenLayers.String.startsWith(url, "http")) {
+ url = OpenLayers.ProxyHost + encodeURIComponent(url);
+ }
+
+ this.transport = OpenLayers.Ajax.getTransport();
+ this.request(url);
+ },
+
+ /**
+ * Method: request
+ *
+ * Parameters:
+ * url - {String}
+ */
+ request: function(url) {
+ this.url = url;
+ this.method = this.options.method;
+ var params = OpenLayers.Util.extend({}, this.options.parameters);
+
+ if (this.method != 'get' && this.method != 'post') {
+ // simulate other verbs over post
+ params['_method'] = this.method;
+ this.method = 'post';
+ }
+
+ this.parameters = params;
+
+ if (params = OpenLayers.Util.getParameterString(params)) {
+ // when GET, append parameters to URL
+ if (this.method == 'get') {
+ this.url += ((this.url.indexOf('?') > -1) ? '&' : '?') + params;
+ } else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+ params += '&_=';
+ }
+ }
+ try {
+ var response = new OpenLayers.Ajax.Response(this);
+ if (this.options.onCreate) {
+ this.options.onCreate(response);
+ }
+
+ OpenLayers.Ajax.Responders.dispatch('onCreate',
+ this,
+ response);
+
+ this.transport.open(this.method.toUpperCase(),
+ this.url,
+ this.options.asynchronous);
+
+ if (this.options.asynchronous) {
+ window.setTimeout(
+ OpenLayers.Function.bind(this.respondToReadyState, this, 1),
+ 10);
+ }
+
+ this.transport.onreadystatechange =
+ OpenLayers.Function.bind(this.onStateChange, this);
+ this.setRequestHeaders();
+
+ this.body = this.method == 'post' ?
+ (this.options.postBody || params) : null;
+ this.transport.send(this.body);
+
+ // Force Firefox to handle ready state 4 for synchronous requests
+ if (!this.options.asynchronous &&
+ this.transport.overrideMimeType) {
+ this.onStateChange();
+ }
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ /**
+ * Method: onStateChange
+ */
+ onStateChange: function() {
+ var readyState = this.transport.readyState;
+ if (readyState > 1 && !((readyState == 4) && this._complete)) {
+ this.respondToReadyState(this.transport.readyState);
+ }
+ },
+
+ /**
+ * Method: setRequestHeaders
+ */
+ setRequestHeaders: function() {
+ var headers = {
+ 'X-Requested-With': 'XMLHttpRequest',
+ 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*',
+ 'OpenLayers': true
+ };
+
+ if (this.method == 'post') {
+ headers['Content-type'] = this.options.contentType +
+ (this.options.encoding ? '; charset=' + this.options.encoding : '');
+
+ /* Force "Connection: close" for older Mozilla browsers to work
+ * around a bug where XMLHttpRequest sends an incorrect
+ * Content-length header. See Mozilla Bugzilla #246651.
+ */
+ if (this.transport.overrideMimeType &&
+ (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) {
+ headers['Connection'] = 'close';
+ }
+ }
+ // user-defined headers
+ if (typeof this.options.requestHeaders == 'object') {
+ var extras = this.options.requestHeaders;
+
+ if (typeof extras.push == 'function') {
+ for (var i = 0, length = extras.length; i < length; i += 2) {
+ headers[extras[i]] = extras[i+1];
+ }
+ } else {
+ for (var i in extras) {
+ headers[i] = pair[i];
+ }
+ }
+ }
+
+ for (var name in headers) {
+ this.transport.setRequestHeader(name, headers[name]);
+ }
+ },
+
+ /**
+ * Method: success
+ *
+ * Returns:
+ * {Boolean} -
+ */
+ success: function() {
+ var status = this.getStatus();
+ return !status || (status >=200 && status < 300);
+ },
+
+ /**
+ * Method: getStatus
+ *
+ * Returns:
+ * {Integer} - Status
+ */
+ getStatus: function() {
+ try {
+ return this.transport.status || 0;
+ } catch (e) {
+ return 0;
+ }
+ },
+
+ /**
+ * Method: respondToReadyState
+ *
+ * Parameters:
+ * readyState - {?}
+ */
+ respondToReadyState: function(readyState) {
+ var state = OpenLayers.Ajax.Request.Events[readyState];
+ var response = new OpenLayers.Ajax.Response(this);
+
+ if (state == 'Complete') {
+ try {
+ this._complete = true;
+ (this.options['on' + response.status] ||
+ this.options['on' + (this.success() ? 'Success' : 'Failure')] ||
+ OpenLayers.Ajax.emptyFunction)(response);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ var contentType = response.getHeader('Content-type');
+ }
+
+ try {
+ (this.options['on' + state] ||
+ OpenLayers.Ajax.emptyFunction)(response);
+ OpenLayers.Ajax.Responders.dispatch('on' + state,
+ this,
+ response);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ if (state == 'Complete') {
+ // avoid memory leak in MSIE: clean up
+ this.transport.onreadystatechange = OpenLayers.Ajax.emptyFunction;
+ }
+ },
+
+ /**
+ * Method: getHeader
+ *
+ * Parameters:
+ * name - {String} Header name
+ *
+ * Returns:
+ * {?} - response header for the given name
+ */
+ getHeader: function(name) {
+ try {
+ return this.transport.getResponseHeader(name);
+ } catch (e) {
+ return null;
+ }
+ },
+
+ /**
+ * Method: dispatchException
+ * If the optional onException function is set, execute it
+ * and then dispatch the call to any other listener registered
+ * for onException.
+ *
+ * If no optional onException function is set, we suspect that
+ * the user may have also not used
+ * OpenLayers.Ajax.Responders.register to register a listener
+ * for the onException call. To make sure that something
+ * gets done with this exception, only dispatch the call if there
+ * are listeners.
+ *
+ * If you explicitly want to swallow exceptions, set
+ * request.options.onException to an empty function (function(){})
+ * or register an empty function with <OpenLayers.Ajax.Responders>
+ * for onException.
+ *
+ * Parameters:
+ * exception - {?}
+ */
+ dispatchException: function(exception) {
+ var handler = this.options.onException;
+ if(handler) {
+ // call options.onException and alert any other listeners
+ handler(this, exception);
+ OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
+ } else {
+ // check if there are any other listeners
+ var listener = false;
+ var responders = OpenLayers.Ajax.Responders.responders;
+ for (var i = 0; i < responders.length; i++) {
+ if(responders[i].onException) {
+ listener = true;
+ break;
+ }
+ }
+ if(listener) {
+ // call all listeners
+ OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
+ } else {
+ // let the exception through
+ throw exception;
+ }
+ }
+ }
+});
+
+/**
+ * Property: Events
+ * {Array(String)}
+ */
+OpenLayers.Ajax.Request.Events =
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+/**
+ * Class: OpenLayers.Ajax.Response
+ */
+OpenLayers.Ajax.Response = OpenLayers.Class({
+
+ /**
+ * Property: status
+ *
+ * {Integer}
+ */
+ status: 0,
+
+
+ /**
+ * Property: statusText
+ *
+ * {String}
+ */
+ statusText: '',
+
+ /**
+ * Constructor: OpenLayers.Ajax.Response
+ *
+ * Parameters:
+ * request - {Object}
+ */
+ initialize: function(request) {
+ this.request = request;
+ var transport = this.transport = request.transport,
+ readyState = this.readyState = transport.readyState;
+
+ if ((readyState > 2 &&
+ !(!!(window.attachEvent && !window.opera))) ||
+ readyState == 4) {
+ this.status = this.getStatus();
+ this.statusText = this.getStatusText();
+ this.responseText = transport.responseText == null ?
+ '' : String(transport.responseText);
+ }
+
+ if(readyState == 4) {
+ var xml = transport.responseXML;
+ this.responseXML = xml === undefined ? null : xml;
+ }
+ },
+
+ /**
+ * Method: getStatus
+ */
+ getStatus: OpenLayers.Ajax.Request.prototype.getStatus,
+
+ /**
+ * Method: getStatustext
+ *
+ * Returns:
+ * {String} - statusText
+ */
+ getStatusText: function() {
+ try {
+ return this.transport.statusText || '';
+ } catch (e) {
+ return '';
+ }
+ },
+
+ /**
+ * Method: getHeader
+ */
+ getHeader: OpenLayers.Ajax.Request.prototype.getHeader,
+
+ /**
+ * Method: getResponseHeader
+ *
+ * Returns:
+ * {?} - response header for given name
+ */
+ getResponseHeader: function(name) {
+ return this.transport.getResponseHeader(name);
+ }
+});
+
+
+/**
+ * Function: getElementsByTagNameNS
+ *
+ * Parameters:
+ * parentnode - {?}
+ * nsuri - {?}
+ * nsprefix - {?}
+ * tagname - {?}
+ *
+ * Returns:
+ * {?}
+ */
+OpenLayers.Ajax.getElementsByTagNameNS = function(parentnode, nsuri,
+ nsprefix, tagname) {
+ var elem = null;
+ if (parentnode.getElementsByTagNameNS) {
+ elem = parentnode.getElementsByTagNameNS(nsuri, tagname);
+ } else {
+ elem = parentnode.getElementsByTagName(nsprefix + ':' + tagname);
+ }
+ return elem;
+};
+
+
+/**
+ * Function: serializeXMLToString
+ * Wrapper function around XMLSerializer, which doesn't exist/work in
+ * IE/Safari. We need to come up with a way to serialize in those browser:
+ * for now, these browsers will just fail. #535, #536
+ *
+ * Parameters:
+ * xmldom {XMLNode} xml dom to serialize
+ *
+ * Returns:
+ * {?}
+ */
+OpenLayers.Ajax.serializeXMLToString = function(xmldom) {
+ var serializer = new XMLSerializer();
+ var data = serializer.serializeToString(xmldom);
+ return data;
+};
+/* ======================================================================
+ OpenLayers/Console.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * 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: 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.
+ */
+ if(window.console) {
+ var scripts = document.getElementsByTagName("script");
+ for(var i=0; i<scripts.length; ++i) {
+ if(scripts[i].src.indexOf("firebug.js") != -1) {
+ OpenLayers.Util.extend(OpenLayers.Console, console);
+ break;
+ }
+ }
+ }
+})();
+/* ======================================================================
+ OpenLayers/BaseTypes/Size.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Class: OpenLayers.Size
+ * Instances of this class represent a width/height pair
+ */
+OpenLayers.Size = OpenLayers.Class({
+
+ /**
+ * APIProperty: w
+ * {Number} width
+ */
+ w: 0.0,
+
+ /**
+ * APIProperty: h
+ * {Number} height
+ */
+ h: 0.0,
+
+
+ /**
+ * Constructor: OpenLayers.Size
+ * Create an instance of OpenLayers.Size
+ *
+ * Parameters:
+ * w - {Number} width
+ * h - {Number} height
+ */
+ initialize: function(w, h) {
+ this.w = parseFloat(w);
+ this.h = parseFloat(h);
+ },
+
+ /**
+ * Method: toString
+ * Return the string representation of a size object
+ *
+ * Returns:
+ * {String} The string representation of OpenLayers.Size object.
+ * (ex. <i>"w=55,h=66"</i>)
+ */
+ toString:function() {
+ return ("w=" + this.w + ",h=" + this.h);
+ },
+
+ /**
+ * APIMethod: clone
+ * Create a clone of this size object
+ *
+ * Returns:
+ * {<OpenLayers.Size>} A new OpenLayers.Size object with the same w and h
+ * values
+ */
+ clone:function() {
+ return new OpenLayers.Size(this.w, this.h);
+ },
+
+ /**
+ *
+ * APIMethod: equals
+ * Determine where this size is equal to another
+ *
+ * Parameters:
+ * sz - {<OpenLayers.Size>}
+ *
+ * Returns:
+ * {Boolean} The passed in size has the same h and w properties as this one.
+ * Note that if sz passed in is null, returns false.
+ *
+ */
+ equals:function(sz) {
+ var equals = false;
+ if (sz != null) {
+ equals = ((this.w == sz.w && this.h == sz.h) ||
+ (isNaN(this.w) && isNaN(this.h) && isNaN(sz.w) && isNaN(sz.h)));
+ }
+ return equals;
+ },
+
+ CLASS_NAME: "OpenLayers.Size"
+});
+/* ======================================================================
+ OpenLayers/BaseTypes/Bounds.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Class: OpenLayers.Bounds
+ * Instances of this class represent bounding boxes. Data stored as left,
+ * bottom, right, top floats. All values are initialized to null, however,
+ * you should make sure you set them before using the bounds for anything.
+ *
+ * Possible use case:
+ * > bounds = new OpenLayers.Bounds();
+ * > bounds.extend(new OpenLayers.LonLat(4,5));
+ * > bounds.extend(new OpenLayers.LonLat(5,6));
+ * > bounds.toBBOX(); // returns 4,5,5,6
+ */
+OpenLayers.Bounds = OpenLayers.Class({
+
+ /**
+ * Property: left
+ * {Number} Minimum horizontal coordinate.
+ */
+ left: null,
+
+ /**
+ * Property: bottom
+ * {Number} Minimum vertical coordinate.
+ */
+ bottom: null,
+
+ /**
+ * Property: right
+ * {Number} Maximum horizontal coordinate.
+ */
+ right: null,
+
+ /**
+ * Property: top
+ * {Number} Maximum vertical coordinate.
+ */
+ top: null,
+
+ /**
+ * Constructor: OpenLayers.Bounds
+ * Construct a new bounds object.
+ *
+ * Parameters:
+ * 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.
+ */
+ initialize: function(left, bottom, right, top) {
+ if (left != null) {
+ this.left = parseFloat(left);
+ }
+ if (bottom != null) {
+ this.bottom = parseFloat(bottom);
+ }
+ if (right != null) {
+ this.right = parseFloat(right);
+ }
+ if (top != null) {
+ this.top = parseFloat(top);
+ }
+ },
+
+ /**
+ * Method: clone
+ * Create a cloned instance of this bounds.
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} 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 - {<OpenLayers.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:
+ * {String} String representation of bounds object.
+ * (ex.<i>"left-bottom=(5,42) right-top=(10,45)"</i>)
+ */
+ toString:function() {
+ return ( "left-bottom=(" + this.left + "," + this.bottom + ")"
+ + " right-top=(" + this.right + "," + this.top + ")" );
+ },
+
+ /**
+ * APIMethod: toArray
+ *
+ * Returns:
+ * {Array} array of left, bottom, right, top
+ */
+ toArray: function() {
+ return [this.left, this.bottom, this.right, this.top];
+ },
+
+ /**
+ * APIMethod: toBBOX
+ *
+ * Parameters:
+ * decimal - {Integer} How many significant digits in the bbox coords?
+ * Default is 6
+ *
+ * Returns:
+ * {String} Simple String representation of bounds object.
+ * (ex. <i>"5,42,10,45"</i>)
+ */
+ toBBOX:function(decimal) {
+ if (decimal== null) {
+ decimal = 6;
+ }
+ var mult = Math.pow(10, decimal);
+ var bbox = Math.round(this.left * mult) / mult + "," +
+ Math.round(this.bottom * mult) / mult + "," +
+ Math.round(this.right * mult) / mult + "," +
+ Math.round(this.top * mult) / mult;
+
+ return bbox;
+ },
+
+ /**
+ * APIMethod: toGeometry
+ * Create a new polygon geometry based on this bounds.
+ *
+ * Returns:
+ * {<OpenLayers.Geometry.Polygon>} 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:
+ * {Float} The width of the bounds
+ */
+ getWidth:function() {
+ return (this.right - this.left);
+ },
+
+ /**
+ * APIMethod: getHeight
+ *
+ * Returns:
+ * {Float} The height of the bounds (top minus bottom).
+ */
+ getHeight:function() {
+ return (this.top - this.bottom);
+ },
+
+ /**
+ * APIMethod: getSize
+ *
+ * Returns:
+ * {<OpenLayers.Size>} The size of the box.
+ */
+ getSize:function() {
+ return new OpenLayers.Size(this.getWidth(), this.getHeight());
+ },
+
+ /**
+ * APIMethod: getCenterPixel
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} 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:
+ * {<OpenLayers.LonLat>} The center of the bounds in map space.
+ */
+ getCenterLonLat:function() {
+ return new OpenLayers.LonLat( (this.left + this.right) / 2,
+ (this.bottom + this.top) / 2);
+ },
+
+ /**
+ * APIMethod: add
+ *
+ * Parameters:
+ * x - {Float}
+ * y - {Float}
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} 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) ) {
+ var msg = OpenLayers.i18n("boundsAddError");
+ OpenLayers.Console.error(msg);
+ return null;
+ }
+ return new OpenLayers.Bounds(this.left + x, this.bottom + y,
+ this.right + x, this.top + y);
+ },
+
+ /**
+ * APIMethod: extend
+ * Extend the bounds to include the point, lonlat, or bounds specified.
+ * Note, this function assumes that left < right and bottom < top.
+ *
+ * Parameters:
+ * object - {Object} Can be LonLat, Point, or Bounds
+ */
+ extend:function(object) {
+ var bounds = null;
+ if (object) {
+ 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) {
+ 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
+ *
+ * Parameters:
+ * ll - {<OpenLayers.LonLat>}
+ * inclusive - {Boolean} Whether or not to include the border.
+ * Default is true.
+ *
+ * Returns:
+ * {Boolean} The passed-in lonlat is within this bounds.
+ */
+ containsLonLat:function(ll, inclusive) {
+ return this.contains(ll.lon, ll.lat, inclusive);
+ },
+
+ /**
+ * APIMethod: containsPixel
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ * 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
+ *
+ * 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;
+ }
+
+ 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
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * inclusive - {Boolean} Whether or not to include the border. Default
+ * is true.
+ *
+ * Returns:
+ * {Boolean} The passed-in OpenLayers.Bounds object intersects this bounds.
+ * Simple math just check if either contains the other, allowing for
+ * partial.
+ */
+ intersectsBounds:function(bounds, inclusive) {
+
+ if (inclusive == null) {
+ inclusive = true;
+ }
+ var inBottom = (bounds.bottom == this.bottom && bounds.top == this.top) ?
+ true : (((bounds.bottom > this.bottom) && (bounds.bottom < this.top)) ||
+ ((this.bottom > bounds.bottom) && (this.bottom < bounds.top)));
+ var inTop = (bounds.bottom == this.bottom && bounds.top == this.top) ?
+ true : (((bounds.top > this.bottom) && (bounds.top < this.top)) ||
+ ((this.top > bounds.bottom) && (this.top < bounds.top)));
+ var inRight = (bounds.right == this.right && bounds.left == this.left) ?
+ true : (((bounds.right > this.left) && (bounds.right < this.right)) ||
+ ((this.right > bounds.left) && (this.right < bounds.right)));
+ var inLeft = (bounds.right == this.right && bounds.left == this.left) ?
+ true : (((bounds.left > this.left) && (bounds.left < this.right)) ||
+ ((this.left > bounds.left) && (this.left < bounds.right)));
+
+ return (this.containsBounds(bounds, true, inclusive) ||
+ bounds.containsBounds(this, true, inclusive) ||
+ ((inTop || inBottom ) && (inLeft || inRight )));
+ },
+
+ /**
+ * APIMethod: containsBounds
+ *
+ * bounds - {<OpenLayers.Bounds>}
+ * partial - {Boolean} If true, only part of passed-in bounds needs be
+ * within this bounds. If false, the entire passed-in bounds must be
+ * within. Default is false
+ * inclusive - {Boolean} Whether or not to include the border. Default is
+ * true.
+ *
+ * Returns:
+ * {Boolean} The passed-in bounds object is contained within this bounds.
+ */
+ containsBounds:function(bounds, partial, inclusive) {
+
+ //set defaults
+ if (partial == null) {
+ partial = false;
+ }
+ if (inclusive == null) {
+ inclusive = true;
+ }
+
+ var inLeft;
+ var inTop;
+ var inRight;
+ var inBottom;
+
+ if (inclusive) {
+ inLeft = (bounds.left >= this.left) && (bounds.left <= this.right);
+ inTop = (bounds.top >= this.bottom) && (bounds.top <= this.top);
+ inRight= (bounds.right >= this.left) && (bounds.right <= this.right);
+ inBottom = (bounds.bottom >= this.bottom) && (bounds.bottom <= this.top);
+ } else {
+ inLeft = (bounds.left > this.left) && (bounds.left < this.right);
+ inTop = (bounds.top > this.bottom) && (bounds.top < this.top);
+ inRight= (bounds.right > this.left) && (bounds.right < this.right);
+ inBottom = (bounds.bottom > this.bottom) && (bounds.bottom < this.top);
+ }
+
+ return (partial) ? (inTop || inBottom ) && (inLeft || inRight )
+ : (inTop && inLeft && inBottom && inRight);
+ },
+
+ /**
+ * APIMethod: determineQuadrant
+ *
+ * Parameters:
+ * lonlat - {<OpenLayers.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 - {<OpenLayers.Projection>} Source projection.
+ * dest - {<OpenLayers.Projection>} Destination projection.
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} Itself, for use in chaining operations.
+ */
+ transform: function(source, dest) {
+ 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
+ *
+ * Parameters:
+ * maxExtent - {<OpenLayers.Bounds>}
+ * options - {Object} Some possible options are:
+ * 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:
+ * {<OpenLayers.Bounds>} 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 be
+ * merely a copy of this one.
+ */
+ wrapDateLine: function(maxExtent, options) {
+ options = options || {};
+
+ var leftTolerance = options.leftTolerance || 0;
+ var rightTolerance = options.rightTolerance || 0;
+
+ var newBounds = this.clone();
+
+ if (maxExtent) {
+
+ //shift right?
+ while ( newBounds.left < maxExtent.left &&
+ (newBounds.right - rightTolerance) <= maxExtent.left ) {
+ newBounds = newBounds.add(maxExtent.getWidth(), 0);
+ }
+
+ //shift left?
+ while ( (newBounds.left + leftTolerance) >= maxExtent.right &&
+ newBounds.right > maxExtent.right ) {
+ newBounds = newBounds.add(-maxExtent.getWidth(), 0);
+ }
+ }
+
+ return newBounds;
+ },
+
+ CLASS_NAME: "OpenLayers.Bounds"
+});
+
+/**
+ * APIFunction: fromString
+ * Alternative constructor that builds a new OpenLayers.Bounds from a
+ * parameter string
+ *
+ * Parameters:
+ * str - {String}Comma-separated bounds string. (ex. <i>"5,42,10,45"</i>)
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} New bounds object built from the
+ * passed-in String.
+ */
+OpenLayers.Bounds.fromString = function(str) {
+ var bounds = str.split(",");
+ return OpenLayers.Bounds.fromArray(bounds);
+};
+
+/**
+ * APIFunction: fromArray
+ * Alternative constructor that builds a new OpenLayers.Bounds
+ * from an array
+ *
+ * Parameters:
+ * bbox - {Array(Float)} Array of bounds values (ex. <i>[5,42,10,45]</i>)
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} New bounds object built from the passed-in Array.
+ */
+OpenLayers.Bounds.fromArray = function(bbox) {
+ return new OpenLayers.Bounds(parseFloat(bbox[0]),
+ parseFloat(bbox[1]),
+ parseFloat(bbox[2]),
+ parseFloat(bbox[3]));
+};
+
+/**
+ * APIFunction: fromSize
+ * Alternative constructor that builds a new OpenLayers.Bounds
+ * from a size
+ *
+ * Parameters:
+ * size - {<OpenLayers.Size>}
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} 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.
+ *
+ * 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-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * 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; i < arguments.length; i++) {
+ var element = OpenLayers.Util.getElement(arguments[i]);
+ var display = OpenLayers.Element.visible(element) ? 'hide'
+ : 'show';
+ OpenLayers.Element[display](element);
+ }
+ },
+
+
+ /**
+ * APIFunction: hide
+ * Hide element(s) passed in
+ *
+ * Parameters:
+ * element - {DOMElement} Actually user can pass any number of elements
+ */
+ hide: function() {
+ for (var i = 0; i < arguments.length; i++) {
+ var element = OpenLayers.Util.getElement(arguments[i]);
+ element.style.display = 'none';
+ }
+ },
+
+ /**
+ * APIFunction: show
+ * Show element(s) passed in
+ *
+ * Parameters:
+ * element - {DOMElement} Actually user can pass any number of elements
+ */
+ show: function() {
+ for (var i = 0; i < arguments.length; i++) {
+ var element = OpenLayers.Util.getElement(arguments[i]);
+ element.style.display = '';
+ }
+ },
+
+ /**
+ * APIFunction: remove
+ * Remove the specified element from the DOM.
+ *
+ * Parameters:
+ * element - {DOMElement}
+ */
+ remove: function(element) {
+ element = OpenLayers.Util.getElement(element);
+ element.parentNode.removeChild(element);
+ },
+
+ /**
+ * APIFunction: getHeight
+ *
+ * Parameters:
+ * element - {DOMElement}
+ *
+ * Returns:
+ * {Integer} The offset height of the element passed in
+ */
+ getHeight: function(element) {
+ element = OpenLayers.Util.getElement(element);
+ return element.offsetHeight;
+ },
+
+ /**
+ * APIFunction: getDimensions
+ *
+ * Parameters:
+ * element - {DOMElement}
+ *
+ * Returns:
+ * {Object} Object with 'width' and 'height' properties which are the
+ * dimensions of the element passed in.
+ */
+ getDimensions: function(element) {
+ element = OpenLayers.Util.getElement(element);
+ if (OpenLayers.Element.getStyle(element, 'display') != 'none') {
+ return {width: element.offsetWidth, height: element.offsetHeight};
+ }
+
+ // All *Width and *Height properties give 0 on elements with display none,
+ // so enable the element temporarily
+ var els = element.style;
+ var originalVisibility = els.visibility;
+ var originalPosition = els.position;
+ els.visibility = 'hidden';
+ els.position = 'absolute';
+ els.display = '';
+ var originalWidth = element.clientWidth;
+ var originalHeight = element.clientHeight;
+ els.display = 'none';
+ els.position = originalPosition;
+ els.visibility = originalVisibility;
+ return {width: originalWidth, height: originalHeight};
+ },
+
+ /**
+ * APIFunction: getStyle
+ *
+ * Parameters:
+ * element - {DOMElement}
+ * style - {?}
+ *
+ * Returns:
+ * {?}
+ */
+ getStyle: function(element, style) {
+ element = OpenLayers.Util.getElement(element);
+ var value = element.style[OpenLayers.String.camelize(style)];
+ if (!value) {
+ if (document.defaultView &&
+ document.defaultView.getComputedStyle) {
+
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css.getPropertyValue(style) : null;
+ } else if (element.currentStyle) {
+ value = element.currentStyle[OpenLayers.String.camelize(style)];
+ }
+ }
+
+ var positions = ['left', 'top', 'right', 'bottom'];
+ if (window.opera &&
+ (OpenLayers.Util.indexOf(positions,style) != -1) &&
+ (OpenLayers.Element.getStyle(element, 'position') == 'static')) {
+ value = 'auto';
+ }
+
+ return value == 'auto' ? null : value;
+ }
+
+};
+/* ======================================================================
+ OpenLayers/BaseTypes/LonLat.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Class: OpenLayers.LonLat
+ * This class represents a longitude and latitude pair
+ */
+OpenLayers.LonLat = OpenLayers.Class({
+
+ /**
+ * APIProperty: lon
+ * {Float} The x-axis coodinate in map units
+ */
+ lon: 0.0,
+
+ /**
+ * APIProperty: lat
+ * {Float} The y-axis coordinate in map units
+ */
+ lat: 0.0,
+
+ /**
+ * Constructor: OpenLayers.LonLat
+ * Create a new map location.
+ *
+ * Parameters:
+ * lon - {Number} The x-axis coordinate in map units. If your map is in
+ * a geographic projection, this will be the Longitude. Otherwise,
+ * it will be the x coordinate of the map location in your map units.
+ * lat - {Number} The y-axis coordinate in map units. If your map is in
+ * a geographic projection, this will be the Latitude. Otherwise,
+ * it will be the y coordinate of the map location in your map units.
+ */
+ initialize: function(lon, lat) {
+ this.lon = parseFloat(lon);
+ this.lat = parseFloat(lat);
+ },
+
+ /**
+ * Method: toString
+ * Return a readable string version of the lonlat
+ *
+ * Returns:
+ * {String} String representation of OpenLayers.LonLat object.
+ * (ex. <i>"lon=5,lat=42"</i>)
+ */
+ toString:function() {
+ return ("lon=" + this.lon + ",lat=" + this.lat);
+ },
+
+ /**
+ * APIMethod: toShortString
+ *
+ * Returns:
+ * {String} Shortened String representation of OpenLayers.LonLat object.
+ * (ex. <i>"5, 42"</i>)
+ */
+ toShortString:function() {
+ return (this.lon + ", " + this.lat);
+ },
+
+ /**
+ * APIMethod: clone
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} 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:
+ * {<OpenLayers.LonLat>} 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) ) {
+ var msg = OpenLayers.i18n("lonlatAddError");
+ OpenLayers.Console.error(msg);
+ return null;
+ }
+ return new OpenLayers.LonLat(this.lon + lon, this.lat + lat);
+ },
+
+ /**
+ * APIMethod: equals
+ *
+ * Parameters:
+ * ll - {<OpenLayers.LonLat>}
+ *
+ * Returns:
+ * {Boolean} Boolean value indicating whether the passed-in
+ * <OpenLayers.LonLat> 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.
+ *
+ * Parameters:
+ * source - {<OpenLayers.Projection>} Source projection.
+ * dest - {<OpenLayers.Projection>} Destination projection.
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} 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 - {<OpenLayers.Bounds>}
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} 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 <OpenLayers.LonLat> from a
+ * parameter string
+ *
+ * Parameters:
+ * str - {String} Comma-separated Lon,Lat coordinate string.
+ * (ex. <i>"5,40"</i>)
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} New <OpenLayers.LonLat> object built from the
+ * passed-in String.
+ */
+OpenLayers.LonLat.fromString = function(str) {
+ var pair = str.split(",");
+ return new OpenLayers.LonLat(parseFloat(pair[0]),
+ parseFloat(pair[1]));
+};
+/* ======================================================================
+ OpenLayers/BaseTypes/Pixel.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * 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:
+ * {<OpenLayers.Pixel>} 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 - {<OpenLayers.Pixel>}
+ *
+ * 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: add
+ *
+ * Parameters:
+ * x - {Integer}
+ * y - {Integer}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the
+ * values passed in.
+ */
+ add:function(x, y) {
+ if ( (x == null) || (y == null) ) {
+ var msg = OpenLayers.i18n("pixelAddError");
+ OpenLayers.Console.error(msg);
+ return null;
+ }
+ return new OpenLayers.Pixel(this.x + x, this.y + y);
+ },
+
+ /**
+ * APIMethod: offset
+ *
+ * Parameters
+ * px - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} 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/Control.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Class: OpenLayers.Control
+ * Controls affect the display or behavior of the map. They allow everything
+ * from panning and zooming to displaying a scale indicator. Controls by
+ * default are added to the map they are contained within however it is
+ * possible to add a control to an external div by passing the div in the
+ * options parameter.
+ *
+ * Example:
+ * The following example shows how to add many of the common controls
+ * to a map.
+ *
+ * > var map = new OpenLayers.Map('map', { controls: [] });
+ * >
+ * > map.addControl(new OpenLayers.Control.PanZoomBar());
+ * > map.addControl(new OpenLayers.Control.MouseToolbar());
+ * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
+ * > map.addControl(new OpenLayers.Control.Permalink());
+ * > map.addControl(new OpenLayers.Control.Permalink('permalink'));
+ * > map.addControl(new OpenLayers.Control.MousePosition());
+ * > map.addControl(new OpenLayers.Control.OverviewMap());
+ * > map.addControl(new OpenLayers.Control.KeyboardDefaults());
+ *
+ * The next code fragment is a quick example of how to intercept
+ * shift-mouse click to display the extent of the bounding box
+ * dragged out by the user. Usually controls are not created
+ * in exactly this manner. See the source for a more complete
+ * example:
+ *
+ * > var control = new OpenLayers.Control();
+ * > OpenLayers.Util.extend(control, {
+ * > draw: function () {
+ * > // this Handler.Box will intercept the shift-mousedown
+ * > // before Control.MouseDefault gets to see it
+ * > this.box = new OpenLayers.Handler.Box( control,
+ * > {"done": this.notice},
+ * > {keyMask: OpenLayers.Handler.MOD_SHIFT});
+ * > this.box.activate();
+ * > },
+ * >
+ * > notice: function (bounds) {
+ * > alert(bounds);
+ * > }
+ * > });
+ * > map.addControl(control);
+ *
+ */
+OpenLayers.Control = OpenLayers.Class({
+
+ /**
+ * Property: id
+ * {String}
+ */
+ id: null,
+
+ /**
+ * Property: map
+ * {<OpenLayers.Map>} this gets set in the addControl() function in
+ * OpenLayers.Map
+ */
+ map: null,
+
+ /**
+ * Property: div
+ * {DOMElement}
+ */
+ div: null,
+
+ /**
+ * Property: type
+ * {OpenLayers.Control.TYPES} Controls can have a 'type'. The type
+ * determines the type of interactions which are possible with them when
+ * they are placed into a toolbar.
+ */
+ type: null,
+
+ /**
+ * Property: allowSelection
+ * {Boolean} By deafault, controls do not allow selection, because
+ * it may interfere with map dragging. If this is true, OpenLayers
+ * will not prevent selection of the control.
+ * Default is false.
+ */
+ allowSelection: false,
+
+ /**
+ * Property: displayClass
+ * {string} This property is used for CSS related to the drawing of the
+ * Control.
+ */
+ displayClass: "",
+
+ /**
+ * Property: title
+ * {string} This property is used for showing a tooltip over the
+ * Control.
+ */
+ title: "",
+
+ /**
+ * Property: active
+ * {Boolean} The control is active.
+ */
+ active: null,
+
+ /**
+ * Property: handler
+ * {<OpenLayers.Handler>} null
+ */
+ handler: null,
+
+ /**
+ * APIProperty: eventListeners
+ * {Object} If set as an option at construction, the eventListeners
+ * object will be registered with <OpenLayers.Events.on>. Object
+ * structure must be a listeners object as shown in the example for
+ * the events.on method.
+ */
+ eventListeners: null,
+
+ /**
+ * Property: events
+ * {<OpenLayers.Events>} Events instance for triggering control specific
+ * events.
+ */
+ events: null,
+
+ /**
+ * Constant: EVENT_TYPES
+ * {Array(String)} Supported application event types. Register a listener
+ * for a particular event with the following syntax:
+ * (code)
+ * control.events.register(type, obj, listener);
+ * (end)
+ *
+ * Listeners will be called with a reference to an event object. The
+ * properties of this event depends on exactly what happened.
+ *
+ * All event objects have at least the following properties:
+ * - *object* {Object} A reference to control.events.object (a reference
+ * to the control).
+ * - *element* {DOMElement} A reference to control.events.element (which
+ * will be null unless documented otherwise).
+ *
+ * Supported map event types:
+ * - *activate* Triggered when activated.
+ * - *deactivate* Triggered when deactivated.
+ */
+ EVENT_TYPES: ["activate", "deactivate"],
+
+ /**
+ * Constructor: OpenLayers.Control
+ * Create an OpenLayers Control. The options passed as a parameter
+ * directly extend the control. For example passing the following:
+ *
+ * > var control = new OpenLayers.Control({div: myDiv});
+ *
+ * Overrides the default div attribute value of null.
+ *
+ * Parameters:
+ * options - {Object}
+ */
+ initialize: function (options) {
+ // We do this before the extend so that instances can override
+ // className in options.
+ this.displayClass =
+ this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, "");
+
+ OpenLayers.Util.extend(this, options);
+
+ this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
+ if(this.eventListeners instanceof Object) {
+ this.events.on(this.eventListeners);
+ }
+ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+ },
+
+ /**
+ * Method: destroy
+ * The destroy method is used to perform any clean up before the control
+ * is dereferenced. Typically this is where event listeners are removed
+ * to prevent memory leaks.
+ */
+ destroy: function () {
+ if(this.events) {
+ if(this.eventListeners) {
+ this.events.un(this.eventListeners);
+ }
+ this.events.destroy();
+ this.events = null;
+ }
+ this.eventListeners = null;
+
+ // eliminate circular references
+ if (this.handler) {
+ this.handler.destroy();
+ this.handler = null;
+ }
+ if(this.handlers) {
+ for(var key in this.handlers) {
+ if(this.handlers.hasOwnProperty(key) &&
+ typeof this.handlers[key].destroy == "function") {
+ this.handlers[key].destroy();
+ }
+ }
+ this.handlers = null;
+ }
+ if (this.map) {
+ this.map.removeControl(this);
+ this.map = null;
+ }
+ },
+
+ /**
+ * Method: setMap
+ * Set the map property for the control. This is done through an accessor
+ * so that subclasses can override this and take special action once
+ * they have their map variable set.
+ *
+ * Parameters:
+ * map - {<OpenLayers.Map>}
+ */
+ setMap: function(map) {
+ this.map = map;
+ if (this.handler) {
+ this.handler.setMap(map);
+ }
+ },
+
+ /**
+ * Method: draw
+ * The draw method is called when the control is ready to be displayed
+ * on the page. If a div has not been created one is created. Controls
+ * with a visual component will almost always want to override this method
+ * to customize the look of control.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>} The top-left pixel position of the control
+ * or null.
+ *
+ * Returns:
+ * {DOMElement} A reference to the DIV DOMElement containing the control
+ */
+ draw: function (px) {
+ if (this.div == null) {
+ this.div = OpenLayers.Util.createDiv(this.id);
+ this.div.className = this.displayClass;
+ if (!this.allowSelection) {
+ this.div.className += " olControlNoSelect";
+ this.div.setAttribute("unselectable", "on", 0);
+ this.div.onselectstart = function() { return(false); };
+ }
+ if (this.title != "") {
+ this.div.title = this.title;
+ }
+ }
+ if (px != null) {
+ this.position = px.clone();
+ }
+ this.moveTo(this.position);
+ return this.div;
+ },
+
+ /**
+ * Method: moveTo
+ * Sets the left and top style attributes to the passed in pixel
+ * coordinates.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ */
+ moveTo: function (px) {
+ if ((px != null) && (this.div != null)) {
+ this.div.style.left = px.x + "px";
+ this.div.style.top = px.y + "px";
+ }
+ },
+
+ /**
+ * Method: activate
+ * Explicitly activates a control and it's associated
+ * handler if one has been set. Controls can be
+ * deactivated by calling the deactivate() method.
+ *
+ * Returns:
+ * {Boolean} True if the control was successfully activated or
+ * false if the control was already active.
+ */
+ activate: function () {
+ if (this.active) {
+ return false;
+ }
+ if (this.handler) {
+ this.handler.activate();
+ }
+ this.active = true;
+ this.events.triggerEvent("activate");
+ return true;
+ },
+
+ /**
+ * Method: deactivate
+ * Deactivates a control and it's associated handler if any. The exact
+ * effect of this depends on the control itself.
+ *
+ * Returns:
+ * {Boolean} True if the control was effectively deactivated or false
+ * if the control was already inactive.
+ */
+ deactivate: function () {
+ if (this.active) {
+ if (this.handler) {
+ this.handler.deactivate();
+ }
+ this.active = false;
+ this.events.triggerEvent("deactivate");
+ return true;
+ }
+ return false;
+ },
+
+ CLASS_NAME: "OpenLayers.Control"
+});
+
+OpenLayers.Control.TYPE_BUTTON = 1;
+OpenLayers.Control.TYPE_TOGGLE = 2;
+OpenLayers.Control.TYPE_TOOL = 3;
+/* ======================================================================
+ OpenLayers/Icon.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * Class: OpenLayers.Icon
+ *
+ * The icon represents a graphical icon on the screen. Typically used in
+ * conjunction with a <OpenLayers.Marker> to represent markers on a screen.
+ *
+ * An icon has a url, size and position. It also contains an offset which
+ * allows the center point to be represented correctly. This can be
+ * provided either as a fixed offset or a function provided to calculate
+ * the desired offset.
+ *
+ */
+OpenLayers.Icon = OpenLayers.Class({
+
+ /**
+ * Property: url
+ * {String} image url
+ */
+ url: null,
+
+ /**
+ * Property: size
+ * {<OpenLayers.Size>}
+ */
+ size: null,
+
+ /**
+ * Property: offset
+ * {<OpenLayers.Pixel>} distance in pixels to offset the image when being rendered
+ */
+ offset: null,
+
+ /**
+ * Property: calculateOffset
+ * {<OpenLayers.Pixel>} Function to calculate the offset (based on the size)
+ */
+ calculateOffset: null,
+
+ /**
+ * Property: imageDiv
+ * {DOMElement}
+ */
+ imageDiv: null,
+
+ /**
+ * Property: px
+ * {<OpenLayers.Pixel>}
+ */
+ px: null,
+
+ /**
+ * Constructor: OpenLayers.Icon
+ * Creates an icon, which is an image tag in a div.
+ *
+ * url - {String}
+ * size - {<OpenLayers.Size>}
+ * offset - {<OpenLayers.Pixel>}
+ * calculateOffset - {Function}
+ */
+ initialize: function(url, size, offset, calculateOffset) {
+ this.url = url;
+ this.size = (size) ? size : new OpenLayers.Size(20,20);
+ this.offset = offset ? offset : new OpenLayers.Pixel(-(this.size.w/2), -(this.size.h/2));
+ this.calculateOffset = calculateOffset;
+
+ var id = OpenLayers.Util.createUniqueID("OL_Icon_");
+ this.imageDiv = OpenLayers.Util.createAlphaImageDiv(id);
+ },
+
+ /**
+ * Method: destroy
+ * Nullify references and remove event listeners to prevent circular
+ * references and memory leaks
+ */
+ destroy: function() {
+ OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);
+ this.imageDiv.innerHTML = "";
+ this.imageDiv = null;
+ },
+
+ /**
+ * Method: clone
+ *
+ * Returns:
+ * {<OpenLayers.Icon>} A fresh copy of the icon.
+ */
+ clone: function() {
+ return new OpenLayers.Icon(this.url,
+ this.size,
+ this.offset,
+ this.calculateOffset);
+ },
+
+ /**
+ * Method: setSize
+ *
+ * Parameters:
+ * size - {<OpenLayers.Size>}
+ */
+ setSize: function(size) {
+ if (size != null) {
+ this.size = size;
+ }
+ this.draw();
+ },
+
+ /**
+ * Method: setUrl
+ *
+ * Parameters:
+ * url - {String}
+ */
+ setUrl: function(url) {
+ if (url != null) {
+ this.url = url;
+ }
+ this.draw();
+ },
+
+ /**
+ * Method: draw
+ * Move the div to the given pixel.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {DOMElement} A new DOM Image of this icon set at the location passed-in
+ */
+ draw: function(px) {
+ OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,
+ null,
+ null,
+ this.size,
+ this.url,
+ "absolute");
+ this.moveTo(px);
+ return this.imageDiv;
+ },
+
+
+ /**
+ * Method: setOpacity
+ * Change the icon's opacity
+ *
+ * Parameters:
+ * opacity - {float}
+ */
+ setOpacity: function(opacity) {
+ OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null,
+ null, null, null, null, opacity);
+
+ },
+
+ /**
+ * Method: moveTo
+ * move icon to passed in px.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ */
+ moveTo: function (px) {
+ //if no px passed in, use stored location
+ if (px != null) {
+ this.px = px;
+ }
+
+ if (this.imageDiv != null) {
+ if (this.px == null) {
+ this.display(false);
+ } else {
+ if (this.calculateOffset) {
+ this.offset = this.calculateOffset(this.size);
+ }
+ var offsetPx = this.px.offset(this.offset);
+ OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, offsetPx);
+ }
+ }
+ },
+
+ /**
+ * Method: display
+ * Hide or show the icon
+ *
+ * Parameters:
+ * display - {Boolean}
+ */
+ display: function(display) {
+ this.imageDiv.style.display = (display) ? "" : "none";
+ },
+
+ CLASS_NAME: "OpenLayers.Icon"
+});
+/* ======================================================================
+ OpenLayers/Lang.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * Namespace: OpenLayers.Lang
+ * Internationalization namespace. Contains dictionaries in various languages
+ * and methods to set and get the current language.
+ */
+OpenLayers.Lang = {
+
+ /**
+ * Property: code
+ * {String} Current language code to use in OpenLayers. Use the
+ * <setCode> method to set this value and the <getCode> method to
+ * retrieve it.
+ */
+ code: null,
+
+ /**
+ * APIProperty: defaultCode
+ * {String} Default language to use when a specific language can't be
+ * found. Default is "en".
+ */
+ defaultCode: "en",
+
+ /**
+ * APIFunction: getCode
+ * Get the current language code.
+ *
+ * Returns:
+ * The current language code.
+ */
+ getCode: function() {
+ if(!OpenLayers.Lang.code) {
+ OpenLayers.Lang.setCode();
+ }
+ return OpenLayers.Lang.code;
+ },
+
+ /**
+ * APIFunction: setCode
+ * Set the language code for string translation. This code is used by
+ * the <OpenLayers.Lang.translate> method.
+ *
+ * Parameters-
+ * code - {String} These codes follow the IETF recommendations at
+ * http://www.ietf.org/rfc/rfc3066.txt. If no value is set, the
+ * browser's language setting will be tested. If no <OpenLayers.Lang>
+ * dictionary exists for the code, the <OpenLayers.String.defaultLang>
+ * will be used.
+ */
+ setCode: function(code) {
+ var lang;
+ if(!code) {
+ code = (OpenLayers.Util.getBrowserName() == "msie") ?
+ navigator.userLanguage : navigator.language;
+ }
+ var parts = code.split('-');
+ parts[0] = parts[0].toLowerCase();
+ if(typeof OpenLayers.Lang[parts[0]] == "object") {
+ lang = parts[0];
+ }
+
+ // check for regional extensions
+ if(parts[1]) {
+ var testLang = parts[0] + '-' + parts[1].toUpperCase();
+ if(typeof OpenLayers.Lang[testLang] == "object") {
+ lang = testLang;
+ }
+ }
+ if(!lang) {
+ OpenLayers.Console.warn(
+ 'Failed to find OpenLayers.Lang.' + parts.join("-") +
+ ' dictionary, falling back to default language'
+ );
+ lang = OpenLayers.Lang.defaultCode;
+ }
+
+ OpenLayers.Lang.code = lang;
+ },
+
+ /**
+ * APIMethod: translate
+ * Looks up a key from a dictionary based on the current language string.
+ * The value of <getCode> will be used to determine the appropriate
+ * dictionary. Dictionaries are stored in <OpenLayers.Lang>.
+ *
+ * Parameters:
+ * key - {String} The key for an i18n string value in the dictionary.
+ * context - {Object} Optional context to be used with
+ * <OpenLayers.String.format>.
+ *
+ * Returns:
+ * {String} A internationalized string.
+ */
+ translate: function(key, context) {
+ var dictionary = OpenLayers.Lang[OpenLayers.Lang.getCode()];
+ var message = dictionary[key];
+ if(!message) {
+ // Message not found, fall back to message key
+ message = key;
+ }
+ if(context) {
+ message = OpenLayers.String.format(message, context);
+ }
+ return message;
+ }
+
+};
+
+
+/**
+ * APIMethod: OpenLayers.i18n
+ * Alias for <OpenLayers.Lang.translate>. Looks up a key from a dictionary
+ * based on the current language string. The value of
+ * <OpenLayers.Lang.getCode> will be used to determine the appropriate
+ * dictionary. Dictionaries are stored in <OpenLayers.Lang>.
+ *
+ * Parameters:
+ * key - {String} The key for an i18n string value in the dictionary.
+ * context - {Object} Optional context to be used with
+ * <OpenLayers.String.format>.
+ *
+ * Returns:
+ * {String} A internationalized string.
+ */
+OpenLayers.i18n = OpenLayers.Lang.translate;
+/* ======================================================================
+ OpenLayers/Tween.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * Namespace: OpenLayers.Tween
+ */
+OpenLayers.Tween = OpenLayers.Class({
+
+ /**
+ * Constant: INTERVAL
+ * {int} Interval in milliseconds between 2 steps
+ */
+ INTERVAL: 10,
+
+ /**
+ * APIProperty: easing
+ * {<OpenLayers.Easing>(Function)} Easing equation used for the animation
+ * Defaultly set to OpenLayers.Easing.Expo.easeOut
+ */
+ easing: null,
+
+ /**
+ * APIProperty: begin
+ * {Object} Values to start the animation with
+ */
+ begin: null,
+
+ /**
+ * APIProperty: finish
+ * {Object} Values to finish the animation with
+ */
+ finish: null,
+
+ /**
+ * APIProperty: duration
+ * {int} duration of the tween (number of steps)
+ */
+ duration: null,
+
+ /**
+ * APIProperty: callbacks
+ * {Object} An object with start, eachStep and done properties whose values
+ * are functions to be call during the animation. They are passed the
+ * current computed value as argument.
+ */
+ callbacks: null,
+
+ /**
+ * Property: time
+ * {int} Step counter
+ */
+ time: null,
+
+ /**
+ * Property: interval
+ * {int} Interval id returned by window.setInterval
+ */
+ interval: null,
+
+ /**
+ * Property: playing
+ * {Boolean} Tells if the easing is currently playing
+ */
+ playing: false,
+
+ /**
+ * Constructor: OpenLayers.Tween
+ * Creates a Tween.
+ *
+ * Parameters:
+ * easing - {<OpenLayers.Easing>(Function)} easing function method to use
+ */
+ initialize: function(easing) {
+ this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut;
+ },
+
+ /**
+ * APIMethod: start
+ * Plays the Tween, and calls the callback method on each step
+ *
+ * Parameters:
+ * begin - {Object} values to start the animation with
+ * finish - {Object} values to finish the animation with
+ * duration - {int} duration of the tween (number of steps)
+ * options - {Object} hash of options (for example callbacks (start, eachStep, done))
+ */
+ start: function(begin, finish, duration, options) {
+ this.playing = true;
+ this.begin = begin;
+ this.finish = finish;
+ this.duration = duration;
+ this.callbacks = options.callbacks;
+ this.time = 0;
+ if (this.interval) {
+ window.clearInterval(this.interval);
+ this.interval = null;
+ }
+ if (this.callbacks && this.callbacks.start) {
+ this.callbacks.start.call(this, this.begin);
+ }
+ this.interval = window.setInterval(
+ OpenLayers.Function.bind(this.play, this), this.INTERVAL);
+ },
+
+ /**
+ * APIMethod: stop
+ * Stops the Tween, and calls the done callback
+ * Doesn't do anything if animation is already finished
+ */
+ stop: function() {
+ if (!this.playing) {
+ return;
+ }
+
+ if (this.callbacks && this.callbacks.done) {
+ this.callbacks.done.call(this, this.finish);
+ }
+ window.clearInterval(this.interval);
+ this.interval = null;
+ this.playing = false;
+ },
+
+ /**
+ * Method: play
+ * Calls the appropriate easing method
+ */
+ play: function() {
+ var value = {};
+ for (var i in this.begin) {
+ var b = this.begin[i];
+ var f = this.finish[i];
+ if (b == null || f == null || isNaN(b) || isNaN(f)) {
+ OpenLayers.Console.error('invalid value for Tween');
+ }
+
+ var c = f - b;
+ value[i] = this.easing.apply(this, [this.time, b, c, this.duration]);
+ }
+ this.time++;
+
+ if (this.callbacks && this.callbacks.eachStep) {
+ this.callbacks.eachStep.call(this, value);
+ }
+
+ if (this.time > this.duration) {
+ if (this.callbacks && this.callbacks.done) {
+ this.callbacks.done.call(this, this.finish);
+ this.playing = false;
+ }
+ window.clearInterval(this.interval);
+ this.interval = null;
+ }
+ },
+
+ /**
+ * Create empty functions for all easing methods.
+ */
+ CLASS_NAME: "OpenLayers.Tween"
+});
+
+/**
+ * Namespace: OpenLayers.Easing
+ *
+ * Credits:
+ * Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>
+ */
+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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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/Control/ArgParser.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.ArgParser
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.ArgParser = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Parameter: center
+ * {<OpenLayers.LonLat>}
+ */
+ center: null,
+
+ /**
+ * Parameter: zoom
+ * {int}
+ */
+ zoom: null,
+
+ /**
+ * Parameter: layers
+ * {Array(<OpenLayers.Layer>)}
+ */
+ layers: null,
+
+ /**
+ * APIProperty: displayProjection
+ * {<OpenLayers.Projection>} Requires proj4js support.
+ * Projection used when reading the coordinates from the URL. This will
+ * reproject the map coordinates from the URL into the map's
+ * projection.
+ *
+ * If you are using this functionality, be aware that any permalink
+ * which is added to the map will determine the coordinate type which
+ * is read from the URL, which means you should not add permalinks with
+ * different displayProjections to the same map.
+ */
+ displayProjection: null,
+
+ /**
+ * Constructor: OpenLayers.Control.ArgParser
+ *
+ * Parameters:
+ * options - {Object}
+ */
+ initialize: function(options) {
+ OpenLayers.Control.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * Method: setMap
+ * Set the map property for the control.
+ *
+ * Parameters:
+ * map - {<OpenLayers.Map>}
+ */
+ setMap: function(map) {
+ OpenLayers.Control.prototype.setMap.apply(this, arguments);
+
+ //make sure we dont already have an arg parser attached
+ for(var i=0; i< this.map.controls.length; i++) {
+ var control = this.map.controls[i];
+ if ( (control != this) &&
+ (control.CLASS_NAME == "OpenLayers.Control.ArgParser") ) {
+
+ // If a second argparser is added to the map, then we
+ // override the displayProjection to be the one added to the
+ // map.
+ if (control.displayProjection != this.displayProjection) {
+ this.displayProjection = control.displayProjection;
+ }
+
+ break;
+ }
+ }
+ if (i == this.map.controls.length) {
+
+ var args = OpenLayers.Util.getParameters();
+ // Be careful to set layer first, to not trigger unnecessary layer loads
+ if (args.layers) {
+ this.layers = args.layers;
+
+ // when we add a new layer, set its visibility
+ this.map.events.register('addlayer', this,
+ this.configureLayers);
+ this.configureLayers();
+ }
+ if (args.lat && args.lon) {
+ this.center = new OpenLayers.LonLat(parseFloat(args.lon),
+ parseFloat(args.lat));
+ if (args.zoom) {
+ this.zoom = parseInt(args.zoom);
+ }
+
+ // when we add a new baselayer to see when we can set the center
+ this.map.events.register('changebaselayer', this,
+ this.setCenter);
+ this.setCenter();
+ }
+ }
+ },
+
+ /**
+ * Method: setCenter
+ * As soon as a baseLayer has been loaded, we center and zoom
+ * ...and remove the handler.
+ */
+ setCenter: function() {
+
+ if (this.map.baseLayer) {
+ //dont need to listen for this one anymore
+ this.map.events.unregister('changebaselayer', this,
+ this.setCenter);
+
+ if (this.displayProjection) {
+ this.center.transform(this.displayProjection,
+ this.map.getProjectionObject());
+ }
+
+ this.map.setCenter(this.center, this.zoom);
+ }
+ },
+
+ /**
+ * Method: configureLayers
+ * As soon as all the layers are loaded, cycle through them and
+ * hide or show them.
+ */
+ configureLayers: function() {
+
+ if (this.layers.length == this.map.layers.length) {
+ this.map.events.unregister('addlayer', this, this.configureLayers);
+
+ for(var i=0; i < this.layers.length; i++) {
+
+ var layer = this.map.layers[i];
+ var c = this.layers.charAt(i);
+
+ if (c == "B") {
+ this.map.setBaseLayer(layer);
+ } else if ( (c == "T") || (c == "F") ) {
+ layer.setVisibility(c == "T");
+ }
+ }
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Control.ArgParser"
+});
+/* ======================================================================
+ OpenLayers/Control/MousePosition.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.MousePosition
+ */
+OpenLayers.Control.MousePosition = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Property: element
+ * {DOMElement}
+ */
+ element: null,
+
+ /**
+ * APIProperty: prefix
+ * {String}
+ */
+ prefix: '',
+
+ /**
+ * APIProperty: separator
+ * {String}
+ */
+ separator: ', ',
+
+ /**
+ * APIProperty: suffix
+ * {String}
+ */
+ suffix: '',
+
+ /**
+ * APIProperty: numDigits
+ * {Integer}
+ */
+ numdigits: 5,
+
+ /**
+ * APIProperty: granularity
+ * {Integer}
+ */
+ granularity: 10,
+
+ /**
+ * Property: lastXy
+ * {<OpenLayers.LonLat>}
+ */
+ lastXy: null,
+
+ /**
+ * APIProperty: displayProjection
+ * {<OpenLayers.Projection>} A projection that the
+ * mousecontrol will display.
+ */
+ displayProjection: null,
+
+ /**
+ * Constructor: OpenLayers.Control.MousePosition
+ *
+ * Parameters:
+ * options - {DOMElement} Options for control.
+ */
+ initialize: function(options) {
+ OpenLayers.Control.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * Method: destroy
+ */
+ destroy: function() {
+ if (this.map) {
+ this.map.events.unregister('mousemove', this, this.redraw);
+ }
+ OpenLayers.Control.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: draw
+ * {DOMElement}
+ */
+ draw: function() {
+ OpenLayers.Control.prototype.draw.apply(this, arguments);
+
+ if (!this.element) {
+ this.div.left = "";
+ this.div.top = "";
+ this.element = this.div;
+ }
+
+ this.redraw();
+ return this.div;
+ },
+
+ /**
+ * Method: redraw
+ */
+ redraw: function(evt) {
+
+ var lonLat;
+
+ if (evt == null) {
+ lonLat = new OpenLayers.LonLat(0, 0);
+ } else {
+ if (this.lastXy == null ||
+ Math.abs(evt.xy.x - this.lastXy.x) > this.granularity ||
+ Math.abs(evt.xy.y - this.lastXy.y) > this.granularity)
+ {
+ this.lastXy = evt.xy;
+ return;
+ }
+
+ lonLat = this.map.getLonLatFromPixel(evt.xy);
+ if (!lonLat) {
+ // map has not yet been properly initialized
+ return;
+ }
+ if (this.displayProjection) {
+ lonLat.transform(this.map.getProjectionObject(),
+ this.displayProjection );
+ }
+ this.lastXy = evt.xy;
+
+ }
+
+ var newHtml = this.formatOutput(lonLat);
+
+ if (newHtml != this.element.innerHTML) {
+ this.element.innerHTML = newHtml;
+ }
+ },
+
+ /**
+ * Method: formatOutput
+ * Override to provide custom display output
+ *
+ * Parameters:
+ * lonLat - {<OpenLayers.LonLat>} Location to display
+ */
+ formatOutput: function(lonLat) {
+ var digits = parseInt(this.numdigits);
+ var newHtml =
+ this.prefix +
+ lonLat.lon.toFixed(digits) +
+ this.separator +
+ lonLat.lat.toFixed(digits) +
+ this.suffix;
+ return newHtml;
+ },
+
+ /**
+ * Method: setMap
+ */
+ setMap: function() {
+ OpenLayers.Control.prototype.setMap.apply(this, arguments);
+ this.map.events.register( 'mousemove', this, this.redraw);
+ },
+
+ CLASS_NAME: "OpenLayers.Control.MousePosition"
+});
+/* ======================================================================
+ OpenLayers/Control/PanZoom.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.PanZoom
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.PanZoom = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * APIProperty: slideFactor
+ * {Integer} Number of pixels by which we'll pan the map in any direction
+ * on clicking the arrow buttons.
+ */
+ slideFactor: 50,
+
+ /**
+ * Property: buttons
+ * {Array(DOMElement)} Array of Button Divs
+ */
+ buttons: null,
+
+ /**
+ * Property: position
+ * {<OpenLayers.Pixel>}
+ */
+ position: null,
+
+ /**
+ * Constructor: OpenLayers.Control.PanZoom
+ *
+ * Parameters:
+ * options - {Object}
+ */
+ initialize: function(options) {
+ this.position = new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,
+ OpenLayers.Control.PanZoom.Y);
+ OpenLayers.Control.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * APIMethod: destroy
+ */
+ destroy: function() {
+ OpenLayers.Control.prototype.destroy.apply(this, arguments);
+ while(this.buttons.length) {
+ var btn = this.buttons.shift();
+ btn.map = null;
+ OpenLayers.Event.stopObservingElement(btn);
+ }
+ this.buttons = null;
+ this.position = null;
+ },
+
+ /**
+ * Method: draw
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {DOMElement} A reference to the container div for the PanZoom control.
+ */
+ draw: function(px) {
+ // initialize our internal div
+ OpenLayers.Control.prototype.draw.apply(this, arguments);
+ px = this.position;
+
+ // place the controls
+ this.buttons = [];
+
+ var sz = new OpenLayers.Size(18,18);
+ var centered = new OpenLayers.Pixel(px.x+sz.w/2, px.y);
+
+ this._addButton("panup", "north-mini.png", centered, sz);
+ px.y = centered.y+sz.h;
+ this._addButton("panleft", "west-mini.png", px, sz);
+ this._addButton("panright", "east-mini.png", px.add(sz.w, 0), sz);
+ this._addButton("pandown", "south-mini.png",
+ centered.add(0, sz.h*2), sz);
+ this._addButton("zoomin", "zoom-plus-mini.png",
+ centered.add(0, sz.h*3+5), sz);
+ this._addButton("zoomworld", "zoom-world-mini.png",
+ centered.add(0, sz.h*4+5), sz);
+ this._addButton("zoomout", "zoom-minus-mini.png",
+ centered.add(0, sz.h*5+5), sz);
+ return this.div;
+ },
+
+ /**
+ * Method: _addButton
+ *
+ * Parameters:
+ * id - {String}
+ * img - {String}
+ * xy - {<OpenLayers.Pixel>}
+ * sz - {<OpenLayers.Size>}
+ *
+ * Returns:
+ * {DOMElement} A Div (an alphaImageDiv, to be precise) that contains the
+ * image of the button, and has all the proper event handlers set.
+ */
+ _addButton:function(id, img, xy, sz) {
+ var imgLocation = OpenLayers.Util.getImagesLocation() + img;
+ var btn = OpenLayers.Util.createAlphaImageDiv(
+ "OpenLayers_Control_PanZoom_" + id,
+ xy, sz, imgLocation, "absolute");
+
+ //we want to add the outer div
+ this.div.appendChild(btn);
+
+ OpenLayers.Event.observe(btn, "mousedown",
+ OpenLayers.Function.bindAsEventListener(this.buttonDown, btn));
+ OpenLayers.Event.observe(btn, "dblclick",
+ OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
+ OpenLayers.Event.observe(btn, "click",
+ OpenLayers.Function.bindAsEventListener(this.doubleClick, btn));
+ btn.action = id;
+ btn.map = this.map;
+ btn.slideFactor = this.slideFactor;
+
+ //we want to remember/reference the outer div
+ this.buttons.push(btn);
+ return btn;
+ },
+
+ /**
+ * Method: doubleClick
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean}
+ */
+ doubleClick: function (evt) {
+ OpenLayers.Event.stop(evt);
+ return false;
+ },
+
+ /**
+ * Method: buttonDown
+ *
+ * Parameters:
+ * evt - {Event}
+ */
+ buttonDown: function (evt) {
+ if (!OpenLayers.Event.isLeftClick(evt)) {
+ return;
+ }
+
+ switch (this.action) {
+ case "panup":
+ this.map.pan(0, -this.slideFactor);
+ break;
+ case "pandown":
+ this.map.pan(0, this.slideFactor);
+ break;
+ case "panleft":
+ this.map.pan(-this.slideFactor, 0);
+ break;
+ case "panright":
+ this.map.pan(this.slideFactor, 0);
+ break;
+ case "zoomin":
+ this.map.zoomIn();
+ break;
+ case "zoomout":
+ this.map.zoomOut();
+ break;
+ case "zoomworld":
+ this.map.zoomToMaxExtent();
+ break;
+ }
+
+ OpenLayers.Event.stop(evt);
+ },
+
+ CLASS_NAME: "OpenLayers.Control.PanZoom"
+});
+
+/**
+ * Constant: X
+ * {Integer}
+ */
+OpenLayers.Control.PanZoom.X = 4;
+
+/**
+ * Constant: Y
+ * {Integer}
+ */
+OpenLayers.Control.PanZoom.Y = 4;
+/* ======================================================================
+ OpenLayers/Control/ScaleLine.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ */
+
+/**
+ * Class: OpenLayers.Control.ScaleLine
+ * Display a small line indicator representing the current map scale on the map.
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ *
+ * Is a very close copy of:
+ * - <OpenLayers.Control.Scale>
+ */
+OpenLayers.Control.ScaleLine = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Property: maxWidth
+ * {Integer} Maximum width of the scale line in pixels. Default is 100.
+ */
+ maxWidth: 100,
+
+ /**
+ * Property: topOutUnits
+ * {String} Units for zoomed out on top bar. Default is km.
+ */
+ topOutUnits: "km",
+
+ /**
+ * Property: topInUnits
+ * {String} Units for zoomed in on top bar. Default is m.
+ */
+ topInUnits: "m",
+
+ /**
+ * Property: bottomOutUnits
+ * {String} Units for zoomed out on bottom bar. Default is mi.
+ */
+ bottomOutUnits: "mi",
+
+ /**
+ * Property: bottomInUnits
+ * {String} Units for zoomed in on bottom bar. Default is ft.
+ */
+ bottomInUnits: "ft",
+
+ /**
+ * Property: eTop
+ * {DOMElement}
+ */
+ eTop: null,
+
+ /**
+ * Property: eBottom
+ * {DOMElement}
+ */
+ eBottom:null,
+
+ /**
+ * Constructor: OpenLayers.ScaleLine
+ * Create a new scale line control.
+ *
+ * Parameters:
+ * options - {Object} An optional object whose properties will be used
+ * to extend the control.
+ */
+ initialize: function(options) {
+ OpenLayers.Control.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * Method: draw
+ *
+ * Returns:
+ * {DOMElement}
+ */
+ draw: function() {
+ OpenLayers.Control.prototype.draw.apply(this, arguments);
+ if (!this.eTop) {
+ this.div.style.display = "block";
+ this.div.style.position = "absolute";
+
+ // stick in the top bar
+ this.eTop = document.createElement("div");
+ this.eTop.className = this.displayClass + "Top";
+ var theLen = this.topInUnits.length;
+ this.div.appendChild(this.eTop);
+ if((this.topOutUnits == "") || (this.topInUnits == "")) {
+ this.eTop.style.visibility = "hidden";
+ } else {
+ this.eTop.style.visibility = "visible";
+ }
+
+ // and the bottom bar
+ this.eBottom = document.createElement("div");
+ this.eBottom.className = this.displayClass + "Bottom";
+ this.div.appendChild(this.eBottom);
+ if((this.bottomOutUnits == "") || (this.bottomInUnits == "")) {
+ this.eBottom.style.visibility = "hidden";
+ } else {
+ this.eBottom.style.visibility = "visible";
+ }
+ }
+ this.map.events.register('moveend', this, this.update);
+ this.update();
+ return this.div;
+ },
+
+ /**
+ * Method: getBarLen
+ * Given a number, round it down to the nearest 1,2,5 times a power of 10.
+ * That seems a fairly useful set of number groups to use.
+ *
+ * Parameters:
+ * maxLen - {float} the number we're rounding down from
+ *
+ * Returns:
+ * {Float} the rounded number (less than or equal to maxLen)
+ */
+ getBarLen: function(maxLen) {
+ // nearest power of 10 lower than maxLen
+ var digits = parseInt(Math.log(maxLen) / Math.log(10));
+ var pow10 = Math.pow(10, digits);
+
+ // ok, find first character
+ var firstChar = parseInt(maxLen / pow10);
+
+ // right, put it into the correct bracket
+ var barLen;
+ if(firstChar > 5) {
+ barLen = 5;
+ } else if(firstChar > 2) {
+ barLen = 2;
+ } else {
+ barLen = 1;
+ }
+
+ // scale it up the correct power of 10
+ return barLen * pow10;
+ },
+
+ /**
+ * Method: update
+ * Update the size of the bars, and the labels they contain.
+ */
+ update: function() {
+ var res = this.map.getResolution();
+ if (!res) {
+ return;
+ }
+
+ var curMapUnits = this.map.units;
+ var inches = OpenLayers.INCHES_PER_UNIT;
+
+ // convert maxWidth to map units
+ var maxSizeData = this.maxWidth * res * inches[curMapUnits];
+
+ // decide whether to use large or small scale units
+ var topUnits;
+ var bottomUnits;
+ if(maxSizeData > 100000) {
+ topUnits = this.topOutUnits;
+ bottomUnits = this.bottomOutUnits;
+ } else {
+ topUnits = this.topInUnits;
+ bottomUnits = this.bottomInUnits;
+ }
+
+ // and to map units units
+ var topMax = maxSizeData / inches[topUnits];
+ var bottomMax = maxSizeData / inches[bottomUnits];
+
+ // now trim this down to useful block length
+ var topRounded = this.getBarLen(topMax);
+ var bottomRounded = this.getBarLen(bottomMax);
+
+ // and back to display units
+ topMax = topRounded / inches[curMapUnits] * inches[topUnits];
+ bottomMax = bottomRounded / inches[curMapUnits] * inches[bottomUnits];
+
+ // and to pixel units
+ var topPx = topMax / res;
+ var bottomPx = bottomMax / res;
+
+ // now set the pixel widths
+ this.eTop.style.width = Math.round(topPx) + "px";
+ this.eBottom.style.width = Math.round(bottomPx) + "px";
+
+ // and the values inside them
+ this.eTop.innerHTML = topRounded + " " + topUnits;
+ this.eBottom.innerHTML = bottomRounded + " " + bottomUnits ;
+ },
+
+ CLASS_NAME: "OpenLayers.Control.ScaleLine"
+});
+
+/* ======================================================================
+ OpenLayers/Events.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Util.js
+ */
+
+/**
+ * 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_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: 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: 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 false
+ */
+ stop: function(event, allowDefault) {
+
+ if (!allowDefault) {
+ if (event.preventDefault) {
+ event.preventDefault();
+ } else {
+ event.returnValue = false;
+ }
+ }
+
+ if (event.stopPropagation) {
+ event.stopPropagation();
+ } else {
+ event.cancelBubble = true;
+ }
+ },
+
+ /**
+ * 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];
+ var args = new Array(entry.element,
+ entry.name,
+ entry.observer,
+ entry.useCapture);
+ var removed = OpenLayers.Event.stopObserving.apply(this, args);
+ }
+ }
+ },
+
+ /**
+ * 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);
+
+// FIXME: Remove this in 3.0. In 3.0, Event.stop will no longer be provided
+// by OpenLayers.
+if (window.Event) {
+ OpenLayers.Util.applyDefaults(window.Event, OpenLayers.Event);
+} else {
+ var Event = OpenLayers.Event;
+}
+
+/**
+ * Class: OpenLayers.Events
+ */
+OpenLayers.Events = OpenLayers.Class({
+
+ /**
+ * Constant: BROWSER_EVENTS
+ * {Array(String)} supported events
+ */
+ BROWSER_EVENTS: [
+ "mouseover", "mouseout",
+ "mousedown", "mouseup", "mousemove",
+ "click", "dblclick",
+ "resize", "focus", "blur"
+ ],
+
+ /**
+ * 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: eventTypes
+ * {Array(String)} list of support application events
+ */
+ eventTypes: null,
+
+ /**
+ * Property: eventHandler
+ * {Function} bound event handler attached to elements
+ */
+ eventHandler: null,
+
+ /**
+ * APIProperty: fallThrough
+ * {Boolean}
+ */
+ fallThrough: 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)} Array of custom application events
+ * fallThrough - {Boolean} Allow events to fall through after these have
+ * been handled?
+ */
+ initialize: function (object, element, eventTypes, fallThrough) {
+ this.object = object;
+ this.element = element;
+ this.eventTypes = eventTypes;
+ this.fallThrough = fallThrough;
+ this.listeners = {};
+
+ // 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
+ );
+
+ // if eventTypes is specified, create a listeners list for each
+ // custom application event.
+ if (this.eventTypes != null) {
+ for (var i = 0; i < this.eventTypes.length; i++) {
+ this.addEventType(this.eventTypes[i]);
+ }
+ }
+
+ // if a dom element is specified, add a listeners list
+ // for browser events on the element and register them
+ if (this.element != null) {
+ this.attachToElement(element);
+ }
+ },
+
+ /**
+ * APIMethod: destroy
+ */
+ destroy: function () {
+ if (this.element) {
+ OpenLayers.Event.stopObservingElement(this.element);
+ }
+ this.element = null;
+
+ this.listeners = null;
+ this.object = null;
+ this.eventTypes = null;
+ this.fallThrough = null;
+ this.eventHandler = null;
+ },
+
+ /**
+ * APIMethod: addEventType
+ * Add a new event type to this events object.
+ * If the event type has already been added, do nothing.
+ *
+ * Parameters:
+ * eventName - {String}
+ */
+ addEventType: function(eventName) {
+ if (!this.listeners[eventName]) {
+ this.listeners[eventName] = [];
+ }
+ },
+
+ /**
+ * Method: attachToElement
+ *
+ * Parameters:
+ * element - {HTMLDOMElement} a DOM element to attach browser events to
+ */
+ attachToElement: function (element) {
+ for (var i = 0; i < this.BROWSER_EVENTS.length; i++) {
+ var eventType = this.BROWSER_EVENTS[i];
+
+ // every browser event has a corresponding application event
+ // (whether it's listened for or not).
+ this.addEventType(eventType);
+
+ // use Prototype to register the event cross-browser
+ OpenLayers.Event.observe(element, eventType, this.eventHandler);
+ }
+ // disable dragstart in IE so that mousedown/move/up works normally
+ OpenLayers.Event.observe(element, "dragstart", OpenLayers.Event.stop);
+ },
+
+ /**
+ * Method: on
+ * Convenience method for registering listeners with a common scope.
+ *
+ * Example use:
+ * (code)
+ * events.on({
+ * "loadstart": loadStartListener,
+ * "loadend": loadEndListener,
+ * scope: object
+ * });
+ * (end)
+ */
+ on: function(object) {
+ for(var type in object) {
+ if(type != "scope") {
+ 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.
+ *
+ *
+ */
+ register: function (type, obj, func) {
+
+ if (func != null &&
+ ((this.eventTypes && OpenLayers.Util.indexOf(this.eventTypes, type) != -1) ||
+ OpenLayers.Util.indexOf(this.BROWSER_EVENTS, type) != -1)) {
+ if (obj == null) {
+ obj = this.object;
+ }
+ var listeners = this.listeners[type];
+ if (listeners != null) {
+ listeners.push( {obj: obj, func: func} );
+ }
+ }
+ },
+
+ /**
+ * 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) {
+
+ if (func != null) {
+ if (obj == null) {
+ obj = this.object;
+ }
+ var listeners = this.listeners[type];
+ if (listeners != null) {
+ listeners.unshift( {obj: obj, func: func} );
+ }
+ }
+ },
+
+ /**
+ * Method: un
+ * Convenience method for unregistering listeners with a common scope.
+ *
+ * Example use:
+ * (code)
+ * events.un({
+ * "loadstart": loadStartListener,
+ * "loadend": loadEndListener,
+ * scope: object
+ * });
+ * (end)
+ */
+ un: function(object) {
+ for(var type in object) {
+ if(type != "scope") {
+ 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; i < listeners.length; i++) {
+ if (listeners[i].obj == obj && listeners[i].func == func) {
+ listeners.splice(i, 1);
+ break;
+ }
+ }
+ }
+ },
+
+ /**
+ * Method: remove
+ * Remove all listeners for a given event type. If type is not registered,
+ * does nothing.
+ *
+ * Parameters:
+ * type - {String}
+ */
+ remove: function(type) {
+ if (this.listeners[type] != null) {
+ this.listeners[type] = [];
+ }
+ },
+
+ /**
+ * APIMethod: triggerEvent
+ * Trigger a specified registered event.
+ *
+ * Parameters:
+ * type - {String}
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} The last listener return. If a listener returns false, the
+ * chain of listeners will stop getting called.
+ */
+ triggerEvent: function (type, evt) {
+
+ // prep evt object with object & div references
+ if (evt == null) {
+ evt = {};
+ }
+ evt.object = this.object;
+ evt.element = this.element;
+ if(!evt.type) {
+ evt.type = type;
+ }
+
+ // execute all callbacks registered for specified type
+ // get a clone of the listeners array to
+ // allow for splicing during callbacks
+ var listeners = (this.listeners[type]) ?
+ this.listeners[type].slice() : null;
+ if ((listeners != null) && (listeners.length > 0)) {
+ var continueChain;
+ for (var i = 0; i < listeners.length; i++) {
+ var callback = listeners[i];
+ // bind the context to callback.obj
+ continueChain = callback.func.apply(callback.obj, [evt]);
+
+ if ((continueChain != undefined) && (continueChain == false)) {
+ // if callback returns false, execute no more callbacks.
+ break;
+ }
+ }
+ // don't fall through to other DOM elements
+ if (!this.fallThrough) {
+ OpenLayers.Event.stop(evt, true);
+ }
+ }
+ return continueChain;
+ },
+
+ /**
+ * Method: handleBrowserEvent
+ * Basically just a wrapper to the triggerEvent() function, but takes
+ * care to set a property 'xy' on the event with the current mouse
+ * position.
+ *
+ * Parameters:
+ * evt - {Event}
+ */
+ handleBrowserEvent: function (evt) {
+ evt.xy = this.getMousePosition(evt);
+ this.triggerEvent(evt.type, evt);
+ },
+
+ /**
+ * Method: getMousePosition
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} The current xy coordinate of the mouse, adjusted
+ * for offsets
+ */
+ getMousePosition: function (evt) {
+ if (!this.element.offsets) {
+ this.element.offsets = OpenLayers.Util.pagePosition(this.element);
+ this.element.offsets[0] += (document.documentElement.scrollLeft
+ || document.body.scrollLeft);
+ this.element.offsets[1] += (document.documentElement.scrollTop
+ || document.body.scrollTop);
+ }
+ return new OpenLayers.Pixel(
+ (evt.clientX + (document.documentElement.scrollLeft
+ || document.body.scrollLeft)) - this.element.offsets[0]
+ - (document.documentElement.clientLeft || 0),
+ (evt.clientY + (document.documentElement.scrollTop
+ || document.body.scrollTop)) - this.element.offsets[1]
+ - (document.documentElement.clientTop || 0)
+ );
+ },
+
+ CLASS_NAME: "OpenLayers.Events"
+});
+/* ======================================================================
+ OpenLayers/Lang/en.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Lang.js
+ */
+
+/**
+ * Namespace: OpenLayers.Lang["en"]
+ * Dictionary for English. Keys for entries are used in calls to
+ * <OpenLayers.Lang.translate>. Entry bodies are normal strings or
+ * strings formatted for use with <OpenLayers.String.format> calls.
+ */
+OpenLayers.Lang.en = {
+
+ 'unhandledRequest': "Unhandled request return ${statusText}",
+
+ 'permalink': "Permalink",
+
+ 'overlays': "Overlays",
+
+ 'baseLayer': "Base Layer",
+
+ 'sameProjection':
+ "The overview map only works when it is in the same projection as the main map",
+
+ 'readNotImplemented': "Read not implemented.",
+
+ 'writeNotImplemented': "Write not implemented.",
+
+ 'noFID': "Can't update a feature for which there is no FID.",
+
+ 'errorLoadingGML': "Error in loading GML file ${url}",
+
+ 'browserNotSupported':
+ "Your browser does not support vector rendering. Currently supported renderers are:\n${renderers}",
+
+ 'componentShouldBe': "addFeatures : component should be an ${geomType}",
+
+ // console message
+ 'getFeatureError':
+ "getFeatureFromEvent called on layer with no renderer. This usually means you " +
+ "destroyed a layer, but not some handler which is associated with it.",
+
+ // console message
+ 'minZoomLevelError':
+ "The minZoomLevel property is only intended for use " +
+ "with the FixedZoomLevels-descendent layers. That this " +
+ "wfs layer checks for minZoomLevel is a relic of the" +
+ "past. We cannot, however, remove it without possibly " +
+ "breaking OL based applications that may depend on it." +
+ " Therefore we are deprecating it -- the minZoomLevel " +
+ "check below will be removed at 3.0. Please instead " +
+ "use min/max resolution setting as described here: " +
+ "http://trac.openlayers.org/wiki/SettingZoomLevels",
+
+ 'commitSuccess': "WFS Transaction: SUCCESS ${response}",
+
+ 'commitFailed': "WFS Transaction: FAILED ${response}",
+
+ 'googleWarning':
+ "The Google Layer was unable to load correctly.<br><br>" +
+ "To get rid of this message, select a new BaseLayer " +
+ "in the layer switcher in the upper-right corner.<br><br>" +
+ "Most likely, this is because the Google Maps library " +
+ "script was either not included, or does not contain the " +
+ "correct API key for your site.<br><br>" +
+ "Developers: For help getting this working correctly, " +
+ "<a href='http://trac.openlayers.org/wiki/Google' " +
+ "target='_blank'>click here</a>",
+
+ 'getLayerWarning':
+ "The ${layerType} Layer was unable to load correctly.<br><br>" +
+ "To get rid of this message, select a new BaseLayer " +
+ "in the layer switcher in the upper-right corner.<br><br>" +
+ "Most likely, this is because the ${layerLib} library " +
+ "script was either not correctly included.<br><br>" +
+ "Developers: For help getting this working correctly, " +
+ "<a href='http://trac.openlayers.org/wiki/${layerLib}' " +
+ "target='_blank'>click here</a>",
+
+ 'scale': "Scale = 1 : ${scaleDenom}",
+
+ // console message
+ 'layerAlreadyAdded':
+ "You tried to add the layer: ${layerName} to the map, but it has already been added",
+
+ // console message
+ 'reprojectDeprecated':
+ "You are using the 'reproject' option " +
+ "on the ${layerName} layer. This option is deprecated: " +
+ "its use was designed to support displaying data over commercial " +
+ "basemaps, but that functionality should now be achieved by using " +
+ "Spherical Mercator support. More information is available from " +
+ "http://trac.openlayers.org/wiki/SphericalMercator.",
+
+ // console message
+ 'methodDeprecated':
+ "This method has been deprecated and will be removed in 3.0. " +
+ "Please use ${newMethod} instead.",
+
+ // console message
+ 'boundsAddError': "You must pass both x and y values to the add function.",
+
+ // console message
+ 'lonlatAddError': "You must pass both lon and lat values to the add function.",
+
+ // console message
+ 'pixelAddError': "You must pass both x and y values to the add function.",
+
+ // console message
+ 'unsupportedGeometryType': "Unsupported geometry type: ${geomType}",
+
+ // console message
+ 'pagePositionFailed':
+ "OpenLayers.Util.pagePosition failed: element with id ${elemId} may be misplaced.",
+
+ 'end': ''
+};
+/* ======================================================================
+ OpenLayers/Projection.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under a modified BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Util.js
+ */
+
+/**
+ * Class: OpenLayers.Projection
+ * Class for coordinate transforms between coordinate systems.
+ * Depends on the proj4js library. If proj4js is not available,
+ * then this is just an empty stub.
+ */
+OpenLayers.Projection = OpenLayers.Class({
+
+ /**
+ * Property: proj
+ * {Object} Proj4js.Proj instance.
+ */
+ proj: null,
+
+ /**
+ * Property: projCode
+ * {String}
+ */
+ projCode: null,
+
+ /**
+ * Constructor: OpenLayers.Projection
+ * This class offers several methods for interacting with a wrapped
+ * pro4js projection object.
+ *
+ * Parameters:
+ * options - {Object} An optional object with properties to set on the
+ * format
+ *
+ * Returns:
+ * {<OpenLayers.Projection>} A projection object.
+ */
+ initialize: function(projCode, options) {
+ OpenLayers.Util.extend(this, options);
+ this.projCode = projCode;
+ if (window.Proj4js) {
+ this.proj = new Proj4js.Proj(projCode);
+ }
+ },
+
+ /**
+ * APIMethod: getCode
+ * Get the string SRS code.
+ *
+ * Returns:
+ * {String} The SRS code.
+ */
+ getCode: function() {
+ return this.proj ? this.proj.srsCode : this.projCode;
+ },
+
+ /**
+ * APIMethod: getUnits
+ * Get the units string for the projection -- returns null if
+ * proj4js is not available.
+ *
+ * Returns:
+ * {String} The units abbreviation.
+ */
+ getUnits: function() {
+ return this.proj ? this.proj.units : null;
+ },
+
+ /**
+ * Method: toString
+ * Convert projection to string (getCode wrapper).
+ *
+ * Returns:
+ * {String} The projection code.
+ */
+ toString: function() {
+ return this.getCode();
+ },
+
+ /**
+ * Method: equals
+ * Test equality of two projection instances. Determines equality based
+ * soley on the projection code.
+ *
+ * Returns:
+ * {Boolean} The two projections are equivalent.
+ */
+ equals: function(projection) {
+ if (projection && projection.getCode) {
+ return this.getCode() == projection.getCode();
+ } else {
+ return false;
+ }
+ },
+
+ /* Method: destroy
+ * Destroy projection object.
+ */
+ destroy: function() {
+ delete this.proj;
+ delete this.projCode;
+ },
+
+ CLASS_NAME: "OpenLayers.Projection"
+});
+
+/**
+ * Property: transforms
+ * Transforms is an object, with from properties, each of which may
+ * have a to property. This allows you to define projections without
+ * requiring support for proj4js to be included.
+ *
+ * This object has keys which correspond to a 'source' projection object. The
+ * keys should be strings, corresponding to the projection.getCode() value.
+ * Each source projection object should have a set of destination projection
+ * keys included in the object.
+ *
+ * Each value in the destination object should be a transformation function,
+ * where the function is expected to be passed an object with a .x and a .y
+ * property. The function should return the object, with the .x and .y
+ * transformed according to the transformation function.
+ *
+ * Note - Properties on this object should not be set directly. To add a
+ * transform method to this object, use the <addTransform> method. For an
+ * example of usage, see the OpenLayers.Layer.SphericalMercator file.
+ */
+OpenLayers.Projection.transforms = {};
+
+/**
+ * APIMethod: addTransform
+ * Set a custom transform method between two projections. Use this method in
+ * cases where the proj4js lib is not available or where custom projections
+ * need to be handled.
+ *
+ * Parameters:
+ * from - {String} The code for the source projection
+ * to - {String} the code for the destination projection
+ * method - {Function} A function that takes a point as an argument and
+ * transforms that point from the source to the destination projection
+ * in place. The original point should be modified.
+ */
+OpenLayers.Projection.addTransform = function(from, to, method) {
+ if(!OpenLayers.Projection.transforms[from]) {
+ OpenLayers.Projection.transforms[from] = {};
+ }
+ OpenLayers.Projection.transforms[from][to] = method;
+};
+
+/**
+ * APIMethod: transform
+ * Transform a point coordinate from one projection to another. Note that
+ * the input point is transformed in place.
+ *
+ * Parameters:
+ * point - {{OpenLayers.Geometry.Point> | Object} An object with x and y
+ * properties representing coordinates in those dimensions.
+ * sourceProj - {OpenLayers.Projection} Source map coordinate system
+ * destProj - {OpenLayers.Projection} Destination map coordinate system
+ *
+ * Returns:
+ * point - {object} A transformed coordinate. The original point is modified.
+ */
+OpenLayers.Projection.transform = function(point, source, dest) {
+ if (source.proj && dest.proj) {
+ point = Proj4js.transform(source.proj, dest.proj, point);
+ } else if (source && dest &&
+ OpenLayers.Projection.transforms[source.getCode()] &&
+ OpenLayers.Projection.transforms[source.getCode()][dest.getCode()]) {
+ OpenLayers.Projection.transforms[source.getCode()][dest.getCode()](point);
+ }
+ return point;
+};
+/* ======================================================================
+ OpenLayers/Tile.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/*
+ * @requires OpenLayers/Util.js
+ */
+
+/*
+ * Class: OpenLayers.Tile
+ * This is a class designed to designate a single tile, however
+ * it is explicitly designed to do relatively little. Tiles store
+ * information about themselves -- such as the URL that they are related
+ * to, and their size - but do not add themselves to the layer div
+ * automatically, for example. Create a new tile with the
+ * <OpenLayers.Tile> constructor, or a subclass.
+ *
+ * TBD 3.0 - remove reference to url in above paragraph
+ *
+ */
+OpenLayers.Tile = OpenLayers.Class({
+
+ /**
+ * Constant: EVENT_TYPES
+ * {Array(String)} Supported application event types
+ */
+ EVENT_TYPES: [ "loadstart", "loadend", "reload", "unload"],
+
+ /**
+ * APIProperty: events
+ * {<OpenLayers.Events>} An events object that handles all
+ * events on the tile.
+ */
+ events: null,
+
+ /**
+ * Property: id
+ * {String} null
+ */
+ id: null,
+
+ /**
+ * Property: layer
+ * {<OpenLayers.Layer>} layer the tile is attached to
+ */
+ layer: null,
+
+ /**
+ * Property: url
+ * {String} url of the request.
+ *
+ * TBD 3.0
+ * Deprecated. The base tile class does not need an url. This should be
+ * handled in subclasses. Does not belong here.
+ */
+ url: null,
+
+ /**
+ * APIProperty: bounds
+ * {<OpenLayers.Bounds>} null
+ */
+ bounds: null,
+
+ /**
+ * Property: size
+ * {<OpenLayers.Size>} null
+ */
+ size: null,
+
+ /**
+ * Property: position
+ * {<OpenLayers.Pixel>} Top Left pixel of the tile
+ */
+ position: null,
+
+ /**
+ * Property: isLoading
+ * {Boolean} Is the tile loading?
+ */
+ isLoading: false,
+
+ /**
+ * Property: isBackBuffer
+ * {Boolean} Is this tile a back buffer tile?
+ */
+ isBackBuffer: false,
+
+ /**
+ * Property: lastRatio
+ * {Float} Used in transition code only. This is the previous ratio
+ * of the back buffer tile resolution to the map resolution. Compared
+ * with the current ratio to determine if zooming occurred.
+ */
+ lastRatio: 1,
+
+ /**
+ * Property: isFirstDraw
+ * {Boolean} Is this the first time the tile is being drawn?
+ * This is used to force resetBackBuffer to synchronize
+ * the backBufferTile with the foreground tile the first time
+ * the foreground tile loads so that if the user zooms
+ * before the layer has fully loaded, the backBufferTile for
+ * tiles that have been loaded can be used.
+ */
+ isFirstDraw: true,
+
+ /**
+ * Property: backBufferTile
+ * {<OpenLayers.Tile>} A clone of the tile used to create transition
+ * effects when the tile is moved or changes resolution.
+ */
+ backBufferTile: null,
+
+ /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor.
+ * there is no need for the base tile class to have a url.
+ *
+ * Constructor: OpenLayers.Tile
+ * Constructor for a new <OpenLayers.Tile> instance.
+ *
+ * Parameters:
+ * layer - {<OpenLayers.Layer>} layer that the tile will go in.
+ * position - {<OpenLayers.Pixel>}
+ * bounds - {<OpenLayers.Bounds>}
+ * url - {<String>}
+ * size - {<OpenLayers.Size>}
+ */
+ initialize: function(layer, position, bounds, url, size) {
+ this.layer = layer;
+ this.position = position.clone();
+ this.bounds = bounds.clone();
+ this.url = url;
+ this.size = size.clone();
+
+ //give the tile a unique id based on its BBOX.
+ this.id = OpenLayers.Util.createUniqueID("Tile_");
+
+ this.events = new OpenLayers.Events(this, null, this.EVENT_TYPES);
+ },
+
+ /**
+ * Method: unload
+ * Call immediately before destroying if you are listening to tile
+ * events, so that counters are properly handled if tile is still
+ * loading at destroy-time. Will only fire an event if the tile is
+ * still loading.
+ */
+ unload: function() {
+ if (this.isLoading) {
+ this.isLoading = false;
+ this.events.triggerEvent("unload");
+ }
+ },
+
+ /**
+ * APIMethod: destroy
+ * Nullify references to prevent circular references and memory leaks.
+ */
+ destroy:function() {
+ if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS,
+ this.layer.transitionEffect) != -1) {
+ this.layer.events.unregister("loadend", this, this.resetBackBuffer);
+ this.events.unregister('loadend', this, this.resetBackBuffer);
+ } else {
+ this.events.unregister('loadend', this, this.showTile);
+ }
+ this.layer = null;
+ this.bounds = null;
+ this.size = null;
+ this.position = null;
+
+ this.events.destroy();
+ this.events = null;
+
+ /* clean up the backBufferTile if it exists */
+ if (this.backBufferTile) {
+ this.backBufferTile.destroy();
+ this.backBufferTile = null;
+ }
+ },
+
+ /**
+ * Method: clone
+ *
+ * Parameters:
+ * obj - {<OpenLayers.Tile>} The tile to be cloned
+ *
+ * Returns:
+ * {<OpenLayers.Tile>} An exact clone of this <OpenLayers.Tile>
+ */
+ clone: function (obj) {
+ if (obj == null) {
+ obj = new OpenLayers.Tile(this.layer,
+ this.position,
+ this.bounds,
+ this.url,
+ this.size);
+ }
+
+ // catch any randomly tagged-on properties
+ OpenLayers.Util.applyDefaults(obj, this);
+
+ return obj;
+ },
+
+ /**
+ * Method: draw
+ * Clear whatever is currently in the tile, then return whether or not
+ * it should actually be re-drawn.
+ *
+ * Returns:
+ * {Boolean} Whether or not the tile should actually be drawn. Note that
+ * this is not really the best way of doing things, but such is
+ * the way the code has been developed. Subclasses call this and
+ * depend on the return to know if they should draw or not.
+ */
+ draw: function() {
+ var maxExtent = this.layer.maxExtent;
+ var withinMaxExtent = (maxExtent &&
+ this.bounds.intersectsBounds(maxExtent, false));
+
+ // The only case where we *wouldn't* want to draw the tile is if the
+ // tile is outside its layer's maxExtent.
+ var drawTile = (withinMaxExtent || this.layer.displayOutsideMaxExtent);
+
+ if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS, this.layer.transitionEffect) != -1) {
+ if (drawTile) {
+ //we use a clone of this tile to create a double buffer for visual
+ //continuity. The backBufferTile is used to create transition
+ //effects while the tile in the grid is repositioned and redrawn
+ if (!this.backBufferTile) {
+ this.backBufferTile = this.clone();
+ this.backBufferTile.hide();
+ // this is important. It allows the backBuffer to place itself
+ // appropriately in the DOM. The Image subclass needs to put
+ // the backBufferTile behind the main tile so the tiles can
+ // load over top and display as soon as they are loaded.
+ this.backBufferTile.isBackBuffer = true;
+
+ // potentially end any transition effects when the tile loads
+ this.events.register('loadend', this, this.resetBackBuffer);
+
+ // clear transition back buffer tile only after all tiles in
+ // this layer have loaded to avoid visual glitches
+ this.layer.events.register("loadend", this, this.resetBackBuffer);
+ }
+ // run any transition effects
+ this.startTransition();
+ } else {
+ // if we aren't going to draw the tile, then the backBuffer should
+ // be hidden too!
+ if (this.backBufferTile) {
+ this.backBufferTile.clear();
+ }
+ }
+ } else {
+ if (drawTile && this.isFirstDraw) {
+ this.events.register('loadend', this, this.showTile);
+ this.isFirstDraw = false;
+ }
+ }
+ this.shouldDraw = drawTile;
+
+ //clear tile's contents and mark as not drawn
+ this.clear();
+
+ return drawTile;
+ },
+
+ /**
+ * Method: moveTo
+ * Reposition the tile.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * position - {<OpenLayers.Pixel>}
+ * redraw - {Boolean} Call draw method on tile after moving.
+ * Default is true
+ */
+ moveTo: function (bounds, position, redraw) {
+ if (redraw == null) {
+ redraw = true;
+ }
+
+ this.bounds = bounds.clone();
+ this.position = position.clone();
+ if (redraw) {
+ this.draw();
+ }
+ },
+
+ /**
+ * Method: clear
+ * Clear the tile of any bounds/position-related data so that it can
+ * be reused in a new location. To be implemented by subclasses.
+ */
+ clear: function() {
+ // to be implemented by subclasses
+ },
+
+ /**
+ * Method: getBoundsFromBaseLayer
+ * Take the pixel locations of the corner of the tile, and pass them to
+ * the base layer and ask for the location of those pixels, so that
+ * displaying tiles over Google works fine.
+ *
+ * Parameters:
+ * position - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * bounds - {<OpenLayers.Bounds>}
+ */
+ getBoundsFromBaseLayer: function(position) {
+ var msg = OpenLayers.i18n('reprojectDeprecated',
+ {'layerName':this.layer.name});
+ OpenLayers.Console.warn(msg);
+ var topLeft = this.layer.map.getLonLatFromLayerPx(position);
+ var bottomRightPx = position.clone();
+ bottomRightPx.x += this.size.w;
+ bottomRightPx.y += this.size.h;
+ var bottomRight = this.layer.map.getLonLatFromLayerPx(bottomRightPx);
+ // Handle the case where the base layer wraps around the date line.
+ // Google does this, and it breaks WMS servers to request bounds in
+ // that fashion.
+ if (topLeft.lon > bottomRight.lon) {
+ if (topLeft.lon < 0) {
+ topLeft.lon = -180 - (topLeft.lon+180);
+ } else {
+ bottomRight.lon = 180+bottomRight.lon+180;
+ }
+ }
+ var bounds = new OpenLayers.Bounds(topLeft.lon,
+ bottomRight.lat,
+ bottomRight.lon,
+ topLeft.lat);
+ return bounds;
+ },
+
+ /**
+ * Method: startTransition
+ * Prepare the tile for a transition effect. To be
+ * implemented by subclasses.
+ */
+ startTransition: function() {},
+
+ /**
+ * Method: resetBackBuffer
+ * Triggered by two different events, layer loadend, and tile loadend.
+ * In any of these cases, we check to see if we can hide the
+ * backBufferTile yet and update its parameters to match the
+ * foreground tile.
+ *
+ * Basic logic:
+ * - If the backBufferTile hasn't been drawn yet, reset it
+ * - If layer is still loading, show foreground tile but don't hide
+ * the backBufferTile yet
+ * - If layer is done loading, reset backBuffer tile and show
+ * foreground tile
+ */
+ resetBackBuffer: function() {
+ this.showTile();
+ if (this.backBufferTile &&
+ (this.isFirstDraw || !this.layer.numLoadingTiles)) {
+ this.isFirstDraw = false;
+ // check to see if the backBufferTile is within the max extents
+ // before rendering it
+ var maxExtent = this.layer.maxExtent;
+ var withinMaxExtent = (maxExtent &&
+ this.bounds.intersectsBounds(maxExtent, false));
+ if (withinMaxExtent) {
+ this.backBufferTile.position = this.position;
+ this.backBufferTile.bounds = this.bounds;
+ this.backBufferTile.size = this.size;
+ this.backBufferTile.imageSize = this.layer.imageSize || this.size;
+ this.backBufferTile.imageOffset = this.layer.imageOffset;
+ this.backBufferTile.resolution = this.layer.getResolution();
+ this.backBufferTile.renderTile();
+ }
+ }
+ },
+
+ /**
+ * Method: showTile
+ * Show the tile only if it should be drawn.
+ */
+ showTile: function() {
+ if (this.shouldDraw) {
+ this.show();
+ }
+ },
+
+ /**
+ * Method: show
+ * Show the tile. To be implemented by subclasses.
+ */
+ show: function() { },
+
+ /**
+ * Method: hide
+ * Hide the tile. To be implemented by subclasses.
+ */
+ hide: function() { },
+
+ CLASS_NAME: "OpenLayers.Tile"
+});
+/* ======================================================================
+ OpenLayers/Handler.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Events.js
+ */
+
+/**
+ * Class: OpenLayers.Handler
+ * Base class to construct a higher-level handler for event sequences. All
+ * handlers have activate and deactivate methods. In addition, they have
+ * methods named like browser events. When a handler is activated, any
+ * additional methods named like a browser event is registered as a
+ * listener for the corresponding event. When a handler is deactivated,
+ * those same methods are unregistered as event listeners.
+ *
+ * Handlers also typically have a callbacks object with keys named like
+ * the abstracted events or event sequences that they are in charge of
+ * handling. The controls that wrap handlers define the methods that
+ * correspond to these abstract events - so instead of listening for
+ * individual browser events, they only listen for the abstract events
+ * defined by the handler.
+ *
+ * Handlers are created by controls, which ultimately have the responsibility
+ * of making changes to the the state of the application. Handlers
+ * themselves may make temporary changes, but in general are expected to
+ * return the application in the same state that they found it.
+ */
+OpenLayers.Handler = OpenLayers.Class({
+
+ /**
+ * Property: id
+ * {String}
+ */
+ id: null,
+
+ /**
+ * APIProperty: control
+ * {<OpenLayers.Control>}. The control that initialized this handler. The
+ * control is assumed to have a valid map property - that map is used
+ * in the handler's own setMap method.
+ */
+ control: null,
+
+ /**
+ * Property: map
+ * {<OpenLayers.Map>}
+ */
+ map: null,
+
+ /**
+ * APIProperty: keyMask
+ * {Integer} Use bitwise operators and one or more of the OpenLayers.Handler
+ * constants to construct a keyMask. The keyMask is used by
+ * <checkModifiers>. If the keyMask matches the combination of keys
+ * down on an event, checkModifiers returns true.
+ *
+ * Example:
+ * (code)
+ * // handler only responds if the Shift key is down
+ * handler.keyMask = OpenLayers.Handler.MOD_SHIFT;
+ *
+ * // handler only responds if Ctrl-Shift is down
+ * handler.keyMask = OpenLayers.Handler.MOD_SHIFT |
+ * OpenLayers.Handler.MOD_CTRL;
+ * (end)
+ */
+ keyMask: null,
+
+ /**
+ * Property: active
+ * {Boolean}
+ */
+ active: false,
+
+ /**
+ * Property: evt
+ * {Event} This property references the last event handled by the handler.
+ * Note that this property is not part of the stable API. Use of the
+ * evt property should be restricted to controls in the library
+ * or other applications that are willing to update with changes to
+ * the OpenLayers code.
+ */
+ evt: null,
+
+ /**
+ * Constructor: OpenLayers.Handler
+ * Construct a handler.
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>} The control that initialized this
+ * handler. The control is assumed to have a valid map property; that
+ * map is used in the handler's own setMap method.
+ * 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;
+ if (control.map) {
+ this.setMap(control.map);
+ }
+
+ OpenLayers.Util.extend(this, options);
+
+ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+ },
+
+ /**
+ * Method: setMap
+ */
+ setMap: function (map) {
+ this.map = map;
+ },
+
+ /**
+ * Method: checkModifiers
+ * Check the keyMask on the handler. If no <keyMask> is set, this always
+ * returns true. If a <keyMask> is set and it matches the combination
+ * of keys down on an event, this returns true.
+ *
+ * Returns:
+ * {Boolean} The keyMask matches the keys down on an event.
+ */
+ checkModifiers: function (evt) {
+ if(this.keyMask == null) {
+ return true;
+ }
+ /* calculate the keyboard modifier mask for this event */
+ var keyModifiers =
+ (evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) |
+ (evt.ctrlKey ? OpenLayers.Handler.MOD_CTRL : 0) |
+ (evt.altKey ? OpenLayers.Handler.MOD_ALT : 0);
+
+ /* if it differs from the handler object's key mask,
+ bail out of the event handler */
+ return (keyModifiers == this.keyMask);
+ },
+
+ /**
+ * APIMethod: activate
+ * Turn on the handler. Returns false if the handler was already active.
+ *
+ * Returns:
+ * {Boolean} The handler was activated.
+ */
+ activate: function() {
+ if(this.active) {
+ return false;
+ }
+ // register for event handlers defined on this class.
+ var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
+ for (var i = 0; i < events.length; i++) {
+ if (this[events[i]]) {
+ this.register(events[i], this[events[i]]);
+ }
+ }
+ this.active = true;
+ return true;
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Turn off the handler. Returns false if the handler was already inactive.
+ *
+ * Returns:
+ * {Boolean} The handler was deactivated.
+ */
+ deactivate: function() {
+ if(!this.active) {
+ return false;
+ }
+ // unregister event handlers defined on this class.
+ var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
+ for (var i = 0; i < events.length; i++) {
+ if (this[events[i]]) {
+ this.unregister(events[i], this[events[i]]);
+ }
+ }
+ this.active = false;
+ return true;
+ },
+
+ /**
+ * Method: callback
+ * Trigger the control's named callback with the given arguments
+ *
+ * Parameters:
+ * name - {String} The key for the callback that is one of the properties
+ * of the handler's callbacks object.
+ * args - {Array(*)} An array of arguments (any type) with which to call
+ * the callback (defined by the control).
+ */
+ callback: function (name, args) {
+ if (name && this.callbacks[name]) {
+ this.callbacks[name].apply(this.control, args);
+ }
+ },
+
+ /**
+ * Method: register
+ * register an event on the map
+ */
+ register: function (name, method) {
+ // TODO: deal with registerPriority in 3.0
+ this.map.events.registerPriority(name, this, method);
+ this.map.events.registerPriority(name, this, this.setEvent);
+ },
+
+ /**
+ * Method: unregister
+ * unregister an event from the map
+ */
+ unregister: function (name, method) {
+ this.map.events.unregister(name, this, method);
+ this.map.events.unregister(name, this, this.setEvent);
+ },
+
+ /**
+ * Method: setEvent
+ * With each registered browser event, the handler sets its own evt
+ * property. This property can be accessed by controls if needed
+ * to get more information about the event that the handler is
+ * processing.
+ *
+ * This allows modifier keys on the event to be checked (alt, shift,
+ * and ctrl cannot be checked with the keyboard handler). For a
+ * control to determine which modifier keys are associated with the
+ * event that a handler is currently processing, it should access
+ * (code)handler.evt.altKey || handler.evt.shiftKey ||
+ * handler.evt.ctrlKey(end).
+ *
+ * Parameters:
+ * evt - {Event} The browser event.
+ */
+ setEvent: function(evt) {
+ this.evt = evt;
+ return true;
+ },
+
+ /**
+ * Method: destroy
+ * Deconstruct the handler.
+ */
+ destroy: function () {
+ // unregister event listeners
+ this.deactivate();
+ // eliminate circular references
+ this.control = this.map = null;
+ },
+
+ CLASS_NAME: "OpenLayers.Handler"
+});
+
+/**
+ * Constant: OpenLayers.Handler.MOD_NONE
+ * If set as the <keyMask>, <checkModifiers> returns false if any key is down.
+ */
+OpenLayers.Handler.MOD_NONE = 0;
+
+/**
+ * Constant: OpenLayers.Handler.MOD_SHIFT
+ * If set as the <keyMask>, <checkModifiers> returns false if Shift is down.
+ */
+OpenLayers.Handler.MOD_SHIFT = 1;
+
+/**
+ * Constant: OpenLayers.Handler.MOD_CTRL
+ * If set as the <keyMask>, <checkModifiers> returns false if Ctrl is down.
+ */
+OpenLayers.Handler.MOD_CTRL = 2;
+
+/**
+ * Constant: OpenLayers.Handler.MOD_ALT
+ * If set as the <keyMask>, <checkModifiers> returns false if Alt is down.
+ */
+OpenLayers.Handler.MOD_ALT = 4;
+
+
+/* ======================================================================
+ OpenLayers/Map.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Util.js
+ * @requires OpenLayers/Events.js
+ * @requires OpenLayers/Tween.js
+ */
+
+/**
+ * Class: OpenLayers.Map
+ * Instances of OpenLayers.Map are interactive maps embedded in a web page.
+ * Create a new map with the <OpenLayers.Map> constructor.
+ *
+ * On their own maps do not provide much functionality. To extend a map
+ * it's necessary to add controls (<OpenLayers.Control>) and
+ * layers (<OpenLayers.Layer>) 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, Popup: 750, Control: 1000 },
+
+ /**
+ * Constant: EVENT_TYPES
+ * {Array(String)} Supported application event types. 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* {<OpenLayers.Pixel>} The pixel location of the event (relative
+ * to the the map viewport).
+ * - other properties that come with browser events
+ *
+ * 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.
+ * - *addlayer* triggered after a layer has been added. The event object
+ * will include a *layer* property that references the added layer.
+ * - *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, or
+ * visibility change (due to resolution thresholds). 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,
+ * visibility, or order).
+ * - *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
+ * - *popupopen* triggered after a popup opens
+ * - *popupclose* triggered after a popup opens
+ * - *addmarker* triggered after a marker has been added
+ * - *removemarker* triggered after a marker has been removed
+ * - *clearmarkers* triggered after markers have been cleared
+ * - *mouseover* triggered after mouseover the map
+ * - *mouseout* triggered after mouseout the map
+ * - *mousemove* triggered after mousemove the map
+ * - *dragstart* triggered after the start of a drag
+ * - *drag* triggered after a drag
+ * - *dragend* triggered after the end of a drag
+ * - *changebaselayer* triggered after the base layer changes
+ */
+ EVENT_TYPES: [
+ "preaddlayer", "addlayer", "removelayer", "changelayer", "movestart",
+ "move", "moveend", "zoomend", "popupopen", "popupclose",
+ "addmarker", "removemarker", "clearmarkers", "mouseover",
+ "mouseout", "mousemove", "dragstart", "drag", "dragend",
+ "changebaselayer"],
+
+ /**
+ * 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
+ * <getResolutionForZoom> instead of layer.resolutions[zoom] as the
+ * former works for non-integer zoom levels.
+ */
+ fractionalZoom: false,
+
+ /**
+ * APIProperty: events
+ * {<OpenLayers.Events>} An events object that handles all
+ * events on the map
+ */
+ events: null,
+
+ /**
+ * APIProperty: div
+ * {DOMElement} The element that contains the map
+ */
+ div: null,
+
+ /**
+ * Property: dragging
+ * {Boolean} The map is currently being dragged.
+ */
+ dragging: false,
+
+ /**
+ * Property: size
+ * {<OpenLayers.Size>} Size of the main div (this.div)
+ */
+ size: null,
+
+ /**
+ * Property: viewPortDiv
+ * {HTMLDivElement} The element that represents the map viewport
+ */
+ viewPortDiv: null,
+
+ /**
+ * Property: layerContainerOrigin
+ * {<OpenLayers.LonLat>} 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(<OpenLayers.Layer>)} Ordered list of layers in the map
+ */
+ layers: null,
+
+ /**
+ * Property: controls
+ * {Array(<OpenLayers.Control>)} List of controls associated with the map
+ */
+ controls: null,
+
+ /**
+ * Property: popups
+ * {Array(<OpenLayers.Popup>)} List of popups associated with the map
+ */
+ popups: null,
+
+ /**
+ * APIProperty: baseLayer
+ * {<OpenLayers.Layer>} The currently selected base layer. This determines
+ * min/max zoom level, projection, etc.
+ */
+ baseLayer: null,
+
+ /**
+ * Property: center
+ * {<OpenLayers.LonLat>} 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: viewRequestID
+ * {String} Used to store a unique identifier that changes when the map
+ * view changes. viewRequestID should be used when adding data
+ * asynchronously to the map: viewRequestID is incremented when
+ * you initiate your request (right now during changing of
+ * baselayers and changing of zooms). It is stored here in the
+ * map and also in the data that will be coming back
+ * asynchronously. Before displaying this data on request
+ * completion, we check that the viewRequestID of the data is
+ * still the same as that of the map. Fix for #480
+ */
+ viewRequestID: 0,
+
+ // Options
+
+ /**
+ * APIProperty: tileSize
+ * {<OpenLayers.Size>} 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 override the default projection
+ * string this map - also set maxExtent, maxResolution, and
+ * units if appropriate.
+ */
+ projection: "EPSG:4326",
+
+ /**
+ * APIProperty: units
+ * {String} The map units. Defaults to 'degrees'. Possible values are
+ * 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
+ */
+ units: 'degrees',
+
+ /**
+ * 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} Default max is 360 deg / 256 px, which corresponds to
+ * zoom level 0 on gmaps. Specify a different value in the map
+ * options if you are not using a geographic projection and
+ * displaying the whole world.
+ */
+ maxResolution: 1.40625,
+
+ /**
+ * APIProperty: minResolution
+ * {Float}
+ */
+ minResolution: null,
+
+ /**
+ * APIProperty: maxScale
+ * {Float}
+ */
+ maxScale: null,
+
+ /**
+ * APIProperty: minScale
+ * {Float}
+ */
+ minScale: null,
+
+ /**
+ * APIProperty: maxExtent
+ * {<OpenLayers.Bounds>} 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.
+ */
+ maxExtent: null,
+
+ /**
+ * APIProperty: minExtent
+ * {<OpenLayers.Bounds>}
+ */
+ minExtent: null,
+
+ /**
+ * APIProperty: restrictedExtent
+ * {<OpenLayers.Bounds>} 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
+ * {<OpenLayers.Projection>} Requires proj4js support.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,
+
+ /**
+ * Property: panTween
+ * {OpenLayers.Tween} 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 <OpenLayers.Events.on>. Object
+ * structure must be a listeners object as shown in the example for
+ * the events.on method.
+ */
+ eventListeners: null,
+
+ /**
+ * Property: 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: paddingForPopups
+ * {<OpenLayers.Bounds>} Outside margin of the popup. Used to prevent
+ * the popup from getting too close to the map border.
+ */
+ paddingForPopups : null,
+
+ /**
+ * Constructor: OpenLayers.Map
+ * Constructor for a new OpenLayers.Map instance.
+ *
+ * Parameters:
+ * div - {String} Id of an element in your page that will contain the map.
+ * options - {Object} Optional object with properties to tag onto the map.
+ *
+ * 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 = {
+ * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000),
+ * maxResolution: 156543,
+ * units: 'm',
+ * projection: "EPSG:41001"
+ * };
+ * var map = new OpenLayers.Map("map2", options);
+ * (end)
+ */
+ initialize: function (div, options) {
+
+ // 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.maxExtent = new OpenLayers.Bounds(-180, -90, 180, 90);
+
+ this.paddingForPopups = new OpenLayers.Bounds(15, 15, 15, 15);
+
+ this.theme = OpenLayers._getScriptLocation() +
+ 'theme/default/style.css';
+
+ // now override default options
+ OpenLayers.Util.extend(this, options);
+
+ this.id = OpenLayers.Util.createUniqueID("OpenLayers.Map_");
+
+ this.div = OpenLayers.Util.getElement(div);
+
+ // the viewPortDiv is the outermost div we modify
+ var id = this.div.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);
+
+ // the layerContainerDiv is the one that holds all the layers
+ id = this.div.id + "_OpenLayers_Container";
+ this.layerContainerDiv = OpenLayers.Util.createDiv(id);
+ this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;
+
+ this.viewPortDiv.appendChild(this.layerContainerDiv);
+
+ this.events = new OpenLayers.Events(this,
+ this.div,
+ this.EVENT_TYPES,
+ this.fallThrough);
+ this.updateSize();
+ if(this.eventListeners instanceof Object) {
+ this.events.on(this.eventListeners);
+ }
+
+ // update the map size and location before the map moves
+ this.events.register("movestart", this, this.updateSize);
+
+ // Because Mozilla does not support the "resize" event for elements
+ // other than "window", we need to put a hack here.
+ if (OpenLayers.String.contains(navigator.appName, "Microsoft")) {
+ // If IE, register the resize on the div
+ this.events.register("resize", this, this.updateSize);
+ } else {
+ // Else 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; i<nodes.length; ++i) {
+ if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,
+ this.theme)) {
+ addNode = false;
+ break;
+ }
+ }
+ // only add a new node if one with an equivalent url hasn't already
+ // been added
+ if(addNode) {
+ var cssNode = document.createElement('link');
+ cssNode.setAttribute('rel', 'stylesheet');
+ cssNode.setAttribute('type', 'text/css');
+ cssNode.setAttribute('href', this.theme);
+ document.getElementsByTagName('head')[0].appendChild(cssNode);
+ }
+ }
+
+ this.layers = [];
+
+ if (this.controls == null) {
+ if (OpenLayers.Control != null) { // running full or lite?
+ this.controls = [ new OpenLayers.Control.Navigation(),
+ new OpenLayers.Control.PanZoom(),
+ new OpenLayers.Control.ArgParser(),
+ new OpenLayers.Control.Attribution()
+ ];
+ } else {
+ this.controls = [];
+ }
+ }
+
+ for(var i=0; i < this.controls.length; i++) {
+ this.addControlToMap(this.controls[i]);
+ }
+
+ this.popups = [];
+
+ this.unloadDestroy = OpenLayers.Function.bind(this.destroy, this);
+
+
+ // always call map.destroy()
+ OpenLayers.Event.observe(window, 'unload', this.unloadDestroy);
+
+ },
+
+ /**
+ * Method: unloadDestroy
+ * Function that is called to destroy the map on page unload. stored here
+ * so that if map is manually destroyed, we can unregister this.
+ */
+ unloadDestroy: null,
+
+ /**
+ * Method: updateSizeDestroy
+ * When the map is destroyed, we need to stop listening to updateSize
+ * events: this method stores the function we need to unregister in
+ * non-IE browsers.
+ */
+ updateSizeDestroy: null,
+
+ /**
+ * APIMethod: destroy
+ * Destroy this map
+ */
+ destroy:function() {
+ // if unloadDestroy is null, we've already been destroyed
+ if (!this.unloadDestroy) {
+ return false;
+ }
+
+ // map has been destroyed. dont do it again!
+ OpenLayers.Event.stopObserving(window, 'unload', this.unloadDestroy);
+ this.unloadDestroy = null;
+
+ if (this.updateSizeDestroy) {
+ OpenLayers.Event.stopObserving(window, 'resize',
+ this.updateSizeDestroy);
+ } else {
+ this.events.unregister("resize", this, this.updateSize);
+ }
+
+ this.paddingForPopups = null;
+
+ if (this.controls != null) {
+ for (var i = this.controls.length - 1; 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;
+
+ },
+
+ /**
+ * APIMethod: setOptions
+ * Change the map options
+ *
+ * Parameters:
+ * options - {Object} Hashtable of options to tag to the map
+ */
+ setOptions: function(options) {
+ OpenLayers.Util.extend(this, options);
+ },
+
+ /**
+ * APIMethod: getTileSize
+ * Get the tile size for the map
+ *
+ * Returns:
+ * {<OpenLayers.Size>}
+ */
+ 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.
+ *
+ * Parameter:
+ * 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(<OpenLayers.Layer>)} 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.
+ *
+ * Parameter:
+ * 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(<OpenLayers.Layer>)} 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).
+ *
+ * Parameter:
+ * 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(<OpenLayers.Layer>)} 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.
+ *
+ * Parameter:
+ * 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(<OpenLayers.Control>)} 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).
+ *
+ * Parameter:
+ * 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(<OpenLayers.Control>)} 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
+ *
+ * Parameter:
+ * id - {String} A layer id
+ *
+ * Returns:
+ * {<OpenLayers.Layer>} 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; i < this.layers.length; i++) {
+ var layer = this.layers[i];
+ if (layer.id == id) {
+ foundLayer = layer;
+ break;
+ }
+ }
+ return foundLayer;
+ },
+
+ /**
+ * Method: setLayerZIndex
+ *
+ * Parameters:
+ * layer - {<OpenLayers.Layer>}
+ * 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; i < this.layers.length; i++) {
+ var layer = this.layers[i];
+ this.setLayerZIndex(layer, i);
+ }
+ },
+
+ /**
+ * APIMethod: addLayer
+ *
+ * Parameters:
+ * layer - {<OpenLayers.Layer>}
+ */
+ addLayer: function (layer) {
+ for(var i=0; i < this.layers.length; i++) {
+ if (this.layers[i] == layer) {
+ var msg = OpenLayers.i18n('layerAlreadyAdded',
+ {'layerName':layer.name});
+ OpenLayers.Console.warn(msg);
+ return false;
+ }
+ }
+
+ this.events.triggerEvent("preaddlayer", {layer: layer});
+
+ 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) {
+ 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});
+ },
+
+ /**
+ * APIMethod: addLayers
+ *
+ * Parameters:
+ * layers - {Array(<OpenLayers.Layer>)}
+ */
+ addLayers: function (layers) {
+ for (var i = 0; i < layers.length; i++) {
+ this.addLayer(layers[i]);
+ }
+ },
+
+ /**
+ * APIMethod: removeLayer
+ * Removes a layer from the map by removing its visual element (the
+ * layer.div property), then removing it from the map's internal list
+ * of layers, setting the layer's map property to null.
+ *
+ * a "removelayer" event is triggered.
+ *
+ * very worthy of mention is that simply removing a layer from a map
+ * will not cause the removal of any popups which may have been created
+ * by the layer. this is due to the fact that it was decided at some
+ * point that popups would not belong to layers. thus there is no way
+ * for us to know here to which layer the popup belongs.
+ *
+ * A simple solution to this is simply to call destroy() on the layer.
+ * the default OpenLayers.Layer class's destroy() function
+ * automatically takes care to remove itself from whatever map it has
+ * been attached to.
+ *
+ * The correct solution is for the layer itself to register an
+ * event-handler on "removelayer" and when it is called, if it
+ * recognizes itself as the layer being removed, then it cycles through
+ * its own personal list of popups, removing them from the map.
+ *
+ * Parameters:
+ * layer - {<OpenLayers.Layer>}
+ * setNewBaseLayer - {Boolean} Default is true
+ */
+ removeLayer: function(layer, setNewBaseLayer) {
+ 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; i < this.layers.length; i++) {
+ var iLayer = this.layers[i];
+ if (iLayer.isBaseLayer) {
+ this.setBaseLayer(iLayer);
+ break;
+ }
+ }
+ }
+ }
+
+ this.resetLayersZIndex();
+
+ this.events.triggerEvent("removelayer", {layer: layer});
+ },
+
+ /**
+ * APIMethod: getNumLayers
+ *
+ * Returns:
+ * {Int} The number of layers attached to the map.
+ */
+ getNumLayers: function () {
+ return this.layers.length;
+ },
+
+ /**
+ * APIMethod: getLayerIndex
+ *
+ * Parameters:
+ * layer - {<OpenLayers.Layer>}
+ *
+ * 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 - {<OpenLayers.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; i < this.layers.length; i++) {
+ this.setLayerZIndex(this.layers[i], i);
+ }
+ this.events.triggerEvent("changelayer", {
+ layer: layer, property: "order"
+ });
+ }
+ },
+
+ /**
+ * APIMethod: raiseLayer
+ * Change the index of the given layer by delta. If delta is positive,
+ * the layer is moved up the map's layer stack; if delta is negative,
+ * the layer is moved down. Again, note that this cannot (or at least
+ * should not) be effectively used to raise base layers above overlays.
+ *
+ * Paremeters:
+ * layer - {<OpenLayers.Layer>}
+ * idx - {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 - {<OpenLayers.Layer>}
+ */
+ setBaseLayer: function(newBaseLayer) {
+ var oldExtent = null;
+ if (this.baseLayer) {
+ oldExtent = this.baseLayer.getExtent();
+ }
+
+ if (newBaseLayer != this.baseLayer) {
+
+ // is newBaseLayer an already loaded layer?m
+ if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) {
+
+ // make the old base layer invisible
+ if (this.baseLayer != null) {
+ this.baseLayer.setVisibility(false);
+ }
+
+ // set new baselayer
+ this.baseLayer = newBaseLayer;
+
+ // Increment viewRequestID since the baseLayer is
+ // changing. This is used by tiles to check if they should
+ // draw themselves.
+ this.viewRequestID++;
+ this.baseLayer.visibility = true;
+
+ //redraw all layers
+ var center = this.getCenter();
+ if (center != null) {
+
+ //either get the center from the old Extent or just from
+ // the current center of the map.
+ var newCenter = (oldExtent)
+ ? oldExtent.getCenterLonLat()
+ : center;
+
+ //the new zoom will either come from the old Extent or
+ // from the current resolution of the map
+ var newZoom = (oldExtent)
+ ? this.getZoomForExtent(oldExtent, true)
+ : this.getZoomForResolution(this.resolution, true);
+
+ // zoom and force zoom change
+ this.setCenter(newCenter, 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
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>}
+ * px - {<OpenLayers.Pixel>}
+ */
+ addControl: function (control, px) {
+ this.controls.push(control);
+ this.addControlToMap(control, px);
+ },
+
+ /**
+ * Method: addControlToMap
+ *
+ * Parameters:
+ *
+ * control - {<OpenLayers.Control>}
+ * px - {<OpenLayers.Pixel>}
+ */
+ 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 );
+ }
+ }
+ },
+
+ /**
+ * APIMethod: getControl
+ *
+ * Parameters:
+ * id - {String} ID of the control to return.
+ *
+ * Returns:
+ * {<OpenLayers.Control>} 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; i < this.controls.length; i++) {
+ var control = this.controls[i];
+ if (control.id == id) {
+ returnControl = control;
+ break;
+ }
+ }
+ return returnControl;
+ },
+
+ /**
+ * APIMethod: removeControl
+ * Remove a control from the map. Removes the control both from the map
+ * object's internal array of controls, as well as from the map's
+ * viewPort (assuming the control was not added outsideViewport)
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>} 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 - {<OpenLayers.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 - {<OpenLayers.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:
+ * {<OpenLayers.Size>} An <OpenLayers.Size> 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
+ this.events.element.offsets = null;
+ var newSize = this.getCurrentSize();
+ 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; i < this.layers.length; i++) {
+ this.layers[i].onMapResize();
+ }
+
+ if (this.baseLayer != null) {
+ var center = new OpenLayers.Pixel(newSize.w /2, newSize.h / 2);
+ var centerLL = this.getLonLatFromViewPortPx(center);
+ var zoom = this.getZoom();
+ this.zoom = null;
+ this.setCenter(this.getCenter(), zoom);
+ }
+
+ }
+ },
+
+ /**
+ * Method: getCurrentSize
+ *
+ * Returns:
+ * {<OpenLayers.Size>} A new <OpenLayers.Size> object with the dimensions
+ * of the map div
+ */
+ getCurrentSize: function() {
+
+ var size = new OpenLayers.Size(this.div.clientWidth,
+ this.div.clientHeight);
+
+ // Workaround for the fact that hidden elements return 0 for size.
+ if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {
+ var dim = OpenLayers.Element.getDimensions(this.div);
+ size.w = dim.width;
+ size.h = dim.height;
+ }
+ 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 - {<OpenLayers.LonLat>} Default is this.getCenter()
+ * resolution - {float} Default is this.getResolution()
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} A bounds based on resolution, center, and
+ * current mapsize.
+ */
+ calculateBounds: function(center, resolution) {
+
+ var extent = null;
+
+ if (center == null) {
+ center = this.getCenter();
+ }
+ if (resolution == null) {
+ resolution = this.getResolution();
+ }
+
+ if ((center != null) && (resolution != null)) {
+
+ var size = this.getSize();
+ var w_deg = size.w * resolution;
+ var h_deg = size.h * resolution;
+
+ extent = new OpenLayers.Bounds(center.lon - w_deg / 2,
+ center.lat - h_deg / 2,
+ center.lon + w_deg / 2,
+ center.lat + h_deg / 2);
+
+ }
+
+ 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:
+ * {<OpenLayers.LonLat>}
+ */
+ getCenter: function () {
+ 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) {
+ // this should be pushed to applyDefaults and extend
+ if (!options) {
+ options = {};
+ }
+ OpenLayers.Util.applyDefaults(options, {
+ animate: true,
+ dragging: false
+ });
+ // getCenter
+ var centerPx = this.getViewPortPxFromLonLat(this.getCenter());
+
+ // adjust
+ var newCenterPx = centerPx.add(dx, dy);
+
+ // only call setCenter if not dragging or there has been a change
+ if (!options.dragging || !newCenterPx.equals(centerPx)) {
+ var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx);
+ if (options.animate) {
+ this.panTo(newCenterLonLat);
+ } else {
+ this.setCenter(newCenterLonLat, null, options.dragging);
+ }
+ }
+
+ },
+
+ /**
+ * 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 - {<OpenLayers.Lonlat>}
+ */
+ panTo: function(lonlat) {
+ if (this.panMethod && this.getExtent().containsLonLat(lonlat)) {
+ if (!this.panTween) {
+ this.panTween = new OpenLayers.Tween(this.panMethod);
+ }
+ var center = this.getCenter();
+ var from = {
+ lon: center.lon,
+ lat: center.lat
+ };
+ var to = {
+ lon: lonlat.lon,
+ lat: lonlat.lat
+ };
+ this.panTween.start(from, to, 50, {
+ callbacks: {
+ start: OpenLayers.Function.bind(function(lonlat) {
+ this.events.triggerEvent("movestart");
+ }, this),
+ eachStep: OpenLayers.Function.bind(function(lonlat) {
+ lonlat = new OpenLayers.LonLat(lonlat.lon, lonlat.lat);
+ this.moveTo(lonlat, this.zoom, {
+ 'dragging': true,
+ 'noEvent': true
+ });
+ }, this),
+ done: OpenLayers.Function.bind(function(lonlat) {
+ lonlat = new OpenLayers.LonLat(lonlat.lon, lonlat.lat);
+ this.moveTo(lonlat, this.zoom, {
+ 'noEvent': true
+ });
+ this.events.triggerEvent("moveend");
+ }, this)
+ }
+ });
+ } else {
+ this.setCenter(lonlat);
+ }
+ },
+
+ /**
+ * APIMethod: setCenter
+ *
+ * Parameters:
+ * lonlat - {<OpenLayers.LonLat>}
+ * zoom - {Integer}
+ * 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.moveTo(lonlat, zoom, {
+ 'dragging': dragging,
+ 'forceZoomChange': forceZoomChange,
+ 'caller': 'setCenter'
+ });
+ },
+
+ /**
+ * Method: moveTo
+ *
+ * Parameters:
+ * lonlat - {<OpenLayers.LonLat>}
+ * zoom - {Integer}
+ * options - {Object}
+ */
+ moveTo: function(lonlat, zoom, options) {
+ if (!options) {
+ options = {};
+ }
+ // dragging is false by default
+ var dragging = options.dragging;
+ // forceZoomChange is false by default
+ var forceZoomChange = options.forceZoomChange;
+ // noEvent is false by default
+ var noEvent = options.noEvent;
+
+ if (this.panTween && options.caller == "setCenter") {
+ this.panTween.stop();
+ }
+
+ if (!this.center && !this.isValidLonLat(lonlat)) {
+ lonlat = this.maxExtent.getCenterLonLat();
+ }
+
+ if(this.restrictedExtent != null) {
+ // In 3.0, decide if we want to change interpretation of maxExtent.
+ if(lonlat == null) {
+ lonlat = this.getCenter();
+ }
+ 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) {
+
+ if (!this.dragging && !noEvent) {
+ 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();
+ }
+
+ // (re)set the layerContainerDiv's location
+ if ((zoomChanged) || (this.layerContainerOrigin == null)) {
+ this.layerContainerOrigin = this.center.clone();
+ this.layerContainerDiv.style.left = "0px";
+ this.layerContainerDiv.style.top = "0px";
+ }
+
+ if (zoomChanged) {
+ this.zoom = zoom;
+ this.resolution = this.getResolutionForZoom(zoom);
+ // zoom level has changed, increment viewRequestID.
+ this.viewRequestID++;
+ }
+
+ var bounds = this.getExtent();
+
+ //send the move call to the baselayer and all the overlays
+ this.baseLayer.moveTo(bounds, zoomChanged, dragging);
+
+ bounds = this.baseLayer.getExtent();
+
+ for (var i = 0; i < this.layers.length; i++) {
+ var layer = this.layers[i];
+ if (!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, dragging);
+ }
+ }
+ }
+
+ if (zoomChanged) {
+ //redraw popups
+ for (var i = 0; i < this.popups.length; i++) {
+ this.popups[i].updatePosition();
+ }
+ }
+
+ this.events.triggerEvent("move");
+
+ if (zoomChanged) { this.events.triggerEvent("zoomend"); }
+ }
+
+ // even if nothing was done, we want to notify of this
+ if (!dragging && !noEvent) {
+ this.events.triggerEvent("moveend");
+ }
+
+ // Store the map dragging state for later use
+ this.dragging = !!dragging;
+
+ },
+
+ /**
+ * Method: centerLayerContainer
+ * This function takes care to recenter the layerContainerDiv.
+ *
+ * Parameters:
+ * lonlat - {<OpenLayers.LonLat>}
+ */
+ centerLayerContainer: function (lonlat) {
+
+ var originPx = this.getViewPortPxFromLonLat(this.layerContainerOrigin);
+ var newPx = this.getViewPortPxFromLonLat(lonlat);
+
+ if ((originPx != null) && (newPx != null)) {
+ this.layerContainerDiv.style.left = Math.round(originPx.x - newPx.x) + "px";
+ this.layerContainerDiv.style.top = Math.round(originPx.y - newPx.y) + "px";
+ }
+ },
+
+ /**
+ * 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 - {<OpenLayers.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();
+ valid = maxExtent.containsLonLat(lonlat);
+ }
+ 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:
+ * {<OpenLayers.Projection>} 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
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>}
+ */
+ getMaxExtent: function () {
+ var maxExtent = null;
+ 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:
+ * {<OpenLayers.Bounds>} 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();
+ }
+ return resolution;
+ },
+
+ /**
+ * 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 - {<OpenLayers.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
+ *
+ * Parameter:
+ * 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
+ *
+ * Parameter:
+ * 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
+ *
+ * Parameters:
+ * zoom - {int}
+ */
+ zoomIn: function() {
+ this.zoomTo(this.getZoom() + 1);
+ },
+
+ /**
+ * APIMethod: zoomOut
+ *
+ * Parameters:
+ * zoom - {int}
+ */
+ zoomOut: function() {
+ this.zoomTo(this.getZoom() - 1);
+ },
+
+ /**
+ * APIMethod: zoomToExtent
+ * Zoom to the passed in bounds, recenter
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ */
+ zoomToExtent: function(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. Because our new bounds is at least partially
+ // outside the bounds of maxExtent, the new calculated center
+ // might also be. We don't want to pass a bad center value to
+ // setCenter, so we have it wrap itself across the date line.
+ //
+ center = bounds.getCenterLonLat().wrapDateLine(maxExtent);
+ }
+ this.setCenter(center, this.getZoomForExtent(bounds));
+ },
+
+ /**
+ * APIMethod: zoomToMaxExtent
+ * Zoom to the full extent and recenter.
+ */
+ zoomToMaxExtent: function() {
+ this.zoomToExtent(this.getMaxExtent());
+ },
+
+ /**
+ * APIMethod: zoomToScale
+ * Zoom to a specified scale
+ *
+ * Parameters:
+ * scale - {float}
+ */
+ zoomToScale: function(scale) {
+ var res = OpenLayers.Util.getResolutionFromScale(scale,
+ this.baseLayer.units);
+ var size = this.getSize();
+ var w_deg = size.w * res;
+ var h_deg = size.h * res;
+ var center = this.getCenter();
+
+ var extent = new OpenLayers.Bounds(center.lon - w_deg / 2,
+ center.lat - h_deg / 2,
+ center.lon + w_deg / 2,
+ center.lat + h_deg / 2);
+ this.zoomToExtent(extent);
+ },
+
+ /********************************************************/
+ /* */
+ /* Translation Functions */
+ /* */
+ /* The following functions translate between */
+ /* LonLat, LayerPx, and ViewPortPx */
+ /* */
+ /********************************************************/
+
+ //
+ // TRANSLATION: LonLat <-> ViewPortPx
+ //
+
+ /**
+ * Method: getLonLatFromViewPortPx
+ *
+ * Parameters:
+ * viewPortPx - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view
+ * port <OpenLayers.Pixel>, 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 - {<OpenLayers.LonLat>}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
+ * <OpenLayers.LonLat>, 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 - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} 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 - {<OpenLayers.LonLat>} A map location.
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} An OpenLayers.Pixel corresponding to the
+ * <OpenLayers.LonLat> 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;
+ },
+
+
+
+ //
+ // TRANSLATION: ViewPortPx <-> LayerPx
+ //
+
+ /**
+ * APIMethod: getViewPortPxFromLayerPx
+ *
+ * Parameters:
+ * layerPx - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} Layer Pixel translated into ViewPort Pixel
+ * coordinates
+ */
+ getViewPortPxFromLayerPx:function(layerPx) {
+ var viewPortPx = null;
+ if (layerPx != null) {
+ var dX = parseInt(this.layerContainerDiv.style.left);
+ var dY = parseInt(this.layerContainerDiv.style.top);
+ viewPortPx = layerPx.add(dX, dY);
+ }
+ return viewPortPx;
+ },
+
+ /**
+ * APIMethod: getLayerPxFromViewPortPx
+ *
+ * Parameters:
+ * viewPortPx - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} ViewPort Pixel translated into Layer Pixel
+ * coordinates
+ */
+ getLayerPxFromViewPortPx:function(viewPortPx) {
+ var layerPx = null;
+ if (viewPortPx != null) {
+ var dX = -parseInt(this.layerContainerDiv.style.left);
+ var dY = -parseInt(this.layerContainerDiv.style.top);
+ layerPx = viewPortPx.add(dX, dY);
+ if (isNaN(layerPx.x) || isNaN(layerPx.y)) {
+ layerPx = null;
+ }
+ }
+ return layerPx;
+ },
+
+ //
+ // TRANSLATION: LonLat <-> LayerPx
+ //
+
+ /**
+ * Method: getLonLatFromLayerPx
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>}
+ */
+ getLonLatFromLayerPx: function (px) {
+ //adjust for displacement of layerContainerDiv
+ px = this.getViewPortPxFromLayerPx(px);
+ return this.getLonLatFromViewPortPx(px);
+ },
+
+ /**
+ * APIMethod: getLayerPxFromLonLat
+ *
+ * Parameters:
+ * lonlat - {<OpenLayers.LonLat>} lonlat
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
+ * <OpenLayers.LonLat>, 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/Marker.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Events.js
+ * @requires OpenLayers/Icon.js
+ */
+
+/**
+ * Class: OpenLayers.Marker
+ * Instances of OpenLayers.Marker are a combination of a
+ * <OpenLayers.LonLat> and an <OpenLayers.Icon>.
+ *
+ * Markers are generally added to a special layer called
+ * <OpenLayers.Layer.Markers>.
+ *
+ * Example:
+ * (code)
+ * var markers = new OpenLayers.Layer.Markers( "Markers" );
+ * map.addLayer(markers);
+ *
+ * var size = new OpenLayers.Size(10,17);
+ * var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
+ * var icon = new OpenLayers.Icon('http://boston.openguides.org/markers/AQUA.png',size,offset);
+ * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon));
+ * markers.addMarker(new OpenLayers.Marker(new OpenLayers.LonLat(0,0),icon.clone()));
+ *
+ * (end)
+ *
+ * Note that if you pass an icon into the Marker constructor, it will take
+ * that icon and use it. This means that you should not share icons between
+ * markers -- you use them once, but you should clone() for any additional
+ * markers using that same icon.
+ */
+OpenLayers.Marker = OpenLayers.Class({
+
+ /**
+ * Property: icon
+ * {<OpenLayers.Icon>} The icon used by this marker.
+ */
+ icon: null,
+
+ /**
+ * Property: lonlat
+ * {<OpenLayers.LonLat>} location of object
+ */
+ lonlat: null,
+
+ /**
+ * Property: events
+ * {<OpenLayers.Events>} the event handler.
+ */
+ events: null,
+
+ /**
+ * Property: map
+ * {<OpenLayers.Map>} the map this marker is attached to
+ */
+ map: null,
+
+ /**
+ * Constructor: OpenLayers.Marker
+ * Paraemeters:
+ * icon - {<OpenLayers.Icon>} the icon for this marker
+ * lonlat - {<OpenLayers.LonLat>} the position of this marker
+ */
+ initialize: function(lonlat, icon) {
+ this.lonlat = lonlat;
+
+ var newIcon = (icon) ? icon : OpenLayers.Marker.defaultIcon();
+ if (this.icon == null) {
+ this.icon = newIcon;
+ } else {
+ this.icon.url = newIcon.url;
+ this.icon.size = newIcon.size;
+ this.icon.offset = newIcon.offset;
+ this.icon.calculateOffset = newIcon.calculateOffset;
+ }
+ this.events = new OpenLayers.Events(this, this.icon.imageDiv, null);
+ },
+
+ /**
+ * APIMethod: destroy
+ * Destroy the marker. You must first remove the marker from any
+ * layer which it has been added to, or you will get buggy behavior.
+ * (This can not be done within the marker since the marker does not
+ * know which layer it is attached to.)
+ */
+ destroy: function() {
+ this.map = null;
+
+ this.events.destroy();
+ this.events = null;
+
+ if (this.icon != null) {
+ this.icon.destroy();
+ this.icon = null;
+ }
+ },
+
+ /**
+ * Method: draw
+ * Calls draw on the icon, and returns that output.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {DOMElement} A new DOM Image with this marker's icon set at the
+ * location passed-in
+ */
+ draw: function(px) {
+ return this.icon.draw(px);
+ },
+
+ /**
+ * Method: moveTo
+ * Move the marker to the new location.
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>} the pixel position to move to
+ */
+ moveTo: function (px) {
+ if ((px != null) && (this.icon != null)) {
+ this.icon.moveTo(px);
+ }
+ this.lonlat = this.map.getLonLatFromLayerPx(px);
+ },
+
+ /**
+ * Method: onScreen
+ *
+ * Returns:
+ * {Boolean} Whether or not the marker is currently visible on screen.
+ */
+ onScreen:function() {
+
+ var onScreen = false;
+ if (this.map) {
+ var screenBounds = this.map.getExtent();
+ onScreen = screenBounds.containsLonLat(this.lonlat);
+ }
+ return onScreen;
+ },
+
+ /**
+ * Method: inflate
+ * Englarges the markers icon by the specified ratio.
+ *
+ * Parameters:
+ * inflate - {float} the ratio to enlarge the marker by (passing 2
+ * will double the size).
+ */
+ inflate: function(inflate) {
+ if (this.icon) {
+ var newSize = new OpenLayers.Size(this.icon.size.w * inflate,
+ this.icon.size.h * inflate);
+ this.icon.setSize(newSize);
+ }
+ },
+
+ /**
+ * Method: setOpacity
+ * Change the opacity of the marker by changin the opacity of
+ * its icon
+ *
+ * Parameters:
+ * opacity - {float} Specified as fraction (0.4, etc)
+ */
+ setOpacity: function(opacity) {
+ this.icon.setOpacity(opacity);
+ },
+
+ /**
+ * Method: setUrl
+ * Change URL of the Icon Image.
+ *
+ * url - {String}
+ */
+ setUrl: function(url) {
+ this.icon.setUrl(url);
+ },
+
+ /**
+ * Method: display
+ * Hide or show the icon
+ *
+ * display - {Boolean}
+ */
+ display: function(display) {
+ this.icon.display(display);
+ },
+
+ CLASS_NAME: "OpenLayers.Marker"
+});
+
+
+/**
+ * Function: defaultIcon
+ * Creates a default <OpenLayers.Icon>.
+ *
+ * Returns:
+ * {<OpenLayers.Icon>} A default OpenLayers.Icon to use for a marker
+ */
+OpenLayers.Marker.defaultIcon = function() {
+ var url = OpenLayers.Util.getImagesLocation() + "marker.png";
+ var size = new OpenLayers.Size(21, 25);
+ var calculateOffset = function(size) {
+ return new OpenLayers.Pixel(-(size.w/2), -size.h);
+ };
+
+ return new OpenLayers.Icon(url, size, null, calculateOffset);
+};
+
+
+/* ======================================================================
+ OpenLayers/Tile/Image.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Tile.js
+ */
+
+/**
+ * Class: OpenLayers.Tile.Image
+ * Instances of OpenLayers.Tile.Image are used to manage the image tiles
+ * used by various layers. Create a new image tile with the
+ * <OpenLayers.Tile.Image> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Tile>
+ */
+OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
+
+ /**
+ * Property: url
+ * {String} The URL of the image being requested. No default. Filled in by
+ * layer.getURL() function.
+ */
+ url: null,
+
+ /**
+ * Property: imgDiv
+ * {DOMElement} The div element which wraps the image.
+ */
+ imgDiv: null,
+
+ /**
+ * Property: frame
+ * {DOMElement} The image element is appended to the frame. Any gutter on
+ * the image will be hidden behind the frame.
+ */
+ frame: null,
+
+
+ /**
+ * Property: layerAlphaHack
+ * {Boolean} True if the png alpha hack needs to be applied on the layer's div.
+ */
+ layerAlphaHack: null,
+
+ /** TBD 3.0 - reorder the parameters to the init function to remove
+ * URL. the getUrl() function on the layer gets called on
+ * each draw(), so no need to specify it here.
+ *
+ * Constructor: OpenLayers.Tile.Image
+ * Constructor for a new <OpenLayers.Tile.Image> instance.
+ *
+ * Parameters:
+ * layer - {<OpenLayers.Layer>} layer that the tile will go in.
+ * position - {<OpenLayers.Pixel>}
+ * bounds - {<OpenLayers.Bounds>}
+ * url - {<String>} Deprecated. Remove me in 3.0.
+ * size - {<OpenLayers.Size>}
+ */
+ initialize: function(layer, position, bounds, url, size) {
+ OpenLayers.Tile.prototype.initialize.apply(this, arguments);
+
+ this.url = url; //deprecated remove me
+
+ this.frame = document.createElement('div');
+ this.frame.style.overflow = 'hidden';
+ this.frame.style.position = 'absolute';
+
+ this.layerAlphaHack = this.layer.alpha && OpenLayers.Util.alphaHack();
+ },
+
+ /**
+ * APIMethod: destroy
+ * nullify references to prevent circular references and memory leaks
+ */
+ destroy: function() {
+ if (this.imgDiv != null) {
+ if (this.layerAlphaHack) {
+ OpenLayers.Event.stopObservingElement(this.imgDiv.childNodes[0].id);
+ } else {
+ OpenLayers.Event.stopObservingElement(this.imgDiv.id);
+ }
+ if (this.imgDiv.parentNode == this.frame) {
+ this.frame.removeChild(this.imgDiv);
+ this.imgDiv.map = null;
+ }
+ }
+ this.imgDiv = null;
+ if ((this.frame != null) && (this.frame.parentNode == this.layer.div)) {
+ this.layer.div.removeChild(this.frame);
+ }
+ this.frame = null;
+ OpenLayers.Tile.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: clone
+ *
+ * Parameters:
+ * obj - {<OpenLayers.Tile.Image>} The tile to be cloned
+ *
+ * Returns:
+ * {<OpenLayers.Tile.Image>} An exact clone of this <OpenLayers.Tile.Image>
+ */
+ clone: function (obj) {
+ if (obj == null) {
+ obj = new OpenLayers.Tile.Image(this.layer,
+ this.position,
+ this.bounds,
+ this.url,
+ this.size);
+ }
+
+ //pick up properties from superclass
+ obj = OpenLayers.Tile.prototype.clone.apply(this, [obj]);
+
+ //dont want to directly copy the image div
+ obj.imgDiv = null;
+
+
+ return obj;
+ },
+
+ /**
+ * Method: draw
+ * Check that a tile should be drawn, and draw it.
+ *
+ * Returns:
+ * {Boolean} Always returns true.
+ */
+ draw: function() {
+ if (this.layer != this.layer.map.baseLayer && this.layer.reproject) {
+ this.bounds = this.getBoundsFromBaseLayer(this.position);
+ }
+ if (!OpenLayers.Tile.prototype.draw.apply(this, arguments)) {
+ return false;
+ }
+
+ if (this.isLoading) {
+ //if we're already loading, send 'reload' instead of 'loadstart'.
+ this.events.triggerEvent("reload");
+ } else {
+ this.isLoading = true;
+ this.events.triggerEvent("loadstart");
+ }
+
+ return this.renderTile();
+ },
+
+ /**
+ * Method: renderTile
+ * Internal function to actually initialize the image tile,
+ * position it correctly, and set its url.
+ */
+ renderTile: function() {
+ if (this.imgDiv == null) {
+ this.initImgDiv();
+ }
+
+ this.imgDiv.viewRequestID = this.layer.map.viewRequestID;
+
+ this.url = this.layer.getURL(this.bounds);
+ // position the frame
+ OpenLayers.Util.modifyDOMElement(this.frame,
+ null, this.position, this.size);
+
+ var imageSize = this.layer.getImageSize();
+ if (this.layerAlphaHack) {
+ OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,
+ null, null, imageSize, this.url);
+ } else {
+ OpenLayers.Util.modifyDOMElement(this.imgDiv,
+ null, null, imageSize) ;
+ this.imgDiv.src = this.url;
+ }
+ return true;
+ },
+
+ /**
+ * Method: clear
+ * Clear the tile of any bounds/position-related data so that it can
+ * be reused in a new location.
+ */
+ clear: function() {
+ if(this.imgDiv) {
+ this.hide();
+ if (OpenLayers.Tile.Image.useBlankTile) {
+ this.imgDiv.src = OpenLayers.Util.getImagesLocation() + "blank.gif";
+ }
+ }
+ },
+
+ /**
+ * Method: initImgDiv
+ * Creates the imgDiv property on the tile.
+ */
+ initImgDiv: function() {
+
+ var offset = this.layer.imageOffset;
+ var size = this.layer.getImageSize();
+
+ if (this.layerAlphaHack) {
+ this.imgDiv = OpenLayers.Util.createAlphaImageDiv(null,
+ offset,
+ size,
+ null,
+ "relative",
+ null,
+ null,
+ null,
+ true);
+ } else {
+ this.imgDiv = OpenLayers.Util.createImage(null,
+ offset,
+ size,
+ null,
+ "relative",
+ null,
+ null,
+ true);
+ }
+
+ this.imgDiv.className = 'olTileImage';
+
+ /* checkImgURL used to be used to called as a work around, but it
+ ended up hiding problems instead of solving them and broke things
+ like relative URLs. See discussion on the dev list:
+ http://openlayers.org/pipermail/dev/2007-January/000205.html
+
+ OpenLayers.Event.observe( this.imgDiv, "load",
+ OpenLayers.Function.bind(this.checkImgURL, this) );
+ */
+ this.frame.style.zIndex = this.isBackBuffer ? 0 : 1;
+ this.frame.appendChild(this.imgDiv);
+ this.layer.div.appendChild(this.frame);
+
+ if(this.layer.opacity != null) {
+
+ OpenLayers.Util.modifyDOMElement(this.imgDiv, null, null, null,
+ null, null, null,
+ this.layer.opacity);
+ }
+
+ // we need this reference to check back the viewRequestID
+ this.imgDiv.map = this.layer.map;
+
+ //bind a listener to the onload of the image div so that we
+ // can register when a tile has finished loading.
+ var onload = function() {
+
+ //normally isLoading should always be true here but there are some
+ // right funky conditions where loading and then reloading a tile
+ // with the same url *really*fast*. this check prevents sending
+ // a 'loadend' if the msg has already been sent
+ //
+ if (this.isLoading) {
+ this.isLoading = false;
+ this.events.triggerEvent("loadend");
+ }
+ };
+
+ if (this.layerAlphaHack) {
+ OpenLayers.Event.observe(this.imgDiv.childNodes[0], 'load',
+ OpenLayers.Function.bind(onload, this));
+ } else {
+ OpenLayers.Event.observe(this.imgDiv, 'load',
+ OpenLayers.Function.bind(onload, this));
+ }
+
+
+ // Bind a listener to the onerror of the image div so that we
+ // can registere when a tile has finished loading with errors.
+ var onerror = function() {
+
+ // If we have gone through all image reload attempts, it is time
+ // to realize that we are done with this image. Since
+ // OpenLayers.Util.onImageLoadError already has taken care about
+ // the error, we can continue as if the image was loaded
+ // successfully.
+ if (this.imgDiv._attempts > OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
+ onload.call(this);
+ }
+ };
+ OpenLayers.Event.observe(this.imgDiv, "error",
+ OpenLayers.Function.bind(onerror, this));
+ },
+
+ /**
+ * Method: checkImgURL
+ * Make sure that the image that just loaded is the one this tile is meant
+ * to display, since panning/zooming might have changed the tile's URL in
+ * the meantime. If the tile URL did change before the image loaded, set
+ * the imgDiv display to 'none', as either (a) it will be reset to visible
+ * when the new URL loads in the image, or (b) we don't want to display
+ * this tile after all because its new bounds are outside our maxExtent.
+ *
+ * This function should no longer be neccesary with the improvements to
+ * Grid.js in OpenLayers 2.3. The lack of a good isEquivilantURL function
+ * caused problems in 2.2, but it's possible that with the improved
+ * isEquivilant URL function, this might be neccesary at some point.
+ *
+ * See discussion in the thread at
+ * http://openlayers.org/pipermail/dev/2007-January/000205.html
+ */
+ checkImgURL: function () {
+ // Sometimes our image will load after it has already been removed
+ // from the map, in which case this check is not needed.
+ if (this.layer) {
+ var loaded = this.layerAlphaHack ? this.imgDiv.firstChild.src : this.imgDiv.src;
+ if (!OpenLayers.Util.isEquivalentUrl(loaded, this.url)) {
+ this.hide();
+ }
+ }
+ },
+
+ /**
+ * Method: startTransition
+ * This method is invoked on tiles that are backBuffers for tiles in the
+ * grid. The grid tile is about to be cleared and a new tile source
+ * loaded. This is where the transition effect needs to be started
+ * to provide visual continuity.
+ */
+ startTransition: function() {
+ // backBufferTile has to be valid and ready to use
+ if (!this.backBufferTile || !this.backBufferTile.imgDiv) {
+ return;
+ }
+
+ // calculate the ratio of change between the current resolution of the
+ // backBufferTile and the layer. If several animations happen in a
+ // row, then the backBufferTile will scale itself appropriately for
+ // each request.
+ var ratio = 1;
+ if (this.backBufferTile.resolution) {
+ ratio = this.backBufferTile.resolution / this.layer.getResolution();
+ }
+
+ // if the ratio is not the same as it was last time (i.e. we are
+ // zooming), then we need to adjust the backBuffer tile
+ if (ratio != this.lastRatio) {
+ if (this.layer.transitionEffect == 'resize') {
+ // In this case, we can just immediately resize the
+ // backBufferTile.
+ var upperLeft = new OpenLayers.LonLat(
+ this.backBufferTile.bounds.left,
+ this.backBufferTile.bounds.top
+ );
+ var size = new OpenLayers.Size(
+ this.backBufferTile.size.w * ratio,
+ this.backBufferTile.size.h * ratio
+ );
+
+ var px = this.layer.map.getLayerPxFromLonLat(upperLeft);
+ OpenLayers.Util.modifyDOMElement(this.backBufferTile.frame,
+ null, px, size);
+ var imageSize = this.backBufferTile.imageSize;
+ imageSize = new OpenLayers.Size(imageSize.w * ratio,
+ imageSize.h * ratio);
+ var imageOffset = this.backBufferTile.imageOffset;
+ if(imageOffset) {
+ imageOffset = new OpenLayers.Pixel(
+ imageOffset.x * ratio, imageOffset.y * ratio
+ );
+ }
+
+ OpenLayers.Util.modifyDOMElement(
+ this.backBufferTile.imgDiv, null, imageOffset, imageSize
+ ) ;
+
+ this.backBufferTile.show();
+ }
+ } else {
+ // default effect is just to leave the existing tile
+ // until the new one loads if this is a singleTile and
+ // there was no change in resolution. Otherwise we
+ // don't bother to show the backBufferTile at all
+ if (this.layer.singleTile) {
+ this.backBufferTile.show();
+ } else {
+ this.backBufferTile.hide();
+ }
+ }
+ this.lastRatio = ratio;
+
+ },
+
+ /**
+ * Method: show
+ * Show the tile by showing its frame.
+ */
+ show: function() {
+ this.frame.style.display = '';
+ // Force a reflow on gecko based browsers to actually show the element
+ // before continuing execution.
+ if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS,
+ this.layer.transitionEffect) != -1) {
+ if (navigator.userAgent.toLowerCase().indexOf("gecko") != -1) {
+ this.frame.scrollLeft = this.frame.scrollLeft;
+ }
+ }
+ },
+
+ /**
+ * Method: hide
+ * Hide the tile by hiding its frame.
+ */
+ hide: function() {
+ this.frame.style.display = 'none';
+ },
+
+ CLASS_NAME: "OpenLayers.Tile.Image"
+ }
+);
+
+OpenLayers.Tile.Image.useBlankTile = (
+ OpenLayers.Util.getBrowserName() == "safari" ||
+ OpenLayers.Util.getBrowserName() == "opera");
+/* ======================================================================
+ OpenLayers/Control/OverviewMap.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/BaseTypes.js
+ * @requires OpenLayers/Events.js
+ */
+
+/**
+ * Class: OpenLayers.Control.OverviewMap
+ * Create an overview map to display the extent of your main map and provide
+ * additional navigation control. Create a new overview map with the
+ * <OpenLayers.Control.OverviewMap> constructor.
+ *
+ * Inerits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Property: element
+ * {DOMElement} The DOM element that contains the overview map
+ */
+ element: null,
+
+ /**
+ * APIProperty: ovmap
+ * {<OpenLayers.Map>} A reference to the overview map itself.
+ */
+ ovmap: null,
+
+ /**
+ * APIProperty: size
+ * {<OpenLayers.Size>} The overvew map size in pixels. Note that this is
+ * the size of the map itself - the element that contains the map (default
+ * class name olControlOverviewMapElement) may have padding or other style
+ * attributes added via CSS.
+ */
+ size: new OpenLayers.Size(180, 90),
+
+ /**
+ * APIProperty: layers
+ * {Array(<OpenLayers.Layer>)} Ordered list of layers in the overview map.
+ * If none are sent at construction, the base layer for the main map is used.
+ */
+ layers: null,
+
+ /**
+ * APIProperty: minRectSize
+ * {Integer} The minimum width or height (in pixels) of the extent
+ * rectangle on the overview map. When the extent rectangle reaches
+ * this size, it will be replaced depending on the value of the
+ * <minRectDisplayClass> property. Default is 15 pixels.
+ */
+ minRectSize: 15,
+
+ /**
+ * APIProperty: minRectDisplayClass
+ * {String} Replacement style class name for the extent rectangle when
+ * <minRectSize> is reached. This string will be suffixed on to the
+ * displayClass. Default is "RectReplacement".
+ *
+ * Example CSS declaration:
+ * (code)
+ * .olControlOverviewMapRectReplacement {
+ * overflow: hidden;
+ * cursor: move;
+ * background-image: url("img/overview_replacement.gif");
+ * background-repeat: no-repeat;
+ * background-position: center;
+ * }
+ * (end)
+ */
+ minRectDisplayClass: "RectReplacement",
+
+ /**
+ * APIProperty: minRatio
+ * {Float} The ratio of the overview map resolution to the main map
+ * resolution at which to zoom farther out on the overview map.
+ */
+ minRatio: 8,
+
+ /**
+ * APIProperty: maxRatio
+ * {Float} The ratio of the overview map resolution to the main map
+ * resolution at which to zoom farther in on the overview map.
+ */
+ maxRatio: 32,
+
+ /**
+ * APIProperty: mapOptions
+ * {Object} An object containing any non-default properties to be sent to
+ * the overview map's map constructor. These should include any non-default
+ * options that the main map was constructed with.
+ */
+ mapOptions: null,
+
+ /**
+ * Property: handlers
+ * {Object}
+ */
+ handlers: null,
+
+ /**
+ * Constructor: OpenLayers.Control.OverviewMap
+ * Create a new overview map
+ *
+ * Parameters:
+ * object - {Object} Properties of this object will be set on the overview
+ * map object. Note, to set options on the map object contained in this
+ * control, set <mapOptions> as one of the options properties.
+ */
+ initialize: function(options) {
+ this.layers = [];
+ this.handlers = {};
+ OpenLayers.Control.prototype.initialize.apply(this, [options]);
+ },
+
+ /**
+ * APIMethod: destroy
+ * Deconstruct the control
+ */
+ destroy: function() {
+ if (!this.mapDiv) { // we've already been destroyed
+ return;
+ }
+ this.handlers.click.destroy();
+
+ this.mapDiv.removeChild(this.extentRectangle);
+ this.extentRectangle = null;
+ this.rectEvents.destroy();
+ this.rectEvents = null;
+
+ this.ovmap.destroy();
+ this.ovmap = null;
+
+ this.element.removeChild(this.mapDiv);
+ this.mapDiv = null;
+
+ this.div.removeChild(this.element);
+ this.element = null;
+
+ if (this.maximizeDiv) {
+ OpenLayers.Event.stopObservingElement(this.maximizeDiv);
+ this.div.removeChild(this.maximizeDiv);
+ this.maximizeDiv = null;
+ }
+
+ if (this.minimizeDiv) {
+ OpenLayers.Event.stopObservingElement(this.minimizeDiv);
+ this.div.removeChild(this.minimizeDiv);
+ this.minimizeDiv = null;
+ }
+
+ this.map.events.un({
+ "moveend": this.update,
+ "changebaselayer": this.baseLayerDraw,
+ scope: this
+ });
+
+ OpenLayers.Control.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: draw
+ * Render the control in the browser.
+ */
+ draw: function() {
+ OpenLayers.Control.prototype.draw.apply(this, arguments);
+ if(!(this.layers.length > 0)) {
+ if (this.map.baseLayer) {
+ var layer = this.map.baseLayer.clone();
+ this.layers = [layer];
+ } else {
+ this.map.events.register("changebaselayer", this, this.baseLayerDraw);
+ return this.div;
+ }
+ }
+
+ // create overview map DOM elements
+ this.element = document.createElement('div');
+ this.element.className = this.displayClass + 'Element';
+ this.element.style.display = 'none';
+
+ this.mapDiv = document.createElement('div');
+ this.mapDiv.style.width = this.size.w + 'px';
+ this.mapDiv.style.height = this.size.h + 'px';
+ this.mapDiv.style.position = 'relative';
+ this.mapDiv.style.overflow = 'hidden';
+ this.mapDiv.id = OpenLayers.Util.createUniqueID('overviewMap');
+
+ this.extentRectangle = document.createElement('div');
+ this.extentRectangle.style.position = 'absolute';
+ this.extentRectangle.style.zIndex = 1000; //HACK
+ this.extentRectangle.className = this.displayClass+'ExtentRectangle';
+ this.mapDiv.appendChild(this.extentRectangle);
+
+ this.element.appendChild(this.mapDiv);
+
+ this.div.appendChild(this.element);
+
+ // Optionally add min/max buttons if the control will go in the
+ // map viewport.
+ if(!this.outsideViewport) {
+ this.div.className += " " + this.displayClass + 'Container';
+ var imgLocation = OpenLayers.Util.getImagesLocation();
+ // maximize button div
+ var img = imgLocation + 'layer-switcher-maximize.png';
+ this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
+ this.displayClass + 'MaximizeButton',
+ null,
+ new OpenLayers.Size(18,18),
+ img,
+ 'absolute');
+ this.maximizeDiv.style.display = 'none';
+ this.maximizeDiv.className = this.displayClass + 'MaximizeButton';
+ OpenLayers.Event.observe(this.maximizeDiv, 'click',
+ OpenLayers.Function.bindAsEventListener(this.maximizeControl,
+ this)
+ );
+ this.div.appendChild(this.maximizeDiv);
+
+ // minimize button div
+ var img = imgLocation + 'layer-switcher-minimize.png';
+ this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
+ 'OpenLayers_Control_minimizeDiv',
+ null,
+ new OpenLayers.Size(18,18),
+ img,
+ 'absolute');
+ this.minimizeDiv.style.display = 'none';
+ this.minimizeDiv.className = this.displayClass + 'MinimizeButton';
+ OpenLayers.Event.observe(this.minimizeDiv, 'click',
+ OpenLayers.Function.bindAsEventListener(this.minimizeControl,
+ this)
+ );
+ this.div.appendChild(this.minimizeDiv);
+
+ var eventsToStop = ['dblclick','mousedown'];
+
+ for (var i = 0; i < eventsToStop.length; i++) {
+
+ OpenLayers.Event.observe(this.maximizeDiv,
+ eventsToStop[i],
+ OpenLayers.Event.stop);
+
+ OpenLayers.Event.observe(this.minimizeDiv,
+ eventsToStop[i],
+ OpenLayers.Event.stop);
+ }
+
+ this.minimizeControl();
+ } else {
+ // show the overview map
+ this.element.style.display = '';
+ }
+ if(this.map.getExtent()) {
+ this.update();
+ }
+
+ this.map.events.register('moveend', this, this.update);
+
+ return this.div;
+ },
+
+ /**
+ * Method: baseLayerDraw
+ * Draw the base layer - called if unable to complete in the initial draw
+ */
+ baseLayerDraw: function() {
+ this.draw();
+ this.map.events.unregister("changebaselayer", this, this.baseLayerDraw);
+ },
+
+ /**
+ * Method: rectDrag
+ * Handle extent rectangle drag
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>} The pixel location of the drag.
+ */
+ rectDrag: function(px) {
+ var deltaX = this.handlers.drag.last.x - px.x;
+ var deltaY = this.handlers.drag.last.y - px.y;
+ if(deltaX != 0 || deltaY != 0) {
+ var rectTop = this.rectPxBounds.top;
+ var rectLeft = this.rectPxBounds.left;
+ var rectHeight = Math.abs(this.rectPxBounds.getHeight());
+ var rectWidth = this.rectPxBounds.getWidth();
+ // don't allow dragging off of parent element
+ var newTop = Math.max(0, (rectTop - deltaY));
+ newTop = Math.min(newTop,
+ this.ovmap.size.h - this.hComp - rectHeight);
+ var newLeft = Math.max(0, (rectLeft - deltaX));
+ newLeft = Math.min(newLeft,
+ this.ovmap.size.w - this.wComp - rectWidth);
+ this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
+ newTop + rectHeight,
+ newLeft + rectWidth,
+ newTop));
+ }
+ },
+
+ /**
+ * Method: mapDivClick
+ * Handle browser events
+ *
+ * Parameters:
+ * evt - {<OpenLayers.Event>} evt
+ */
+ mapDivClick: function(evt) {
+ var pxCenter = this.rectPxBounds.getCenterPixel();
+ var deltaX = evt.xy.x - pxCenter.x;
+ var deltaY = evt.xy.y - pxCenter.y;
+ var top = this.rectPxBounds.top;
+ var left = this.rectPxBounds.left;
+ var height = Math.abs(this.rectPxBounds.getHeight());
+ var width = this.rectPxBounds.getWidth();
+ var newTop = Math.max(0, (top + deltaY));
+ newTop = Math.min(newTop, this.ovmap.size.h - height);
+ var newLeft = Math.max(0, (left + deltaX));
+ newLeft = Math.min(newLeft, this.ovmap.size.w - width);
+ this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
+ newTop + height,
+ newLeft + width,
+ newTop));
+ this.updateMapToRect();
+ },
+
+ /**
+ * Method: maximizeControl
+ * Unhide the control. Called when the control is in the map viewport.
+ *
+ * Parameters:
+ * e - {<OpenLayers.Event>}
+ */
+ maximizeControl: function(e) {
+ this.element.style.display = '';
+ this.showToggle(false);
+ if (e != null) {
+ OpenLayers.Event.stop(e);
+ }
+ },
+
+ /**
+ * Method: minimizeControl
+ * Hide all the contents of the control, shrink the size,
+ * add the maximize icon
+ *
+ * Parameters:
+ * e - {<OpenLayers.Event>}
+ */
+ minimizeControl: function(e) {
+ this.element.style.display = 'none';
+ this.showToggle(true);
+ if (e != null) {
+ OpenLayers.Event.stop(e);
+ }
+ },
+
+ /**
+ * Method: showToggle
+ * Hide/Show the toggle depending on whether the control is minimized
+ *
+ * Parameters:
+ * minimize - {Boolean}
+ */
+ showToggle: function(minimize) {
+ this.maximizeDiv.style.display = minimize ? '' : 'none';
+ this.minimizeDiv.style.display = minimize ? 'none' : '';
+ },
+
+ /**
+ * Method: update
+ * Update the overview map after layers move.
+ */
+ update: function() {
+ if(this.ovmap == null) {
+ this.createMap();
+ }
+
+ if(!this.isSuitableOverview()) {
+ this.updateOverview();
+ }
+
+ // update extent rectangle
+ this.updateRectToMap();
+ },
+
+ /**
+ * Method: isSuitableOverview
+ * Determines if the overview map is suitable given the extent and
+ * resolution of the main map.
+ */
+ isSuitableOverview: function() {
+ var mapExtent = this.map.getExtent();
+ var maxExtent = this.map.maxExtent;
+ var testExtent = new OpenLayers.Bounds(
+ Math.max(mapExtent.left, maxExtent.left),
+ Math.max(mapExtent.bottom, maxExtent.bottom),
+ Math.min(mapExtent.right, maxExtent.right),
+ Math.min(mapExtent.top, maxExtent.top));
+ var resRatio = this.ovmap.getResolution() / this.map.getResolution();
+ return ((resRatio > this.minRatio) &&
+ (resRatio <= this.maxRatio) &&
+ (this.ovmap.getExtent().containsBounds(testExtent)));
+ },
+
+ /**
+ * Method updateOverview
+ * Called by <update> if <isSuitableOverview> returns true
+ */
+ updateOverview: function() {
+ var mapRes = this.map.getResolution();
+ var targetRes = this.ovmap.getResolution();
+ var resRatio = targetRes / mapRes;
+ if(resRatio > this.maxRatio) {
+ // zoom in overview map
+ targetRes = this.minRatio * mapRes;
+ } else if(resRatio <= this.minRatio) {
+ // zoom out overview map
+ targetRes = this.maxRatio * mapRes;
+ }
+ this.ovmap.setCenter(this.map.center,
+ this.ovmap.getZoomForResolution(targetRes));
+ this.updateRectToMap();
+ },
+
+ /**
+ * Method: createMap
+ * Construct the map that this control contains
+ */
+ createMap: function() {
+ // create the overview map
+ var options = OpenLayers.Util.extend(
+ {controls: [], maxResolution: 'auto',
+ fallThrough: false}, this.mapOptions);
+ this.ovmap = new OpenLayers.Map(this.mapDiv, options);
+
+ // prevent ovmap from being destroyed when the page unloads, because
+ // the OverviewMap control has to do this (and does it).
+ OpenLayers.Event.stopObserving(window, 'unload', this.ovmap.unloadDestroy);
+
+ this.ovmap.addLayers(this.layers);
+ this.ovmap.zoomToMaxExtent();
+ // check extent rectangle border width
+ this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+ 'border-left-width')) +
+ parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+ 'border-right-width'));
+ this.wComp = (this.wComp) ? this.wComp : 2;
+ this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+ 'border-top-width')) +
+ parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
+ 'border-bottom-width'));
+ this.hComp = (this.hComp) ? this.hComp : 2;
+
+ this.handlers.drag = new OpenLayers.Handler.Drag(
+ this, {move: this.rectDrag, done: this.updateMapToRect},
+ {map: this.ovmap}
+ );
+ this.handlers.click = new OpenLayers.Handler.Click(
+ this, {
+ "click": this.mapDivClick
+ },{
+ "single": true, "double": false,
+ "stopSingle": true, "stopDouble": true,
+ "pixelTolerance": 1,
+ map: this.ovmap
+ }
+ );
+ this.handlers.click.activate();
+
+ this.rectEvents = new OpenLayers.Events(this, this.extentRectangle,
+ null, true);
+ this.rectEvents.register("mouseover", this, function(e) {
+ if(!this.handlers.drag.active && !this.map.dragging) {
+ this.handlers.drag.activate();
+ }
+ });
+ this.rectEvents.register("mouseout", this, function(e) {
+ if(!this.handlers.drag.dragging) {
+ this.handlers.drag.deactivate();
+ }
+ });
+
+ },
+
+ /**
+ * Method: updateRectToMap
+ * Updates the extent rectangle position and size to match the map extent
+ */
+ updateRectToMap: function() {
+ // The base layer for overview map needs to be in the same projection
+ // as the base layer for the main map. This should be made more robust.
+ if(this.map.units != 'degrees') {
+ if(this.ovmap.getProjection() && (this.map.getProjection() != this.ovmap.getProjection())) {
+ alert(OpenLayers.i18n("sameProjection"));
+ }
+ }
+ var pxBounds = this.getRectBoundsFromMapBounds(this.map.getExtent());
+ if (pxBounds) {
+ this.setRectPxBounds(pxBounds);
+ }
+ },
+
+ /**
+ * Method: updateMapToRect
+ * Updates the map extent to match the extent rectangle position and size
+ */
+ updateMapToRect: function() {
+ var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds);
+ this.map.panTo(lonLatBounds.getCenterLonLat());
+ },
+
+ /**
+ * Method: setRectPxBounds
+ * Set extent rectangle pixel bounds.
+ *
+ * Parameters:
+ * pxBounds - {<OpenLayers.Bounds>}
+ */
+ setRectPxBounds: function(pxBounds) {
+ var top = Math.max(pxBounds.top, 0);
+ var left = Math.max(pxBounds.left, 0);
+ var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()),
+ this.ovmap.size.h - this.hComp);
+ var right = Math.min(pxBounds.left + pxBounds.getWidth(),
+ this.ovmap.size.w - this.wComp);
+ var width = Math.max(right - left, 0);
+ var height = Math.max(bottom - top, 0);
+ if(width < this.minRectSize || height < this.minRectSize) {
+ this.extentRectangle.className = this.displayClass +
+ this.minRectDisplayClass;
+ var rLeft = left + (width / 2) - (this.minRectSize / 2);
+ var rTop = top + (height / 2) - (this.minRectSize / 2);
+ this.extentRectangle.style.top = Math.round(rTop) + 'px';
+ this.extentRectangle.style.left = Math.round(rLeft) + 'px';
+ this.extentRectangle.style.height = this.minRectSize + 'px';
+ this.extentRectangle.style.width = this.minRectSize + 'px';
+ } else {
+ this.extentRectangle.className = this.displayClass +
+ 'ExtentRectangle';
+ this.extentRectangle.style.top = Math.round(top) + 'px';
+ this.extentRectangle.style.left = Math.round(left) + 'px';
+ this.extentRectangle.style.height = Math.round(height) + 'px';
+ this.extentRectangle.style.width = Math.round(width) + 'px';
+ }
+ this.rectPxBounds = new OpenLayers.Bounds(
+ Math.round(left), Math.round(bottom),
+ Math.round(right), Math.round(top)
+ );
+ },
+
+ /**
+ * Method: getRectBoundsFromMapBounds
+ * Get the rect bounds from the map bounds.
+ *
+ * Parameters:
+ * lonLatBounds - {<OpenLayers.Bounds>}
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>}A bounds which is the passed-in map lon/lat extent
+ * translated into pixel bounds for the overview map
+ */
+ getRectBoundsFromMapBounds: function(lonLatBounds) {
+ var leftBottomLonLat = new OpenLayers.LonLat(lonLatBounds.left,
+ lonLatBounds.bottom);
+ var rightTopLonLat = new OpenLayers.LonLat(lonLatBounds.right,
+ lonLatBounds.top);
+ var leftBottomPx = this.getOverviewPxFromLonLat(leftBottomLonLat);
+ var rightTopPx = this.getOverviewPxFromLonLat(rightTopLonLat);
+ var bounds = null;
+ if (leftBottomPx && rightTopPx) {
+ bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y,
+ rightTopPx.x, rightTopPx.y);
+ }
+ return bounds;
+ },
+
+ /**
+ * Method: getMapBoundsFromRectBounds
+ * Get the map bounds from the rect bounds.
+ *
+ * Parameters:
+ * pxBounds - {<OpenLayers.Bounds>}
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} Bounds which is the passed-in overview rect bounds
+ * translated into lon/lat bounds for the overview map
+ */
+ getMapBoundsFromRectBounds: function(pxBounds) {
+ var leftBottomPx = new OpenLayers.Pixel(pxBounds.left,
+ pxBounds.bottom);
+ var rightTopPx = new OpenLayers.Pixel(pxBounds.right,
+ pxBounds.top);
+ var leftBottomLonLat = this.getLonLatFromOverviewPx(leftBottomPx);
+ var rightTopLonLat = this.getLonLatFromOverviewPx(rightTopPx);
+ return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat,
+ rightTopLonLat.lon, rightTopLonLat.lat);
+ },
+
+ /**
+ * Method: getLonLatFromOverviewPx
+ * Get a map location from a pixel location
+ *
+ * Parameters:
+ * overviewMapPx - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} Location which is the passed-in overview map
+ * OpenLayers.Pixel, translated into lon/lat by the overview map
+ */
+ getLonLatFromOverviewPx: function(overviewMapPx) {
+ var size = this.ovmap.size;
+ var res = this.ovmap.getResolution();
+ var center = this.ovmap.getExtent().getCenterLonLat();
+
+ var delta_x = overviewMapPx.x - (size.w / 2);
+ var delta_y = overviewMapPx.y - (size.h / 2);
+
+ return new OpenLayers.LonLat(center.lon + delta_x * res ,
+ center.lat - delta_y * res);
+ },
+
+ /**
+ * Method: getOverviewPxFromLonLat
+ * Get a pixel location from a map location
+ *
+ * Parameters:
+ * lonlat - {<OpenLayers.LonLat>}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} Location which is the passed-in OpenLayers.LonLat,
+ * translated into overview map pixels
+ */
+ getOverviewPxFromLonLat: function(lonlat) {
+ var res = this.ovmap.getResolution();
+ var extent = this.ovmap.getExtent();
+ var px = null;
+ if (extent) {
+ px = new OpenLayers.Pixel(
+ Math.round(1/res * (lonlat.lon - extent.left)),
+ Math.round(1/res * (extent.top - lonlat.lat)));
+ }
+ return px;
+ },
+
+ CLASS_NAME: 'OpenLayers.Control.OverviewMap'
+});
+/* ======================================================================
+ OpenLayers/Handler/Click.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the clear BSD license.
+ * See http://svn.openlayers.org/trunk/openlayers/license.txt
+ * for the full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Click
+ * A handler for mouse clicks. The intention of this handler is to give
+ * controls more flexibility with handling clicks. Browsers trigger
+ * click events twice for a double-click. In addition, the mousedown,
+ * mousemove, mouseup sequence fires a click event. With this handler,
+ * controls can decide whether to ignore clicks associated with a double
+ * click. By setting a <pixelTolerance>, controls can also ignore clicks
+ * that include a drag. Create a new instance with the
+ * <OpenLayers.Handler.Click> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
+
+ /**
+ * APIProperty: delay
+ * {Number} Number of milliseconds between clicks before the event is
+ * considered a double-click.
+ */
+ delay: 300,
+
+ /**
+ * APIProperty: single
+ * {Boolean} Handle single clicks. Default is true. If false, clicks
+ * will not be reported. If true, single-clicks will be reported.
+ */
+ single: true,
+
+ /**
+ * APIProperty: double
+ * {Boolean} Handle double-clicks. Default is false.
+ */
+ 'double': false,
+
+ /**
+ * APIProperty: pixelTolerance
+ * {Number} Maximum number of pixels between mouseup and mousedown for an
+ * event to be considered a click. Default is 0. If set to an
+ * integer value, clicks with a drag greater than the value will be
+ * ignored. This property can only be set when the handler is
+ * constructed.
+ */
+ pixelTolerance: 0,
+
+ /**
+ * APIProperty: stopSingle
+ * {Boolean} Stop other listeners from being notified of clicks. Default
+ * is false. If true, any click listeners registered before this one
+ * will not be notified of *any* click event (associated with double
+ * or single clicks).
+ */
+ stopSingle: false,
+
+ /**
+ * APIProperty: stopDouble
+ * {Boolean} Stop other listeners from being notified of double-clicks.
+ * Default is false. If true, any click listeners registered before
+ * this one will not be notified of *any* double-click events.
+ *
+ * The one caveat with stopDouble is that given a map with two click
+ * handlers, one with stopDouble true and the other with stopSingle
+ * true, the stopSingle handler should be activated last to get
+ * uniform cross-browser performance. Since IE triggers one click
+ * with a dblclick and FF triggers two, if a stopSingle handler is
+ * activated first, all it gets in IE is a single click when the
+ * second handler stops propagation on the dblclick.
+ */
+ stopDouble: false,
+
+ /**
+ * Property: timerId
+ * {Number} The id of the timeout waiting to clear the <delayedCall>.
+ */
+ timerId: null,
+
+ /**
+ * Property: down
+ * {<OpenLayers.Pixel>} The pixel location of the last mousedown.
+ */
+ down: null,
+
+ /**
+ * Constructor: OpenLayers.Handler.Click
+ * Create a new click handler.
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>} The control that is making use of
+ * this handler. If a handler is being used without a control, the
+ * handler's setMap method must be overridden to deal properly with
+ * the map.
+ * callbacks - {Object} An object with keys corresponding to callbacks
+ * that will be called by the handler. The callbacks should
+ * expect to recieve a single argument, the click event.
+ * Callbacks for 'click' and 'dblclick' are supported.
+ * options - {Object} Optional object whose properties will be set on the
+ * handler.
+ */
+ initialize: function(control, callbacks, options) {
+ OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+ // optionally register for mouseup and mousedown
+ if(this.pixelTolerance != null) {
+ this.mousedown = function(evt) {
+ this.down = evt.xy;
+ return true;
+ };
+ }
+ },
+
+ /**
+ * Method: mousedown
+ * Handle mousedown. Only registered as a listener if pixelTolerance is
+ * a non-zero value at construction.
+ *
+ * Returns:
+ * {Boolean} Continue propagating this event.
+ */
+ mousedown: null,
+
+ /**
+ * Method: dblclick
+ * Handle dblclick. For a dblclick, we get two clicks in some browsers
+ * (FF) and one in others (IE). So we need to always register for
+ * dblclick to properly handle single clicks.
+ *
+ * Returns:
+ * {Boolean} Continue propagating this event.
+ */
+ dblclick: function(evt) {
+ if(this.passesTolerance(evt)) {
+ if(this["double"]) {
+ this.callback('dblclick', [evt]);
+ }
+ this.clearTimer();
+ }
+ return !this.stopDouble;
+ },
+
+ /**
+ * Method: click
+ * Handle click.
+ *
+ * Returns:
+ * {Boolean} Continue propagating this event.
+ */
+ click: function(evt) {
+ if(this.passesTolerance(evt)) {
+ if(this.timerId != null) {
+ // already received a click
+ this.clearTimer();
+ } else {
+ // set the timer, send evt only if single is true
+ //use a clone of the event object because it will no longer
+ //be a valid event object in IE in the timer callback
+ var clickEvent = this.single ?
+ OpenLayers.Util.extend({}, evt) : null;
+ this.timerId = window.setTimeout(
+ OpenLayers.Function.bind(this.delayedCall, this, clickEvent),
+ this.delay
+ );
+ }
+ }
+ return !this.stopSingle;
+ },
+
+ /**
+ * Method: passesTolerance
+ * Determine whether the event is within the optional pixel tolerance. Note
+ * that the pixel tolerance check only works if mousedown events get to
+ * the listeners registered here. If they are stopped by other elements,
+ * the <pixelTolerance> will have no effect here (this method will always
+ * return true).
+ *
+ * Returns:
+ * {Boolean} The click is within the pixel tolerance (if specified).
+ */
+ passesTolerance: function(evt) {
+ var passes = true;
+ if(this.pixelTolerance != null && this.down) {
+ var dpx = Math.sqrt(
+ Math.pow(this.down.x - evt.xy.x, 2) +
+ Math.pow(this.down.y - evt.xy.y, 2)
+ );
+ if(dpx > this.pixelTolerance) {
+ passes = false;
+ }
+ }
+ return passes;
+ },
+
+ /**
+ * Method: clearTimer
+ * Clear the timer and set <timerId> to null.
+ */
+ clearTimer: function() {
+ if(this.timerId != null) {
+ window.clearTimeout(this.timerId);
+ this.timerId = null;
+ }
+ },
+
+ /**
+ * Method: delayedCall
+ * Sets <timerId> to null. And optionally triggers the click callback if
+ * evt is set.
+ */
+ delayedCall: function(evt) {
+ this.timerId = null;
+ if(evt) {
+ this.callback('click', [evt]);
+ }
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Deactivate the handler.
+ *
+ * Returns:
+ * {Boolean} The handler was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = false;
+ if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+ this.clearTimer();
+ this.down = null;
+ deactivated = true;
+ }
+ return deactivated;
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.Click"
+});
+/* ======================================================================
+ OpenLayers/Handler/Drag.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Drag
+ * The drag handler is used to deal with sequences of browser events related
+ * to dragging. The handler is used by controls that want to know when
+ * a drag sequence begins, when a drag is happening, and when it has
+ * finished.
+ *
+ * Controls that use the drag handler typically construct it with callbacks
+ * for 'down', 'move', and 'done'. Callbacks for these keys are called
+ * when the drag begins, with each move, and when the drag is done. In
+ * addition, controls can have callbacks keyed to 'up' and 'out' if they
+ * care to differentiate between the types of events that correspond with
+ * the end of a drag sequence. If no drag actually occurs (no mouse move)
+ * the 'down' and 'up' callbacks will be called, but not the 'done'
+ * callback.
+ *
+ * Create a new drag handler with the <OpenLayers.Handler.Drag> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, {
+
+ /**
+ * Property: started
+ * {Boolean} When a mousedown event is received, we want to record it, but
+ * not set 'dragging' until the mouse moves after starting.
+ */
+ started: false,
+
+ /**
+ * Property: stopDown
+ * {Boolean} Stop propagation of mousedown events from getting to listeners
+ * on the same element. Default is true.
+ */
+ stopDown: true,
+
+ /**
+ * Property: dragging
+ * {Boolean}
+ */
+ dragging: false,
+
+ /**
+ * Property: last
+ * {<OpenLayers.Pixel>} The last pixel location of the drag.
+ */
+ last: null,
+
+ /**
+ * Property: start
+ * {<OpenLayers.Pixel>} The first pixel location of the drag.
+ */
+ start: null,
+
+ /**
+ * Property: oldOnselectstart
+ * {Function}
+ */
+ oldOnselectstart: null,
+
+ /**
+ * Constructor: OpenLayers.Handler.Drag
+ * Returns OpenLayers.Handler.Drag
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>} The control that is making use of
+ * this handler. If a handler is being used without a control, the
+ * handlers setMap method must be overridden to deal properly with
+ * the map.
+ * callbacks - {Object} An object containing a single function to be
+ * called when the drag operation is finished. The callback should
+ * expect to recieve a single argument, the pixel location of the event.
+ * Callbacks for 'move' and 'done' are supported. You can also speficy
+ * callbacks for 'down', 'up', and 'out' to respond to those events.
+ * options - {Object}
+ */
+ initialize: function(control, callbacks, options) {
+ OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * The four methods below (down, move, up, and out) are used by subclasses
+ * to do their own processing related to these mouse events.
+ */
+
+ /**
+ * Method: down
+ * This method is called during the handling of the mouse down event.
+ * Subclasses can do their own processing here.
+ *
+ * Parameters:
+ * evt - {Event} The mouse down event
+ */
+ down: function(evt) {
+ },
+
+ /**
+ * Method: move
+ * This method is called during the handling of the mouse move event.
+ * Subclasses can do their own processing here.
+ *
+ * Parameters:
+ * evt - {Event} The mouse move event
+ *
+ */
+ move: function(evt) {
+ },
+
+ /**
+ * Method: up
+ * This method is called during the handling of the mouse up event.
+ * Subclasses can do their own processing here.
+ *
+ * Parameters:
+ * evt - {Event} The mouse up event
+ */
+ up: function(evt) {
+ },
+
+ /**
+ * Method: out
+ * This method is called during the handling of the mouse out event.
+ * Subclasses can do their own processing here.
+ *
+ * Parameters:
+ * evt - {Event} The mouse out event
+ */
+ out: function(evt) {
+ },
+
+ /**
+ * The methods below are part of the magic of event handling. Because
+ * they are named like browser events, they are registered as listeners
+ * for the events they represent.
+ */
+
+ /**
+ * Method: mousedown
+ * Handle mousedown events
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} Let the event propagate.
+ */
+ mousedown: function (evt) {
+ var propagate = true;
+ this.dragging = false;
+ if (this.checkModifiers(evt) && OpenLayers.Event.isLeftClick(evt)) {
+ this.started = true;
+ this.start = evt.xy;
+ this.last = evt.xy;
+ // TBD replace with CSS classes
+ this.map.div.style.cursor = "move";
+ this.down(evt);
+ this.callback("down", [evt.xy]);
+ OpenLayers.Event.stop(evt);
+
+ if(!this.oldOnselectstart) {
+ this.oldOnselectstart = (document.onselectstart) ? document.onselectstart : function() { return true; };
+ document.onselectstart = function() {return false;};
+ }
+
+ propagate = !this.stopDown;
+ } else {
+ this.started = false;
+ this.start = null;
+ this.last = null;
+ }
+ return propagate;
+ },
+
+ /**
+ * Method: mousemove
+ * Handle mousemove events
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} Let the event propagate.
+ */
+ mousemove: function (evt) {
+ if (this.started) {
+ if(evt.xy.x != this.last.x || evt.xy.y != this.last.y) {
+ this.dragging = true;
+ this.move(evt);
+ this.callback("move", [evt.xy]);
+ if(!this.oldOnselectstart) {
+ this.oldOnselectstart = document.onselectstart;
+ document.onselectstart = function() {return false;};
+ }
+ this.last = evt.xy;
+ }
+ }
+ return true;
+ },
+
+ /**
+ * Method: mouseup
+ * Handle mouseup events
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} Let the event propagate.
+ */
+ mouseup: function (evt) {
+ if (this.started) {
+ var dragged = (this.start != this.last);
+ this.started = false;
+ this.dragging = false;
+ // TBD replace with CSS classes
+ this.map.div.style.cursor = "";
+ this.up(evt);
+ this.callback("up", [evt.xy]);
+ if(dragged) {
+ this.callback("done", [evt.xy]);
+ }
+ document.onselectstart = this.oldOnselectstart;
+ }
+ return true;
+ },
+
+ /**
+ * Method: mouseout
+ * Handle mouseout events
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} Let the event propagate.
+ */
+ mouseout: function (evt) {
+ if (this.started && OpenLayers.Util.mouseLeft(evt, this.map.div)) {
+ var dragged = (this.start != this.last);
+ this.started = false;
+ this.dragging = false;
+ // TBD replace with CSS classes
+ this.map.div.style.cursor = "";
+ this.out(evt);
+ this.callback("out", []);
+ if(dragged) {
+ this.callback("done", [evt.xy]);
+ }
+ if(document.onselectstart) {
+ document.onselectstart = this.oldOnselectstart;
+ }
+ }
+ return true;
+ },
+
+ /**
+ * Method: click
+ * The drag handler captures the click event. If something else registers
+ * for clicks on the same element, its listener will not be called
+ * after a drag.
+ *
+ * Parameters:
+ * evt - {Event}
+ *
+ * Returns:
+ * {Boolean} Let the event propagate.
+ */
+ click: function (evt) {
+ // let the click event propagate only if the mouse moved
+ return (this.start == this.last);
+ },
+
+ /**
+ * Method: activate
+ * Activate the handler.
+ *
+ * Returns:
+ * {Boolean} The handler was successfully activated.
+ */
+ activate: function() {
+ var activated = false;
+ if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+ this.dragging = false;
+ activated = true;
+ }
+ return activated;
+ },
+
+ /**
+ * Method: deactivate
+ * Deactivate the handler.
+ *
+ * Returns:
+ * {Boolean} The handler was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = false;
+ if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+ this.started = false;
+ this.dragging = false;
+ this.start = null;
+ this.last = null;
+ deactivated = true;
+ }
+ return deactivated;
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.Drag"
+});
+/* ======================================================================
+ OpenLayers/Handler/MouseWheel.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.MouseWheel
+ * Handler for wheel up/down events.
+ *
+ * Inherits from:
+ * - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.MouseWheel = OpenLayers.Class(OpenLayers.Handler, {
+ /**
+ * Property: wheelListener
+ * {function}
+ */
+ wheelListener: null,
+
+ /**
+ * Property: mousePosition
+ * {<OpenLayers.Pixel>} mousePosition is necessary because
+ * evt.clientX/Y is buggy in Moz on wheel events, so we cache and use the
+ * value from the last mousemove.
+ */
+ mousePosition: null,
+
+ /**
+ * Constructor: OpenLayers.Handler.MouseWheel
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>}
+ * callbacks - {Object} An object containing a single function to be
+ * called when the drag operation is finished.
+ * The callback should expect to recieve a single
+ * argument, the point geometry.
+ * options - {Object}
+ */
+ initialize: function(control, callbacks, options) {
+ OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+ this.wheelListener = OpenLayers.Function.bindAsEventListener(
+ this.onWheelEvent, this
+ );
+ },
+
+ /**
+ * Method: destroy
+ */
+ destroy: function() {
+ OpenLayers.Handler.prototype.destroy.apply(this, arguments);
+ this.wheelListener = null;
+ },
+
+ /**
+ * Mouse ScrollWheel code thanks to http://adomas.org/javascript-mouse-wheel/
+ */
+
+ /**
+ * Method: onWheelEvent
+ * Catch the wheel event and handle it xbrowserly
+ *
+ * Parameters:
+ * e - {Event}
+ */
+ onWheelEvent: function(e){
+
+ // make sure we have a map and check keyboard modifiers
+ if (!this.map || !this.checkModifiers(e)) {
+ return;
+ }
+
+ // Ride up the element's DOM hierarchy to determine if it or any of
+ // its ancestors was:
+ // * specifically marked as scrollable
+ // * one of our layer divs
+ // * the map div
+ //
+ var overScrollableDiv = false;
+ var overLayerDiv = false;
+ var overMapDiv = false;
+
+ var elem = OpenLayers.Event.element(e);
+ while((elem != null) && !overMapDiv && !overScrollableDiv) {
+
+ if (!overScrollableDiv) {
+ try {
+ if (elem.currentStyle) {
+ overflow = elem.currentStyle["overflow"];
+ } else {
+ var style =
+ document.defaultView.getComputedStyle(elem, null);
+ var overflow = style.getPropertyValue("overflow");
+ }
+ overScrollableDiv = ( overflow &&
+ (overflow == "auto") || (overflow == "scroll") );
+ } catch(err) {
+ //sometimes when scrolling in a popup, this causes
+ // obscure browser error
+ }
+ }
+
+ if (!overLayerDiv) {
+ for(var i=0; i < this.map.layers.length; i++) {
+ // Are we in the layer div? Note that we have two cases
+ // here: one is to catch EventPane layers, which have a
+ // pane above the layer (layer.pane)
+ if (elem == this.map.layers[i].div
+ || elem == this.map.layers[i].pane) {
+ overLayerDiv = true;
+ break;
+ }
+ }
+ }
+ overMapDiv = (elem == this.map.div);
+
+ elem = elem.parentNode;
+ }
+
+ // Logic below is the following:
+ //
+ // If we are over a scrollable div or not over the map div:
+ // * do nothing (let the browser handle scrolling)
+ //
+ // otherwise
+ //
+ // If we are over the layer div:
+ // * zoom/in out
+ // then
+ // * kill event (so as not to also scroll the page after zooming)
+ //
+ // otherwise
+ //
+ // Kill the event (dont scroll the page if we wheel over the
+ // layerswitcher or the pan/zoom control)
+ //
+ if (!overScrollableDiv && overMapDiv) {
+ if (overLayerDiv) {
+ 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 = 0;
+ if (!e) {
+ e = window.event;
+ }
+ if (e.wheelDelta) {
+ delta = e.wheelDelta/120;
+ if (window.opera && window.opera.version() < 9.2) {
+ delta = -delta;
+ }
+ } else if (e.detail) {
+ delta = -e.detail / 3;
+ }
+ if (delta) {
+ // add the mouse position to the event because mozilla has
+ // a bug with clientX and clientY (see
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=352179)
+ // getLonLatFromViewPortPx(e) returns wrong values
+ if (this.mousePosition) {
+ e.xy = this.mousePosition;
+ }
+ if (!e.xy) {
+ // If the mouse hasn't moved over the map yet, then
+ // we don't have a mouse position (in FF), so we just
+ // act as if the mouse was at the center of the map.
+ // Note that we can tell we are in the map -- and
+ // this.map is ensured to be true above.
+ e.xy = this.map.getPixelFromLonLat(
+ this.map.getCenter()
+ );
+ }
+ if (delta < 0) {
+ this.callback("down", [e, delta]);
+ } else {
+ this.callback("up", [e, delta]);
+ }
+ }
+ },
+
+ /**
+ * Method: mousemove
+ * Update the stored mousePosition on every move.
+ *
+ * Parameters:
+ * evt - {Event} The browser event
+ *
+ * Returns:
+ * {Boolean} Allow event propagation
+ */
+ mousemove: function (evt) {
+ this.mousePosition = evt.xy;
+ },
+
+ /**
+ * Method: activate
+ */
+ activate: function (evt) {
+ if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+ //register mousewheel events specifically on the window and document
+ var wheelListener = this.wheelListener;
+ OpenLayers.Event.observe(window, "DOMMouseScroll", wheelListener);
+ OpenLayers.Event.observe(window, "mousewheel", wheelListener);
+ OpenLayers.Event.observe(document, "mousewheel", wheelListener);
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Method: deactivate
+ */
+ deactivate: function (evt) {
+ if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+ // unregister mousewheel events specifically on the window and document
+ var wheelListener = this.wheelListener;
+ OpenLayers.Event.stopObserving(window, "DOMMouseScroll", wheelListener);
+ OpenLayers.Event.stopObserving(window, "mousewheel", wheelListener);
+ OpenLayers.Event.stopObserving(document, "mousewheel", wheelListener);
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.MouseWheel"
+});
+/* ======================================================================
+ OpenLayers/Layer.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @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,
+
+ /**
+ * Property: opacity
+ * {Float} The layer's opacity. Float number between 0.0 and 1.0.
+ */
+ opacity: null,
+
+ /**
+ * Constant: EVENT_TYPES
+ * {Array(String)} Supported application event types. Register a listener
+ * for a particular event with the following syntax:
+ * (code)
+ * layer.events.register(type, obj, listener);
+ * (end)
+ *
+ * Listeners will be called with a reference to an event object. The
+ * properties of this event depends on exactly what happened.
+ *
+ * All event objects have at least the following properties:
+ * - *object* {Object} A reference to layer.events.object.
+ * - *element* {DOMElement} A reference to layer.events.element.
+ *
+ * Supported map event types:
+ * - *loadstart* Triggered when layer loading starts.
+ * - *loadend* Triggered when layer loading ends.
+ * - *loadcancel* Triggered when layer loading is canceled.
+ * - *visibilitychanged* Triggered when layer visibility is changed.
+ */
+ EVENT_TYPES: ["loadstart", "loadend", "loadcancel", "visibilitychanged"],
+
+ /**
+ * APIProperty: events
+ * {<OpenLayers.Events>}
+ */
+ events: null,
+
+ /**
+ * APIProperty: map
+ * {<OpenLayers.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
+ * <OpenLayers.Control.Attribution> 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 <OpenLayers.Map.setCenter> whenever the zoom
+ * changes.
+ */
+ inRange: false,
+
+ /**
+ * Propery: imageSize
+ * {<OpenLayers.Size>} For layers with a gutter, the image is larger than
+ * the tile by twice the gutter in each dimension.
+ */
+ imageSize: null,
+
+ /**
+ * Property: imageOffset
+ * {<OpenLayers.Pixel>} For layers with a gutter, the image offset
+ * represents displacement due to the gutter.
+ */
+ imageOffset: 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 <OpenLayers.Events.on>. 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
+ * {<OpenLayers.Projection>} or {<String>} Set in the layer options to
+ * override the default projection string this layer - also set maxExtent,
+ * maxResolution, and units if appropriate. Can be either a string or
+ * an <OpenLayers.Projection> object when created -- will be converted
+ * to an object when setMap is called if a string is passed.
+ */
+ projection: null,
+
+ /**
+ * APIProperty: units
+ * {String} The layer map units. Defaults to 'degrees'. Possible values
+ * are 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
+ */
+ 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 <resolutions> 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
+ * {<OpenLayers.Bounds>} The center of these bounds will not stray outside
+ * of the viewport extent during panning. In addition, if
+ * <displayOutsideMaxExtent> is set to false, data will not be
+ * requested that falls completely outside of these bounds.
+ */
+ maxExtent: null,
+
+ /**
+ * APIProperty: minExtent
+ * {<OpenLayers.Bounds>}
+ */
+ 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 a geographic projection 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} #487 for more info.
+ */
+ wrapDateLine: false,
+
+ /**
+ * APIProperty: transitionEffect
+ * {String} The transition effect to use when the map is panned or
+ * zoomed.
+ *
+ * There are currently two supported 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.
+ */
+ transitionEffect: null,
+
+ /**
+ * Property: SUPPORTED_TRANSITIONS
+ * {Array} An immutable (that means don't change it!) list of supported
+ * transitionEffect values.
+ */
+ SUPPORTED_TRANSITIONS: ['resize'],
+
+ /**
+ * 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.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.events = new OpenLayers.Events(this, this.div,
+ this.EVENT_TYPES);
+ if(this.eventListeners instanceof Object) {
+ this.events.on(this.eventListeners);
+ }
+
+ }
+
+ if (this.wrapDateLine) {
+ this.displayOutsideMaxExtent = true;
+ }
+ },
+
+ /**
+ * 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 - {<OpenLayers.Layer>} The layer to be cloned
+ *
+ * Returns:
+ * {<OpenLayers.Layer>} An exact clone of this <OpenLayers.Layer>
+ */
+ clone: function (obj) {
+
+ if (obj == null) {
+ obj = new OpenLayers.Layer(this.name, this.options);
+ }
+
+ // 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;
+ },
+
+ /**
+ * 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}
+ */
+ addOptions: function (newOptions) {
+
+ if (this.options == null) {
+ this.options = {};
+ }
+
+ // update our copy for clone
+ OpenLayers.Util.extend(this.options, newOptions);
+
+ // add new options to this
+ OpenLayers.Util.extend(this, newOptions);
+ },
+
+ /**
+ * 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) {
+ this.moveTo(extent, true, false);
+ redrawn = true;
+ }
+ }
+ return redrawn;
+ },
+
+ /**
+ * Method: moveTo
+ *
+ * Parameters:
+ * bound - {<OpenLayers.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: 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 - {<OpenLayers.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.projection = this.projection || this.map.projection;
+
+ if (this.projection && 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();
+ }
+ },
+
+ /**
+ * 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 - {<OpenLayers.Map>}
+ */
+ removeMap: function(map) {
+ //to be overridden by subclasses
+ },
+
+ /**
+ * APIMethod: getImageSize
+ *
+ * Returns:
+ * {<OpenLayers.Size>} The size that the image should be, taking into
+ * account gutters.
+ */
+ getImageSize: function() {
+ return (this.imageSize || this.tileSize);
+ },
+
+ /**
+ * APIMethod: setTileSize
+ * Set the tile size based on the map size. This also sets layer.imageSize
+ * and layer.imageOffset for use by Tile.Image.
+ *
+ * Parameters:
+ * size - {<OpenLayers.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.imageOffset = new OpenLayers.Pixel(-this.gutter,
+ -this.gutter);
+ 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:
+ * visible - {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
+ *
+ * Parameters:
+ * display - {Boolean}
+ */
+ display: function(display) {
+ var inRange = this.calculateInRange();
+ if (display != (this.div.style.display != "none")) {
+ this.div.style.display = (display && inRange) ? "block" : "none";
+ }
+ },
+
+ /**
+ * Method: calculateInRange
+ *
+ * Returns:
+ * {Boolean} The layer is displayable at the current map's current
+ * resolution.
+ */
+ calculateInRange: function() {
+ var inRange = false;
+ 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() {
+
+ // These are the relevant options which are used for calculating
+ // resolutions information.
+ //
+ var props = new Array(
+ 'projection', 'units',
+ 'scales', 'resolutions',
+ 'maxScale', 'minScale',
+ 'maxResolution', 'minResolution',
+ 'minExtent', 'maxExtent',
+ 'numZoomLevels', 'maxZoomLevel'
+ );
+
+ // First we create a new object where we will store all of the
+ // resolution-related properties that we find in either the layer's
+ // 'options' array or from the map.
+ //
+ var confProps = {};
+ for(var i=0; i < props.length; i++) {
+ var property = props[i];
+ confProps[property] = this.options[property] || this.map[property];
+ }
+
+ // Do not use the scales/resolutions at the map level if
+ // minScale/minResolution and maxScale/maxResolution are
+ // specified at the layer level
+ if (this.options.minScale != null &&
+ this.options.maxScale != null &&
+ this.options.scales == null) {
+ confProps.scales = null;
+ }
+ if (this.options.minResolution != null &&
+ this.options.maxResolution != null &&
+ this.options.resolutions == null) {
+ confProps.resolutions = null;
+ }
+
+ // If numZoomLevels hasn't been set and the maxZoomLevel *has*,
+ // then use maxZoomLevel to calculate numZoomLevels
+ //
+ if ( (!confProps.numZoomLevels) && (confProps.maxZoomLevel) ) {
+ confProps.numZoomLevels = confProps.maxZoomLevel + 1;
+ }
+
+ // First off, we take whatever hodge-podge of values we have and
+ // calculate/distill them down into a resolutions[] array
+ //
+ if ((confProps.scales != null) || (confProps.resolutions != null)) {
+ //preset levels
+ if (confProps.scales != null) {
+ confProps.resolutions = [];
+ for(var i = 0; i < confProps.scales.length; i++) {
+ var scale = confProps.scales[i];
+ confProps.resolutions[i] =
+ OpenLayers.Util.getResolutionFromScale(scale,
+ confProps.units);
+ }
+ }
+ confProps.numZoomLevels = confProps.resolutions.length;
+
+ } else {
+ //maxResolution and numZoomLevels based calculation
+
+ // determine maxResolution
+ if (confProps.minScale) {
+ confProps.maxResolution =
+ OpenLayers.Util.getResolutionFromScale(confProps.minScale,
+ confProps.units);
+ } else if (confProps.maxResolution == "auto") {
+ var viewSize = this.map.getSize();
+ var wRes = confProps.maxExtent.getWidth() / viewSize.w;
+ var hRes = confProps.maxExtent.getHeight()/ viewSize.h;
+ confProps.maxResolution = Math.max(wRes, hRes);
+ }
+
+ // determine minResolution
+ if (confProps.maxScale != null) {
+ confProps.minResolution =
+ OpenLayers.Util.getResolutionFromScale(confProps.maxScale,
+ confProps.units);
+ } else if ( (confProps.minResolution == "auto") &&
+ (confProps.minExtent != null) ) {
+ var viewSize = this.map.getSize();
+ var wRes = confProps.minExtent.getWidth() / viewSize.w;
+ var hRes = confProps.minExtent.getHeight()/ viewSize.h;
+ confProps.minResolution = Math.max(wRes, hRes);
+ }
+
+ // determine numZoomLevels if not already set on the layer
+ // this gives numZoomLevels assuming approximately base 2 scaling
+ if (confProps.minResolution != null &&
+ this.options.numZoomLevels == undefined) {
+ var ratio = confProps.maxResolution / confProps.minResolution;
+ confProps.numZoomLevels =
+ Math.floor(Math.log(ratio) / Math.log(2)) + 1;
+ }
+
+ // now we have numZoomLevels and maxResolution,
+ // we can populate the resolutions array
+ confProps.resolutions = new Array(confProps.numZoomLevels);
+ var base = 2;
+ if(typeof confProps.minResolution == "number" &&
+ confProps.numZoomLevels > 1) {
+ /**
+ * If maxResolution and minResolution are set (or related
+ * scale properties), we calculate the base for exponential
+ * scaling that starts at maxResolution and ends at
+ * minResolution in numZoomLevels steps.
+ */
+ base = Math.pow(
+ (confProps.maxResolution / confProps.minResolution),
+ (1 / (confProps.numZoomLevels - 1))
+ );
+ }
+ for (var i=0; i < confProps.numZoomLevels; i++) {
+ var res = confProps.maxResolution / Math.pow(base, i);
+ confProps.resolutions[i] = res;
+ }
+ }
+
+ //sort resolutions array ascendingly
+ //
+ confProps.resolutions.sort( function(a, b) { return(b-a); } );
+
+ // now set our newly calculated values back to the layer
+ // Note: We specifically do *not* set them to layer.options, which we
+ // will preserve as it was when we added this layer to the map.
+ // this way cloned layers reset themselves to new map div
+ // dimensions)
+ //
+
+ this.resolutions = confProps.resolutions;
+ this.maxResolution = confProps.resolutions[0];
+ var lastIndex = confProps.resolutions.length - 1;
+ this.minResolution = confProps.resolutions[lastIndex];
+
+ this.scales = [];
+ for(var i = 0; i < confProps.resolutions.length; i++) {
+ this.scales[i] =
+ OpenLayers.Util.getScaleFromResolution(confProps.resolutions[i],
+ confProps.units);
+ }
+ this.minScale = this.scales[0];
+ this.maxScale = this.scales[this.scales.length - 1];
+
+ this.numZoomLevels = confProps.numZoomLevels;
+ },
+
+ /**
+ * APIMethod: getResolution
+ *
+ * Returns:
+ * {Float} The currently selected resolution of the map, taken from the
+ * resolutions array, indexed by current zoom level.
+ */
+ getResolution: function() {
+ var zoom = this.map.getZoom();
+ return this.getResolutionForZoom(zoom);
+ },
+
+ /**
+ * APIMethod: getExtent
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} 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:
+ * bounds - {<OpenLayers.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} 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:
+ * {<OpenLayers.Bounds>}
+ */
+ getDataExtent: function () {
+ //to be implemented by subclasses
+ },
+
+ /**
+ * APIMethod: getResolutionForZoom
+ *
+ * Parameter:
+ * 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[high] +
+ ((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;
+ 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(var i=0; i<this.resolutions.length; ++i) {
+ res = this.resolutions[i];
+ if(res >= resolution) {
+ highRes = res;
+ lowZoom = i;
+ }
+ if(res <= resolution) {
+ lowRes = res;
+ highZoom = i;
+ break;
+ }
+ }
+ var dRes = highRes - lowRes;
+ if(dRes > 0) {
+ zoom = lowZoom + ((resolution - lowRes) / dRes);
+ } else {
+ zoom = lowZoom;
+ }
+ } else {
+ var diff;
+ var minDiff = Number.POSITIVE_INFINITY;
+ for(var i=0; i < this.resolutions.length; i++) {
+ if (closest) {
+ diff = Math.abs(this.resolutions[i] - resolution);
+ if (diff > minDiff) {
+ break;
+ }
+ minDiff = diff;
+ } else {
+ if (this.resolutions[i] < resolution) {
+ break;
+ }
+ }
+ }
+ zoom = Math.max(0, i-1);
+ }
+ return zoom;
+ },
+
+ /**
+ * APIMethod: getLonLatFromViewPortPx
+ *
+ * Parameters:
+ * viewPortPx - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in
+ * view port <OpenLayers.Pixel>, translated into lon/lat by the layer.
+ */
+ getLonLatFromViewPortPx: function (viewPortPx) {
+ var lonlat = null;
+ if (viewPortPx != null) {
+ var size = this.map.getSize();
+ var center = this.map.getCenter();
+ if (center) {
+ var res = this.map.getResolution();
+
+ var delta_x = viewPortPx.x - (size.w / 2);
+ var delta_y = viewPortPx.y - (size.h / 2);
+
+ lonlat = new OpenLayers.LonLat(center.lon + delta_x * res ,
+ center.lat - delta_y * res);
+
+ if (this.wrapDateLine) {
+ lonlat = lonlat.wrapDateLine(this.maxExtent);
+ }
+ } // else { DEBUG STATEMENT }
+ }
+ return lonlat;
+ },
+
+ /**
+ * APIMethod: getViewPortPxFromLonLat
+ * Returns a pixel location given a map location. This method will return
+ * fractional pixel values.
+ *
+ * Parameters:
+ * lonlat - {<OpenLayers.LonLat>}
+ *
+ * Returns:
+ * {<OpenLayers.Pixel>} An <OpenLayers.Pixel> which is the passed-in
+ * <OpenLayers.LonLat>,translated into view port pixels.
+ */
+ getViewPortPxFromLonLat: function (lonlat) {
+ var px = null;
+ if (lonlat != null) {
+ var resolution = this.map.getResolution();
+ var extent = this.map.getExtent();
+ 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)
+ *
+ * Parameter:
+ * opacity - {Float}
+ */
+ setOpacity: function(opacity) {
+ if (opacity != this.opacity) {
+ this.opacity = opacity;
+ for(var i=0; i<this.div.childNodes.length; ++i) {
+ var element = this.div.childNodes[i].firstChild;
+ OpenLayers.Util.modifyDOMElement(element, null, null, null,
+ null, null, null, opacity);
+ }
+ }
+ },
+
+ /**
+ * 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 - {<OpenLayers.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()
+ };
+ bounds = bounds.wrapDateLine(this.maxExtent, wrappingOptions);
+
+ }
+ return bounds;
+ },
+
+ CLASS_NAME: "OpenLayers.Layer"
+});
+/* ======================================================================
+ OpenLayers/Marker/Box.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Marker.js
+ */
+
+/**
+ * Class: OpenLayers.Marker.Box
+ *
+ * Inherits from:
+ * - <OpenLayers.Marker>
+ */
+OpenLayers.Marker.Box = OpenLayers.Class(OpenLayers.Marker, {
+
+ /**
+ * Property: bounds
+ * {<OpenLayers.Bounds>}
+ */
+ bounds: null,
+
+ /**
+ * Property: div
+ * {DOMElement}
+ */
+ div: null,
+
+ /**
+ * Constructor: OpenLayers.Marker.Box
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * borderColor - {String}
+ * borderWidth - {int}
+ */
+ initialize: function(bounds, borderColor, borderWidth) {
+ this.bounds = bounds;
+ this.div = OpenLayers.Util.createDiv();
+ this.div.style.overflow = 'hidden';
+ this.events = new OpenLayers.Events(this, this.div, null);
+ this.setBorder(borderColor, borderWidth);
+ },
+
+ /**
+ * Method: destroy
+ */
+ destroy: function() {
+
+ this.bounds = null;
+ this.div = null;
+
+ OpenLayers.Marker.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: setBorder
+ * Allow the user to change the box's color and border width
+ *
+ * Parameters:
+ * color - {String} Default is "red"
+ * width - {int} Default is 2
+ */
+ setBorder: function (color, width) {
+ if (!color) {
+ color = "red";
+ }
+ if (!width) {
+ width = 2;
+ }
+ this.div.style.border = width + "px solid " + color;
+ },
+
+ /**
+ * Method: draw
+ *
+ * Parameters:
+ * px - {<OpenLayers.Pixel>}
+ * sz - {<OpenLayers.Size>}
+ *
+ * Returns:
+ * {DOMElement} A new DOM Image with this marker´s icon set at the
+ * location passed-in
+ */
+ draw: function(px, sz) {
+ OpenLayers.Util.modifyDOMElement(this.div, null, px, sz);
+ return this.div;
+ },
+
+ /**
+ * Method: onScreen
+ *
+ * Rreturn:
+ * {Boolean} Whether or not the marker is currently visible on screen.
+ */
+ onScreen:function() {
+ var onScreen = false;
+ if (this.map) {
+ var screenBounds = this.map.getExtent();
+ onScreen = screenBounds.containsBounds(this.bounds, true, true);
+ }
+ return onScreen;
+ },
+
+ /**
+ * Method: display
+ * Hide or show the icon
+ *
+ * Parameters:
+ * display - {Boolean}
+ */
+ display: function(display) {
+ this.div.style.display = (display) ? "" : "none";
+ },
+
+ CLASS_NAME: "OpenLayers.Marker.Box"
+});
+
+/* ======================================================================
+ OpenLayers/Control/DragPan.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Handler/Drag.js
+ */
+
+/**
+ * Class: OpenLayers.Control.DragPan
+ * DragPan control.
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Property: type
+ * {OpenLayers.Control.TYPES}
+ */
+ type: OpenLayers.Control.TYPE_TOOL,
+
+ /**
+ * Property: panned
+ * {Boolean} The map moved.
+ */
+ panned: false,
+
+ /**
+ * Method: draw
+ * Creates a Drag handler, using <panMap> and
+ * <panMapDone> as callbacks.
+ */
+ draw: function() {
+ this.handler = new OpenLayers.Handler.Drag(this,
+ {"move": this.panMap, "done": this.panMapDone});
+ },
+
+ /**
+ * Method: panMap
+ *
+ * Parameters:
+ * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
+ */
+ panMap: function(xy) {
+ this.panned = true;
+ this.map.pan(
+ this.handler.last.x - xy.x,
+ this.handler.last.y - xy.y,
+ {dragging: this.handler.dragging, animate: false}
+ );
+ },
+
+ /**
+ * Method: panMapDone
+ * Finish the panning operation. Only call setCenter (through <panMap>)
+ * if the map has actually been moved.
+ *
+ * Parameters:
+ * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
+ */
+ panMapDone: function(xy) {
+ if(this.panned) {
+ this.panMap(xy);
+ this.panned = false;
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Control.DragPan"
+});
+/* ======================================================================
+ OpenLayers/Handler/Box.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Handler.js
+ * @requires OpenLayers/Handler/Drag.js
+ */
+
+/**
+ * Class: OpenLayers.Handler.Box
+ * Handler for dragging a rectangle across the map. Box is displayed
+ * on mouse down, moves on mouse move, and is finished on mouse up.
+ *
+ * Inherits from:
+ * - <OpenLayers.Handler>
+ */
+OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, {
+
+ /**
+ * Property: dragHandler
+ * {<OpenLayers.Handler.Drag>}
+ */
+ dragHandler: null,
+
+ /**
+ * APIProperty: boxDivClassName
+ * {String} The CSS class to use for drawing the box. Default is
+ * olHandlerBoxZoomBox
+ */
+ boxDivClassName: 'olHandlerBoxZoomBox',
+
+ /**
+ * Constructor: OpenLayers.Handler.Box
+ *
+ * Parameters:
+ * control - {<OpenLayers.Control>}
+ * callbacks - {Object} An object containing a single function to be
+ * called when the drag operation is finished.
+ * The callback should expect to recieve a single
+ * argument, the point geometry.
+ * options - {Object}
+ */
+ initialize: function(control, callbacks, options) {
+ OpenLayers.Handler.prototype.initialize.apply(this, arguments);
+ var callbacks = {
+ "down": this.startBox,
+ "move": this.moveBox,
+ "out": this.removeBox,
+ "up": this.endBox
+ };
+ this.dragHandler = new OpenLayers.Handler.Drag(
+ this, callbacks, {keyMask: this.keyMask});
+ },
+
+ /**
+ * Method: setMap
+ */
+ setMap: function (map) {
+ OpenLayers.Handler.prototype.setMap.apply(this, arguments);
+ if (this.dragHandler) {
+ this.dragHandler.setMap(map);
+ }
+ },
+
+ /**
+ * Method: startBox
+ *
+ * Parameters:
+ * evt - {Event}
+ */
+ startBox: function (xy) {
+ this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
+ this.dragHandler.start);
+ this.zoomBox.className = this.boxDivClassName;
+ this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
+ this.map.viewPortDiv.appendChild(this.zoomBox);
+
+ // TBD: use CSS classes instead
+ this.map.div.style.cursor = "crosshair";
+ },
+
+ /**
+ * Method: moveBox
+ */
+ moveBox: function (xy) {
+ var deltaX = Math.abs(this.dragHandler.start.x - xy.x);
+ var deltaY = Math.abs(this.dragHandler.start.y - xy.y);
+ this.zoomBox.style.width = Math.max(1, deltaX) + "px";
+ this.zoomBox.style.height = Math.max(1, deltaY) + "px";
+ if (xy.x < this.dragHandler.start.x) {
+ this.zoomBox.style.left = xy.x+"px";
+ }
+ if (xy.y < this.dragHandler.start.y) {
+ this.zoomBox.style.top = xy.y+"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();
+
+ // TBD: use CSS classes instead
+ this.map.div.style.cursor = "";
+
+ 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;
+ },
+
+ /**
+ * Method: activate
+ */
+ activate: function () {
+ if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
+ this.dragHandler.activate();
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Method: deactivate
+ */
+ deactivate: function () {
+ if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
+ this.dragHandler.deactivate();
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Handler.Box"
+});
+/* ======================================================================
+ OpenLayers/Layer/HTTPRequest.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.HTTPRequest
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer>
+ */
+OpenLayers.Layer.HTTPRequest = OpenLayers.Class(OpenLayers.Layer, {
+
+ /**
+ * Constant: URL_HASH_FACTOR
+ * {Float} Used to hash URL param strings for multi-WMS server selection.
+ * Set to the Golden Ratio per Knuth's recommendation.
+ */
+ URL_HASH_FACTOR: (Math.sqrt(5) - 1) / 2,
+
+ /**
+ * Property: url
+ * {Array(String) or String} This is either an array of url strings or
+ * a single url string.
+ */
+ url: null,
+
+ /**
+ * Property: params
+ * {Object} Hashtable of key/value parameters
+ */
+ params: null,
+
+ /**
+ * APIProperty: reproject
+ * *Deprecated*. See http://trac.openlayers.org/wiki/SpatialMercator
+ * for information on the replacement for this functionality.
+ * {Boolean} Whether layer should reproject itself based on base layer
+ * locations. This allows reprojection onto commercial layers.
+ * Default is false: Most layers can't reproject, but layers
+ * which can create non-square geographic pixels can, like WMS.
+ *
+ */
+ reproject: false,
+
+ /**
+ * Constructor: OpenLayers.Layer.HTTPRequest
+ *
+ * Parameters:
+ * name - {String}
+ * url - {Array(String) or String}
+ * params - {Object}
+ * options - {Object} Hashtable of extra options to tag onto the layer
+ */
+ initialize: function(name, url, params, options) {
+ var newArguments = arguments;
+ newArguments = [name, options];
+ OpenLayers.Layer.prototype.initialize.apply(this, newArguments);
+ this.url = url;
+ this.params = OpenLayers.Util.extend( {}, params);
+ },
+
+ /**
+ * APIMethod: destroy
+ */
+ destroy: function() {
+ this.url = null;
+ this.params = null;
+ OpenLayers.Layer.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * APIMethod: clone
+ *
+ * Parameters:
+ * obj - {Object}
+ *
+ * Returns:
+ * {<OpenLayers.Layer.HTTPRequest>} An exact clone of this
+ * <OpenLayers.Layer.HTTPRequest>
+ */
+ clone: function (obj) {
+
+ if (obj == null) {
+ obj = new OpenLayers.Layer.HTTPRequest(this.name,
+ this.url,
+ this.params,
+ this.options);
+ }
+
+ //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);
+ return this.redraw();
+ },
+
+ /**
+ * 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; i < paramString.length; i++) {
+ product *= paramString.charCodeAt(i) * this.URL_HASH_FACTOR;
+ product -= Math.floor(product);
+ }
+ return urls[Math.floor(product * urls.length)];
+ },
+
+ /**
+ * Method: getFullRequestString
+ * Combine url with layer's params and these newParams.
+ *
+ * does checking on the serverPath variable, allowing for cases when it
+ * is supplied with trailing ? or &, as well as cases where not.
+ *
+ * return in formatted string like this:
+ * "server?key1=value1&key2=value2&key3=value3"
+ *
+ * WARNING: The altUrl parameter is deprecated and will be removed in 3.0.
+ *
+ * Parameters:
+ * newParams - {Object}
+ * altUrl - {String} Use this as the url instead of the layer's url
+ *
+ * Returns:
+ * {String}
+ */
+ getFullRequestString:function(newParams, altUrl) {
+
+ // if not altUrl passed in, use layer's url
+ var url = altUrl || this.url;
+
+ // create a new params hashtable with all the layer params and the
+ // new params together. then convert to string
+ var allParams = OpenLayers.Util.extend({}, this.params);
+ allParams = OpenLayers.Util.extend(allParams, newParams);
+ var paramsString = OpenLayers.Util.getParameterString(allParams);
+
+ // if url is not a string, it should be an array of strings,
+ // in which case we will deterministically select one of them in
+ // order to evenly distribute requests to different urls.
+ //
+ if (url instanceof Array) {
+ url = this.selectUrl(paramsString, url);
+ }
+
+ // ignore parameters that are already in the url search string
+ var urlParams =
+ OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));
+ for(var key in allParams) {
+ if(key.toUpperCase() in urlParams) {
+ delete allParams[key];
+ }
+ }
+ paramsString = OpenLayers.Util.getParameterString(allParams);
+
+ // requestString always starts with url
+ var requestString = url;
+
+ if (paramsString != "") {
+ var lastServerChar = url.charAt(url.length - 1);
+ if ((lastServerChar == "&") || (lastServerChar == "?")) {
+ requestString += paramsString;
+ } else {
+ if (url.indexOf('?') == -1) {
+ //serverPath has no ? -- add one
+ requestString += '?' + paramsString;
+ } else {
+ //serverPath contains ?, so must already have
+ // paramsString at the end
+ requestString += '&' + paramsString;
+ }
+ }
+ }
+ return requestString;
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.HTTPRequest"
+});
+/* ======================================================================
+ OpenLayers/Control/ZoomBox.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control.js
+ * @requires OpenLayers/Handler/Box.js
+ */
+
+/**
+ * Class: OpenLayers.Control.ZoomBox
+ *
+ * Inherits from:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.ZoomBox = OpenLayers.Class(OpenLayers.Control, {
+ /**
+ * Property: type
+ * {OpenLayers.Control.TYPE}
+ */
+ type: OpenLayers.Control.TYPE_TOOL,
+
+ /**
+ * Property: out
+ * {Boolean} Should the control be used for zooming out?
+ */
+ out: false,
+
+ /**
+ * Method: draw
+ */
+ draw: function() {
+ this.handler = new OpenLayers.Handler.Box( this,
+ {done: this.zoomBox}, {keyMask: this.keyMask} );
+ },
+
+ /**
+ * Method: zoomBox
+ *
+ * Parameters:
+ * position - {<OpenLayers.Bounds>} or {<OpenLayers.Pixel>}
+ */
+ zoomBox: function (position) {
+ if (position instanceof OpenLayers.Bounds) {
+ if (!this.out) {
+ var minXY = this.map.getLonLatFromPixel(
+ new OpenLayers.Pixel(position.left, position.bottom));
+ var maxXY = this.map.getLonLatFromPixel(
+ new OpenLayers.Pixel(position.right, position.top));
+ var 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;
+ var bounds = new OpenLayers.Bounds(xmin, ymin, xmax, ymax);
+ }
+ this.map.zoomToExtent(bounds);
+ } else { // it's a pixel
+ if (!this.out) {
+ this.map.setCenter(this.map.getLonLatFromPixel(position),
+ this.map.getZoom() + 1);
+ } else {
+ this.map.setCenter(this.map.getLonLatFromPixel(position),
+ this.map.getZoom() - 1);
+ }
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Control.ZoomBox"
+});
+/* ======================================================================
+ OpenLayers/Layer/Grid.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/HTTPRequest.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.Grid
+ * Base class for layers that use a lattice of tiles. Create a new grid
+ * layer with the <OpenLayers.Layer.Grid> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer.HTTPRequest>
+ */
+OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
+
+ /**
+ * APIProperty: tileSize
+ * {<OpenLayers.Size>}
+ */
+ tileSize: null,
+
+ /**
+ * Property: grid
+ * {Array(Array(<OpenLayers.Tile>))} This is an array of rows, each row is
+ * an array of tiles.
+ */
+ grid: null,
+
+ /**
+ * APIProperty: singleTile
+ * {Boolean} Moves the layer into single-tile mode, meaning that one tile
+ * will be loaded. The tile's size will be determined by the 'ratio'
+ * property. When the tile is dragged such that it does not cover the
+ * entire viewport, it is reloaded.
+ */
+ singleTile: false,
+
+ /** APIProperty: ratio
+ * {Float} Used only when in single-tile mode, this specifies the
+ * ratio of the size of the single tile to the size of the map.
+ */
+ ratio: 1.5,
+
+ /**
+ * APIProperty: buffer
+ * {Integer} Used only when in gridded mode, this specifies the number of
+ * extra rows and colums of tiles on each side which will
+ * surround the minimum grid tiles to cover the map.
+ */
+ buffer: 2,
+
+ /**
+ * APIProperty: numLoadingTiles
+ * {Integer} How many tiles are still loading?
+ */
+ numLoadingTiles: 0,
+
+ /**
+ * Constructor: OpenLayers.Layer.Grid
+ * Create a new grid layer
+ *
+ * Parameters:
+ * name - {String}
+ * url - {String}
+ * params - {Object}
+ * options - {Object} Hashtable of extra options to tag onto the layer
+ */
+ initialize: function(name, url, params, options) {
+ OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,
+ arguments);
+
+ //grid layers will trigger 'tileloaded' when each new tile is
+ // loaded, as a means of progress update to listeners.
+ // listeners can access 'numLoadingTiles' if they wish to keep track
+ // of the loading progress
+ //
+ this.events.addEventType("tileloaded");
+
+ this.grid = [];
+ },
+
+ /**
+ * APIMethod: destroy
+ * Deconstruct the layer and clear the grid.
+ */
+ destroy: function() {
+ this.clearGrid();
+ this.grid = null;
+ this.tileSize = null;
+ OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments);
+ },
+
+ /**
+ * Method: clearGrid
+ * Go through and remove all tiles from the grid, calling
+ * destroy() on each of them to kill circular references
+ */
+ clearGrid:function() {
+ if (this.grid) {
+ for(var iRow=0; iRow < this.grid.length; iRow++) {
+ var row = this.grid[iRow];
+ for(var iCol=0; iCol < row.length; iCol++) {
+ var tile = row[iCol];
+ this.removeTileMonitoringHooks(tile);
+ tile.destroy();
+ }
+ }
+ this.grid = [];
+ }
+ },
+
+ /**
+ * APIMethod: clone
+ * Create a clone of this layer
+ *
+ * Parameters:
+ * obj - {Object} Is this ever used?
+ *
+ * Returns:
+ * {<OpenLayers.Layer.Grid>} An exact clone of this OpenLayers.Layer.Grid
+ */
+ clone: function (obj) {
+
+ if (obj == null) {
+ obj = new OpenLayers.Layer.Grid(this.name,
+ this.url,
+ this.params,
+ this.options);
+ }
+
+ //get all additions from superclasses
+ obj = OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this, [obj]);
+
+ // copy/set any non-init, non-simple values here
+ if (this.tileSize != null) {
+ obj.tileSize = this.tileSize.clone();
+ }
+
+ // we do not want to copy reference to grid, so we make a new array
+ obj.grid = [];
+
+ return obj;
+ },
+
+ /**
+ * Method: moveTo
+ * This function is called whenever the map is moved. All the moving
+ * of actual 'tiles' is done by the map, but moveTo's role is to accept
+ * a bounds and make sure the data that that bounds requires is pre-loaded.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * zoomChanged - {Boolean}
+ * dragging - {Boolean}
+ */
+ moveTo:function(bounds, zoomChanged, dragging) {
+ OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this, arguments);
+
+ bounds = bounds || this.map.getExtent();
+
+ if (bounds != null) {
+
+ // if grid is empty or zoom has changed, we *must* re-tile
+ var forceReTile = !this.grid.length || zoomChanged;
+
+ // total bounds of the tiles
+ var tilesBounds = this.getTilesBounds();
+
+ if (this.singleTile) {
+
+ // We want to redraw whenever even the slightest part of the
+ // current bounds is not contained by our tile.
+ // (thus, we do not specify partial -- its default is false)
+ if ( forceReTile ||
+ (!dragging && !tilesBounds.containsBounds(bounds))) {
+ this.initSingleTile(bounds);
+ }
+ } else {
+
+ // if the bounds have changed such that they are not even
+ // *partially* contained by our tiles (IE user has
+ // programmatically panned to the other side of the earth)
+ // then we want to reTile (thus, partial true).
+ //
+ if (forceReTile || !tilesBounds.containsBounds(bounds, true)) {
+ this.initGriddedTiles(bounds);
+ } else {
+ //we might have to shift our buffer tiles
+ this.moveGriddedTiles(bounds);
+ }
+ }
+ }
+ },
+
+ /**
+ * APIMethod: setTileSize
+ * Check if we are in singleTile mode and if so, set the size as a ratio
+ * of the map size (as specified by the layer's 'ratio' property).
+ *
+ * Parameters:
+ * size - {<OpenLayers.Size>}
+ */
+ setTileSize: function(size) {
+ if (this.singleTile) {
+ size = this.map.getSize().clone();
+ size.h = parseInt(size.h * this.ratio);
+ size.w = parseInt(size.w * this.ratio);
+ }
+ OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this, [size]);
+ },
+
+ /**
+ * Method: getGridBounds
+ * Deprecated. This function will be removed in 3.0. Please use
+ * getTilesBounds() instead.
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
+ * currently loaded tiles (including those partially or not at all seen
+ * onscreen)
+ */
+ getGridBounds: function() {
+ var msg = "The getGridBounds() function is deprecated. It will be " +
+ "removed in 3.0. Please use getTilesBounds() instead.";
+ OpenLayers.Console.warn(msg);
+ return this.getTilesBounds();
+ },
+
+ /**
+ * APIMethod: getTilesBounds
+ * Return the bounds of the tile grid.
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
+ * currently loaded tiles (including those partially or not at all seen
+ * onscreen).
+ */
+ getTilesBounds: function() {
+ var bounds = null;
+
+ if (this.grid.length) {
+ var bottom = this.grid.length - 1;
+ var bottomLeftTile = this.grid[bottom][0];
+
+ var right = this.grid[0].length - 1;
+ var topRightTile = this.grid[0][right];
+
+ bounds = new OpenLayers.Bounds(bottomLeftTile.bounds.left,
+ bottomLeftTile.bounds.bottom,
+ topRightTile.bounds.right,
+ topRightTile.bounds.top);
+
+ }
+ return bounds;
+ },
+
+ /**
+ * Method: initSingleTile
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ */
+ initSingleTile: function(bounds) {
+
+ //determine new tile bounds
+ var center = bounds.getCenterLonLat();
+ var tileWidth = bounds.getWidth() * this.ratio;
+ var tileHeight = bounds.getHeight() * this.ratio;
+
+ var tileBounds =
+ new OpenLayers.Bounds(center.lon - (tileWidth/2),
+ center.lat - (tileHeight/2),
+ center.lon + (tileWidth/2),
+ center.lat + (tileHeight/2));
+
+ var ul = new OpenLayers.LonLat(tileBounds.left, tileBounds.top);
+ var px = this.map.getLayerPxFromLonLat(ul);
+
+ if (!this.grid.length) {
+ this.grid[0] = [];
+ }
+
+ var tile = this.grid[0][0];
+ if (!tile) {
+ tile = this.addTile(tileBounds, px);
+
+ this.addTileMonitoringHooks(tile);
+ tile.draw();
+ this.grid[0][0] = tile;
+ } else {
+ tile.moveTo(tileBounds, px);
+ }
+
+ //remove all but our single tile
+ this.removeExcessTiles(1,1);
+ },
+
+ /**
+ * Method: calculateGridLayout
+ * Generate parameters for the grid layout. This
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bound>}
+ * extent - {<OpenLayers.Bounds>}
+ * resolution - {Number}
+ *
+ * Returns:
+ * Object containing properties tilelon, tilelat, tileoffsetlat,
+ * tileoffsetlat, tileoffsetx, tileoffsety
+ */
+ calculateGridLayout: function(bounds, extent, resolution) {
+ var tilelon = resolution * this.tileSize.w;
+ var tilelat = resolution * this.tileSize.h;
+
+ var offsetlon = bounds.left - extent.left;
+ var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
+ var tilecolremain = offsetlon/tilelon - tilecol;
+ var tileoffsetx = -tilecolremain * this.tileSize.w;
+ var tileoffsetlon = extent.left + tilecol * tilelon;
+
+ var offsetlat = bounds.top - (extent.bottom + tilelat);
+ var tilerow = Math.ceil(offsetlat/tilelat) + this.buffer;
+ var tilerowremain = tilerow - offsetlat/tilelat;
+ var tileoffsety = -tilerowremain * this.tileSize.h;
+ var tileoffsetlat = extent.bottom + tilerow * tilelat;
+
+ return {
+ tilelon: tilelon, tilelat: tilelat,
+ tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
+ tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
+ };
+
+ },
+
+ /**
+ * Method: initGriddedTiles
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ */
+ initGriddedTiles:function(bounds) {
+
+ // work out mininum number of rows and columns; this is the number of
+ // tiles required to cover the viewport plus at least one for panning
+
+ var viewSize = this.map.getSize();
+ var minRows = Math.ceil(viewSize.h/this.tileSize.h) +
+ Math.max(1, 2 * this.buffer);
+ var minCols = Math.ceil(viewSize.w/this.tileSize.w) +
+ Math.max(1, 2 * this.buffer);
+
+ var extent = this.map.getMaxExtent();
+ var resolution = this.map.getResolution();
+
+ var tileLayout = this.calculateGridLayout(bounds, extent, resolution);
+
+ var tileoffsetx = Math.round(tileLayout.tileoffsetx); // heaven help us
+ var tileoffsety = Math.round(tileLayout.tileoffsety);
+
+ var tileoffsetlon = tileLayout.tileoffsetlon;
+ var tileoffsetlat = tileLayout.tileoffsetlat;
+
+ var tilelon = tileLayout.tilelon;
+ var tilelat = tileLayout.tilelat;
+
+ this.origin = new OpenLayers.Pixel(tileoffsetx, tileoffsety);
+
+ var startX = tileoffsetx;
+ var startLon = tileoffsetlon;
+
+ var rowidx = 0;
+
+ var layerContainerDivLeft = parseInt(this.map.layerContainerDiv.style.left);
+ var layerContainerDivTop = parseInt(this.map.layerContainerDiv.style.top);
+
+
+ do {
+ var row = this.grid[rowidx++];
+ if (!row) {
+ row = [];
+ this.grid.push(row);
+ }
+
+ tileoffsetlon = startLon;
+ tileoffsetx = startX;
+ var colidx = 0;
+
+ do {
+ var tileBounds =
+ new OpenLayers.Bounds(tileoffsetlon,
+ tileoffsetlat,
+ tileoffsetlon + tilelon,
+ tileoffsetlat + tilelat);
+
+ var x = tileoffsetx;
+ x -= layerContainerDivLeft;
+
+ var y = tileoffsety;
+ y -= layerContainerDivTop;
+
+ var px = new OpenLayers.Pixel(x, y);
+ var tile = row[colidx++];
+ if (!tile) {
+ tile = this.addTile(tileBounds, px);
+ this.addTileMonitoringHooks(tile);
+ row.push(tile);
+ } else {
+ tile.moveTo(tileBounds, px, false);
+ }
+
+ tileoffsetlon += tilelon;
+ tileoffsetx += this.tileSize.w;
+ } while ((tileoffsetlon <= bounds.right + tilelon * this.buffer)
+ || colidx < minCols)
+
+ tileoffsetlat -= tilelat;
+ tileoffsety += this.tileSize.h;
+ } while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer)
+ || rowidx < minRows)
+
+ //shave off exceess rows and colums
+ this.removeExcessTiles(rowidx, colidx);
+
+ //now actually draw the tiles
+ this.spiralTileLoad();
+ },
+
+ /**
+ * Method: spiralTileLoad
+ * Starts at the top right corner of the grid and proceeds in a spiral
+ * towards the center, adding tiles one at a time to the beginning of a
+ * queue.
+ *
+ * Once all the grid's tiles have been added to the queue, we go back
+ * and iterate through the queue (thus reversing the spiral order from
+ * outside-in to inside-out), calling draw() on each tile.
+ */
+ spiralTileLoad: function() {
+ var tileQueue = [];
+
+ var directions = ["right", "down", "left", "up"];
+
+ var iRow = 0;
+ var iCell = -1;
+ var direction = OpenLayers.Util.indexOf(directions, "right");
+ var directionsTried = 0;
+
+ while( directionsTried < directions.length) {
+
+ var testRow = iRow;
+ var testCell = iCell;
+
+ switch (directions[direction]) {
+ case "right":
+ testCell++;
+ break;
+ case "down":
+ testRow++;
+ break;
+ case "left":
+ testCell--;
+ break;
+ case "up":
+ testRow--;
+ break;
+ }
+
+ // if the test grid coordinates are within the bounds of the
+ // grid, get a reference to the tile.
+ var tile = null;
+ if ((testRow < this.grid.length) && (testRow >= 0) &&
+ (testCell < this.grid[0].length) && (testCell >= 0)) {
+ tile = this.grid[testRow][testCell];
+ }
+
+ if ((tile != null) && (!tile.queued)) {
+ //add tile to beginning of queue, mark it as queued.
+ tileQueue.unshift(tile);
+ tile.queued = true;
+
+ //restart the directions counter and take on the new coords
+ directionsTried = 0;
+ iRow = testRow;
+ iCell = testCell;
+ } else {
+ //need to try to load a tile in a different direction
+ direction = (direction + 1) % 4;
+ directionsTried++;
+ }
+ }
+
+ // now we go through and draw the tiles in forward order
+ for(var i=0; i < tileQueue.length; i++) {
+ var tile = tileQueue[i];
+ tile.draw();
+ //mark tile as unqueued for the next time (since tiles are reused)
+ tile.queued = false;
+ }
+ },
+
+ /**
+ * APIMethod: addTile
+ * Gives subclasses of Grid the opportunity to create an
+ * OpenLayer.Tile of their choosing. The implementer should initialize
+ * the new tile and take whatever steps necessary to display it.
+ *
+ * Parameters
+ * bounds - {<OpenLayers.Bounds>}
+ * position - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Tile>} The added OpenLayers.Tile
+ */
+ addTile:function(bounds, position) {
+ // Should be implemented by subclasses
+ },
+
+ /**
+ * Method: addTileMonitoringHooks
+ * This function takes a tile as input and adds the appropriate hooks to
+ * the tile so that the layer can keep track of the loading tiles.
+ *
+ * Parameters:
+ * tile - {<OpenLayers.Tile>}
+ */
+ addTileMonitoringHooks: function(tile) {
+
+ tile.onLoadStart = function() {
+ //if that was first tile then trigger a 'loadstart' on the layer
+ if (this.numLoadingTiles == 0) {
+ this.events.triggerEvent("loadstart");
+ }
+ this.numLoadingTiles++;
+ };
+ tile.events.register("loadstart", this, tile.onLoadStart);
+
+ tile.onLoadEnd = function() {
+ this.numLoadingTiles--;
+ this.events.triggerEvent("tileloaded");
+ //if that was the last tile, then trigger a 'loadend' on the layer
+ if (this.numLoadingTiles == 0) {
+ this.events.triggerEvent("loadend");
+ }
+ };
+ tile.events.register("loadend", this, tile.onLoadEnd);
+ tile.events.register("unload", this, tile.onLoadEnd);
+ },
+
+ /**
+ * Method: removeTileMonitoringHooks
+ * This function takes a tile as input and removes the tile hooks
+ * that were added in addTileMonitoringHooks()
+ *
+ * Parameters:
+ * tile - {<OpenLayers.Tile>}
+ */
+ removeTileMonitoringHooks: function(tile) {
+ tile.unload();
+ tile.events.un({
+ "loadstart": tile.onLoadStart,
+ "loadend": tile.onLoadEnd,
+ "unload": tile.onLoadEnd,
+ scope: this
+ });
+ },
+
+ /**
+ * Method: moveGriddedTiles
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ */
+ moveGriddedTiles: function(bounds) {
+ var buffer = this.buffer || 1;
+ while (true) {
+ var tlLayer = this.grid[0][0].position;
+ var tlViewPort =
+ this.map.getViewPortPxFromLayerPx(tlLayer);
+ if (tlViewPort.x > -this.tileSize.w * (buffer - 1)) {
+ this.shiftColumn(true);
+ } else if (tlViewPort.x < -this.tileSize.w * buffer) {
+ this.shiftColumn(false);
+ } else if (tlViewPort.y > -this.tileSize.h * (buffer - 1)) {
+ this.shiftRow(true);
+ } else if (tlViewPort.y < -this.tileSize.h * buffer) {
+ this.shiftRow(false);
+ } else {
+ break;
+ }
+ };
+ },
+
+ /**
+ * Method: shiftRow
+ * Shifty grid work
+ *
+ * Parameters:
+ * prepend - {Boolean} if true, prepend to beginning.
+ * if false, then append to end
+ */
+ shiftRow:function(prepend) {
+ var modelRowIndex = (prepend) ? 0 : (this.grid.length - 1);
+ var grid = this.grid;
+ var modelRow = grid[modelRowIndex];
+
+ var resolution = this.map.getResolution();
+ var deltaY = (prepend) ? -this.tileSize.h : this.tileSize.h;
+ var deltaLat = resolution * -deltaY;
+
+ var row = (prepend) ? grid.pop() : grid.shift();
+
+ for (var i=0; i < modelRow.length; i++) {
+ var modelTile = modelRow[i];
+ var bounds = modelTile.bounds.clone();
+ var position = modelTile.position.clone();
+ bounds.bottom = bounds.bottom + deltaLat;
+ bounds.top = bounds.top + deltaLat;
+ position.y = position.y + deltaY;
+ row[i].moveTo(bounds, position);
+ }
+
+ if (prepend) {
+ grid.unshift(row);
+ } else {
+ grid.push(row);
+ }
+ },
+
+ /**
+ * Method: shiftColumn
+ * Shift grid work in the other dimension
+ *
+ * Parameters:
+ * prepend - {Boolean} if true, prepend to beginning.
+ * if false, then append to end
+ */
+ shiftColumn: function(prepend) {
+ var deltaX = (prepend) ? -this.tileSize.w : this.tileSize.w;
+ var resolution = this.map.getResolution();
+ var deltaLon = resolution * deltaX;
+
+ for (var i=0; i<this.grid.length; i++) {
+ var row = this.grid[i];
+ var modelTileIndex = (prepend) ? 0 : (row.length - 1);
+ var modelTile = row[modelTileIndex];
+
+ var bounds = modelTile.bounds.clone();
+ var position = modelTile.position.clone();
+ bounds.left = bounds.left + deltaLon;
+ bounds.right = bounds.right + deltaLon;
+ position.x = position.x + deltaX;
+
+ var tile = prepend ? this.grid[i].pop() : this.grid[i].shift();
+ tile.moveTo(bounds, position);
+ if (prepend) {
+ row.unshift(tile);
+ } else {
+ row.push(tile);
+ }
+ }
+ },
+
+ /**
+ * Method: removeExcessTiles
+ * When the size of the map or the buffer changes, we may need to
+ * remove some excess rows and columns.
+ *
+ * Parameters:
+ * rows - {Integer} Maximum number of rows we want our grid to have.
+ * colums - {Integer} Maximum number of columns we want our grid to have.
+ */
+ removeExcessTiles: function(rows, columns) {
+
+ // remove extra rows
+ while (this.grid.length > rows) {
+ var row = this.grid.pop();
+ for (var i=0, l=row.length; i<l; i++) {
+ var tile = row[i];
+ this.removeTileMonitoringHooks(tile);
+ tile.destroy();
+ }
+ }
+
+ // remove extra columns
+ while (this.grid[0].length > columns) {
+ for (var i=0, l=this.grid.length; i<l; i++) {
+ var row = this.grid[i];
+ var tile = row.pop();
+ this.removeTileMonitoringHooks(tile);
+ tile.destroy();
+ }
+ }
+ },
+
+ /**
+ * Method: onMapResize
+ * For singleTile layers, this will set a new tile size according to the
+ * dimensions of the map pane.
+ */
+ onMapResize: function() {
+ if (this.singleTile) {
+ this.clearGrid();
+ this.setTileSize();
+ }
+ },
+
+ /**
+ * APIMethod: getTileBounds
+ * Returns The tile bounds for a layer given a pixel location.
+ *
+ * Parameters:
+ * viewPortPx - {<OpenLayers.Pixel>} The location in the viewport.
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} Bounds of the tile at the given pixel location.
+ */
+ getTileBounds: function(viewPortPx) {
+ var maxExtent = this.map.getMaxExtent();
+ 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/Control/Navigation.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Control/ZoomBox.js
+ * @requires OpenLayers/Control/DragPan.js
+ * @requires OpenLayers/Handler/MouseWheel.js
+ * @requires OpenLayers/Handler/Click.js
+ */
+
+/**
+ * Class: OpenLayers.Control.Navigation
+ * The navigation control handles map browsing with mouse events (dragging,
+ * double-clicking, and scrolling the wheel). Create a new navigation
+ * control with the <OpenLayers.Control.Navigation> control.
+ *
+ * Note that this control is added to the map by default (if no controls
+ * array is sent in the options object to the <OpenLayers.Map>
+ * constructor).
+ *
+ * Inherits:
+ * - <OpenLayers.Control>
+ */
+OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, {
+
+ /**
+ * Property: dragPan
+ * {<OpenLayers.Control.DragPan>}
+ */
+ dragPan: null,
+
+ /**
+ * Property: zoomBox
+ * {<OpenLayers.Control.ZoomBox>}
+ */
+ zoomBox: null,
+
+ /**
+ * APIProperty: zoomWheelEnabled
+ * {Boolean} Whether the mousewheel should zoom the map
+ */
+ zoomWheelEnabled: true,
+
+ /**
+ * Constructor: OpenLayers.Control.Navigation
+ * Create a new navigation control
+ *
+ * Parameters:
+ * options - {Object} An optional object whose properties will be set on
+ * the control
+ */
+ initialize: function(options) {
+ this.handlers = {};
+ OpenLayers.Control.prototype.initialize.apply(this, arguments);
+ },
+
+ /**
+ * Method: destroy
+ * The destroy method is used to perform any clean up before the control
+ * is dereferenced. Typically this is where event listeners are removed
+ * to prevent memory leaks.
+ */
+ destroy: function() {
+ this.deactivate();
+
+ if (this.dragPan) {
+ this.dragPan.destroy();
+ }
+ this.dragPan = null;
+
+ if (this.zoomBox) {
+ this.zoomBox.destroy();
+ }
+ this.zoomBox = null;
+ OpenLayers.Control.prototype.destroy.apply(this,arguments);
+ },
+
+ /**
+ * Method: activate
+ */
+ activate: function() {
+ this.dragPan.activate();
+ if (this.zoomWheelEnabled) {
+ this.handlers.wheel.activate();
+ }
+ this.handlers.click.activate();
+ this.zoomBox.activate();
+ return OpenLayers.Control.prototype.activate.apply(this,arguments);
+ },
+
+ /**
+ * Method: deactivate
+ */
+ deactivate: function() {
+ this.zoomBox.deactivate();
+ this.dragPan.deactivate();
+ this.handlers.click.deactivate();
+ this.handlers.wheel.deactivate();
+ return OpenLayers.Control.prototype.deactivate.apply(this,arguments);
+ },
+
+ /**
+ * Method: draw
+ */
+ draw: function() {
+ this.handlers.click = new OpenLayers.Handler.Click(this,
+ { 'dblclick': this.defaultDblClick },
+ {
+ 'double': true,
+ 'stopDouble': true
+ });
+ this.dragPan = new OpenLayers.Control.DragPan({map: this.map});
+ this.zoomBox = new OpenLayers.Control.ZoomBox(
+ {map: this.map, keyMask: OpenLayers.Handler.MOD_SHIFT});
+ this.dragPan.draw();
+ this.zoomBox.draw();
+ this.handlers.wheel = new OpenLayers.Handler.MouseWheel(
+ this, {"up" : this.wheelUp,
+ "down": this.wheelDown} );
+ this.activate();
+ },
+
+ /**
+ * Method: defaultDblClick
+ *
+ * Parameters:
+ * evt - {Event}
+ */
+ defaultDblClick: function (evt) {
+ var newCenter = this.map.getLonLatFromViewPortPx( evt.xy );
+ this.map.setCenter(newCenter, this.map.zoom + 1);
+ },
+
+ /**
+ * Method: wheelChange
+ *
+ * Parameters:
+ * evt - {Event}
+ * deltaZ - {Integer}
+ */
+ wheelChange: function(evt, deltaZ) {
+ var newZoom = this.map.getZoom() + deltaZ;
+ if (!this.map.isValidZoomLevel(newZoom)) {
+ 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}
+ */
+ wheelUp: function(evt) {
+ this.wheelChange(evt, 1);
+ },
+
+ /**
+ * Method: wheelDown
+ * User spun scroll wheel down
+ *
+ * Parameters:
+ * evt - {Event}
+ */
+ wheelDown: function(evt) {
+ this.wheelChange(evt, -1);
+ },
+
+ /**
+ * 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/MapGuide.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * licence. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Ajax.js
+ * @requires OpenLayers/Layer/Grid.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.MapGuide
+ * Instances of OpenLayers.Layer.MapGuide are used to display
+ * data from a MapGuide OS instance.
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+ /**
+ * APIProperty: isBaseLayer
+ * {Boolean} Treat this layer as a base layer. Default is true.
+ **/
+ isBaseLayer: true,
+
+ /**
+ * APIProperty: singleTile
+ * {Boolean} use tile server or request single tile image. Note that using
+ * singleTile *and* isBaseLayer false is *not recommend*: it uses synchronous
+ * XMLHttpRequests to load tiles, and this will *lock up users browsers*
+ * during requests.
+ **/
+ singleTile: false,
+
+ /**
+ * Constant: TILE_PARAMS
+ * {Object} Hashtable of default parameter key/value pairs for tiled layer
+ */
+ TILE_PARAMS: {
+ operation: 'GETTILEIMAGE',
+ version: '1.2.0'
+ },
+
+ /**
+ * Constant: SINGLE_TILE_PARAMS
+ * {Object} Hashtable of default parameter key/value pairs for untiled layer
+ */
+ SINGLE_TILE_PARAMS: {
+ operation: 'GETMAPIMAGE',
+ format: 'PNG',
+ locale: 'en',
+ clip: '1',
+ version: '1.0.0'
+ },
+
+ /**
+ * Property: defaultSize
+ * {<OpenLayers.Size>} Tile size as produced by MapGuide server
+ **/
+ defaultSize: new OpenLayers.Size(300,300),
+
+ /**
+ * Constructor: OpenLayers.Layer.MapGuide
+ * Create a new Mapguide layer, either tiled or untiled.
+ *
+ * For tiled layers, the 'groupName' and 'mapDefnition' options
+ * must be specified as options.
+ *
+ * For untiled layers, specify either combination of 'mapName' and
+ * 'session', or 'mapDefinition' and 'locale'.
+ *
+ * Parameters:
+ * name - {String} Name of the layer displayed in the interface
+ * url - {String} Location of the MapGuide mapagent executable
+ * (e.g. http://localhost:8008/mapguide/mapagent/mapagent.fcgi)
+ * params - {Object} hashtable of additional parameters to use. Some
+ * parameters may require additional code on the serer. The ones that
+ * you may want to use are:
+ * - mapDefinition - {String} The MapGuide resource definition
+ * (e.g. Library://Samples/Gmap/Maps/gmapTiled.MapDefinition)
+ * - locale - Locale setting
+ * (for untiled overlays layers only)
+ * - mapName - {String} Name of the map as stored in the MapGuide session.
+ * (for untiled layers with a session parameter only)
+ * - session - { String} MapGuide session ID
+ * (for untiled overlays layers only)
+ * - basemaplayergroupname - {String} GroupName for tiled MapGuide layers only
+ * - format - Image format to be returned (for untiled overlay layers only)
+ * - showLayers - {String} A comma separated list of GUID's for the
+ * layers to display eg: 'cvc-xcv34,453-345-345sdf'.
+ * - hideLayers - {String} A comma separated list of GUID's for the
+ * layers to hide eg: 'cvc-xcv34,453-345-345sdf'.
+ * - showGroups - {String} A comma separated list of GUID's for the
+ * groups to display eg: 'cvc-xcv34,453-345-345sdf'.
+ * - hideGroups - {String} A comma separated list of GUID's for the
+ * groups to hide eg: 'cvc-xcv34,453-345-345sdf'
+ * - selectionXml - {String} A selection xml string Some server plumbing
+ * is required to read such a value.
+ * options - {Ojbect} Hashtable of extra options to tag onto the layer;
+ * will vary depending if tiled or untiled maps are being requested
+ */
+ initialize: function(name, url, params, options) {
+
+ OpenLayers.Layer.Grid.prototype.initialize.apply(this, arguments);
+
+ // unless explicitly set in options, if the layer is transparent,
+ // it will be an overlay
+ if (options == null || options.isBaseLayer == null) {
+ this.isBaseLayer = ((this.transparent != "true") &&
+ (this.transparent != true));
+ }
+
+ //initialize for untiled layers
+ if (this.singleTile) {
+ OpenLayers.Util.applyDefaults(
+ this.params,
+ this.SINGLE_TILE_PARAMS
+ );
+ } else {
+ //initialize for tiled layers
+ OpenLayers.Util.applyDefaults(
+ this.params,
+ this.TILE_PARAMS
+ );
+ this.setTileSize(this.defaultSize);
+ }
+ },
+
+ /**
+ * Method: clone
+ * Create a clone of this layer
+ *
+ * Returns:
+ * {<OpenLayers.Layer.MapGuide>} An exact clone of this layer
+ */
+ clone: function (obj) {
+ if (obj == null) {
+ obj = new OpenLayers.Layer.MapGuide(this.name,
+ this.url,
+ this.params,
+ this.options);
+ }
+ //get all additions from superclasses
+ obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+ return obj;
+ },
+
+ /**
+ * Method: addTile
+ * Creates a tile, initializes it, and adds it to the layer div.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * position - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+ */
+ addTile:function(bounds,position) {
+ return new OpenLayers.Tile.Image(this, position, bounds,
+ null, this.tileSize);
+ },
+
+ /**
+ * Method: getURL
+ * Return a query string for this layer
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox
+ * for the request
+ *
+ * Returns:
+ * {String} A string with the layer's url and parameters and also
+ * the passed-in bounds and appropriate tile size specified
+ * as parameters.
+ */
+ getURL: function (bounds) {
+ var url;
+ var center = bounds.getCenterLonLat();
+ var mapSize = this.map.getCurrentSize();
+
+ if (this.singleTile) {
+ //set up the call for GETMAPIMAGE or GETDYNAMICMAPOVERLAY
+ var params = {};
+ params.setdisplaydpi = OpenLayers.DOTS_PER_INCH;
+ params.setdisplayheight = mapSize.h*this.ratio;
+ params.setdisplaywidth = mapSize.w*this.ratio;
+ params.setviewcenterx = center.lon;
+ params.setviewcentery = center.lat;
+ params.setviewscale = this.map.getScale();
+
+ if (!this.isBaseLayer) {
+ // in this case the main image operation is remapped to this
+ this.params.operation = "GETDYNAMICMAPOVERLAYIMAGE";
+
+ //but we first need to call GETVISIBLEMAPEXTENT to set the extent
+ var getVisParams = {};
+ getVisParams.operation = "GETVISIBLEMAPEXTENT";
+ getVisParams.version = "1.0.0";
+ getVisParams.session = this.params.session;
+ getVisParams.mapName = this.params.mapName;
+ getVisParams.format = 'text/xml';
+ getVisParams = OpenLayers.Util.extend(getVisParams, params);
+
+ new OpenLayers.Ajax.Request(this.url,
+ { parameters: getVisParams,
+ method: 'get',
+ asynchronous: false //must be synchronous call to return control here
+ });
+ }
+
+ //construct the full URL
+ url = this.getFullRequestString( params );
+ } else {
+
+ //tiled version
+ var currentRes = this.map.getResolution();
+ var colidx = Math.floor((bounds.left-this.maxExtent.left)/currentRes);
+ colidx = Math.round(colidx/this.tileSize.w);
+ var rowidx = Math.floor((this.maxExtent.top-bounds.top)/currentRes);
+ rowidx = Math.round(rowidx/this.tileSize.h);
+
+ url = this.getFullRequestString(
+ {
+ tilecol: colidx,
+ tilerow: rowidx,
+ scaleindex: this.resolutions.length - this.map.zoom - 1
+ });
+ }
+
+ return url;
+ },
+
+ /**
+ * Method: getFullRequestString
+ * getFullRequestString on MapGuide layers is special, because we
+ * do a regular expression replace on ',' in parameters to '+'.
+ * This is why it is subclassed here.
+ *
+ * Parameters:
+ * altUrl - {String} Alternative base URL to use.
+ *
+ * Returns:
+ * {String} A string with the layer's url appropriately encoded for MapGuide
+ */
+ getFullRequestString:function(newParams, altUrl) {
+ // use layer's url unless altUrl passed in
+ var url = (altUrl == null) ? this.url : altUrl;
+
+ // if url is not a string, it should be an array of strings,
+ // in which case we will randomly select one of them in order
+ // to evenly distribute requests to different urls.
+ if (typeof url == "object") {
+ url = url[Math.floor(Math.random()*url.length)];
+ }
+ // requestString always starts with url
+ var requestString = url;
+
+ // create a new params hashtable with all the layer params and the
+ // new params together. then convert to string
+ var allParams = OpenLayers.Util.extend({}, this.params);
+ allParams = OpenLayers.Util.extend(allParams, newParams);
+ // ignore parameters that are already in the url search string
+ var urlParams = OpenLayers.Util.upperCaseObject(
+ OpenLayers.Util.getArgs(url));
+ for(var key in allParams) {
+ if(key.toUpperCase() in urlParams) {
+ delete allParams[key];
+ }
+ }
+ var paramsString = OpenLayers.Util.getParameterString(allParams);
+
+ /* MapGuide needs '+' seperating things like bounds/height/width.
+ Since typically this is URL encoded, we use a slight hack: we
+ depend on the list-like functionality of getParameterString to
+ leave ',' only in the case of list items (since otherwise it is
+ encoded) then do a regular expression replace on the , characters
+ to '+' */
+ paramsString = paramsString.replace(/,/g, "+");
+
+ if (paramsString != "") {
+ var lastServerChar = url.charAt(url.length - 1);
+ if ((lastServerChar == "&") || (lastServerChar == "?")) {
+ requestString += paramsString;
+ } else {
+ if (url.indexOf('?') == -1) {
+ //serverPath has no ? -- add one
+ requestString += '?' + paramsString;
+ } else {
+ //serverPath contains ?, so must already have paramsString at the end
+ requestString += '&' + paramsString;
+ }
+ }
+ }
+ return requestString;
+ },
+
+ /**
+ * Method: calculateGridLayout
+ * Generate parameters for the grid layout. This
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bound>}
+ * extent - {<OpenLayers.Bounds>}
+ * resolution - {Number}
+ *
+ * Returns:
+ * Object containing properties tilelon, tilelat, tileoffsetlat,
+ * tileoffsetlat, tileoffsetx, tileoffsety
+ */
+ calculateGridLayout: function(bounds, extent, resolution) {
+ var tilelon = resolution * this.tileSize.w;
+ var tilelat = resolution * this.tileSize.h;
+
+ var offsetlon = bounds.left - extent.left;
+ var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
+ var tilecolremain = offsetlon/tilelon - tilecol;
+ var tileoffsetx = -tilecolremain * this.tileSize.w;
+ var tileoffsetlon = extent.left + tilecol * tilelon;
+
+ var offsetlat = extent.top - bounds.top + tilelat;
+ var tilerow = Math.floor(offsetlat/tilelat) - this.buffer;
+ var tilerowremain = tilerow - offsetlat/tilelat;
+ var tileoffsety = tilerowremain * this.tileSize.h;
+ var tileoffsetlat = extent.top - tilelat*tilerow;
+
+ return {
+ tilelon: tilelon, tilelat: tilelat,
+ tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
+ tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
+ };
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.MapGuide"
+});
+/* ======================================================================
+ OpenLayers/Layer/MapServer.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.MapServer
+ * Instances of OpenLayers.Layer.MapServer are used to display
+ * data from a MapServer CGI instance.
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.MapServer = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+ /**
+ * Constant: DEFAULT_PARAMS
+ * {Object} Hashtable of default parameter key/value pairs
+ */
+ DEFAULT_PARAMS: {
+ mode: "map",
+ map_imagetype: "png"
+ },
+
+ /**
+ * Constructor: OpenLayers.Layer.MapServer
+ * Create a new MapServer layer object
+ *
+ * Parameters:
+ * name - {String} A name for the layer
+ * url - {String} Base url for the MapServer CGI
+ * (e.g. http://www2.dmsolutions.ca/cgi-bin/mapserv)
+ * params - {Object} An object with key/value pairs representing the
+ * GetMap query string parameters and parameter values.
+ * options - {Ojbect} Hashtable of extra options to tag onto the layer
+ */
+ initialize: function(name, url, params, options) {
+ var newArguments = [];
+ newArguments.push(name, url, params, options);
+ OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
+
+ if (arguments.length > 0) {
+ OpenLayers.Util.applyDefaults(
+ this.params,
+ this.DEFAULT_PARAMS
+ );
+ }
+
+ // unless explicitly set in options, if the layer is transparent,
+ // it will be an overlay
+ if (options == null || options.isBaseLayer == null) {
+ this.isBaseLayer = ((this.params.transparent != "true") &&
+ (this.params.transparent != true));
+ }
+ },
+
+ /**
+ * Method: clone
+ * Create a clone of this layer
+ *
+ * Returns:
+ * {<OpenLayers.Layer.MapServer>} An exact clone of this layer
+ */
+ clone: function (obj) {
+ if (obj == null) {
+ obj = new OpenLayers.Layer.MapServer(this.name,
+ this.url,
+ this.params,
+ this.options);
+ }
+ //get all additions from superclasses
+ obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+ // copy/set any non-init, non-simple values here
+
+ return obj;
+ },
+
+ /**
+ * Method: addTile
+ * Creates a tile, initializes it, and adds it to the layer div.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * position - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+ */
+ addTile:function(bounds,position) {
+ return new OpenLayers.Tile.Image(this, position, bounds,
+ null, this.tileSize);
+ },
+
+ /**
+ * Method: getURL
+ * Return a query string for this layer
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox
+ * for the request
+ *
+ * Returns:
+ * {String} A string with the layer's url and parameters and also
+ * the passed-in bounds and appropriate tile size specified
+ * as parameters.
+ */
+ getURL: function (bounds) {
+ bounds = this.adjustBounds(bounds);
+ // Make a list, so that getFullRequestString uses literal ","
+ var extent = [bounds.left, bounds. bottom, bounds.right, bounds.top];
+
+ var imageSize = this.getImageSize();
+
+ // make lists, so that literal ','s are used
+ var url = this.getFullRequestString(
+ {mapext: extent,
+ imgext: extent,
+ map_size: [imageSize.w, imageSize.h],
+ imgx: imageSize.w / 2,
+ imgy: imageSize.h / 2,
+ imgxy: [imageSize.w, imageSize.h]
+ });
+
+ return url;
+ },
+
+ /**
+ * Method: getFullRequestString
+ * combine the layer's url with its params and these newParams.
+ *
+ * Parameter:
+ * newParams - {Object} New parameters that should be added to the
+ * request string.
+ * altUrl - {String} (optional) Replace the URL in the full request
+ * string with the provided URL.
+ *
+ * Returns:
+ * {String} A string with the layer's url and parameters embedded in it.
+ */
+ getFullRequestString:function(newParams, altUrl) {
+ // use layer's url unless altUrl passed in
+ var url = (altUrl == null) ? this.url : altUrl;
+
+ // create a new params hashtable with all the layer params and the
+ // new params together. then convert to string
+ var allParams = OpenLayers.Util.extend({}, this.params);
+ allParams = OpenLayers.Util.extend(allParams, newParams);
+ var paramsString = OpenLayers.Util.getParameterString(allParams);
+
+ // if url is not a string, it should be an array of strings,
+ // in which case we will deterministically select one of them in
+ // order to evenly distribute requests to different urls.
+ if (url instanceof Array) {
+ url = this.selectUrl(paramsString, url);
+ }
+
+ // ignore parameters that are already in the url search string
+ var urlParams = OpenLayers.Util.upperCaseObject(
+ OpenLayers.Util.getParameters(url));
+ for(var key in allParams) {
+ if(key.toUpperCase() in urlParams) {
+ delete allParams[key];
+ }
+ }
+ paramsString = OpenLayers.Util.getParameterString(allParams);
+
+ // requestString always starts with url
+ var requestString = url;
+
+ // MapServer needs '+' seperating things like bounds/height/width.
+ // Since typically this is URL encoded, we use a slight hack: we
+ // depend on the list-like functionality of getParameterString to
+ // leave ',' only in the case of list items (since otherwise it is
+ // encoded) then do a regular expression replace on the , characters
+ // to '+'
+ //
+ paramsString = paramsString.replace(/,/g, "+");
+
+ if (paramsString != "") {
+ var lastServerChar = url.charAt(url.length - 1);
+ if ((lastServerChar == "&") || (lastServerChar == "?")) {
+ requestString += paramsString;
+ } else {
+ if (url.indexOf('?') == -1) {
+ //serverPath has no ? -- add one
+ requestString += '?' + paramsString;
+ } else {
+ //serverPath contains ?, so must already have paramsString at the end
+ requestString += '&' + paramsString;
+ }
+ }
+ }
+ return requestString;
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.MapServer"
+});
+/* ======================================================================
+ OpenLayers/Layer/WMS.js
+ ====================================================================== */
+
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/Layer/Grid.js
+ * @requires OpenLayers/Tile/Image.js
+ */
+
+/**
+ * Class: OpenLayers.Layer.WMS
+ * Instances of OpenLayers.Layer.WMS are used to display data from OGC Web
+ * Mapping Services. Create a new WMS layer with the <OpenLayers.Layer.WMS>
+ * constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Layer.Grid>
+ */
+OpenLayers.Layer.WMS = OpenLayers.Class(OpenLayers.Layer.Grid, {
+
+ /**
+ * Constant: DEFAULT_PARAMS
+ * {Object} Hashtable of default parameter key/value pairs
+ */
+ DEFAULT_PARAMS: { service: "WMS",
+ version: "1.1.1",
+ request: "GetMap",
+ styles: "",
+ exceptions: "application/vnd.ogc.se_inimage",
+ format: "image/jpeg"
+ },
+
+ /**
+ * Property: reproject
+ * *Deprecated*. See http://trac.openlayers.org/wiki/SphericalMercator
+ * for information on the replacement for this functionality.
+ * {Boolean} Try to reproject this layer if its coordinate reference system
+ * is different than that of the base layer. Default is true.
+ * Set this in the layer options. Should be set to false in
+ * most cases.
+ */
+ reproject: false,
+
+ /**
+ * APIProperty: isBaseLayer
+ * {Boolean} Default is true for WMS layer
+ */
+ isBaseLayer: true,
+
+ /**
+ * APIProperty: encodeBBOX
+ * {Boolean} Should the BBOX commas be encoded? The WMS spec says 'no',
+ * but some services want it that way. Default false.
+ */
+ encodeBBOX: false,
+
+ /**
+ * Constructor: OpenLayers.Layer.WMS
+ * Create a new WMS layer object
+ *
+ * Example:
+ * (code)
+ * var wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
+ * "http://wms.jpl.nasa.gov/wms.cgi",
+ * {layers: "modis,global_mosaic"});
+ * (end)
+ *
+ * Parameters:
+ * name - {String} A name for the layer
+ * url - {String} Base url for the WMS
+ * (e.g. http://wms.jpl.nasa.gov/wms.cgi)
+ * params - {Object} An object with key/value pairs representing the
+ * GetMap query string parameters and parameter values.
+ * options - {Ojbect} Hashtable of extra options to tag onto the layer
+ */
+ initialize: function(name, url, params, options) {
+ var newArguments = [];
+ //uppercase params
+ params = OpenLayers.Util.upperCaseObject(params);
+ 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.params.TRANSPARENT &&
+ this.params.TRANSPARENT.toString().toLowerCase() == "true") {
+
+ // unless explicitly set in options, make layer an overlay
+ if ( (options == null) || (!options.isBaseLayer) ) {
+ this.isBaseLayer = false;
+ }
+
+ // jpegs can never be transparent, so intelligently switch the
+ // format, depending on teh browser's capabilities
+ if (this.params.FORMAT == "image/jpeg") {
+ this.params.FORMAT = OpenLayers.Util.alphaHack() ? "image/gif"
+ : "image/png";
+ }
+ }
+
+ },
+
+ /**
+ * Method: destroy
+ * Destroy this layer
+ */
+ destroy: function() {
+ // for now, nothing special to do here.
+ OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);
+ },
+
+
+ /**
+ * Method: clone
+ * Create a clone of this layer
+ *
+ * Returns:
+ * {<OpenLayers.Layer.WMS>} An exact clone of this layer
+ */
+ clone: function (obj) {
+
+ if (obj == null) {
+ obj = new OpenLayers.Layer.WMS(this.name,
+ this.url,
+ this.params,
+ this.options);
+ }
+
+ //get all additions from superclasses
+ obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
+
+ // copy/set any non-init, non-simple values here
+
+ return obj;
+ },
+
+ /**
+ * Method: getURL
+ * Return a GetMap query string for this layer
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the
+ * request.
+ *
+ * Returns:
+ * {String} A string with the layer's url and parameters and also the
+ * passed-in bounds and appropriate tile size specified as
+ * parameters.
+ */
+ getURL: function (bounds) {
+ bounds = this.adjustBounds(bounds);
+
+ var imageSize = this.getImageSize();
+ var newParams = {
+ 'BBOX': this.encodeBBOX ? bounds.toBBOX() : bounds.toArray(),
+ 'WIDTH': imageSize.w,
+ 'HEIGHT': imageSize.h
+ };
+ var requestString = this.getFullRequestString(newParams);
+ return requestString;
+ },
+
+ /**
+ * Method: addTile
+ * addTile creates a tile, initializes it, and adds it to the layer div.
+ *
+ * Parameters:
+ * bounds - {<OpenLayers.Bounds>}
+ * position - {<OpenLayers.Pixel>}
+ *
+ * Returns:
+ * {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
+ */
+ addTile:function(bounds,position) {
+ return new OpenLayers.Tile.Image(this, position, bounds,
+ null, this.tileSize);
+ },
+
+ /**
+ * 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, we will need to re-init our tiles.
+ *
+ * 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);
+ },
+
+ /**
+ * Method: getFullRequestString
+ * Combine the layer's url with its params and these newParams.
+ *
+ * Add the SRS parameter from projection -- this is probably
+ * more eloquently done via a setProjection() method, but this
+ * works for now and always.
+ *
+ * Parameters:
+ * newParams - {Object}
+ * altUrl - {String} Use this as the url instead of the layer's url
+ *
+ * Returns:
+ * {String}
+ */
+ getFullRequestString:function(newParams, altUrl) {
+ var projectionCode = this.map.getProjection();
+ this.params.SRS = (projectionCode == "none") ? null : projectionCode;
+
+ return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(
+ this, arguments);
+ },
+
+ CLASS_NAME: "OpenLayers.Layer.WMS"
+});
Copied: sandbox/aboudreault/lib/OpenLayers/theme/default/img/blank.gif (from rev 1412, trunk/lib/OpenLayers/theme/default/img/blank.gif)
===================================================================
(Binary files differ)
Copied: sandbox/aboudreault/lib/OpenLayers/theme/default/img/editing_tool_bar.png (from rev 1412, trunk/lib/OpenLayers/theme/default/img/editing_tool_bar.png)
===================================================================
(Binary files differ)
Copied: sandbox/aboudreault/lib/OpenLayers/theme/default/img/overview_replacement.gif (from rev 1412, trunk/lib/OpenLayers/theme/default/img/overview_replacement.gif)
===================================================================
(Binary files differ)
Copied: sandbox/aboudreault/lib/OpenLayers/theme/default/img/view_next_off.png (from rev 1412, trunk/lib/OpenLayers/theme/default/img/view_next_off.png)
===================================================================
(Binary files differ)
Copied: sandbox/aboudreault/lib/OpenLayers/theme/default/img/view_next_on.png (from rev 1412, trunk/lib/OpenLayers/theme/default/img/view_next_on.png)
===================================================================
(Binary files differ)
Copied: sandbox/aboudreault/lib/OpenLayers/theme/default/img/view_previous_off.png (from rev 1412, trunk/lib/OpenLayers/theme/default/img/view_previous_off.png)
===================================================================
(Binary files differ)
Copied: sandbox/aboudreault/lib/OpenLayers/theme/default/img/view_previous_on.png (from rev 1412, trunk/lib/OpenLayers/theme/default/img/view_previous_on.png)
===================================================================
(Binary files differ)
Modified: sandbox/aboudreault/lib/OpenLayers/theme/default/style.css
===================================================================
--- sandbox/aboudreault/lib/OpenLayers/theme/default/style.css 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/OpenLayers/theme/default/style.css 2008-05-29 14:21:40 UTC (rev 1413)
@@ -1,4 +1,4 @@
-div.olMapViewport {
+div.olLayerDiv {
-moz-user-select: none
}
@@ -10,18 +10,49 @@
left: 2px;
bottom: 15px;
}
-
+.olControlAttribution {
+ font-size: smaller;
+ right: 3px;
+ bottom: 4.5em;
+ position: absolute;
+ display: block;
+}
.olControlScale {
right: 3px;
bottom: 3em;
display: block;
position: absolute;
+ font-size: smaller;
}
+.olControlScaleLine {
+ left: 10px;
+ bottom: 15px;
+}
+.olControlScaleLineBottom {
+ background-color: #000;
+ border: 1px solid #fff;
+ margin: 1px;
+ font-size: 9px;
+ padding-left: 2px;
+ line-height: 12px;
+ color: #fff;
+}
+.olControlScaleLineTop {
+ background-color: #000;
+ border: 1px solid #fff;
+ margin: 1px;
+ font-size: 9px;
+ padding-left: 2px;
+ line-height: 12px;
+ color: #fff;
+}
+
.olControlPermalink {
right: 3px;
bottom: 1.5em;
display: block;
position: absolute;
+ font-size: smaller;
}
div.olControlMousePosition {
@@ -39,13 +70,13 @@
right: 0px;
}
-/*
.olControlOverviewMapElement {
+/* modified for fusion
padding: 10px 18px 10px 10px;
background-color: #00008B;
-moz-border-radius: 1em 0 0 0;
+ */
}
-*/
.olControlOverviewMapMinimizeButton {
right: 0px;
@@ -58,9 +89,19 @@
}
.olControlOverviewMapExtentRectangle {
- cursor: move;
+ overflow: hidden;
+ background-image: url("img/blank.gif");
+ cursor: move;
border: 2px dotted red;
}
+.olControlOverviewMapRectReplacement {
+ overflow: hidden;
+ cursor: move;
+ background-image: url("img/overview_replacement.gif");
+ background-repeat: no-repeat;
+ background-position: center;
+}
+
.olLayerGeoRSSDescription {
float:left;
width:100%;
@@ -81,6 +122,10 @@
.olPopupContent {
padding:5px;
}
+.olControlNavToolbar {
+ width:0px;
+ height:0px;
+}
.olControlNavToolbar div {
display:block;
width: 28px;
@@ -90,6 +135,31 @@
position: relative;
}
+.olControlNavigationHistoryPreviousItemActive {
+ background-image: url("img/view_previous_on.png");
+ background-repeat: no-repeat;
+ width: 24px;
+ height: 24px;
+}
+.olControlNavigationHistoryPreviousItemInactive {
+ background-image: url("img/view_previous_off.png");
+ background-repeat: no-repeat;
+ width: 24px;
+ height: 24px;
+}
+.olControlNavigationHistoryNextItemActive {
+ background-image: url("img/view_next_on.png");
+ background-repeat: no-repeat;
+ width: 24px;
+ height: 24px;
+}
+.olControlNavigationHistoryNextItemInactive {
+ background-image: url("img/view_next_off.png");
+ background-repeat: no-repeat;
+ width: 24px;
+ height: 24px;
+}
+
.olControlNavToolbar .olControlNavigationItemActive {
background-image: url("img/panning-hand-on.png");
background-repeat: no-repeat;
@@ -120,34 +190,51 @@
margin: 5px;
}
.olControlEditingToolbar .olControlNavigationItemActive {
- background-image: url("img/pan_on.png");
+ background-image: url("img/editing_tool_bar.png");
background-repeat: no-repeat;
+ background-position: -103px -23px;
}
.olControlEditingToolbar .olControlNavigationItemInactive {
- background-image: url("img/pan_off.png");
+ background-image: url("img/editing_tool_bar.png");
background-repeat: no-repeat;
+ background-position: -103px -0px;
}
.olControlEditingToolbar .olControlDrawFeaturePointItemActive {
- background-image: url("img/draw_point_on.png");
+ background-image: url("img/editing_tool_bar.png");
background-repeat: no-repeat;
+ background-position: -77px -23px;
}
.olControlEditingToolbar .olControlDrawFeaturePointItemInactive {
- background-image: url("img/draw_point_off.png");
+ background-image: url("img/editing_tool_bar.png");
background-repeat: no-repeat;
+ background-position: -77px -0px;
}
.olControlEditingToolbar .olControlDrawFeaturePathItemInactive {
- background-image: url("img/draw_line_off.png");
+ background-image: url("img/editing_tool_bar.png");
background-repeat: no-repeat;
+ background-position: -51px 0px;
}
.olControlEditingToolbar .olControlDrawFeaturePathItemActive {
- background-image: url("img/draw_line_on.png");
+ background-image: url("img/editing_tool_bar.png");
background-repeat: no-repeat;
+ background-position: -51px -23px;
}
.olControlEditingToolbar .olControlDrawFeaturePolygonItemInactive {
- background-image: url("img/draw_polygon_off.png");
+ background-image: url("img/editing_tool_bar.png");
background-repeat: no-repeat;
+ background-position: -26px 0px;
}
.olControlEditingToolbar .olControlDrawFeaturePolygonItemActive {
- background-image: url("img/draw_polygon_on.png");
+ background-image: url("img/editing_tool_bar.png");
background-repeat: no-repeat;
+ background-position: -26px -23px ;
}
+
+.olHandlerBoxZoomBox {
+ border: 2px solid red;
+ position: absolute;
+ background-color: white;
+ opacity: 0.50;
+ font-size: 1px;
+ filter: alpha(opacity=50);
+}
Modified: sandbox/aboudreault/lib/RectTool.js
===================================================================
--- sandbox/aboudreault/lib/RectTool.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/RectTool.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,8 +30,7 @@
* through the doAction function.
* All classes should redifine the doAction function
* **********************************************************************/
-Fusion.Tool.Rectangle = Class.create();
-Fusion.Tool.Rectangle.prototype = {
+Fusion.Tool.Rectangle = OpenLayers.Class({
oRectDiv : null,
_sStartPos : null,
_bIsActive : null,
@@ -55,10 +54,10 @@
this._bIsActive = false;
- this.mouseMoveCB = this.mouseMove.bindAsEventListener(this);
- this.mouseUpCB = this.mouseUp.bindAsEventListener(this);
- this.mouseDownCB = this.mouseDown.bindAsEventListener(this);
- this.mouseOutCB = this.mouseOut.bindAsEventListener(this);
+ this.mouseMoveCB = OpenLayers.Function.bindAsEventListener(this.mouseMove, this);
+ this.mouseUpCB = OpenLayers.Function.bindAsEventListener(this.mouseUp, this);
+ this.mouseDownCB = OpenLayers.Function.bindAsEventListener(this.mouseDown, this);
+ this.mouseOutCB = OpenLayers.Function.bindAsEventListener(this.mouseOut, this);
},
execute : function(l,b,r,t) {},
@@ -159,4 +158,4 @@
}
}
-};
+});
Modified: sandbox/aboudreault/lib/Search.js
===================================================================
--- sandbox/aboudreault/lib/Search.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/Search.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -38,9 +38,7 @@
*
* **********************************************************************/
-Fusion.Tool.Search = Class.create();
-
-Fusion.Tool.Search.prototype = {
+Fusion.Tool.Search = OpenLayers.Class({
lastSearch: null,
lastResult: null,
resultOffset: 0,
@@ -98,7 +96,7 @@
var params = {};
params.parameters = 'session='+this.getMap().getSessionID()+'&mapname='+ this.getMap().getMapName()+
'&layers='+this.layerName+filter;
- params.onComplete = this.selectComplete.bind(this);
+ params.onComplete = OpenLayers.Function.bind(this.selectComplete, this);
Fusion.ajaxRequest(s, params);
},
selectComplete: function(r) {
@@ -106,7 +104,7 @@
var success = node.getNodeText('Selection');
if (success == 'true') {
this.getMap().newSelection();
- this.getMap().getSelection(this.zoomToSelection.bind(this));
+ this.getMap().getSelection(OpenLayers.Function.bind(this.zoomToSelection, this));
}
},
/**
@@ -127,5 +125,5 @@
ur.y = ur.y + dY;
this.getMap().setExtents(new OpenLayers.Bounds(ll.x,ll.y,ur.x,ur.y));
}
-};
+});
Copied: sandbox/aboudreault/lib/SingleFile.js (from rev 1412, trunk/lib/SingleFile.js)
===================================================================
--- sandbox/aboudreault/lib/SingleFile.js (rev 0)
+++ sandbox/aboudreault/lib/SingleFile.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -0,0 +1,9 @@
+/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
+ * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
+ * full text of the license. */
+
+var Fusion = {
+ singleFile: true
+};
+
+
Modified: sandbox/aboudreault/lib/Widget.js
===================================================================
--- sandbox/aboudreault/lib/Widget.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/Widget.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -33,8 +33,7 @@
Fusion.Event.WIDGET_STATE_CHANGED = Fusion.Event.lastEventId++;
-Fusion.Widget = Class.create();
-Fusion.Widget.prototype = {
+Fusion.Widget = OpenLayers.Class(Fusion.Lib.EventMgr, {
bIsMutuallyExclusive: null,
sName: null,
sType: null,
@@ -55,7 +54,6 @@
this.sType = widgetTag.type;
this.sName = widgetTag.name;
this.widgetTag = widgetTag;
- Object.inheritFrom(this, Fusion.Lib.EventMgr, []);
this.registerEventID(Fusion.Event.WIDGET_STATE_CHANGED);
var group = widgetTag.extension.Group ? widgetTag.extension.Group[0] : '';
@@ -86,7 +84,7 @@
this.oMap = oMap;
if (oMap) {
- this.mapLoadedWatcher = this._mapLoaded.bind(this);
+ this.mapLoadedWatcher = OpenLayers.Function.bind(this._mapLoaded, this);
oMap.registerForEvent(Fusion.Event.MAP_LOADED, this.mapLoadedWatcher);
}
@@ -105,7 +103,14 @@
},
/**
+ * utility method to add an OL control to the OL map object
*/
+ addControl: function(control) {
+ this.getMap().oMapOL.addControl(control);
+ },
+
+ /**
+ */
_mapLoaded: function() {
if (this.oMap && this.oMap.isLoaded()) {
//console.log('enable');
@@ -165,4 +170,4 @@
registerParameter : function(param) {
this.paramRegister.push(param);
}
-};
+});
Modified: sandbox/aboudreault/lib/fusion.js
===================================================================
--- sandbox/aboudreault/lib/fusion.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/fusion.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -29,103 +29,50 @@
var Jx = {};
/**
- * declare global namespace object for Fusion library to use
- */
-var Fusion = {};
-
-/* set to true if you want to use the compressed version of the core files,
- * currently this saves about 100kb and quite a few HTTP connections so it is
- * faster, but less convenient if you want to debug one of the core files
- */
-Fusion.useCompressed = false;
-
-if (Fusion.useCompressed) {
- Fusion.coreScripts = ['lib/OpenLayers/OpenLayersCompressed.js',
- 'jx/lib/jx_compressed.js',
- 'lib/fusion-compressed.js',
- 'lib/excanvas/excanvas-compressed.js'];
-} else {
- Fusion.coreScripts = ['lib/OpenLayers/OpenLayers.js',
- 'jx/lib/jx_combined.js',
- 'lib/excanvas/excanvas-compressed.js',
- 'lib/utils.js',
- 'lib/Error.js',
- 'lib/ApplicationDefinition.js',
- 'lib/MGBroker.js',
- 'lib/Widget.js',
- 'lib/ButtonBase.js',
- 'lib/MenuBase.js',
- 'lib/ButtonTool.js',
- 'lib/CanvasTool.js',
- 'lib/ClickTool.js',
- 'lib/RectTool.js',
- 'lib/Map.js',
- 'lib/Search.js',
- 'text/en/strings.json'];
-}
-
-/* bootstrap function that gets everything Fusion needs, loaded */
-Fusion.bootstrap = function() {
- //determine the language to use and add resource bundles to be loaded to the core scripts
- var locale = navigator.language ?
- navigator.language.substring(0,2): //e.g. en-CA becomes just en
- navigator.userLanguage.substring(0,2);//only use the prefix part for now,
- var s=window.location.search.toLowerCase();
- var idx = s.indexOf('locale=');
- if (idx>0) {
- locale = s.substring(idx+7,idx+9);
- }
- if ( locale!='en' ) {
- Fusion.coreScripts.push('lib/OpenLayers/Strings/'+locale+'.js');
- Fusion.coreScripts.push('text/'+locale+'/strings.json');
- }
- window._FusionLocale = locale;
-
- var aScripts = document.getElementsByTagName('SCRIPT');
- var gszFusionURL = '';
- for (var i=0; i<aScripts.length; i++) {
- var s = aScripts[i].src;
- var n = s.indexOf('lib/fusion.js');
- if (n != -1) {
- gszFusionURL = s.substring(0,n);
- FusionScriptObject = aScripts[i];
- /* import the compressed version of jx and its CSS */
- Jx.baseURL = gszFusionURL + 'jx/';
- Jx.COMBINED_CSS = true;
- for (var j=0; j<Fusion.coreScripts.length; j++) {
- document.write('<script type="text/javascript" src="'+gszFusionURL+Fusion.coreScripts[j]+'"></script>');
- }
- break;
- }
- }
-};
-
-Fusion.bootstrap();
-
-/**
* reverse inheritance logic to allow for delayed loading of dependencies.
* Under normal circumstances, Object.extend from Prototype would be used,
* but in Fusion, widget code is loaded before base class code and the
* extend function won't work until all the base class code is available.
+ * DEPRECATED
*/
Object.inheritFrom = function(destination, source, args) {
- for (property in source) {
+ var parent;
+ if(typeof source == "function") {
+ // get the prototype of the superclass
+ parent = source.prototype;
+ } else {
+ // in this case we're extending with the prototype
+ parent = source;
+ }
+ for (property in parent) {
if (typeof destination[property] == 'undefined') {
- destination[property] = source[property];
+ destination[property] = parent[property];
}
}
- source.initialize.apply(destination, args);
+ parent.initialize.apply(destination, args);
};
-/* now we can safely replace the global fusion object */
-/***************************************************************************
-* Class: Fusion
-*
-* The main global object for Fusion applications.
-***************************************************************************/
+(function() {
+ /**
+ * Before creating the OpenLayers namespace, check to see if
+ * OpenLayers.singleFile is true. This occurs if the
+ * OpenLayers/SingleFile.js script is included before this one - as is the
+ * case with single file builds.
+ */
+ var singleFile = (typeof Fusion == "object" && Fusion.singleFile);
+
+ /* set to true if you want to use the compressed version of the core files,
+ * currently this saves about 100kb and quite a few HTTP connections so it is
+ * faster, but less convenient if you want to debug one of the core files
+ */
+ var useCompressed = false;
-Fusion = {
-
+ /**
+ * Namespace: Fusion
+ * declare global namespace object for Fusion library to use
+ */
+ window.Fusion = {
+
/***************************************************************************
* Class: Fusion.Tools
*
@@ -285,87 +232,72 @@
var sessionIdParam = this.getQueryParam('Session');
this.sessionId = sessionIdParam || (options.sessionId || null);
- if (options.applicationDefinition) {
+ if (options.applicationDefinitionURL) {
this.applicationDefinitionURL = options.applicationDefinitionURL;
} else {
var queryAppDef = this.getQueryParam('ApplicationDefinition');
if (queryAppDef) {
this.applicationDefinitionURL = queryAppDef.split('+').join(' ');
+ this.appDefJson = null; //wipe out any preloaded AppDef in a single file build
} else {
this.applicationDefinitionURL = 'ApplicationDefinition.xml';
}
}
-
+ if (Fusion._singleFile) {
+ //override this method since OL is loaded in the fusion file
+ OpenLayers._getScriptLocation = function() {
+ return Fusion.fusionURL + 'lib/OpenLayers/';
+ }
+ }
this.initializeLocale();
this.sWebagentURL = "";
this.sScriptLang = "";
- this.configuration = {};
- /* determine the URL to fusion based on the script tag
- * that was used to load this file
- */
- var aScripts = document.getElementsByTagName('SCRIPT');
- for (var i=0; i<aScripts.length; i++) {
- var s = aScripts[i].src;
- var n = s.indexOf('lib/fusion.js');
- if (n != -1) {
- this.fusionURL = s.substring(0,n);
- if (this.fusionURL.indexOf("http://")<0) {
- if (this.fusionURL.slice(0,1) == "/") {
- this.fusionURL = window.location.protocol + "//" + window.location.host + this.fusionURL;
- } else {
- var newLoc = window.location.href;
- if (newLoc.slice(-1) != "/") {
- newLoc = newLoc.slice(0,newLoc.lastIndexOf("?"));
- newLoc = newLoc.slice(0,newLoc.lastIndexOf("/")+1);
- }
- this.fusionURL = newLoc + this.fusionURL;
- }
- }
- /*
+ /*
* if the application has been loaded from the same host as
* fusion is installed in, then technically we don't need to
* use the redirect script because we conform to the
* Same Origin Policy for XmlHttpRequest to work.
*/
- var options = {};
- options.onSuccess = this.serverSet.bind(this);
- options.onFailure = this.serverFailed.bind(this);
- var test = window.location.protocol+'//'+window.location.host;
- //if (this.fusionURL.indexOf(test,0) == 0) {
- if ( ((this.fusionURL.indexOf("http://") < 0) || (this.fusionURL.indexOf(test,0) == 0)) && !(this.bForceRedirect)) {
- this.sRedirectScript = '';
- options.method = 'get';
- this.ajaxRequest('config.json', options);
- } else {
- this.sRedirectScript = 'redirect.php';
- this.ajaxRequest('config.json&method=get', options);
- }
- /*script language*/
- this.sScriptLang = 'php';
-
- break;
- }
+ var test = window.location.protocol+'//'+window.location.host;
+ var configUrl = 'config.json';
+ //if (this.fusionURL.indexOf(test,0) == 0) {
+ if ( ((this.fusionURL.indexOf("http://") < 0) || (this.fusionURL.indexOf(test,0) == 0)) && !(this.bForceRedirect)) {
+ this.sRedirectScript = '';
+ } else {
+ this.sRedirectScript = 'redirect.php';
+ configUrl += '&method=get';
}
- if (!this.fusionURL) {
- alert('failed to determine fusionURL. Initailization aborted');
- return;
+
+ /*script language*/
+ this.sScriptLang = 'php';
+
+ if (Fusion.configuration) {
+ //config.json loaded via single file build
+ this.serverSet();
+ } else {
+ var options = {
+ onSuccess: OpenLayers.Function.bind(this.getConfigCB, this),
+ onFailure: OpenLayers.Function.bind(this.serverFailed, this),
+ method: 'get'
+ };
+ this.ajaxRequest(configUrl, options);
}
},
initializeLocale: function(locale) {
this.locale = locale ? locale : window._FusionLocale;
- OpenLayers.String.langCode = this.locale;
+ OpenLayers.Lang.setCode(this.locale);
//check if strings are defined for specified locale, if not, set them to the default locale
- if (!OpenLayers.Strings[this.locale]) {
- OpenLayers.Strings[this.locale] = OpenLayers.Strings[OpenLayers.String.defaultLangCode];
+ if (!OpenLayers.Lang[this.locale]) {
+ OpenLayers.Lang[this.locale] = OpenLayers.Lang[OpenLayers.String.defaultLangCode];
}
if (!Fusion.Strings[this.locale]) {
Fusion.Strings[this.locale] = Fusion.Strings[OpenLayers.String.defaultLangCode];
}
- OpenLayers.Util.extend(OpenLayers.Strings[this.locale], Fusion.Strings[this.locale]);
+ OpenLayers.Util.extend(OpenLayers.Lang[this.locale], Fusion.Strings[this.locale]);
},
/**
@@ -412,6 +344,7 @@
//increment the load state
if (this.aScripts.length == 0) {
this.setLoadState(this.loadState+1);
+ return;
}
this.aLoadingScripts = [];
@@ -428,7 +361,8 @@
}
//if IE or Safari
- this.checkLoadInterval = window.setInterval(this.checkLoadingScripts.bind(this), 500);
+ this.checkLoadInterval = window.setInterval(
+ OpenLayers.Function.bind(this.checkLoadingScripts, this), 500);
},
/**
@@ -450,8 +384,8 @@
//TODO: test url to see if it needs to come from fusion
script.id = url;
script.src = this.getFusionURL() + url;
- script.onload = this.scriptLoaded.bind(this, url);
- script.onerror = this.scriptFailed.bind(this, script.src);
+ script.onload = OpenLayers.Function.bind(this.scriptLoaded, this, url);
+ script.onerror = OpenLayers.Function.bind(this.scriptFailed, this, script.src);
this.aScripts[url] = script;
this.aScripts.push(script);
}
@@ -470,7 +404,7 @@
*/
scriptFailed: function(url) {
Fusion.reportError(new Fusion.Error(Fusion.Error.FATAL,
- OpenLayers.String.translate('scriptFailed',url)));
+ OpenLayers.i18n('scriptFailed',{'script':url})));
},
/**
@@ -544,10 +478,13 @@
this.oBroker.setSiteURL(url, "Anonymous", "");
}
this.applicationDefinition = new Fusion.Lib.ApplicationDefinition(this.sessionId);
+ if (Fusion.appDefJson) {
+ Fusion.setLoadState(Fusion.LOAD_WIDGETS);
+ }
},
/**
- * Function: serverSet
+ * Function: getConfigCB
*
* the server has returned the application configuration file that
* contains enough information to bootstrap the application.
@@ -555,39 +492,52 @@
* Parameter {Object} r
* an XMLHttpRequest object
*/
- serverSet : function(r) {
+ getConfigCB : function(r) {
if (r.responseText) {
eval("this.configuration="+r.responseText);
- var s = this.configuration.mapguide.webTierUrl;
- /* if it is set, use it ... otherwise assume fusion is installed in
- * the default location and compute the web tier url from that
- */
- if (s) {
- var nLength = s.length;
- var slastChar = s.charAt((nLength-1));
- if (slastChar != '/') {
- s = s + "/";
- }
- } else {
- var idx = this.fusionURL.lastIndexOf('fusion');
- if (idx == -1) {
- s = this.fusionURL + "../"; //loaded relatively from within fusion directory
- } else {
- s = this.fusionURL.substring(0, idx);
- }
- }
- this.configuration.mapguide.webTierUrl = s;
- this.configuration.mapguide.mapAgentUrl = s + 'mapagent/mapagent.fcgi?';
-
- //trigger loading stuff ...
- this.setLoadState(this.LOAD_CONFIG);
+ this.serverSet();
} else {
//console.log('Error parsing configuration file, it is not valid somehow?');
- alert(OpenLayers.String.translate('configParseError'));
+ alert(OpenLayers.i18n('configParseError'));
}
},
/**
+ * Function: serverSet
+ *
+ * the server has returned the application configuration file that
+ * contains enough information to bootstrap the application.
+ *
+ * Parameter {Object} r
+ * an XMLHttpRequest object
+ */
+ serverSet : function() {
+ var s = this.configuration.mapguide.webTierUrl;
+ /* if it is set, use it ... otherwise assume fusion is installed in
+ * the default location and compute the web tier url from that
+ */
+ if (s) {
+ var nLength = s.length;
+ var slastChar = s.charAt((nLength-1));
+ if (slastChar != '/') {
+ s = s + "/";
+ }
+ } else {
+ var idx = this.fusionURL.lastIndexOf('fusion');
+ if (idx == -1) {
+ s = this.fusionURL + "../"; //loaded relatively from within fusion directory
+ } else {
+ s = this.fusionURL.substring(0, idx);
+ }
+ }
+ this.configuration.mapguide.webTierUrl = s;
+ this.configuration.mapguide.mapAgentUrl = s + 'mapagent/mapagent.fcgi?';
+
+ //trigger loading stuff ...
+ this.setLoadState(this.LOAD_CONFIG);
+ },
+
+ /**
* Function: serverFailed
*
* the application failed to load the application configuration file.
@@ -602,7 +552,7 @@
*/
serverFailed: function(r) {
//console.log('error loading server configuration file');
- alert(OpenLayers.String.translate('configLoadError'));
+ alert(OpenLayers.i18n('configLoadError'));
},
/**
@@ -628,9 +578,17 @@
}
var url = r + this.getFusionURL() + scriptURL;
if (!options.onException) {
- options.onException = this.ajaxException.bind(this);
+ options.onException = OpenLayers.Function.bind(this.ajaxException, this);
}
- new Ajax.Request( url, options);
+ if (!options.contentType) {
+ options.contentType = 'application/x-www-form-urlencoded';
+ }
+ if (options.parameters && typeof options.parameters == 'string') {
+ if (options.parameters.indexOf('?') < 0) {
+ options.parameters = '?' + options.parameters;
+ }
+ }
+ new OpenLayers.Ajax.Request( url, options);
},
/**
@@ -644,9 +602,64 @@
*/
ajaxException: function(r, e) {
this.reportError(new Fusion.Error(Fusion.Error.WARNING,
- OpenLayers.String.translate('ajaxError', e, e.filename, e.lineNumber, 'xx')));
+ OpenLayers.i18n('ajaxError', {'exception':e.message,
+ 'filename':e.fileName,
+ 'line':e.lineNumber,
+ 'response': r.transport.responseText
+ })));
},
+ /**
+ * Function: convertXML
+ *
+ * Optionally convert XML to JSON using a server-side script
+ * for requests that aren't available in JSON.
+ *
+ * Parameter: {XmlHttpRequest} r
+ *
+ * the XmlHttpRequest object
+ *
+ * Parameter: json
+ *
+ * boolean indicator if the content is JSON or not.
+ *
+ * Parameter: callback
+ *
+ * callback method to be executed on success and will be passed a parsed json object
+ */
+ getXmlAsJson: function(url, callback) {
+ var options = {
+ method: 'get',
+ onSuccess: OpenLayers.Function.bind(this.xml2json, this, callback),
+ onFailure: OpenLayers.Function.bind(this.ajaxException, this)
+ };
+ new OpenLayers.Ajax.Request(url, options);
+ },
+
+ xml2json: function(callback, r, json) {
+ if (json) {
+ var o;
+ eval("o="+r.responseText);
+ callback(o);
+ } else {
+ //this check only works on Firefox - it is safely ignored in IE and IE
+ //will happily parse an invalid XML document
+ if (r.responseXML.documentElement.nodeName == 'parsererror') {
+ Fusion.reportError(new Fusion.Error(Fusion.Error.FATAL,
+ 'invalid XML document: ' + r.url));
+ }
+
+ var options = {
+ onSuccess: callback,
+ method: 'post',
+ //parameters = 'xml='+encodeURIComponent(r.responseText.replace(/\\/g, '\\\\\\\\'));
+ parameters: {'xml': encodeURIComponent(r.responseText)}
+ };
+ var sl = Fusion.getScriptLanguage();
+ Fusion.ajaxRequest('common/'+sl+'/Xml2JSON.'+sl, options);
+ }
+ },
+
/**
* Function: getMapByName
*
@@ -760,6 +773,14 @@
}
},
+ getSearchCategories: function() {
+ if (this.applicationDefinition) {
+ return this.applicationDefinition.searchCategories;
+ } else {
+ return {};
+ }
+ },
+
getApplicationDefinitionURL: function() { return this.applicationDefinitionURL; },
/**
@@ -793,7 +814,7 @@
require: function(url) { this.queueScript(url); },
- reportError: function(o) { this.triggerEvent(Fusion.Event.FUSION_ERROR, o); },
+ reportError: function(o) { console.log(o.message); this.triggerEvent(Fusion.Event.FUSION_ERROR, o); },
unitFromName: function(unit) {
switch(unit.toLowerCase()) {
@@ -892,11 +913,54 @@
}
return false;
},
+
+ /**
+ * initializes the meters per unit values when a new map is loaded. Some systems make different
+ * assumptions for the conversion of degrees to meters so this makes sure both Fusion and
+ * OpenLayers are using the same value.
+ *
+ * @param metersPerUnit the value returned by LoadMap.php for meters per unit
+ */
+ initUnits: function(metersPerUnit) {
+ var eps = 1000;
+ if (Math.abs(metersPerUnit-Fusion.aMeterPerUnit[Fusion.DEGREES]) < eps){
+ Fusion.aMeterPerUnit[Fusion.DEGREES] = metersPerUnit;
+ Fusion.aMeterPerUnit[Fusion.DECIMALDEGREES] = metersPerUnit;
+ Fusion.aMeterPerUnit[Fusion.DMX] = metersPerUnit;
+ var inverse = 1.0/metersPerUnit;
+ Fusion.aUnitPerMeter[Fusion.DEGREES] = inverse;
+ Fusion.aUnitPerMeter[Fusion.DECIMALDEGREES] = inverse;
+ Fusion.aUnitPerMeter[Fusion.DMX] = inverse;
+
+ var inPerUnit = OpenLayers.INCHES_PER_UNIT.m * metersPerUnit;
+ OpenLayers.INCHES_PER_UNIT["dd"] = inPerUnit;
+ OpenLayers.INCHES_PER_UNIT["degrees"] = inPerUnit;
+ }
+ },
+
+ /**
+ * find the OpenLayers units identifier given the Fusion metersPerUnit value
+ *
+ * @param metersPerUnit the value returned by LoadMap.php for meters per unit
+ */
+ getClosestUnits: function(metersPerUnit) {
+ var units = "degrees";
+ var minDiff = 100000000;
+ for (var key in OpenLayers.INCHES_PER_UNIT) {
+ var newDiff = Math.abs((metersPerUnit * 39.3701) - OpenLayers.INCHES_PER_UNIT[key]);
+ if(newDiff < minDiff)
+ {
+ minDiff = newDiff;
+ units = key;
+ }
+ }
+ return units;
+ },
addWidgetStyleSheet: function(url) {
var lnk = document.createElement('link');
var hd = document.getElementsByTagName('HEAD')[0];
- hd.insertBefore(lnk, FusionScriptObject);
+ hd.insertBefore(lnk, Fusion._scriptObject);
lnk.type = 'text/css';
lnk.rel='stylesheet';
lnk.href = Fusion.getFusionURL()+url;
@@ -926,127 +990,129 @@
} else {
return '';
}
- }
-};
-
-/**
- * Class: Fusion.Lib.EventMgr
- *
- * an internal class for managing generic events. Classes that wish to
- * publish and trigger events that other objects can listen for need to
- * inherit from Fusion.Lib.EventMgr.
- *
- * To publish an event, call registerEventID with some unique numeric or
- * string value. Other objects can then call registerForEvent with the
- * eventID and a function to call when the event is triggered.
- *
- * To trigger an event, call triggerEvent with the eventID and any additional
- * arguments that should be passed to listeners.
- */
-//Fusion.Lib.EventMgr = Class.create();
-Fusion.Lib.EventMgr = {
- /* an array of eventIDs and associated listener functions */
- events : null,
+ },
- initialize: function() { if (!this.events) {this.events = []; }},
+ /**
+ * Property: _scriptName
+ * {String} Relative path of this script.
+ */
+ _scriptName: "lib/fusion",
- /**
- * Method: destroy
- *
- */
- destroy: function() {
- this.events = [];
- },
+ /**
+ * Function: _getScriptLocation
+ * Return the path to this script.
+ *
+ * Returns:
+ * {String} Path to this script
+ */
+ _getScriptLocation: function () {
+ Fusion.fusionURL = null;
+ var scriptName = Fusion._scriptName;
+
+ var scripts = document.getElementsByTagName('script');
+ for (var i = 0; i < scripts.length; i++) {
+ var src = scripts[i].getAttribute('src');
+ if (src) {
+ var index = src.lastIndexOf(scriptName);
+ if (index > -1) {
+ Fusion.fusionURL = src.slice(0, index);
+ Fusion._scriptObject = scripts[i];
+
+ if (Fusion.fusionURL.indexOf("http://")<0) {
+ if (Fusion.fusionURL.slice(0,1) == "/") {
+ Fusion.fusionURL = window.location.protocol + "//" + window.location.host + Fusion.fusionURL;
+ } else {
+ var newLoc = window.location.href;
+ if (newLoc.slice(-1) != "/") {
+ newLoc = newLoc.slice(0,newLoc.lastIndexOf("?"));
+ newLoc = newLoc.slice(0,newLoc.lastIndexOf("/")+1);
+ }
+ Fusion.fusionURL = newLoc + Fusion.fusionURL;
+ }
+ }
+ break;
+ }
+ }
+ }
+ if (!this.fusionURL) {
+ alert('failed to determine fusionURL. Initialization aborted');
+ return;
+ }
+ return Fusion.fusionURL;
+ }
+ };
+
+ /*********************************************************************************/
+ /* actual bootstrap execution code follows */
- /**
- * register an event ID so that others can use it. This should really
- * only be called by 'this' object.
- *
- * @param eventID the event ID to register
- */
- registerEventID : function( eventID ) {
- if (!eventID) {
- Fusion.reportError(new Fusion.Error(Fusion.Error.WARNING,
- OpenLayers.String.translate('regsiterEventError')));
+ Fusion._singleFile = singleFile;
+ var host = Fusion._getScriptLocation();
+ Jx.baseURL = host + 'jx/';
+ Jx.COMBINED_CSS = true;
+
+ //determine the language to use and add resource bundles to be loaded to the core scripts
+ var locale = navigator.language ?
+ navigator.language.substring(0,2): //e.g. en-CA becomes just en
+ navigator.userLanguage.substring(0,2);//only use the prefix part for now,
+ var s = window.location.search.toLowerCase();
+ var idx = s.indexOf('locale=');
+ if (idx>0) {
+ locale = s.substring(idx+7,idx+9);
+ }
+ window._FusionLocale = locale;
+
+ if (!Fusion._singleFile) {
+ if (useCompressed) {
+ var coreScripts = ['lib/OpenLayers/OpenLayers.js',
+ 'jx/lib/jx_compressed.js',
+ 'lib/fusion-compressed.js',
+ 'lib/excanvas/excanvas-compressed.js'];
+ } else {
+ var coreScripts = ['lib/OpenLayers/OpenLayers.js',
+ 'jx/lib/jx_combined.js',
+ 'lib/excanvas/excanvas-compressed.js',
+ 'lib/EventMgr.js',
+ 'lib/Error.js',
+ 'lib/ApplicationDefinition.js',
+ 'lib/MGBroker.js',
+ 'lib/Widget.js',
+ 'lib/ButtonBase.js',
+ 'lib/MenuBase.js',
+ 'lib/ButtonTool.js',
+ 'lib/CanvasTool.js',
+ 'lib/ClickTool.js',
+ 'lib/RectTool.js',
+ 'lib/Map.js',
+ 'lib/Search.js',
+ 'text/en/strings.json'];
}
- var ev = new String(eventID);
- if (!this.events[eventID]) {
- this.events[eventID] = [];
+
+ if (locale != 'en') {
+ coreScripts.push('lib/OpenLayers/Lang/'+locale+'.js');
+ coreScripts.push('text/'+locale+'/strings.json');
}
- },
-
- /**
- * register for receiving a callback when an event happens. If you
- * want the callback to be a method on an instance of some object,
- * use the bind() function as in:
- *
- * otherObj.registerForEvent(SOME_EVENT, this.callback.bind(this));
- *
- * @param eventID the event ID to register for
- * @param f the function to call when the event happens.
- */
- registerForEvent : function(eventID, f) {
- var ev = new String(eventID);
- this.events[eventID].push(f);
- },
-
- /**
- * deregister a callback function when you no longer want to
- * recieve it. Note that if you used bind() when registering,
- * you need to pass EXACTLY THE SAME FUNCTION when
- * deregistering. Typically, this means you need to assign the
- * result of bind() to an instance variable and pass that instance
- * variable to both registerForEvent and deregisterForEvent.
- *
- * For instance:
- *
- * this.callbackFn = this.callback.bind(this);
- * otherObj.registerForEvent(SOME_EVENT, this.callbackFn);
- * otherObj.deregisterForEvent(SOME_EVENT, this.callbackFn);
- *
- * @param eventID the event ID to deregister
- * @param f the function that used when registering.
- */
- deregisterForEvent : function( eventID, f ) {
- var ev = new String(eventID);
- var bResult = false;
- if (!this.events[eventID]){
- return false;
+
+ var agent = navigator.userAgent;
+ var docWrite = (agent.match("MSIE") || agent.match("Safari"));
+ if (docWrite) {
+ var allScriptTags = new Array(coreScripts.length);
}
-
- for (var i=0;i<this.events[eventID].length;i++) {
- if (this.events[eventID][i]== f) {
- this.events[eventID].splice(i,1);
- bResult = true;
+ for (var i = 0; i < coreScripts.length; i++) {
+ if (docWrite) {
+ allScriptTags[i] = "<script src='" + host + coreScripts[i] +
+ "'></script>";
+ } else {
+ var s = document.createElement("script");
+ s.src = host + coreScripts[i];
+ var h = document.getElementsByTagName("head").length ?
+ document.getElementsByTagName("head")[0] :
+ document.body;
+ h.appendChild(s);
}
}
- return bResult;
- },
-
- /**
- * trigger an event and call all registered listener functions.
- * This is intended to be called by 'this'. The eventID param
- * is mandatory. Any additional arguments will be passed to the
- * listener function.
- *
- * @param eventID the event ID to trigger
- */
- triggerEvent : function( eventID ) {
- var ev = new String(eventID);
- if (!this.events || !this.events[eventID]) {
- return false;
+ if (docWrite) {
+ document.write(allScriptTags.join(""));
}
-
- for (var i=0; i<this.events[eventID].length; i++) {
- this.events[eventID][i].apply(null, arguments);
- }
- return true;
}
-};
+})();
-Object.inheritFrom(Fusion, Fusion.Lib.EventMgr, []);
-
-Fusion.Event.FUSION_INITIALIZED = Fusion.Event.lastEventId++;
-Fusion.Event.FUSION_ERROR = Fusion.Event.lastEventId++;
-Fusion.registerEventID(Fusion.Event.FUSION_INITIALIZED);
-Fusion.registerEventID(Fusion.Event.FUSION_ERROR);
Deleted: sandbox/aboudreault/lib/utils.js
===================================================================
--- sandbox/aboudreault/lib/utils.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/lib/utils.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -1,215 +0,0 @@
-/**
- * Utils
- *
- * $Id$
- *
- * Copyright (c) 2007, DM Solutions Group Inc.
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-var DomNode = Class.create();
-
-DomNode.prototype = {
- initialize: function( xmlNode /*, parent */ ) {
- this.textContent = '';
- this.nodeName = xmlNode?xmlNode.nodeName:'';
- this.parentNode = arguments[1]?arguments[1]:null;
- this.childNodes = [];
- this.attributes = [];
- this.attributeNames = [];
- if (xmlNode) {
- if (xmlNode.attributes) {
- for (var i=0; i<xmlNode.attributes.length; i++) {
- this.attributeNames.push(xmlNode.attributes[i].name);
- this.attributes[xmlNode.attributes[i].name] = xmlNode.attributes[i].nodeValue;
- }
- }
- for (var i=0; i<xmlNode.childNodes.length; i++) {
- if (xmlNode.childNodes[i].nodeType != 3) {
- this.childNodes.push(new DomNode(xmlNode.childNodes[i], this));
- } else {
- this.textContent = this.textContent + xmlNode.childNodes[i].nodeValue;
- }
- }
- }
- this._currentNode = 0;
- },
- getAttribute: function(name) {
- return typeof(this.attributes[name]) != 'undefined' ? this.attributes[name] : null;
- },
- removeChild: function(child) {
- var result = null;
- for(var i=0; i<this.childNodes.length; i++) {
- if (this.childNodes[i] == child) {
- this._currentNode = 0;
- this.childNodes.splice(i,1);
- child.parentNode = null;
- result = child;
- break;
- }
- }
- return result;
- },
- appendChild: function(child) {
- if (child.parentNode) {
- child.parentNode.removeChild(child);
- }
- child.parentNode = this;
- this.childNodes.push(child);
- },
- insertBefore: function(newChild,refChild) {
- var bInserted = false;
- if (refChild) {
- for (var i=0; i<this.childNodes.length; i++) {
- if (this.childNodes[i] == refChild) {
- if (newChild.parentNode) {
- newChild.parentNode.removeChild(child);
- }
- newChild.parentNode = this;
- this.childNodes.splice(i,0,newChild);
- bInserted = true;
- break;
- }
- }
- }
- if (!bInserted) {
- this.appendChild(newChild);
- }
- },
- toString: function(depth) {
- var s = '';
- var spacer = '';
- for (i=0; i<depth; i++) {
- spacer = spacer + '';
- }
- s = spacer + '<' + this.nodeName;
- if (this.attributes.length > 0) {
- for (var name in this.attributes) {
- if (typeof(this.attributes[name]) == 'String' ) {
- s = s + ' ' + name + '="' + this.attributes[name] + '"';
- }
- }
- }
- s = s + '>';
- if (this.childNodes.length == 0) {
- s = s + this.textContent;
- spacer = '';
- } else {
- s = s + '\n';
- }
- for (var i=0; i<this.childNodes.length; i++) {
- s = s + this.childNodes[i].toString( depth + 1 );
- }
- s = s + spacer + '</'+this.nodeName+'>';
- return s;
- },
- toXML: function() {
- var s = this.parentNode?'':'<?xml version="1.0" encoding="UTF-8"?>\n';
- s = s+ '<' + this.nodeName;
- if (this.attributeNames.length > 0) {
- for (var i=0; i<this.attributeNames.length; i++) {
- var name = this.attributeNames[i];
- s = s + ' ' + name + '="' + this.attributes[name] + '"';
- }
- }
- s = s + '>';
- if (this.childNodes.length == 0) {
- var content = this.textContent + ''; //force string value if textContent was automatically made to a number
- content = content.replace('&','&');
- content = content.replace(/</g, encodeURIComponent('<'));
- content = content.replace(/>/g, encodeURIComponent('>'));
- s = s + content;
-
- }
- for (var i=0; i<this.childNodes.length; i++) {
- s = s + this.childNodes[i].toXML();
- }
- s = s + '</'+this.nodeName+'>\n';
- return s;
- },
- getNodeText: function(name) {
- var s = '';
- var n = this.findFirstNode(name);
- if (n) {
- s = n.textContent;
- }
- return s;
- },
- setNodeText: function(name, value) {
- var n = this.findFirstNode(name);
- if (n) {
- n.setTextContent(value);
- }
- },
- setTextContent: function(value) {
- this.textContent = value;
- },
- setAttribute: function(name, value) {
- if (typeof this.attributes[name] == 'undefined') {
- this.attributeNames.push(name);
- }
- this.attributes[name] = value;
- },
- findFirstNode: function( name ) {
- this._currentNode = 0;
- if (this.nodeName == name) {
- return this;
- } else {
- for (var i=0; i<this.childNodes.length; i++) {
- var node = this.childNodes[i].findFirstNode(name);
- if (node) {
- if (node.parentNode == this) {
- this._currentNode = i + 1;
- } else {
- this._currentNode = i;
- }
- return node;
- }
- }
- return false;
- }
- },
- findNextNode: function( name ) {
- if (this.nodeName == name) {
- return this;
- } else {
- for (var i=this._currentNode; i<this.childNodes.length; i++) {
- var node = this.childNodes[i].findNextNode(name);
- if (node) {
- if (node.parentNode == this) {
- this._currentNode = i + 1;
- } else {
- this._currentNode = i;
- }
- return node;
- }
- }
- return false;
- }
- }
-};
-
-var DomNodeFactory = {
- create: function( name, value ) {
- var node = new DomNode();
- node.nodeName = name;
- node.textContent = value || '';
- return node;
- }
-};
\ No newline at end of file
Copied: sandbox/aboudreault/parseAppDef.xsl (from rev 1412, trunk/parseAppDef.xsl)
===================================================================
--- sandbox/aboudreault/parseAppDef.xsl (rev 0)
+++ sandbox/aboudreault/parseAppDef.xsl 2008-05-29 14:21:40 UTC (rev 1413)
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+Description: Generates a list of widget and map files required for a single file build of Fusion
+$Id$
+$Name$
+-->
+
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ exclude-result-prefixes="xs">
+
+ <xsl:output method="xml" omit-xml-declaration="yes"/>
+ <xsl:strip-space elements="*"/>
+ <xsl:param name="buildHome">./build</xsl:param>
+
+ <!-- Root node. -->
+ <xsl:template match="/ApplicationDefinition">
+ <xsl:variable name="widgetFileList">
+ <xsl:apply-templates select="WidgetSet"/>
+ </xsl:variable>
+ <xsl:variable name="mapFileList">
+ <xsl:apply-templates select="MapSet"/>
+ </xsl:variable>
+ <AppDef>
+ <Widgets>
+ <xsl:call-template name="removeDuplicates">
+ <xsl:with-param name="str" select="$widgetFileList"/>
+ <xsl:with-param name="sep" select="' '"/>
+ </xsl:call-template>
+ </Widgets>
+ <Maps>
+ <xsl:call-template name="removeDuplicates">
+ <xsl:with-param name="str" select="$mapFileList"/>
+ <xsl:with-param name="sep" select="' '"/>
+ </xsl:call-template>
+ </Maps>
+ </AppDef>
+ </xsl:template>
+
+ <xsl:template match="Container"/> <!-- empty templates to suppress output -->
+ <xsl:template match="MapWidget"/>
+
+ <xsl:template match="Widget">
+ <xsl:variable name="loc">
+ <xsl:choose>
+ <xsl:when test="Location">
+ <xsl:value-of select="Location"/>
+ </xsl:when>
+ <xsl:otherwise>widgets</xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:value-of select="$loc"/>/<xsl:value-of select="Type"/>.js
+ </xsl:template>
+
+ <xsl:template match="MapGroup/Map">
+ <xsl:value-of select="Type"/>/<xsl:value-of select="Type"/>.js
+ </xsl:template>
+
+ <xsl:template name="removeDuplicates"> <!-- tokenize a string -->
+ <xsl:param name="str"/> <!-- String to process -->
+ <xsl:param name="sep"/> <!-- Legal separator character -->
+ <xsl:param name="result"/> <!-- result to be returned -->
+ <xsl:choose>
+ <xsl:when test="contains($str,$sep)"> <!-- Only tokenize if there is a separator present in the string -->
+ <xsl:choose>
+ <xsl:when test="not(contains($result, substring-before($str,$sep)))"><!-- result doesn't already contain this token -->
+ <xsl:call-template name="removeDuplicates"> <!-- Re-tokenize the new string which is contained after the separator -->
+ <xsl:with-param name="str" select="substring-after($str,$sep)"/>
+ <xsl:with-param name="sep" select="$sep"/>
+ <xsl:with-param name="result" select="concat($result, ' ', substring-before($str,$sep))"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise> <!-- it's a duplicate, continue without concating -->
+ <xsl:call-template name="removeDuplicates"> <!-- Re-tokenize the new string which is contained after the separator -->
+ <xsl:with-param name="str" select="substring-after($str,$sep)"/>
+ <xsl:with-param name="sep" select="$sep"/>
+ <xsl:with-param name="result" select="$result"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise> <!-- If there is nothing else to tokenize, just return the result -->
+ <xsl:value-of select="$result"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+</xsl:stylesheet>
Modified: sandbox/aboudreault/templates/mapguide/standard/ApplicationDefinition.xml
===================================================================
--- sandbox/aboudreault/templates/mapguide/standard/ApplicationDefinition.xml 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/templates/mapguide/standard/ApplicationDefinition.xml 2008-05-29 14:21:40 UTC (rev 1413)
@@ -18,6 +18,24 @@
</Extension>
</Map>
</MapGroup>
+ <MapGroup id="gmap-tiled" xsi:type="MapType">
+ <Map xsi:type="MapGuideLayerType">
+ <Type>MapGuide</Type>
+ <SingleTile>false</SingleTile>
+ <Extension>
+ <ResourceId>Library://Samples/Gmap/Maps/gmapTiled.MapDefinition</ResourceId>
+ </Extension>
+ </Map>
+ </MapGroup>
+ <MapGroup id="gmap" xsi:type="MapType">
+ <Map xsi:type="MapGuideLayerType">
+ <Type>MapGuide</Type>
+ <SingleTile>false</SingleTile>
+ <Extension>
+ <ResourceId>Library://Samples/Gmap/Maps/gmap.MapDefinition</ResourceId>
+ </Extension>
+ </Map>
+ </MapGroup>
</MapSet>
<!-- ******************************************
@@ -188,6 +206,10 @@
<Type>Toolbar</Type>
<Item xsi:type="WidgetItemType">
<Function>Widget</Function>
+ <Widget>MapMenu</Widget>
+ </Item>
+ <Item xsi:type="WidgetItemType">
+ <Function>Widget</Function>
<Widget>toolbarHelp</Widget>
</Item>
<Item xsi:type="WidgetItemType">
@@ -277,6 +299,19 @@
</Item>
</Container>
+<!-- MAP -->
+
+ <MapWidget xsi:type="WidgetType">
+ <Name>Map</Name>
+ <Type>Map</Type>
+ <StatusItem>The map.</StatusItem>
+ <Extension xsi:type="CustomContentType">
+ <MenuContainer>MapContextMenu</MenuContainer>
+ <Scales>2000000 1000000 500000 250000 125000 50000</Scales>
+ </Extension>
+ <MapId>sheboygan</MapId>
+ </MapWidget>
+
<!-- ******************************************
* Context Menu - Widgets
*
@@ -920,7 +955,7 @@
<Type>ZoomOnClick</Type>
<StatusItem>Zoom in by a preset increment.</StatusItem>
<Extension xsi:type="CustomContentType">
- <Factor>2</Factor>
+ <Factor>4</Factor>
</Extension>
<ImageUrl>images/icons/zoom-in-fixed.png</ImageUrl>
<ImageClass/>
@@ -972,18 +1007,6 @@
<Disabled/>
</Widget>
-<!-- MAP -->
-
- <MapWidget xsi:type="WidgetType">
- <Name>Map</Name>
- <Type>Map</Type>
- <StatusItem>The map.</StatusItem>
- <Extension xsi:type="CustomContentType">
- <MenuContainer>MapContextMenu</MenuContainer>
- </Extension>
- <MapId>sheboygan</MapId>
- </MapWidget>
-
<!-- OVERVIEW MAP -->
<Widget xsi:type="WidgetType">
@@ -1029,8 +1052,23 @@
<Disabled/>
</Widget>
- </WidgetSet>
+ <Widget xsi:type="UiWidgetType">
+ <Name>Scalebar</Name>
+ <Type>ScalebarDual</Type>
+ </Widget>
+
+ <Widget xsi:type="WidgetType">
+ <Name>MapTip</Name>
+ <Type>Maptip</Type>
+ <Extension>
+ <Label>Map Tips</Label>
+ <Delay>350</Delay>
+ <Layer>Parcels</Layer>
+ </Extension>
+ </Widget>
+ </WidgetSet>
+
<Extension/>
</ApplicationDefinition>
Modified: sandbox/aboudreault/templates/mapguide/standard/index.html
===================================================================
--- sandbox/aboudreault/templates/mapguide/standard/index.html 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/templates/mapguide/standard/index.html 2008-05-29 14:21:40 UTC (rev 1413)
@@ -14,6 +14,10 @@
background-color: #999;
cursor: 'col-resize';
}
+
+ body {
+ overflow: hidden;
+ }
#Toolbar .jxToolbar {
/*width: 100%;*/
@@ -52,7 +56,14 @@
line-height: 18px;
}
+ #Scalebar {
+ position: absolute;
+ bottom: 5px;
+ left: 5px;
+ z-index: 1001;
+ }
+
li.jxToolItem.activityIndicator {
float: right;
padding: 6px 3px;
@@ -122,12 +133,14 @@
<div id="PanelPane"></div>
<div id="Map">
<div id="Navigator"></div>
+ <div id="Scalebar"></div>
</div>
</div>
</div>
<div id="TaskPane"></div>
<div id="Statusbar"></div>
+ <div id="MapTip"></div>
<div id="PoweredBy" class="statusBarItem">
<a href="http://mapserver.gis.umn.edu.org/" target="_blank">
<img src="images/PoweredBy_MapServer.gif" width="137" height="18" border="0">
@@ -141,4 +154,4 @@
</div>
</body>
-</html>
\ No newline at end of file
+</html>
Modified: sandbox/aboudreault/text/en/strings.json
===================================================================
--- sandbox/aboudreault/text/en/strings.json 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/text/en/strings.json 2008-05-29 14:21:40 UTC (rev 1413)
@@ -1,20 +1,20 @@
-Fusion.Strings.en = {
-'scriptFailed': 'failed to load script: {0}',
+Fusion.Strings.en = {
+'scriptFailed': 'failed to load script: ${script}',
'configParseError': 'Error parsing fusion configuration file, initialization aborted',
'configLoadError': 'Error loading fusion configuration file, initialization aborted',
-'ajaxError': 'Exception occurred in AJAX callback.\n{0}\nLocation: {1} ({2})\n{3})',
-'importFailed': 'failed to import stylesheet: {0}',
+'ajaxError': 'Exception occurred in AJAX callback.\nMessage: ${exception}\nLocation: ${filename} (${line})\nResponse: ${response}',
+'importFailed': 'failed to import stylesheet: ${url}',
'registerEventError': 'Error registering eventID, invalid (empty) eventID.',
-'appDefLoadFailed': 'failed to load: {0}',
+'appDefLoadFailed': 'failed to load: ${script}',
'appDefParseError': 'failed to parse ApplicationDefinition',
'widgetSetParseError': 'failed to parse the WidgetSet',
-'fusionError': 'Fusion Error: {0}\n{1}',
+'fusionError': 'Fusion Error: ${type}\n${message}',
'nullExtents': 'Map.setExtents called with null extents',
-'mapLoadError': 'Failed to load requested map:\n{0}',
-'setLayersError': "setLayers failure: {0}",
+'mapLoadError': 'Failed to load requested map:\n${error}',
+'setLayersError': "setLayers failure: ${error}",
'printTitle': 'Printable Page ',
'noSelection': 'No Selection',
-'selectionInfo': '{0} features selected on {1} layers',
+'selectionInfo': '${features} features selected on ${layers} layers',
'attribute': 'Attribute',
'value': 'Value',
'taskHome': 'return to the task pane home',
@@ -36,7 +36,7 @@
'ovmapTitle': 'Overview Map',
'ovmapTitleShort': 'Overview',
'taskPaneTitle': 'Tasks',
-'segment': 'Segment {0}',
+'segment': 'Segment ${seg}',
'calculating': 'calculating ...',
'panWest': 'Pan West',
'panEast': 'Pan East',
Modified: sandbox/aboudreault/text/fr/strings.json
===================================================================
--- sandbox/aboudreault/text/fr/strings.json 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/text/fr/strings.json 2008-05-29 14:21:40 UTC (rev 1413)
@@ -1,21 +1,20 @@
Fusion.Strings.fr = {
-'scriptFailed': 'failed to load script: {0}',
+'scriptFailed': 'failed to load script: ${script}',
'configParseError': 'Error parsing fusion configuration file, initialization aborted',
'configLoadError': 'Error loading fusion configuration file, initialization aborted',
-'ajaxError': 'Exception occurred in AJAX callback.\n{0}\nLocation: {1} ({2})\n{3})',
-'importFailed': 'failed to import stylesheet: {0}',
+'ajaxError': 'Exception occurred in AJAX callback.\n${exception}\nLocation: ${file} (${line}))',
+'importFailed': 'failed to import stylesheet: ${url}',
'registerEventError': 'Error registering eventID, invalid (empty) eventID.',
-'appDefLoadFailed': 'failed to load: {0}',
+'appDefLoadFailed': 'failed to load: ${script}',
'appDefParseError': 'failed to parse ApplicationDefinition',
'widgetSetParseError': 'failed to parse the WidgetSet',
-'fusionError': 'Fusion Error: {0}\n{1}',
+'fusionError': 'Fusion Error: ${type}\n${message}',
'nullExtents': 'Map.setExtents called with null extents',
-'mapLoadError': 'Failed to load requested map:\n{0}',
-'setLayersError': "setLayers failure: {0}",
+'mapLoadError': 'Failed to load requested map:\n${error}',
+'setLayersError': "setLayers failure: ${error}",
'printTitle': 'Printable Page ',
'noSelection': 'Aucun Sélection',
-'No Selection': 'Aucun Sélection',
-'selectionInfo': '{0} features selected on {1} layers - translate me',
+'selectionInfo': '${features} features selected on ${layers} layers',
'attribute': 'Attribute',
'value': 'Value',
'taskHome': 'return to the task pane home',
@@ -37,7 +36,7 @@
'ovmapTitle': 'Overview Map',
'ovmapTitleShort': 'Overview',
'taskPaneTitle': 'Tasks',
-'segment': 'Segment {0}',
+'segment': 'Segment ${seg}',
'calculating': 'calculating ...',
'panWest': 'Ouest',
'panEast': 'Est',
Modified: sandbox/aboudreault/widgets/About.js
===================================================================
--- sandbox/aboudreault/widgets/About.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/About.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -31,9 +31,7 @@
*
* **********************************************************************/
-Fusion.Widget.About = Class.create();
-Fusion.Widget.About.prototype =
-{
+Fusion.Widget.About = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase, {
_nWidth : 500,
_nHeight : 400,
_sDefaultUrl : '/mapguide/mapadmin/about.php', //TBD we need a Fusion specific About page
@@ -48,8 +46,9 @@
*/
initialize : function(widgetTag) {
//console.log('About.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
var json = widgetTag.extension;
this._sAboutUrl = (json.AboutURL) ?
json.AboutURL[0] : this._sDefaultUrl;
@@ -70,4 +69,4 @@
sFeatures += ',height=' + this._nHeight;
window.open(this._sAboutUrl, 'AboutPopup', sFeatures);
}
-};
+});
Modified: sandbox/aboudreault/widgets/ActivityIndicator.js
===================================================================
--- sandbox/aboudreault/widgets/ActivityIndicator.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/ActivityIndicator.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -33,11 +33,12 @@
*
* **************************************************************************/
-Fusion.Widget.ActivityIndicator = Class.create();
-Fusion.Widget.ActivityIndicator.prototype = {
+
+Fusion.Widget.ActivityIndicator = OpenLayers.Class(Fusion.Widget, {
element: null,
initialize : function(widgetTag) {
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
this.element = this.domObj;
var json = widgetTag.extension;
if (json.ElementId) {
@@ -48,9 +49,10 @@
}
}
this.element.style.visibility = 'hidden';
- this.getMap().registerForEvent(Fusion.Event.MAP_BUSY_CHANGED, this.busyChanged.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_BUSY_CHANGED,
+ OpenLayers.Function.bind(this.busyChanged, this));
},
busyChanged: function() {
this.element.style.visibility = this.getMap().isBusy() ? 'visible' : 'hidden';
}
-};
+});
Modified: sandbox/aboudreault/widgets/Buffer.js
===================================================================
--- sandbox/aboudreault/widgets/Buffer.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/Buffer.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -34,9 +34,8 @@
*
* **************************************************************************/
-
-Fusion.Widget.Buffer = Class.create();
-Fusion.Widget.Buffer.prototype = {
+Fusion.Widget.Buffer = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase,
+{
layerName: null,
layerNameInput: null,
bufferDistance: null,
@@ -49,8 +48,9 @@
fillColorInput: null,
initialize: function(widgetTag) {
//console.log('Buffer.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
var json = widgetTag.extension;
@@ -90,8 +90,8 @@
/* override selection behaviour */
this.enable = Fusion.Widget.Buffer.prototype.enable;
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON, this.enable.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF, this.disable.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON, OpenLayers.Function.bind(this.enable, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF, OpenLayers.Function.bind(this.disable, this));
},
setValue: function(input, value) {
@@ -216,7 +216,7 @@
'&session='+aMaps[0].getSessionID() +
'&mapname='+ aMaps[0].getMapName()+
layer+distance+borderColor+fillColor;
- params.onComplete = this.bufferCreated.bind(this);
+ params.onComplete = OpenLayers.Function.bind(this.bufferCreated, this);
Fusion.ajaxRequest(s, params);
},
@@ -225,4 +225,4 @@
aMaps[0].reloadMap();
aMaps[0].drawMap();
}
-};
+});
Modified: sandbox/aboudreault/widgets/BufferPanel/Buffer.php
===================================================================
--- sandbox/aboudreault/widgets/BufferPanel/Buffer.php 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/BufferPanel/Buffer.php 2008-05-29 14:21:40 UTC (rev 1413)
@@ -282,9 +282,8 @@
}
}
while($features->ReadNext());
-
- $features->Close();
}
+ $features->Close();
}
if($merge)
Modified: sandbox/aboudreault/widgets/BufferPanel.js
===================================================================
--- sandbox/aboudreault/widgets/BufferPanel.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/BufferPanel.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -35,15 +35,15 @@
* there, otherwise it will open a new window with that name.
* **********************************************************************/
-Fusion.Widget.BufferPanel = Class.create();
-Fusion.Widget.BufferPanel.prototype = {
+Fusion.Widget.BufferPanel = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase, {
sFeatures : 'menubar=no,location=no,resizable=no,status=no',
initialize : function(widgetTag) {
//console.log('BufferPanel.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
+
var json = widgetTag.extension;
this.sTarget = json.Target ? json.Target[0] : "BufferPanelWindow";
this.sBaseUrl = Fusion.getFusionURL() + 'widgets/BufferPanel/BufferPanel.php';
@@ -63,8 +63,8 @@
}
this.enable = Fusion.Widget.BufferPanel.prototype.enable;
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON, this.enable.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF, this.enable.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON, OpenLayers.Function.bind(this.enable, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF, OpenLayers.Function.bind(this.enable, this));
this.disable();
},
@@ -130,4 +130,4 @@
}
}
}
-};
+});
Deleted: sandbox/aboudreault/widgets/CTRLClick.js
===================================================================
--- sandbox/aboudreault/widgets/CTRLClick.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/CTRLClick.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -1,113 +0,0 @@
-/**
- * Fusion.Widget.CTRLClick
- *
- * $Id$
- *
- * Copyright (c) 2007, DM Solutions Group Inc.
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
- /********************************************************************
- * Class: Fusion.Widget.CTRLClick
- *
- * Launch a window with a CTRL click if a URL expression is set on the layer
- * **********************************************************************/
-
-Fusion.Widget.CTRLClick = Class.create();
-Fusion.Widget.CTRLClick.prototype =
-{
- aLayers: null,
-
- initialize : function(widgetTag)
- {
- //console.log('CTRLClick.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
- var json = widgetTag.extension;
-
- this.aLayers = [];
- if (json.Layer) {
- for (var i=0; i<json.Layer.length; i++) {
- this.aLayers.push(json.Layer[i]);
- }
- }
-
- this.getMap().observeEvent('mouseup', this.mouseUpCRTLClick.bind(this));
- },
-
- /**
- * called when there is a click on the map: query features at that postion.
- **/
- mouseUpCRTLClick: function(e) {
- if (e.ctrlKey)
- {
- var map = this.getMap();
- var p = map.getEventPosition(e);
- var min = map.pixToGeo(p.x, p.y);
- var max = map.pixToGeo(p.x, p.y);
- if (!min) {
- return;
- }
- var oBroker = Fusion.oBroker;
- var cellSize = map._nCellSize;
- //cell size not set in map file. Use default value
- cellSize = 1e-6;
-
- min.x -= cellSize;
- min.y -= cellSize;
-
- max.x += cellSize;
- max.y += cellSize;
-
- var sGeometry = 'POLYGON(('+ min.x + ' ' + min.y + ', ' + min.x + ' ' + max.y + ', ' + max.x + ' ' + max.y + ', ' + max.x + ' ' + min.y + ', ' + min.x + ' ' + min.y + '))';
-
- //var sGeometry = 'POINT('+ min.x + ' ' + min.y + ')';
-
- var maxFeatures = 1;
- var persist = 0;
- var selection = 'INTERSECTS';
- var maps = this.getMap().getAllMaps();
- //TODO: possibly make the layer names configurable?
- var layerNames = this.aLayers.toString();
- var r = new Fusion.Lib.MGRequest.MGQueryMapFeatures(maps[0].getSessionID(),
- maps[0]._sMapname,
- sGeometry,
- maxFeatures, persist, selection, layerNames);
- oBroker.dispatchRequest(r,
- this._display.bind(this));
- }
- },
-
- /**
- * open a window if a URL is defined for the feature.
- **/
- _display: function(r) {
- //console.log('ctrlclcik _display');
- if (r.responseXML)
- {
- var d = new DomNode(r.responseXML);
- var h = d.getNodeText('Hyperlink');
- if (h != '')
- {
- window.open(h, "");
- }
-
- }
- }
-
-};
Modified: sandbox/aboudreault/widgets/CenterSelection.js
===================================================================
--- sandbox/aboudreault/widgets/CenterSelection.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/CenterSelection.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -32,18 +32,16 @@
* **********************************************************************/
-
-Fusion.Widget.CenterSelection = Class.create();
-Fusion.Widget.CenterSelection.prototype = {
+Fusion.Widget.CenterSelection = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase, {
initialize : function(widgetTag) {
//console.log('CenterSelection.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
this.enable = Fusion.Widget.CenterSelection.prototype.enable;
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON, this.enable.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF, this.disable.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON, OpenLayers.Function.bind(this.enable, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF, OpenLayers.Function.bind(this.disable, this));
},
/**
@@ -51,7 +49,7 @@
* zoomToSelection is called when the selection is ready.
*/
execute : function() {
- this.getMap().getSelection(this.centerSelection.bind(this));
+ this.getMap().getSelection(OpenLayers.Function.bind(this.centerSelection, this));
},
/**
@@ -61,12 +59,13 @@
* @param selection the active selection, or null if there is none
*/
centerSelection : function(selection) {
- var extents = this.getMap().getCurrentExtents();
+ var map = this.getMap();
+ var extents = map.getCurrentExtents();
var curWidth = extents[2] - extents[0];
var curHeight = extents[3] - extents[1];
- var ll = selection.getLowerLeftCoord();
- var ur = selection.getUpperRightCoord();
+ var ll = selection[map.getMapName()].getLowerLeftCoord();
+ var ur = selection[map.getMapName()].getUpperRightCoord();
var newWidth = ur.x - ll.x;
var newHeight = ur.y - ll.y;
@@ -74,14 +73,14 @@
if (newWidth < curWidth && newHeight < curHeight) {
var cx = (ur.x + ll.x) / 2;
var cy = (ur.y + ll.y) / 2;
- this.getMap().zoom(cx,cy,1);
+ map.zoom(cx,cy,1);
} else {
var buffer = 0.1;
var minx = ll.x-newWidth*buffer;
var miny = ll.y-newHeight*buffer;
var maxx = ur.x+newWidth*buffer;
var maxy = ur.y+newHeight*buffer;
- this.getMap().setExtents(new OpenLayers.Bounds(minx,miny,maxx,maxy));
+ map.setExtents(new OpenLayers.Bounds(minx,miny,maxx,maxy));
}
},
@@ -92,4 +91,4 @@
this.disable();
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/ClearSelection.js
===================================================================
--- sandbox/aboudreault/widgets/ClearSelection.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/ClearSelection.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -29,19 +29,18 @@
* Clears the current selection, if any.
* **********************************************************************/
+Fusion.Widget.ClearSelection = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase, {
-
-Fusion.Widget.ClearSelection = Class.create();
-Fusion.Widget.ClearSelection.prototype = {
initialize : function(widgetTag) {
//console.log('ClearSelection.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
this.enable = Fusion.Widget.ClearSelection.prototype.enable;
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON, this.enable.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF, this.disable.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON, OpenLayers.Function.bind(this.enable, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF, OpenLayers.Function.bind(this.disable, this));
},
/**
@@ -58,4 +57,4 @@
this.disable();
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/ColorPicker.js
===================================================================
--- sandbox/aboudreault/widgets/ColorPicker.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/ColorPicker.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -31,10 +31,7 @@
*
* **********************************************************************/
-
-Fusion.Widget.ColorPicker = Class.create();
-Fusion.Widget.ColorPicker.prototype =
-{
+Fusion.Widget.ColorPicker = OpenLayers.Class(Fusion.Widget, {
/* HTML input element that is used to store both the initial
value for this widget and receives the color value as the
color changes */
@@ -49,9 +46,8 @@
colorButton: null,
- initialize : function(widgetTag) {
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
-
+ initialize : function(widgetTag) {
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
var json = widgetTag.extension;
if (json.ColorInputId) {
this.colorInput = $(json.ColorInputId[0]);
@@ -79,4 +75,4 @@
this.colorInput.value = c;
}
}
-};
\ No newline at end of file
+});
\ No newline at end of file
Modified: sandbox/aboudreault/widgets/CursorPosition.js
===================================================================
--- sandbox/aboudreault/widgets/CursorPosition.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/CursorPosition.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -54,8 +54,7 @@
* x: {x}<br/>y: {y}
* **********************************************************************/
-Fusion.Widget.CursorPosition = Class.create();
-Fusion.Widget.CursorPosition.prototype = {
+Fusion.Widget.CursorPosition = OpenLayers.Class(Fusion.Widget, {
defaultTemplate: 'x: {x}, y: {y}',
domSpan: null,
@@ -64,7 +63,7 @@
initialize : function(widgetTag) {
//console.log('CursorPosition.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
var json = widgetTag.extension;
@@ -83,13 +82,13 @@
this.enable = Fusion.Widget.CursorPosition.prototype.enable;
this.disable = Fusion.Widget.CursorPosition.prototype.enable;
- this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.setUnits.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, OpenLayers.Function.bind(this.setUnits, this));
this.registerParameter('Units');
},
enable: function() {
- this.mouseMoveWatcher = this.mouseMove.bind(this);
- this.mouseOutWatcher = this.mouseOut.bind(this);
+ this.mouseMoveWatcher = OpenLayers.Function.bind(this.mouseMove, this);
+ this.mouseOutWatcher = OpenLayers.Function.bind(this.mouseOut, this);
this.getMap().observeEvent('mousemove', this.mouseMoveWatcher);
this.getMap().observeEvent('mouseout', this.mouseOutWatcher);
@@ -111,8 +110,9 @@
p = map.pixToGeo(p.x, p.y);
if (p) {
if (this.units != Fusion.UNKNOWN) {
- p.x = Fusion.fromMeter(this.units, p.x * map._fMetersperunit);
- p.y = Fusion.fromMeter(this.units, p.y * map._fMetersperunit);
+ var convFactor = map.getMetersPerUnit();
+ p.x = Fusion.fromMeter(this.units, p.x * convFactor);
+ p.y = Fusion.fromMeter(this.units, p.y * convFactor);
}
if (this.precision >= 0) {
var factor = Math.pow(10,this.precision);
@@ -123,7 +123,6 @@
}
if (p) {
var unitAbbr = Fusion.unitAbbr(this.units);
-
this.domSpan.innerHTML = this.template.replace('{x}',p.x).replace('{y}',p.y).replace('{units}', unitAbbr).replace('{units}', unitAbbr);
}
},
@@ -139,4 +138,4 @@
this.units = Fusion.unitFromName(value);
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/EditableScale.js
===================================================================
--- sandbox/aboudreault/widgets/EditableScale.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/EditableScale.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,12 +30,11 @@
*
* **********************************************************************/
-Fusion.Widget.EditableScale = Class.create();
-Fusion.Widget.EditableScale.prototype = {
+Fusion.Widget.EditableScale = OpenLayers.Class(Fusion.Widget, {
precision: 4,
initialize : function(widgetTag) {
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
var json = widgetTag.extension;
@@ -46,10 +45,11 @@
this.domScale = document.createElement('input');
this.domScale.className = 'inputEditableScale';
this.domObj.appendChild(this.domScale);
- Event.observe(this.domScale, 'keypress', this.keyPressHandler.bindAsEventListener(this));
+ Event.observe(this.domScale, 'keypress',
+ OpenLayers.Function.bindAsEventListener(this.keyPressHandler, this));
this.precision = json.Precision ? parseInt(json.Precision[0]) : this.precision;
- this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, this.scaleChanged.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, OpenLayers.Function.bind(this.scaleChanged, this));
Fusion.addWidgetStyleSheet(widgetTag.location + '/EditableScale/EditableScale.css');
@@ -77,4 +77,4 @@
this.getMap().zoomToScale(scale);
}
}
-};
\ No newline at end of file
+});
\ No newline at end of file
Modified: sandbox/aboudreault/widgets/ExtentHistory.js
===================================================================
--- sandbox/aboudreault/widgets/ExtentHistory.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/ExtentHistory.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -32,15 +32,15 @@
Fusion.Event.HISTORY_CHANGED = Fusion.Event.lastEventId++;
-Fusion.Widget.ExtentHistory = Class.create();
-Fusion.Widget.ExtentHistory.prototype = {
+Fusion.Widget.ExtentHistory = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase, {
events: [],
aHistory: [],
sDirection: null,
EPS: 0.00000001, //percentage difference allowed in bounds values for test for equal
initialize : function(widgetTag) {
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
var json = widgetTag.extension;
var sDirection = json.Direction ? json.Direction[0].toLowerCase() : 'previous';
@@ -53,8 +53,10 @@
if (!this.aHistory['history']) {
this.aHistory['history'] = [];
this.aHistory['index'] = -1;
- this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, this.extentsChanged.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.reset.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED,
+ OpenLayers.Function.bind(this.extentsChanged, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_LOADED,
+ OpenLayers.Function.bind(this.reset, this));
}
this.enable = Fusion.Widget.ExtentHistory.prototype.historyChanged;
@@ -63,7 +65,8 @@
this.registerEventID(Fusion.Event.HISTORY_CHANGED);
- this.registerForEvent(Fusion.Event.HISTORY_CHANGED, this.historyChanged.bind(this));
+ this.registerForEvent(Fusion.Event.HISTORY_CHANGED,
+ OpenLayers.Function.bind(this.historyChanged, this));
//console.log(this.events[Fusion.Event.HISTORY_CHANGED].length);
this.disable();
},
@@ -162,5 +165,5 @@
Math.abs(b1.right - b2.right)/b2.right < this.EPS);
return equal;
}
-};
+});
Modified: sandbox/aboudreault/widgets/Help.js
===================================================================
--- sandbox/aboudreault/widgets/Help.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/Help.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,8 +30,7 @@
*
* **********************************************************************/
-Fusion.Widget.Help = Class.create();
-Fusion.Widget.Help.prototype = {
+Fusion.Widget.Help = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase, {
/* popup window initialization parameters */
sFeatures : 'menubar=no,location=no,resizable=no,status=no',
@@ -47,8 +46,8 @@
initialize : function(widgetTag) {
//console.log('Help.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
var json = widgetTag.extension;
this.target = json.Target ? json.Target[0] : "HelpWindow";
@@ -79,4 +78,4 @@
}
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/InitialMapView.js
===================================================================
--- sandbox/aboudreault/widgets/InitialMapView.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/InitialMapView.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,16 +30,17 @@
*
* **********************************************************************/
-Fusion.Widget.InitialMapView = Class.create();
-Fusion.Widget.InitialMapView.prototype = {
+
+Fusion.Widget.InitialMapView = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase, {
initialize : function(widgetTag) {
//console.log('InitialMapView.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
},
execute: function() {
//console.log('InitialMapView.activateTool');
this.getMap().fullExtents();
}
-};
+});
Modified: sandbox/aboudreault/widgets/InvokeScript.js
===================================================================
--- sandbox/aboudreault/widgets/InvokeScript.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/InvokeScript.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -29,12 +29,13 @@
* Executes an arbitrary piece of JavaScript code
* **********************************************************************/
-Fusion.Widget.InvokeScript = Class.create();
-Fusion.Widget.InvokeScript.prototype = {
+Fusion.Widget.InvokeScript = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase, {
sScript: null,
initialize : function(widgetTag) {
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
+
var json = widgetTag.extension;
this.sScript = json.Script ? json.Script[0] : '';
},
@@ -45,4 +46,4 @@
execute : function() {
eval(this.sScript);
}
-};
\ No newline at end of file
+});
\ No newline at end of file
Modified: sandbox/aboudreault/widgets/InvokeURL.js
===================================================================
--- sandbox/aboudreault/widgets/InvokeURL.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/InvokeURL.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -35,15 +35,15 @@
*
* **********************************************************************/
-Fusion.Widget.InvokeURL = Class.create();
-Fusion.Widget.InvokeURL.prototype = {
+Fusion.Widget.InvokeURL = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase, {
sFeatures : 'menubar=no,location=no,resizable=no,status=no',
initialize : function(widgetTag) {
//console.log('InvokeURL.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
+
var json = widgetTag.extension;
this.sTarget = json.Target ? json.Target[0] : "InvokeUrlWindow";
this.sBaseUrl = json.Url[0]; //must be supplied
@@ -63,8 +63,8 @@
}
this.enable = Fusion.Widget.InvokeURL.prototype.enable;
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON, this.enable.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF, this.enable.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON, OpenLayers.Function.bind(this.enable, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF, OpenLayers.Function.bind(this.enable, this));
this.disable();
},
@@ -121,4 +121,4 @@
}
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/LayerManager.js
===================================================================
--- sandbox/aboudreault/widgets/LayerManager.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/LayerManager.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -50,14 +50,14 @@
*
* **********************************************************************/
-Fusion.Widget.LayerManager = Class.create();
-Fusion.Widget.LayerManager.prototype = {
+Fusion.Widget.LayerManager = OpenLayers.Class(Fusion.Widget, {
currentNode: null,
bIsDrawn: false,
initialize : function(widgetTag) {
//console.log('LayerManager.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
+
var json = widgetTag.extension;
this.delIconSrc = json.DeleteIcon ? json.DeleteIcon[0] : 'images/icons/select-delete.png';
@@ -65,8 +65,8 @@
this.cursorNormal = ["url('images/grab.cur'),move", 'grab', '-moz-grab', 'move'];
this.cursorDrag = ["url('images/grabbing.cur'),move", 'grabbing', '-moz-grabbing', 'move'];
- this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.mapLoaded.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_RELOADED, this.mapLoaded.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, OpenLayers.Function.bind(this.mapLoaded, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_RELOADED, OpenLayers.Function.bind(this.mapLoaded, this));
},
@@ -121,7 +121,7 @@
if (map.aMaps.length >1) {
var options = [];
- options.onUpdate = this.updateMapBlock.bind(this, map);
+ options.onUpdate = OpenLayers.Function.bind(this.updateMapBlock, this, map);
options.handle = 'jxLmanHandle';
options.scroll = this.domObj.id;
Sortable.create(this.mapList.id, options);
@@ -150,7 +150,7 @@
}
var options = [];
- options.onUpdate = this.updateLayer.bind(this, map);
+ options.onUpdate = OpenLayers.Function.bind(this.updateLayer, this, map);
options.scroll = this.domObj.id; //docs for this at: http://wiki.script.aculo.us/scriptaculous/show/Sortable.create
Position.includeScrollOffsets = true;
Sortable.create(mapBlockList.id, options);
@@ -159,13 +159,13 @@
createItemHtml: function(parent, layer) {
var delIcon = document.createElement('img');
delIcon.src = this.delIconSrc;
- Event.observe(delIcon, 'click', this.deleteLayer.bind(this, layer));
+ Event.observe(delIcon, 'click', OpenLayers.Function.bind(this.deleteLayer, this, layer));
delIcon.style.visibility = 'hidden';
parent.appendChild(delIcon);
var visSelect = document.createElement('input');
visSelect.type = 'checkbox';
- Event.observe(visSelect, 'click', this.visChanged.bind(this, layer));
+ Event.observe(visSelect, 'click', OpenLayers.Function.bind(this.visChanged, this, layer));
parent.appendChild(visSelect);
if (layer.visible) {
visSelect.checked = true;
@@ -175,13 +175,13 @@
var label = document.createElement('a');
label.innerHTML = layer.legendLabel;
- Event.observe(label, 'mouseover', this.setGrabCursor.bind(this));
- Event.observe(label, 'mousedown', this.setDragCursor.bind(this));
- Event.observe(label, 'mouseout', this.setNormalCursor.bind(this));
+ Event.observe(label, 'mouseover', OpenLayers.Function.bind(this.setGrabCursor, this));
+ Event.observe(label, 'mousedown', OpenLayers.Function.bind(this.setDragCursor, this));
+ Event.observe(label, 'mouseout', OpenLayers.Function.bind(this.setNormalCursor, this));
parent.appendChild(label);
- Event.observe(parent, 'mouseover', this.setHandleVis.bind(this, delIcon));
- Event.observe(parent, 'mouseout', this.setHandleHide.bind(this, delIcon));
+ Event.observe(parent, 'mouseover', OpenLayers.Function.bind(this.setHandleVis, this, delIcon));
+ Event.observe(parent, 'mouseout', OpenLayers.Function.bind(this.setHandleHide, this, delIcon));
},
setHandleVis: function(delIcon) {
@@ -269,4 +269,4 @@
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/Legend.js
===================================================================
--- sandbox/aboudreault/widgets/Legend.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/Legend.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -50,8 +50,7 @@
*
* **********************************************************************/
-Fusion.Widget.Legend = Class.create();
-Fusion.Widget.Legend.prototype = {
+Fusion.Widget.Legend = OpenLayers.Class(Fusion.Widget, {
currentNode: null,
bIsDrawn: false,
targetFolder: null,
@@ -66,8 +65,8 @@
this.bIncludeVisToggle = true;
//console.log('Legend.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
-
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
+
var json = widgetTag.extension;
this.imgLayerDWFIcon = json.LayerDWFIcon ? json.LayerDWFIcon[0] : this.defLayerDWFIcon;
@@ -85,16 +84,16 @@
this.hideInvisibleLayers = (json.HideInvisibleLayers && json.HideInvisibleLayers[0]) == 'true' ? true : false;
- this.refreshAction = new Jx.Action(this.update.bind(this));
- this.refreshItem = new Jx.MenuItem(this.refreshAction, {label: OpenLayers.String.translate('refresh')});
- this.expandAllAction = new Jx.Action(this.expandAll.bind(this));
- this.expandAllItem = new Jx.MenuItem(this.expandAllAction, {label: OpenLayers.String.translate('expandAll')});
- this.expandBranchAction = new Jx.Action(this.expandBranch.bind(this));
- this.expandBranchItem = new Jx.MenuItem(this.expandBranchAction, {label: OpenLayers.String.translate('expand')});
- this.collapseAllAction = new Jx.Action(this.collapseAll.bind(this));
- this.collapseAllItem = new Jx.MenuItem(this.collapseAllAction, {label: OpenLayers.String.translate('collapseAll')});
- this.collapseBranchAction = new Jx.Action(this.collapseBranch.bind(this));
- this.collapseBranchItem = new Jx.MenuItem(this.collapseBranchAction, {label: OpenLayers.String.translate('collapse')});
+ this.refreshAction = new Jx.Action(OpenLayers.Function.bind(this.update, this));
+ this.refreshItem = new Jx.MenuItem(this.refreshAction, {label: OpenLayers.i18n('refresh')});
+ this.expandAllAction = new Jx.Action(OpenLayers.Function.bind(this.expandAll, this));
+ this.expandAllItem = new Jx.MenuItem(this.expandAllAction, {label: OpenLayers.i18n('expandAll')});
+ this.expandBranchAction = new Jx.Action(OpenLayers.Function.bind(this.expandBranch, this));
+ this.expandBranchItem = new Jx.MenuItem(this.expandBranchAction, {label: OpenLayers.i18n('expand')});
+ this.collapseAllAction = new Jx.Action(OpenLayers.Function.bind(this.collapseAll, this));
+ this.collapseAllItem = new Jx.MenuItem(this.collapseAllAction, {label: OpenLayers.i18n('collapseAll')});
+ this.collapseBranchAction = new Jx.Action(OpenLayers.Function.bind(this.collapseBranch, this));
+ this.collapseBranchItem = new Jx.MenuItem(this.collapseBranchAction, {label: OpenLayers.i18n('collapse')});
//this.collapseBranchItem.disable();
this.contextMenu = new Jx.ContextMenu(this.sName);
@@ -107,7 +106,7 @@
this.showMapFolder = (json.ShowMapFolder && json.ShowMapFolder[0] == 'false') ? false:true;
if (this.showRootFolder) {
var opt = {};
- opt.label = OpenLayers.String.translate('defaultMapTitle');
+ opt.label = OpenLayers.i18n('defaultMapTitle');
opt.data = null;
opt.imgTreeFolder = json.RootFolderIcon ? json.RootFolderIcon[0] : this.defRootFolderIcon;
opt.imgTreeFolderOpen = opt.imgTreeFolder;
@@ -115,16 +114,16 @@
opt.contextMenu = this.contextMenu;
this.oRoot = new Jx.TreeFolder(opt);
this.oTree.append(this.oRoot);
- Event.observe(this.oRoot.domObj, 'mouseover', this.setFolder.bind(this));
+ Event.observe(this.oRoot.domObj, 'mouseover', OpenLayers.Function.bind(this.setFolder, this));
} else {
this.oRoot = this.oTree;
}
this.extentsChangedWatcher = this.update.bind(this);
- this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.mapLoaded.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_RELOADED, this.draw.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_LOADING, this.mapLoading.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, OpenLayers.Function.bind(this.mapLoaded, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_RELOADED, OpenLayers.Function.bind(this.draw, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_LOADING, OpenLayers.Function.bind(this.mapLoading, this));
},
expandAll: function() {
@@ -244,8 +243,8 @@
group.legend.checkBox.type = 'checkbox';
group.legend.treeItem.domObj.insertBefore(group.legend.checkBox, group.legend.treeItem.domObj.childNodes[1]);
group.legend.checkBox.checked = group.visible?true:false;
- Event.observe(group.legend.checkBox, 'click', this.stateChanged.bind(this, group));
- Event.observe(group.legend.treeItem.domObj, 'mouseover', this.setFolder.bind(this));
+ Event.observe(group.legend.checkBox, 'click', OpenLayers.Function.bind(this.stateChanged, this, group));
+ Event.observe(group.legend.treeItem.domObj, 'mouseover', OpenLayers.Function.bind(this.setFolder, this));
var groupInfo = group.oMap.getGroupInfoUrl(group.groupName);
if (groupInfo) {
var a = document.createElement('a');
@@ -275,9 +274,9 @@
layer.legend.parentItem = folder;
layer.legend.checkBox = document.createElement('input');
layer.legend.checkBox.type = 'checkbox';
- Event.observe(layer.legend.checkBox, 'click', this.stateChanged.bind(this, layer));
+ Event.observe(layer.legend.checkBox, 'click', OpenLayers.Function.bind(this.stateChanged, this, layer));
layer.legend.currentRange = null;
- layer.registerForEvent(Fusion.Event.LAYER_PROPERTY_CHANGED, this.layerPropertyChanged.bind(this));
+ layer.registerForEvent(Fusion.Event.LAYER_PROPERTY_CHANGED, OpenLayers.Function.bind(this.layerPropertyChanged, this));
},
layerPropertyChanged: function(eventID, layer) {
@@ -286,7 +285,7 @@
update: function() {
if (this.bIsDrawn) {
- window.setTimeout(this._update.bind(this), 1);
+ window.setTimeout(OpenLayers.Function.bind(this._update, this), 1);
}
},
@@ -435,7 +434,7 @@
folder.domObj.insertBefore(a, folder.domObj.childNodes[4]);
}
folder.addSelectionListener(this);
- Event.observe(folder.domObj, 'mouseover', this.setFolder.bind(this));
+ Event.observe(folder.domObj, 'mouseover', OpenLayers.Function.bind(this.setFolder, this));
return folder;
},
@@ -500,4 +499,4 @@
}
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/LinkToView.js
===================================================================
--- sandbox/aboudreault/widgets/LinkToView.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/LinkToView.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -29,13 +29,13 @@
* A widget that displays a link to the currently displayedd map view.
* **********************************************************************/
-Fusion.Widget.LinkToView = Class.create();
-Fusion.Widget.LinkToView.prototype = {
+Fusion.Widget.LinkToView = OpenLayers.Class(Fusion.Widget, {
initialize : function(widgetTag) {
//console.log('LinkToView.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
+
var json = widgetTag.extension;
this.baseUrl = window.location.protocol + '//' + window.location.host + window.location.pathname + '?';
@@ -63,7 +63,7 @@
this.domObj.innerHTML = '';
this.domObj.appendChild(this.anchor);
- this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, this.updateLink.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, OpenLayers.Function.bind(this.updateLink, this));
this.enable();
},
@@ -72,4 +72,4 @@
var join = (this.baseUrl.indexOf('?')==this.baseUrl.length-1)?'':'&';
this.anchor.href = this.baseUrl + join +'extent=' + sBbox;
}
-};
+});
Modified: sandbox/aboudreault/widgets/MapMenu.js
===================================================================
--- sandbox/aboudreault/widgets/MapMenu.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/MapMenu.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,31 +30,43 @@
* application. The list of maps is configured in the ApplicationDefinition.
* **********************************************************************/
-
-Fusion.Widget.MapMenu = Class.create();
-Fusion.Widget.MapMenu.prototype =
+Fusion.Widget.MapMenu = OpenLayers.Class(Fusion.Widget, Fusion.Tool.MenuBase,
{
domObj: null,
oMenu: null,
+ mapGroupData: null,
sRootFolder: '',
aMenus : null,
initialize : function(widgetTag)
{
//console.log('MapMenu.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
- Object.inheritFrom(this, Fusion.Tool.MenuBase.prototype, []);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
+ Fusion.Tool.MenuBase.prototype.initialize.apply(this, []);
+
this.enable();
var json = widgetTag.extension;
+
+ //If no folder is specified for enumeration, build a menu
+ //from the mapgroup alone. Folders are only supported with MapGuide.
+ //Otherwise, create a hash of mapgroup resourceId to mapGroup data
+ //to be used to assign mapgroup extensions to enumerated maps.
+
var mapGroups = Fusion.applicationDefinition.mapGroups;
+ this.mapGroupData = {};
for (var i=0; i<mapGroups.length; i++) {
var mapGroup = mapGroups[i];
- var opt = {};
- opt.label = mapGroup.mapId;
- var data = mapGroup;
- var action = new Jx.Action(this.switchMap.bind(this, data));
- var menuItem = new Jx.MenuItem(action,opt);
- this.oMenu.add(menuItem);
+ if (json.Folder) {
+ this.mapGroupData[mapGroup.maps[0].resourceId] = mapGroup;
+ } else {
+ var opt = {};
+ opt.label = mapGroup.mapId;
+ var data = mapGroup;
+ var action = new Jx.Action(this.switchMap.bind(this, data));
+ var menuItem = new Jx.MenuItem(action,opt);
+ this.oMenu.add(menuItem);
+ }
}
//get the mapdefinitions as xml if there is a folder specified
@@ -66,8 +78,8 @@
this.sRootFolder = json.Folder ? json.Folder[0] : 'Library://';
var s = this.arch + '/' + Fusion.getScriptLanguage() +
'/MapMenu.' + Fusion.getScriptLanguage();
- var params = {parameters:'folder='+this.sRootFolder,
- onComplete: this.processMapMenu.bind(this)};
+ var params = {parameters: {'folder': this.sRootFolder},
+ onComplete: OpenLayers.Function.bind(this.processMapMenu, this)};
Fusion.ajaxRequest(s, params);
};
@@ -82,21 +94,32 @@
var sId = mapNode.getNodeText('ResourceId');
var sPath = sId.replace(this.sRootFolder, '');
- sPath = sPath.slice(0, sPath.lastIndexOf('/'));
- this.createFolders(sPath);
+ if (sPath.lastIndexOf('/') > -1) {
+ sPath = sPath.slice(0, sPath.lastIndexOf('/'));
+ this.createFolders(sPath);
+ } else {
+ sPath = '';
+ }
var opt = {};
opt.label = mapNode.getNodeText('Name');
+
+ // check for mapgroup data and if there is none,
// create a maptag that will be passed to the map
- // widget constructor
- var data = {maps:[{'resourceId':mapNode.getNodeText('ResourceId'),
+ // widget constructor
+ var data = null;
+ if (this.mapGroupData[mapNode.getNodeText('ResourceId')]) {
+ data = this.mapGroupData[mapNode.getNodeText('ResourceId')];
+ } else {
+ data = {maps:[{'resourceId':mapNode.getNodeText('ResourceId'),
'singleTile':true,
'type': this.arch,
'extension':{'ResourceId': [mapNode.getNodeText('ResourceId')]}
}]};
- //set up needed accessor
- data.getInitialView = function() {
- return this.initialView;
- };
+ //set up needed accessor
+ data.getInitialView = function() {
+ return this.initialView;
+ };
+ }
var action = new Jx.Action(this.switchMap.bind(this, data));
var menuItem = new Jx.MenuItem(action,opt);
@@ -147,4 +170,4 @@
};
this.getMap().loadMapGroup(data);
}
-};
\ No newline at end of file
+});
Modified: sandbox/aboudreault/widgets/Maptip.js
===================================================================
--- sandbox/aboudreault/widgets/Maptip.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/Maptip.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -47,8 +47,8 @@
*
* **********************************************************************/
-Fusion.Widget.Maptip = Class.create();
-Fusion.Widget.Maptip.prototype =
+
+Fusion.Widget.Maptip = OpenLayers.Class(Fusion.Widget,
{
oCurrentPosition: null,
oMapTipPosition: null,
@@ -61,7 +61,8 @@
initialize : function(widgetTag)
{
//console.log('Maptip.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
var json = widgetTag.extension;
this.sTarget = json.Target ? json.Target[0] : "MaptipWindow";
@@ -96,14 +97,14 @@
this.iframe.scrolling = 'no';
this.iframe.frameborder = 0;
- Event.observe(this.domObj, 'mouseover', this.mouseOverTip.bind(this));
- Event.observe(this.domObj, 'mouseout', this.mouseOutTip.bind(this));
+ Event.observe(this.domObj, 'mouseover', OpenLayers.Function.bind(this.mouseOverTip, this));
+ Event.observe(this.domObj, 'mouseout', OpenLayers.Function.bind(this.mouseOutTip, this));
var oDomElem = this.getMap().getDomObj();
document.getElementsByTagName('BODY')[0].appendChild(this.domObj);
- this.getMap().observeEvent('mousemove', this.mouseMove.bind(this));
- this.getMap().observeEvent('mouseout', this.mouseOut.bind(this));
+ this.getMap().observeEvent('mousemove', OpenLayers.Function.bind(this.mouseMove, this));
+ this.getMap().observeEvent('mouseout', OpenLayers.Function.bind(this.mouseOut, this));
},
@@ -113,7 +114,7 @@
window.clearTimeout(this.nTimer);
if (!this.nHideTimer) {
/*console.log('mouseOut: set hide timer');*/
- this.nHideTimer = window.setTimeout(this.hideMaptip.bind(this), 250);
+ this.nHideTimer = window.setTimeout(OpenLayers.Function.bind(this.hideMaptip, this), 250);
}
}
},
@@ -130,7 +131,7 @@
window.clearTimeout(this.nTimer);
this.nTimer = null;
}
- this.nTimer = window.setTimeout(this.showMaptip.bind(this), this.delay);
+ this.nTimer = window.setTimeout(OpenLayers.Function.bind(this.showMaptip, this), this.delay);
//Event.stop(e);
},
@@ -157,20 +158,29 @@
var maxFeatures = 1;
var persist = 0;
var selection = 'INTERSECTS';
+ // only select visible layers with maptips defined (1+4)
+ var layerAttributeFilter = 5;
var maps = this.getMap().getAllMaps();
//TODO: possibly make the layer names configurable?
var layerNames = this.aLayers.toString();
var r = new Fusion.Lib.MGRequest.MGQueryMapFeatures(maps[0].getSessionID(),
maps[0]._sMapname,
sGeometry,
- maxFeatures, persist, selection, layerNames);
+ maxFeatures, persist, selection, layerNames,
+ layerAttributeFilter);
oBroker.dispatchRequest(r,
- this._display.bind(this));
-
+ OpenLayers.Function.bind(Fusion.xml2json, this,
+ OpenLayers.Function.bind(this.requestCB, this)));
},
- _display: function(r) {
+
+ requestCB: function(xhr) {
+ var o;
+ eval("o="+xhr.responseText);
+ this._display(o);
+ },
+
+ _display: function(tooltip) {
//console.log('maptip _display');
- if (r.responseXML) {
this.domObj.innerHTML = ' ';
var contentDiv = document.createElement('div');
contentDiv.className = 'maptipContent';
@@ -178,20 +188,19 @@
var empty = true;
this.bIsVisible = true;
- var d = new DomNode(r.responseXML);
- var t = d.getNodeText('Tooltip');
- if (t != '') {
- t = t.replace(/\\n/g, "<br>");
- contentDiv.innerHTML = t;
+ var t = tooltip['FeatureInformation']['Tooltip'];
+ if (t) {
+ contentDiv.innerHTML = t[0].replace(/\\n/g, "<br>");
empty = false;
}
- var h = d.getNodeText('Hyperlink');
- if (h != '') {
+ var h = tooltip['FeatureInformation']['Hyperlink'];
+ if (h) {
var linkDiv = document.createElement('div');
var a = document.createElement('a');
- a.innerHTML = h;
+ a.innerHTML = h[0];
a.href = 'javascript:void(0)';
- a.onclick = this.openLink.bindAsEventListener(this, h);
+ var openLink = OpenLayers.Function.bind(this.openLink, this, h[0]);
+ a.onclick = OpenLayers.Function.bindAsEventListener(openLink, this);
linkDiv.appendChild(a);
contentDiv.appendChild(linkDiv);
empty = false;
@@ -214,22 +223,19 @@
} else {
this.hideMaptip();
}
- } else {
- this.bIsVisible = false;
- }
},
hideMaptip: function() {
//console.log('hideMaptip');
this.bIsVisible = false;
- this.hideTimer = window.setTimeout(this._hide.bind(this),10);
+ this.hideTimer = window.setTimeout(OpenLayers.Function.bind(this._hide, this),10);
},
_hide: function() {
//console.log('maptip _hide');
this.hideTimer = null;
this.domObj.style.display = 'none';
- this.oMapTipPosition = null;
+ //this.oMapTipPosition = null;
},
mouseOverTip: function() {
@@ -241,11 +247,11 @@
mouseOutTip: function() {
//console.log('mouseOutTip');
- this.nHideTimer = window.setTimeout(this.hideMaptip.bind(this), 250);
+ this.nHideTimer = window.setTimeout(OpenLayers.Function.bind(this.hideMaptip, this), 250);
this.bOverTip = false;
},
- openLink : function(evt, url) {
+ openLink : function(url, evt) {
var taskPaneTarget = Fusion.getWidgetById(this.sTarget);
if ( taskPaneTarget ) {
taskPaneTarget.setContent(url);
@@ -260,4 +266,4 @@
OpenLayers.Event.stop(evt, true);
return false;
}
-};
+});
Modified: sandbox/aboudreault/widgets/Measure.js
===================================================================
--- sandbox/aboudreault/widgets/Measure.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/Measure.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -39,8 +39,8 @@
Fusion.Event.MEASURE_CLEAR = Fusion.Event.lastEventId++;
Fusion.Event.MEASURE_COMPLETE = Fusion.Event.lastEventId++;
-Fusion.Widget.Measure = Class.create();
-Fusion.Widget.Measure.prototype = {
+Fusion.Widget.Measure = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase, Fusion.Tool.Canvas,
+{
isDigitizing: false,
//distance of each segment
distances: null,
@@ -78,9 +78,11 @@
areaStyle: null,
initialize : function(widgetTag) {
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
- Object.inheritFrom(this, Fusion.Tool.Canvas.prototype, []);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
+ Fusion.Tool.Canvas.prototype.initialize.apply(this, []);
+
this.asCursor = ['crosshair'];
var json = widgetTag.extension;
this.units = (json.Units && (json.Units[0] != '')) ? Fusion.unitFromName(json.Units[0]): this.units;
@@ -119,11 +121,11 @@
this.registerEventID(Fusion.Event.MEASURE_CLEAR);
this.registerEventID(Fusion.Event.MEASURE_COMPLETE);
- this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, this.resetCanvas.bind(this));
- this.keyHandler = this.onKeyPress.bind(this);
+ this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, OpenLayers.Function.bind(this.resetCanvas, this));
+ this.keyHandler = OpenLayers.Function.bind(this.onKeyPress, this);
Fusion.addWidgetStyleSheet(widgetTag.location + 'Measure/Measure.css');
- this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.setUnits.bind(this, this.units));
+ this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, OpenLayers.Function.bind(this.setUnits, this, this.units));
this.registerParameter('Units');
},
@@ -186,9 +188,9 @@
} else {
outputWin = window.open(url, this.sTarget, this.sWinFeatures);
}
- this.registerForEvent(Fusion.Event.MEASURE_CLEAR, this.clearDisplay.bind(this, outputWin));
- this.registerForEvent(Fusion.Event.MEASURE_SEGMENT_UPDATE, this.updateDisplay.bind(this, outputWin));
- this.registerForEvent(Fusion.Event.MEASURE_COMPLETE, this.updateDisplay.bind(this, outputWin));
+ this.registerForEvent(Fusion.Event.MEASURE_CLEAR, OpenLayers.Function.bind(this.clearDisplay, this, outputWin));
+ this.registerForEvent(Fusion.Event.MEASURE_SEGMENT_UPDATE, OpenLayers.Function.bind(this.updateDisplay, this, outputWin));
+ this.registerForEvent(Fusion.Event.MEASURE_COMPLETE, OpenLayers.Function.bind(this.updateDisplay, this, outputWin));
} else {
this.totalDistanceMarker = new Fusion.Widget.Measure.DistanceMarker(this.units, this.distPrecision, 'Total:');
var oDomElem = this.getMap().getDomObj();
@@ -198,9 +200,9 @@
}
Element.addClassName(this.totalDistanceMarker.domObj, 'divMeasureTotal');
this.totalDistanceMarker.domObj.style.display = 'none';
- this.registerForEvent(Fusion.Event.MEASURE_CLEAR, this.clearTotalDistance.bind(this));
- this.registerForEvent(Fusion.Event.MEASURE_SEGMENT_UPDATE, this.updateTotalDistance.bind(this));
- this.registerForEvent(Fusion.Event.MEASURE_COMPLETE, this.updateTotalDistance.bind(this));
+ this.registerForEvent(Fusion.Event.MEASURE_CLEAR, OpenLayers.Function.bind(this.clearTotalDistance, this));
+ this.registerForEvent(Fusion.Event.MEASURE_SEGMENT_UPDATE, OpenLayers.Function.bind(this.updateTotalDistance, this));
+ this.registerForEvent(Fusion.Event.MEASURE_COMPLETE, OpenLayers.Function.bind(this.updateTotalDistance, this));
}
},
@@ -305,7 +307,7 @@
this.clearContext();
this.feature.draw(this.context);
this.lastMarker.setCalculating();
- this.delayUpdateTimer = window.setTimeout(this.delayUpdate.bind(this, lastSegment, e), 100);
+ this.delayUpdateTimer = window.setTimeout(OpenLayers.Function.bind(this.delayUpdate, this, lastSegment, e), 100);
this.positionMarker(this.lastMarker, lastSegment);
if (this.totalDistanceMarker) {
@@ -375,20 +377,25 @@
},
measureSegment: function(segment, marker) {
- var points = '&x1='+segment.from.x+'&y1='+segment.from.y+
- '&x2='+segment.to.x+'&y2='+segment.to.y;
- var map = this.getMap();
- var aMaps = map.getAllMaps();
+ var aMaps = this.getMap().getAllMaps();
var s = aMaps[0].arch + '/' + Fusion.getScriptLanguage() + "/Measure." + Fusion.getScriptLanguage() ;
- var sessionId = aMaps[0].getSessionID();
- var params = {};
- params.parameters = 'session='+sessionId+'&locale='+Fusion.locale+'&mapname='+ this.getMap().getMapName()+points;
- params.onComplete = this.measureCompleted.bind(this, segment, marker);
- Fusion.ajaxRequest(s, params);
+ var options = {
+ parameters: {
+ 'session': aMaps[0].getSessionID(),
+ 'locale': Fusion.locale,
+ 'mapname': this.getMap().getMapName(),
+ 'x1': segment.from.x,
+ 'y1': segment.from.y,
+ 'x2': segment.to.x,
+ 'y2': segment.to.y
+ },
+ 'onComplete': OpenLayers.Function.bind(this.measureCompleted, this, segment, marker)
+ };
+ Fusion.ajaxRequest(s, options);
},
- measureCompleted: function(segment, marker, r, json) {
- if (json && r.status == 200) {
+ measureCompleted: function(segment, marker, r) {
+ if (r.status == 200) {
var o;
eval('o='+r.responseText);
if (o.distance) {
@@ -425,7 +432,7 @@
var tr = outputDoc.createElement('tr');
var td = outputDoc.createElement('td');
- td.innerHTML = OpenLayers.String.translate('segment',i+1);
+ td.innerHTML = OpenLayers.i18n('segment',{'seg':i+1});
tr.appendChild(td);
td = outputDoc.createElement('td');
if (this.distPrecision == 0) {
@@ -510,14 +517,16 @@
}
}
}
-};
+});
/*
* A class for handling the 'tooltip' for the distance measurement. Markers also hold the distance
values and all markers are held in an array in the Measure widget for access.
*/
-Fusion.Widget.Measure.DistanceMarker = Class.create();
-Fusion.Widget.Measure.DistanceMarker.prototype = {
+//Fusion.Widget.Measure.DistanceMarker = Class.create();
+//Fusion.Widget.Measure.DistanceMarker.prototype = {
+Fusion.Widget.Measure.DistanceMarker = OpenLayers.Class(
+{
calculatingImg: null,
distance: 0,
initialize: function(units, precision, label) {
@@ -586,4 +595,4 @@
}
return size;
}
-};
+});
Modified: sandbox/aboudreault/widgets/Navigator.js
===================================================================
--- sandbox/aboudreault/widgets/Navigator.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/Navigator.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -29,64 +29,71 @@
* A widget that immplements an in-map navigation control with zoom and pan.
* **********************************************************************/
-Fusion.Widget.Navigator = Class.create();
-Fusion.Widget.Navigator.prototype = {
+Fusion.Widget.Navigator = OpenLayers.Class(Fusion.Widget,
+{
bInternalChange: false,
- zoomFactor: 2,
+ zoomInFactor: 4,
+ zoomOutFactor: 2,
panAmount: 50,
initialize : function(widgetTag) {
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
var m = document.createElement('map');
m.name = 'Navigator_ImageMap';
m.id = 'Navigator_ImageMap';
var a = document.createElement('area');
a.shape = 'poly';
- a.alt = OpenLayers.String.translate('panEast');
- a.title = OpenLayers.String.translate('panEast');
+ a.alt = OpenLayers.i18n('panEast');
+ a.title = OpenLayers.i18n('panEast');
a.coords = '27,176, 27,177, 40,190, 44,182, 44,159';
- Event.observe(a, 'mouseup', this.pan.bindAsEventListener(this, this.panAmount/100, 0) );
+ var panEast = OpenLayers.Function.bind(this.pan, this, this.panAmount/100, 0);
+ Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(panEast, this));
m.appendChild(a);
var a = document.createElement('area');
a.shape = 'poly';
- a.alt = OpenLayers.String.translate('panWest');
- a.title = OpenLayers.String.translate('panWest');
+ a.alt = OpenLayers.i18n('panWest');
+ a.title = OpenLayers.i18n('panWest');
a.coords = '24,177, 24,176, 7,159, 7,182, 11,190';
- Event.observe(a, 'mouseup', this.pan.bindAsEventListener(this, -this.panAmount/100, 0) );
+ var panWest = OpenLayers.Function.bind(this.pan, this, -this.panAmount/100, 0);
+ Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(panWest, this) );
m.appendChild(a);
var a = document.createElement('area');
a.shape = 'poly';
- a.alt = OpenLayers.String.translate('panSouth');
- a.title = OpenLayers.String.translate('panSouth');
+ a.alt = OpenLayers.i18n('panSouth');
+ a.title = OpenLayers.i18n('panSouth');
a.coords = '25,178, 12,191, 21,197, 30,197, 39,191, 26,178';
- Event.observe(a, 'mouseup', this.pan.bindAsEventListener(this, 0, -this.panAmount/100) );
+ var panSouth = OpenLayers.Function.bind(this.pan, this, 0, -this.panAmount/100 );
+ Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(panSouth, this) );
m.appendChild(a);
var a = document.createElement('area');
a.shape = 'poly';
- a.alt = OpenLayers.String.translate('panNorth');
- a.title = OpenLayers.String.translate('panNorth');
+ a.alt = OpenLayers.i18n('panNorth');
+ a.title = OpenLayers.i18n('panNorth');
a.coords = '26,175, 43,158, 8,158, 25,175';
- Event.observe(a, 'mouseup', this.pan.bindAsEventListener(this, 0, this.panAmount/100) );
+ var panNorth = OpenLayers.Function.bind(this.pan, this, 0, this.panAmount/100 );
+ Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(panNorth, this) );
m.appendChild(a);
var a = document.createElement('area');
a.shape = 'circle';
- a.alt = OpenLayers.String.translate('zoomOut');
- a.title = OpenLayers.String.translate('zoomOut');
+ a.alt = OpenLayers.i18n('zoomOut');
+ a.title = OpenLayers.i18n('zoomOut');
a.coords = '25,142,8';
- Event.observe(a, 'mouseup', this.zoom.bindAsEventListener(this, 1/this.zoomFactor) );
+ var zoomOut = OpenLayers.Function.bind(this.zoom, this, 1/this.zoomOutFactor);
+ Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(zoomOut, this) );
m.appendChild(a);
var a = document.createElement('area');
a.shape = 'circle';
- a.alt = OpenLayers.String.translate('zoomIn');
- a.title = OpenLayers.String.translate('zoomIn');
+ a.alt = OpenLayers.i18n('zoomIn');
+ a.title = OpenLayers.i18n('zoomIn');
a.coords = '25,34,8';
- Event.observe(a, 'mouseup', this.zoom.bindAsEventListener(this, this.zoomFactor) );
+ var zoomIn = OpenLayers.Function.bind(this.zoom, this, this.zoomInFactor);
+ Event.observe(a, 'mouseup', OpenLayers.Function.bindAsEventListener(zoomIn, this) );
m.appendChild(a);
this.domObj.appendChild(m);
@@ -143,7 +150,7 @@
this.domObj.style.height = '204px';
this.domObj.style.cursor = 'pointer';
- var checkPosition = this.checkPosition.bind(this);
+ var checkPosition = OpenLayers.Function.bind(this.checkPosition, this);
//set up the navigator as draggable
new Draggable(this.domObj, {handle: handleDiv, starteffect: false, endeffect: false});
@@ -162,16 +169,16 @@
options.axis = 'vertical';
options.range = $R(1, 91);
options.sliderValue = 91;
- options.onChange = this.scaleChanged.bindAsEventListener(this);
+ options.onChange = OpenLayers.Function.bind(this.scaleChanged, this);
this.slider = new Control.Slider(sliderHandle,sliderDiv, options);
this.slider.setDisabled();
- this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.updateSlider.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_RESIZED, this.checkPosition.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, this.updateValue.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_BUSY_CHANGED, this.busyChanged.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, OpenLayers.Function.bind(this.updateSlider, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_RESIZED, OpenLayers.Function.bind(this.checkPosition, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, OpenLayers.Function.bind(this.updateValue, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_BUSY_CHANGED, OpenLayers.Function.bind(this.busyChanged, this));
},
- scaleChanged: function(e, value) {
+ scaleChanged: function(value) {
var map = this.getMap();
var activeWidget = null;
if (map.oActiveWidget) {
@@ -189,7 +196,7 @@
center.x + w_deg / 2,
center.y + h_deg / 2));
}
- Event.stop(e);
+ //Event.stop(e);
if (activeWidget) {
map.activateWidget(activeWidget);
}
@@ -248,7 +255,7 @@
this.bInternalChange = false;
},
- pan: function(e,x,y) {
+ pan: function(x,y,e) {
//console.log('pan by : ' + x + ', ' + y);
var map = this.getMap();
var activeWidget = null;
@@ -268,7 +275,7 @@
return false;
},
- zoom: function(e, factor) {
+ zoom: function(factor, e) {
//console.log('zoom by factor: ' + factor);
var map = this.getMap();
var activeWidget = null;
@@ -290,4 +297,4 @@
}
-};
+});
Modified: sandbox/aboudreault/widgets/OverviewMap.js
===================================================================
--- sandbox/aboudreault/widgets/OverviewMap.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/OverviewMap.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,8 +30,8 @@
* primary map.
* **********************************************************************/
-Fusion.Widget.OverviewMap = Class.create();
-Fusion.Widget.OverviewMap.prototype = {
+Fusion.Widget.OverviewMap = OpenLayers.Class(Fusion.Widget,
+{
oSize: null,
nMinRatio : 4,
nMaxRatio : 32,
@@ -39,7 +39,8 @@
initialize : function(widgetTag) {
//console.log('OverviewMap.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
var json = widgetTag.extension;
if (json.MinRatio) {
@@ -59,7 +60,7 @@
mapTag = mainMap.mapGroup.maps[0]; //TODO: always use the baselayer Map in the group?
}
this.mapObject = eval("new Fusion.Maps."+mapTag.type+"(this.getMap(),mapTag,false)");
- this.mapObject.registerForEvent(Fusion.Event.MAP_LOADED, this.loadOverview.bind(this));
+ this.mapObject.registerForEvent(Fusion.Event.MAP_LOADED, OpenLayers.Function.bind(this.loadOverview, this));
//first set the size to the size of the DOM element if available
if (this.domObj) {
@@ -67,13 +68,13 @@
if (this.domObj.jxLayout) {
this.domObj.jxLayout.addSizeChangeListener(this);
} else {
- this.domObj.resize = this.sizeChanged.bind(this);
+ this.domObj.resize = OpenLayers.Function.bind(this.sizeChanged, this);
}
}
this.oMapOptions = {}; //TODO: allow setting some mapOptions in AppDef
- //this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.mapWidgetLoaded.bind(this));
+ //this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, OpenLayers.Function.bind(this.mapWidgetLoaded, this));
},
mapWidgetLoaded: function()
@@ -146,5 +147,5 @@
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/Pan.js
===================================================================
--- sandbox/aboudreault/widgets/Pan.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/Pan.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -29,12 +29,14 @@
* A widget that allows for naviagtion by panning
* **********************************************************************/
-Fusion.Widget.Pan = Class.create();
-Fusion.Widget.Pan.prototype = {
+Fusion.Widget.Pan = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase,
+{
initialize : function(widgetTag) {
//console.log('Pan.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
+
this.control = new OpenLayers.Control.DragPan();
this.getMap().oMapOL.addControl(this.control);
this.control.handler.keyMask = 0;
@@ -65,4 +67,4 @@
/*icon button*/
this._oButton.deactivateTool();
}
-};
+});
Modified: sandbox/aboudreault/widgets/PanOnClick.js
===================================================================
--- sandbox/aboudreault/widgets/PanOnClick.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/PanOnClick.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,8 +30,8 @@
*
* **********************************************************************/
-Fusion.Widget.PanOnClick = Class.create();
-Fusion.Widget.PanOnClick.prototype =
+
+Fusion.Widget.PanOnClick = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase,
{
fPercent: null,
nDeltaX: null,
@@ -39,8 +39,9 @@
initialize : function(widgetTag)
{
//console.log('FitToWindow.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
var json = widgetTag.extension;
@@ -84,4 +85,4 @@
fY = center.y + this.nDeltaY * (extents[3] - extents[1]) * this.fPercent;
this.getMap().zoom(fX, fY, 1);
}
-};
\ No newline at end of file
+});
\ No newline at end of file
Modified: sandbox/aboudreault/widgets/PanQuery.js
===================================================================
--- sandbox/aboudreault/widgets/PanQuery.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/PanQuery.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -31,23 +31,25 @@
*
* **********************************************************************/
-Fusion.require('widgets/Pan.js');
+//Fusion.require('widgets/Pan.js');
-Fusion.Widget.PanQuery = Class.create();
-Fusion.Widget.PanQuery.prototype = {
+Fusion.Widget.PanQuery = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase,
+{
selectionType: 'INTERSECTS',
nTolerance: 3,
bActiveOnly: false,
initialize : function(widgetTag) {
//console.log('PanQuery.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
- Object.inheritFrom(this, Fusion.Widget.Pan.prototype, [widgetTag]);
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
+ //OpenLayers.Util.extend(this, Fusion.Widget.Pan.prototype);
+ //Fusion.Widget.Pan.prototype.initialize.apply(this, [widgetTag]);
+
this.control = new OpenLayers.Control.DragPan();
this.getMap().oMapOL.addControl(this.control);
//TODO figure out how to set the mouseup via handlerOptions
- this.control.handler.up = this.mouseUp.bind(this);
+ this.control.handler.up = OpenLayers.Function.bind(this.mouseUp, this);
var json = widgetTag.extension;
@@ -106,6 +108,29 @@
Event.stop(e);
},
+ /**
+ * called when the button is clicked by the Fusion.Tool.ButtonBase widget
+ */
+ activateTool : function() {
+ /*console.log('Pan.activateTool');*/
+ this.getMap().activateWidget(this);
+ },
+
+ activate : function() {
+ this.control.activate();
+ this.getMap().setCursor(this.cursorNormal);
+ /*button*/
+ this._oButton.activateTool();
+ },
+
+ deactivate: function() {
+ /*console.log('Pan.deactivate');*/
+ this.control.deactivate();
+ this.getMap().setCursor('auto');
+ /*icon button*/
+ this._oButton.deactivateTool();
+ },
+
setParameter : function(param, value) {
if (param == "Tolerance" && value > 0) {
this.nTolerance = value;
@@ -114,4 +139,4 @@
this.selectionType = value;
}
}
-};
\ No newline at end of file
+});
\ No newline at end of file
Modified: sandbox/aboudreault/widgets/Print/printablepage.templ
===================================================================
--- sandbox/aboudreault/widgets/Print/printablepage.templ 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/Print/printablepage.templ 2008-05-29 14:21:40 UTC (rev 1413)
@@ -15,6 +15,7 @@
var msie = agent.indexOf("msie") != -1;
var safari = agent.indexOf("safari") != -1;
var firefox = agent.indexOf("firefox") != -1;
+ var clientAgent = "Fusion Viewer";
var webAgent = '%s';
var scale = %s;
@@ -38,7 +39,7 @@
{
var legendElt = document.getElementById("Legend");
legendElt.style.width = "180px";
- legendElt.innerHTML = "<img id=\"legendImage\" width=\"180\" height=\"" + mapHeight + "\" src=\"" + webAgent + "?OPERATION=GETMAPLEGENDIMAGE&VERSION=1.0.0&MAPNAME=" + encodeURIComponent(mapName) + "&SESSION=" + sessionId + "&WIDTH=180&HEIGHT=" + mapHeight + "&FORMAT=PNG\" style=\"visibility: hidden\" onload=\"OnImageLoaded('legendImage');\">";
+ legendElt.innerHTML = "<img id=\"legendImage\" width=\"180\" height=\"" + mapHeight + "\" src=\"" + webAgent + "?OPERATION=GETMAPLEGENDIMAGE&VERSION=1.0.0&MAPNAME=" + encodeURIComponent(mapName) + "&SESSION=" + sessionId + "&CLIENTAGENT=" + encodeURIComponent(clientAgent) + "&WIDTH=180&HEIGHT=" + mapHeight + "&FORMAT=PNG\" style=\"visibility: hidden\" onload=\"OnImageLoaded('legendImage');\">";
}
else
mapWidth += 180;
@@ -49,7 +50,7 @@
document.getElementById("ScaleAndArrow").style.height = "0px";
}
- var imgReq = webAgent + "?OPERATION=GETMAPIMAGE&VERSION=1.0.0&FORMAT=PNG&LOCALE="+locale+"&MAPNAME=" + encodeURIComponent(mapName) + "&SESSION=" + sessionId + "&SETDISPLAYWIDTH=" + mapWidth + "&SETDISPLAYHEIGHT=" + mapHeight + "&SETDISPLAYDPI=" + dpi + "&SETVIEWSCALE=" + scale + "&SETVIEWCENTERX=" + centerX + "&SETVIEWCENTERY=" + centerY + "&SEQ=" + Math.random();
+ var imgReq = webAgent + "?OPERATION=GETMAPIMAGE&VERSION=1.0.0&FORMAT=PNG&LOCALE="+locale+"&MAPNAME=" + encodeURIComponent(mapName) + "&SESSION=" + sessionId + "&SETDISPLAYWIDTH=" + mapWidth + "&SETDISPLAYHEIGHT=" + mapHeight + "&SETDISPLAYDPI=" + dpi + "&SETVIEWSCALE=" + scale + "&SETVIEWCENTERX=" + centerX + "&SETVIEWCENTERY=" + centerY + "&SEQ=" + Math.random() + "&CLIENTAGENT=" + encodeURIComponent(clientAgent);
var mapElt = document.getElementById("Map");
mapElt.style.width = mapWidth + "px";
Modified: sandbox/aboudreault/widgets/Print.js
===================================================================
--- sandbox/aboudreault/widgets/Print.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/Print.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,11 +30,12 @@
*
* **********************************************************************/
-Fusion.Widget.Print = Class.create();
-Fusion.Widget.Print.prototype = {
+Fusion.Widget.Print = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase,
+{
initialize : function(widgetTag) {
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
var json = widgetTag.extension;
@@ -62,7 +63,7 @@
/*
* TODO: this is bad, why did we do this?
- this.getMap().registerForEvent(Fusion.Event.SELECTION_COMPLETE, this.getSelection.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.SELECTION_COMPLETE, OpenLayers.Function.bind(this.getSelection, this));
*/
},
@@ -83,10 +84,10 @@
var size = Element.getPageDimensions();
var o = {
- title: OpenLayers.String.translate('printTitle'),
+ title: OpenLayers.i18n('printTitle'),
id: 'printablePage',
contentURL : this.dialogContentURL,
- onContentLoaded: this.contentLoaded.bind(this),
+ onContentLoaded: OpenLayers.Function.bind(this.contentLoaded, this),
imageBaseUrl: this.imageBaseUrl,
width: 350,
height: 250,
@@ -94,7 +95,7 @@
top: (size.height-250)/2,
left: (size.width-350)/2,
buttons: ['generate', 'cancel'],
- handler: this.handler.bind(this)
+ handler: OpenLayers.Function.bind(this.handler, this)
};
this.dialog = new Jx.Dialog(o);
@@ -130,7 +131,7 @@
dialog.getObj('dialogPrintShowlegend').checked = this.showLegend;
dialog.getObj('dialogPrintShowNorthArrow').checked = this.showNorthArrow;
- Event.observe(dialog.getObj('dialogPrintShowtitle'), 'click', this.controlTitle.bind(this));
+ Event.observe(dialog.getObj('dialogPrintShowtitle'), 'click', OpenLayers.Function.bind(this.controlTitle, this));
},
controlTitle: function() {
@@ -175,4 +176,4 @@
window.open(url, 'printablepage', '');
}
-};
+});
Modified: sandbox/aboudreault/widgets/RefreshMap.js
===================================================================
--- sandbox/aboudreault/widgets/RefreshMap.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/RefreshMap.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,12 +30,14 @@
*
* **********************************************************************/
-Fusion.Widget.RefreshMap = Class.create();
-Fusion.Widget.RefreshMap.prototype = {
+
+Fusion.Widget.RefreshMap = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase,
+{
initialize : function(widgetTag) {
//console.log('RefreshMap.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
},
/**
@@ -45,4 +47,4 @@
var map = this.getMap();
map.redraw();
}
-};
+});
Modified: sandbox/aboudreault/widgets/SaveMap.js
===================================================================
--- sandbox/aboudreault/widgets/SaveMap.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/SaveMap.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -38,31 +38,74 @@
* </Extension>
* **********************************************************************/
-Fusion.Widget.SaveMap = Class.create();
-Fusion.Widget.SaveMap.prototype = {
+Fusion.Widget.SaveMap = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase,
+{
iframe : null,
printLayout : null,
printScale : null,
+ imageWidth : null,
+ imageHeight : null,
initialize : function(widgetTag) {
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
+
var json = widgetTag.extension;
this.format = (json.Format && json.Format[0] != '')?
json.Format[0] : 'png';
//for DWF, parse printLayouts and build menu
- if (this.format == 'DWF') {
- if (json.ResourceId) {
- this.printLayout = json.ResourceId[0];
- if (json.Scale) {
- this.printScale = json.Scale[0];
- }
- } else {
- //TODO: Warning that the widget is improperly configured
- //because we need print layout for this to work.
- //TODO: deactivate the widget?
+ if (this.format == 'DWF' && json.PrintLayout.length) {
+ Object.inheritFrom(this, Fusion.Tool.MenuBase.prototype, []);
+
+ var layouts = json.PrintLayout;
+ for (var i = 0; i < layouts.length; i++) {
+ var layout = layouts[i];
+ var opt = {};
+ opt.label = layout.Name[0];
+ var data = {rid:layout.ResourceId[0]};
+ if (layout.PageHeight) {
+ data.pageHeight = layout.PageHeight[0];
+ };
+ if (layout.PageWidth) {
+ data.pageWidth = layout.PageWidth[0];
+ };
+ if (layout.Margins) {
+ data.margins = [layout.Margins[0].Top[0],
+ layout.Margins[0].Left[0],
+ layout.Margins[0].Right[0],
+ layout.Margins[0].Bottom[0]];
+ };
+ var menuItem = null;
+ if (layout.Scale) {
+ //create entries for weblayout specified scales
+ menuItem = new Jx.SubMenu(opt);
+ for (var j=0; j < layout.Scale.length; j++) {
+ data.scale = layout.Scale[j];
+ var scaleAction = new Jx.Action(this.setLayout.bind(this, data));
+ var subMenuItem = new Jx.MenuItem(scaleAction,{label:data.scale});
+ menuItem.add(subMenuItem);
+ }
+ //add an entry for current scale
+ var currentScaleAction = new Jx.Action(this.setLayout.bind(this, data));
+ var currentScaleItem = new Jx.MenuItem(currentScaleAction,
+ {label:'Current Scale'});
+ menuItem.add(currentScaleItem);
+ } else {
+ //if there are no scales, the layout is used with current scale
+ var action = new Jx.Action(this.setLayout.bind(this, data));
+ menuItem = new Jx.MenuItem(action,opt);
+ };
+ this.oMenu.add(menuItem);
}
+ } else {
+ Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+ if (json.Width && json.Width[0] != '') {
+ this.imageWidth = json.Width[0];
+ }
+ if (json.Height && json.Height[0] != '') {
+ this.imageHeight = json.Height[0];
+ }
}
this.enable = Fusion.Widget.SaveMap.prototype.enable;
@@ -72,6 +115,16 @@
Fusion.Tool.ButtonBase.prototype.enable.apply(this, []);
},
+ setLayout: function(data) {
+ this.printScale = data.scale;
+ this.printLayout = data.rid;
+ this.pageHeight = data.pageHeight;
+ this.pageWidth = data.pageWidth;
+ this.pageMargins = data.margins;
+
+ this.activateTool();
+ },
+
/**
* called when the button is clicked by the Fusion.Tool.ButtonBase widget
* prompts user to save the map.
@@ -85,30 +138,45 @@
}
var szLayout = '';
var szScale = '';
+ var szPageHeight = '';
+ var szPageWidth = '';
+ var szPageMargins = '';
if (this.format === 'DWF') {
if (this.printLayout) {
szLayout = '&layout=' + this.printLayout;
} else {
- //TODO: issue an error?
+ alert('DWF Save is not properly configured.');
return;
}
if (this.printScale) {
szScale = '&scale=' + this.printScale;
+ }
+ if (this.pageHeight) {
+ szPageHeight = '&pageheight=' + this.pageHeight;
}
+ if (this.pageWidth) {
+ szPageWidth = '&pagewidth=' + this.pageWidth;
+ }
+ if (this.pageMargins) {
+ szPageMargins = '&margins=' + this.pageMargins.join(',');
+ }
}
- //TODO: revisit Fusion.getWebAgentURL
- var m = this.getMap().aMaps[0];
+ var szHeight = '';
+ if (this.imageHeight) {
+ szHeight = '&height=' + this.imageHeight;
+ }
+ var szWidth = '';
+ if (this.imageWidth) {
+ szWidth = '&width=' + this.imageWidth;
+ }
+ var m = this.getMap().aMaps[0];
if(navigator.appVersion.match(/\bMSIE\b/)) {
- //var url = Fusion.getWebAgentURL() + "OPERATION=GETDYNAMICMAPOVERLAYIMAGE&FORMAT=PNG&VERSION=1.0.0&SESSION=" + this.getMap().getSessionID() + "&MAPNAME=" + this.getMap().getMapName() + "&SEQ=" + Math.random();
-
- var url = Fusion.fusionURL + '/' + m.arch + '/' + Fusion.getScriptLanguage() + "/SaveMapFrame." + Fusion.getScriptLanguage() + '?session='+m.getSessionID() + '&mapname=' + m.getMapName() + '&format=' + this.format + szLayout;
- //this.iframe.src = url;
+ var url = Fusion.fusionURL + '/' + m.arch + '/' + Fusion.getScriptLanguage() + "/SaveMapFrame." + Fusion.getScriptLanguage() + '?session='+m.getSessionID() + '&mapname=' + m.getMapName() + '&format=' + this.format + szLayout + szWidth + szHeight + szPageHeight + szPageWidth + szPageMargins;
w = open(url, "Save", 'menubar=no,height=200,width=300');
} else {
- var s = Fusion.fusionURL + '/' + m.arch + '/' + Fusion.getScriptLanguage() + "/SaveMap." + Fusion.getScriptLanguage() + '?session='+m.getSessionID() + '&mapname=' + m.getMapName() + '&format=' + this.format + szLayout;
- //console.log(s);
+ var s = Fusion.fusionURL + '/' + m.arch + '/' + Fusion.getScriptLanguage() + "/SaveMap." + Fusion.getScriptLanguage() + '?session='+m.getSessionID() + '&mapname=' + m.getMapName() + '&format=' + this.format + szLayout + szWidth + szHeight + szPageHeight + szPageWidth + szPageMargins;
this.iframe.src = s;
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/Scalebar.js
===================================================================
--- sandbox/aboudreault/widgets/Scalebar.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/Scalebar.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -37,8 +37,8 @@
Fusion.require('widgets/scalebar/scalebartool.js');
}
-Fusion.Widget.Scalebar = Class.create();
-Fusion.Widget.Scalebar.prototype = {
+Fusion.Widget.Scalebar = OpenLayers.Class(Fusion.Widget,
+{
style: 'thin',
displaySystem: 'metric',
minWidth: 100,
@@ -50,8 +50,9 @@
singleLine: false,
initialize : function(widgetTag) {
//console.log('Scalebar.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
+
var json = widgetTag.extension;
this.style = json.Style ? json.Style[0].toLowerCase() : this.style;
if (this.style != 'fancy' &&
@@ -98,13 +99,13 @@
//debugging using firebug, the problem doesn't occur.
//this.oScaleBar.place(widgetTag.name);
//A parameter or an operation is not supported by the underlying object" code: "15
- window.setTimeout(this.oScaleBar.place.bind(this.oScaleBar, widgetTag.name), 1);
+ window.setTimeout(OpenLayers.Function.bind(this.oScaleBar, widgetTag.name), 1);
- this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, this.extentsChangedCB.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.extentsChangedCB.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, OpenLayers.Function.bind(this.extentsChangedCB, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, OpenLayers.Function.bind(this.extentsChangedCB, this));
},
extentsChangedCB : function() {
this.oScaleBar.update(this.getMap().getScale());
}
-};
+});
Modified: sandbox/aboudreault/widgets/ScalebarDual.js
===================================================================
--- sandbox/aboudreault/widgets/ScalebarDual.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/ScalebarDual.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,128 +30,18 @@
*
* **********************************************************************/
-Fusion.Widget.ScalebarDual = Class.create();
-Fusion.Widget.ScalebarDual.prototype = {
- nominalSize: 100,
+Fusion.Widget.ScalebarDual = OpenLayers.Class(Fusion.Widget, {
+ nominalSize: 500,
initialize : function(widgetTag) {
- //console.log('Scalebar.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
-
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag]);
var json = widgetTag.extension;
-
- this.content = $(this.getName());
-
- var scaleDiv = document.createElement('div');
- Element.addClassName(scaleDiv, 'scaleDiv');
- Element.addClassName(scaleDiv, 'scaleMetric');
- this.content.appendChild(scaleDiv);
-
- this.metricDiv = document.createElement('div');
- Element.addClassName(this.metricDiv, 'scaleLabel');
- scaleDiv.appendChild(this.metricDiv);
-
- scaleDiv = document.createElement('div');
- Element.addClassName(scaleDiv, 'scaleDiv');
- Element.addClassName(scaleDiv, 'scaleImperial');
- this.content.appendChild(scaleDiv);
-
- this.imperialDiv = document.createElement('div');
- Element.addClassName(this.imperialDiv, 'scaleLabel');
- scaleDiv.appendChild(this.imperialDiv);
-
- Element.addClassName(this.domObj, 'dualScalebar');
-
- this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, this.extentsChangedCB.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.extentsChangedCB.bind(this));
-
- Fusion.addWidgetStyleSheet(widgetTag.location + '/ScalebarDual/ScalebarDual.css');
-
- },
-
- extentsChangedCB : function() {
- var maxWidth = this.content.getWidth();
-
- //TODO: support projected data
- var map = this.getMap();
- var oExtent = map.getCurrentExtents();
- var res = map.getResolution();
-
- var kmPerPixel;
- var units = map.getUnits()
- if (units == 'degrees' || units == 'dd' ) { //TODO: add case for units='ft'
- var cp = oExtent.getCenterLonLat();
- if (Math.abs(cp.lat) > 89.9) return;
-
- var ddPerPixel = res;
- var metersPerDD = 110570;
- //adjust for latitude
- var kmPerDD = 110.570 * Math.cos(cp.lat*Math.PI/180);
- kmPerPixel = kmPerDD * ddPerPixel;
- } else {
- kmPerPixel = res/1000.0;
- }
- var miPerPixel = kmPerPixel * 0.621371192;
- var ftPerPixel = kmPerPixel * 3280.8399;
- var kmBarLength = 0; //pixels
- var miBarLength = 0;
- var km = 0;
- var mi = 0;
- var ft = 0;
- var kmDone = miDone = false;
- while(!kmDone && !miDone) {
- if (kmBarLength < this.nominalSize) {
- if (km < 1)
- km = (km * 10 + 1)/10 ;
- else if (km < 10)
- km = km + 1;
- else if (km < 100)
- km = km + 10;
- else if (km < 1000)
- km = km + 100;
- else
- km = km + 1000;
- } else {
- kmDone = true;
- }
- if (miBarLength < this.nominalSize) {
- if (mi < 1)
- mi = (mi * 10 + 1)/10 ;
- else if (mi < 10)
- mi = mi + 1;
- else if (mi < 100)
- mi = mi + 10;
- else if (mi < 1000)
- mi = mi + 100;
- else
- mi = mi + 1000;
- } else {
- miDone = true;
- }
-
- kmBarLength = km / kmPerPixel;
- miBarLength = mi / miPerPixel;
- }
- //for small values, convert to feet and round
- if (mi < 0.4) {
- ft = (Math.floor(mi * 52.8) * 100);
- miBarLength = ft / ftPerPixel;
- }
-
- var sbMax = Math.max(kmBarLength, miBarLength) + 2;
- this.content.style.width = Math.round(sbMax) + 'px';
- //(document.getElementById(this.id)).style.width = sbMax + 'px';
- this.metricDiv.parentNode.style.width = Math.round(kmBarLength - 0) + "px"; //0 was 24 why?
- //for small values, convert units
- if (km <= 0.5) {
- this.metricDiv.innerHTML = km * 1000 + " m";
- }else{
- this.metricDiv.innerHTML = km + " km";
- }
- this.imperialDiv.style.width = Math.round(miBarLength - 0) + "px"; //0 was 24 why?
- if (mi < 0.4) {
- this.imperialDiv.innerHTML = ft + " ft";
- }else{
- this.imperialDiv.innerHTML = mi + " mi";
- }
- }
-};
+ var options = { //set these from widgetTag extension
+ maxWidth: this.nominalSize,
+ topInUnits: 'ft',
+ topOutUnits: 'mi',
+ bottomInUnits: 'm',
+ bottomOutUnits: 'km'
+ };
+ this.addControl(new OpenLayers.Control.ScaleLine(options));
+ }
+});
Modified: sandbox/aboudreault/widgets/Search/Search.php
===================================================================
--- sandbox/aboudreault/widgets/Search/Search.php 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/Search/Search.php 2008-05-29 14:21:40 UTC (rev 1413)
@@ -228,10 +228,20 @@
}
catch(MgException $ae)
{
+ if($features)
+ {
+ // Close the feature reader
+ $features->Close();
+ }
OnError($searchError, $ae->GetDetails());
}
catch(SearchError $e)
{
+ if($features)
+ {
+ // Close the feature reader
+ $features->Close();
+ }
OnError($e->title, $e->getMessage());
}
Modified: sandbox/aboudreault/widgets/Search.js
===================================================================
--- sandbox/aboudreault/widgets/Search.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/Search.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -33,15 +33,16 @@
* (http://mapserver.commenspace.org/tools/scalebar/
* **********************************************************************/
-Fusion.Widget.Search = Class.create();
-Fusion.Widget.Search.prototype = {
+Fusion.Widget.Search = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase,
+{
sFeatures : 'menubar=no,location=no,status=no,scrollbars=yes',
initialize : function(widgetTag) {
//console.log('Search.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
+
var json = widgetTag.extension;
this.sTarget = json.Target ? json.Target[0] : "SearchWindow";
this.sBaseUrl = Fusion.getFusionURL() + 'widgets/Search/SearchPrompt.php';
@@ -89,4 +90,4 @@
}
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/Select.js
===================================================================
--- sandbox/aboudreault/widgets/Select.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/Select.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,8 +30,9 @@
*
* **********************************************************************/
-Fusion.Widget.Select = Class.create();
-Fusion.Widget.Select.prototype = {
+
+Fusion.Widget.Select = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase,
+{
selectionType: 'INTERSECTS',
nTolerance : 3, //default pixel tolernace for a point click
bActiveOnly: false, //only select feature(s) on the active layer?
@@ -39,9 +40,10 @@
initialize : function(widgetTag) {
//console.log('Select.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
- //Object.inheritFrom(this, Fusion.Tool.Rectangle.prototype, []);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
+
this.asCursor = ['auto'];
this.enable = Fusion.Widget.Select.prototype.enable;
@@ -63,7 +65,7 @@
json.QueryActiveLayer[0] == '1')) ? true : false;
if (this.bActiveOnly) {
- this.getMap().registerForEvent(Fusion.Event.MAP_ACTIVE_LAYER_CHANGED, this.enable.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_ACTIVE_LAYER_CHANGED, OpenLayers.Function.bind(this.enable, this));
}
this.map = this.getMap().oMapOL;
@@ -226,4 +228,4 @@
this.selectionType = value;
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/SelectPolygon.js
===================================================================
--- sandbox/aboudreault/widgets/SelectPolygon.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/SelectPolygon.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,15 +30,18 @@
*
* **********************************************************************/
-Fusion.Widget.SelectPolygon = Class.create();
-Fusion.Widget.SelectPolygon.prototype = {
+
+Fusion.Widget.SelectPolygon = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase, Fusion.Tool.ButtonBase, Fusion.Tool.Canvas,
+{
selectionType: 'INTERSECTS',
nTolerance : 3, //default pixel tolernace for a point click
initialize : function(widgetTag) {
//console.log('Select.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
- Object.inheritFrom(this, Fusion.Tool.Canvas.prototype, []);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
+ Fusion.Tool.Canvas.prototype.initialize.apply(this, []);
+
this.asCursor = ['auto'];
var json = widgetTag.extension;
@@ -206,4 +209,4 @@
this.selectionType = value;
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/SelectRadius.js
===================================================================
--- sandbox/aboudreault/widgets/SelectRadius.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/SelectRadius.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -29,19 +29,23 @@
* perform a selection by radius from a point
*
* **********************************************************************/
+Fusion.Event.RADIUS_WIDGET_ACTIVATED = Fusion.Event.lastEventId++;
-Fusion.Widget.SelectRadius = Class.create();
-Fusion.Widget.SelectRadius.prototype = {
+
+Fusion.Widget.SelectRadius = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase, Fusion.Tool.Canvas,
+{
selectionType: 'INTERSECTS',
nTolerance : 3, //default pixel tolernace for a point click
- defaultRadius: 20,
+ defaultRadius: 20, //this is in map units
initialize : function(widgetTag) {
//console.log('Select.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
- Object.inheritFrom(this, Fusion.Tool.Canvas.prototype, []);
-
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
+ Fusion.Tool.Canvas.prototype.initialize.apply(this, []);
+
this.asCursor = ['auto'];
+ this.isDigitizing = false;
var json = widgetTag.extension;
this.selectionType = json.SelectionType ? json.SelectionType[0] : 'INTERSECTS';
@@ -70,6 +74,8 @@
this.radiusTip.style.zIndex = 101;
}
}
+
+ this.registerEventID(Fusion.Event.RADIUS_WIDGET_ACTIVATED);
},
setRadius: function(r) {
@@ -107,6 +113,7 @@
}
/*map units for tool tip*/
this.units = this.getMap().getAllMaps()[0].units;
+ this.triggerEvent(Fusion.Event.RADIUS_WIDGET_ACTIVATED, true);
},
/**
@@ -115,10 +122,11 @@
* as a widget in the map
**/
deactivate : function() {
- this.deactivateCanvas();
- this.getMap().setCursor('auto');
- /*icon button*/
- this._oButton.deactivateTool();
+ this.deactivateCanvas();
+ this.getMap().setCursor('auto');
+ /*icon button*/
+ this._oButton.deactivateTool();
+ this.triggerEvent(Fusion.Event.RADIUS_WIDGET_ACTIVATED, false);
},
/**
@@ -129,11 +137,11 @@
* @param e Event the event that happened on the mapObj
*/
mouseDown: function(e) {
- //console.log('SelectRadius.mouseDown');
+ //console.log('SelectRadius.mouseDown'+this.isDigitizing);
if (Event.isLeftClick(e)) {
var p = this.getMap().getEventPosition(e);
var point = this.getMap().pixToGeo(p.x, p.y);
- var radius = this.getMap().pixToGeoMeasure(this.defaultRadius);
+ var radius = this.defaultRadius;
if (!this.isDigitizing) {
this.circle.setCenter(point.x, point.y);
@@ -148,7 +156,7 @@
var size = Element.getDimensions(this.radiusTip);
this.radiusTip.style.top = (p.y - size.height*2) + 'px';
this.radiusTip.style.left = p.x + 'px';
- var r = this.getMap().pixToGeoMeasure(this.circle.radius);
+ var r = this.circle.radius;
if (this.units == 'm' || this.units == 'ft') {
r = Math.round(r * 100)/100;
}
@@ -164,7 +172,7 @@
* @param e Event the event that happened on the mapObj
*/
mouseMove: function(e) {
- //console.log('SelectRadius.mouseMove');
+ //console.log('SelectRadius.mouseMove'+this.isDigitizing);
if (!this.isDigitizing) {
return;
}
@@ -175,7 +183,7 @@
var center = this.circle.center;
var radius = Math.sqrt(Math.pow(center.x-point.x,2) + Math.pow(center.y-point.y,2));
- if (map.geoToPixMeasure(radius) > this.nTolerance) {
+ if (radius > this.nTolerance) {
this.circle.setRadius(radius);
}
this.clearContext();
@@ -186,7 +194,7 @@
var size = Element.getDimensions(this.radiusTip);
this.radiusTip.style.top = (p.y - size.height*2) + 'px';
this.radiusTip.style.left = p.x + 'px';
- var r = map.pixToGeoMeasure(this.circle.radius);
+ var r = this.circle.radius;
if (this.units == 'm' || this.units == 'ft') {
r = Math.round(r * 100)/100;
}
@@ -196,9 +204,9 @@
},
mouseUp: function(e) {
+ //console.log('SelectRadius.mouseUp'+this.isDigitizing);
if (this.isDigitizing) {
this.event = e;
- //this.circle.draw(this.context);
this.clearContext();
this.isDigitizing = false;
var center = this.circle.center;
@@ -265,4 +273,4 @@
this.selectionType = value;
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/SelectRadiusValue.js
===================================================================
--- sandbox/aboudreault/widgets/SelectRadiusValue.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/SelectRadiusValue.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -31,14 +31,15 @@
*
* **********************************************************************/
-Fusion.Widget.SelectRadiusValue = Class.create();
-Fusion.Widget.SelectRadiusValue.prototype = {
+Fusion.Widget.SelectRadiusValue = OpenLayers.Class(Fusion.Widget,
+{
radiusWidgetName: null,
label: '',
className: '',
domLabel: null,
initialize : function(widgetTag) {
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
/* parse widget properties */
var json = widgetTag.extension;
@@ -47,15 +48,16 @@
this.label = json.Label ? json.Label[0] : '';
this.className = json.ClassName ? json.ClassName[0] : '';
- /* a container for the widget */
- //this.domObj = document.createElement('div');
- //this.domObj.className = this.className;
-
+ this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, OpenLayers.Function.bind(this.mapLoaded, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, OpenLayers.Function.bind(this.mapExtentsChanged, this));
+ },
+
+ draw: function() {
/* put in the label */
+ var units = this.getMap().getAllMaps()[0].units;
this.domLabel = document.createElement('label');
this.domLabel.className = this.className;
- this.domLabel.innerHTML = this.label;
- //this.domObj.appendChild(label);
+ this.domLabel.innerHTML = this.label + '(' + units + ')';
/* put in the input */
this.input = document.createElement('input');
@@ -64,22 +66,33 @@
/* put into page */
this.domObj.appendChild(this.domLabel);
- Event.observe(this.input, 'blur', this.onBlur.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.mapLoaded.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, this.mapExtentsChanged.bind(this));
-
+ Event.observe(this.input, 'blur', OpenLayers.Function.bind(this.onBlur, this));
},
mapLoaded: function() {
+ this.draw();
+ this.input.disabled = true;
var widgets = Fusion.getWidgetsByType('SelectRadius');
for (var i=0; i<widgets.length; i++) {
- if (widgets[i].sName == this.radiusWidgetName) {
+ if (widgets[i].widgetTag.name == this.radiusWidgetName) {
this.widget = widgets[i];
+ this.widget.registerForEvent(Fusion.Event.RADIUS_WIDGET_ACTIVATED, this.dependantEnable.bind(this));
+ break;
}
}
this.updateFromWidgetValue();
},
+ dependantEnable: function(eventId, active) {
+ if (this.widget) {
+ if (active) {
+ this.input.disabled = false;
+ } else {
+ this.input.disabled = true;
+ }
+ }
+ },
+
mapExtentsChanged: function() {
this.updateWidgetValue();
},
@@ -90,14 +103,14 @@
updateWidgetValue: function() {
if (this.widget) {
- var radius = this.getMap().geoToPixMeasure(this.input.getValue());
+ var radius = this.input.getValue();
this.widget.setRadius(radius);
}
},
updateFromWidgetValue: function() {
if (this.widget) {
- this.input.value = this.getMap().pixToGeoMeasure(this.widget.getRadius());
+ this.input.value = this.widget.getRadius();
}
}
-};
\ No newline at end of file
+});
Modified: sandbox/aboudreault/widgets/SelectWithin/SelectWithin.php
===================================================================
--- sandbox/aboudreault/widgets/SelectWithin/SelectWithin.php 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/SelectWithin/SelectWithin.php 2008-05-29 14:21:40 UTC (rev 1413)
@@ -173,6 +173,7 @@
}
$geomColl->Add($geom);
}
+ $features->Close();
}
}
if($geomColl->GetCount() == 0)
Modified: sandbox/aboudreault/widgets/SelectWithin/SelectWithinPanel.templ
===================================================================
--- sandbox/aboudreault/widgets/SelectWithin/SelectWithinPanel.templ 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/SelectWithin/SelectWithinPanel.templ 2008-05-29 14:21:40 UTC (rev 1413)
@@ -40,6 +40,7 @@
var webAgent = '%s';
var mapName = '%s';
var sessionId = '%s';
+var zoomTo = false;
function InitDocument()
{
@@ -83,11 +84,25 @@
var mapWidget = GetParent().Fusion.getMapByName(mapName);
var map = mapWidget.aMaps[0];
- var params = "mapname=" + encodeURIComponent(mapName) + "&session=" + sessionId + "&layers=" + encodeURIComponent(layerSet);
- var options = {onSuccess: map.processQueryResults.bind(map), onFailure: selectedError, parameters:params};
+ var params = {
+ "mapname": encodeURIComponent(mapName),
+ "session": sessionId,
+ "layers": encodeURIComponent(layerSet)
+ };
+ var options = {
+ onSuccess: selectedSuccess,
+ onFailure: selectedError,
+ parameters:params
+ };
GetParent().Fusion.ajaxRequest(webAgent, options);
}
+function selectedSuccess(r) {
+ var mapWidget = GetParent().Fusion.getMapByName(mapName);
+ var map = mapWidget.aMaps[0];
+ map.processQueryResults(zoomTo, r);
+}
+
function selectedError(r) {
alert(r.responseText);
}
Modified: sandbox/aboudreault/widgets/SelectWithin.js
===================================================================
--- sandbox/aboudreault/widgets/SelectWithin.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/SelectWithin.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,15 +30,17 @@
*
* **********************************************************************/
-Fusion.Widget.SelectWithin = Class.create();
-Fusion.Widget.SelectWithin.prototype = {
+
+Fusion.Widget.SelectWithin = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase,
+{
sFeatures : 'menubar=no,location=no,resizable=no,status=no',
initialize : function(widgetTag) {
//console.log('SelectWithin.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
+
var json = widgetTag.extension;
this.sTarget = json.Target ? json.Target[0] : "SelectWithinWindow";
this.sBaseUrl = Fusion.getFusionURL() + 'widgets/SelectWithin/SelectWithinPanel.php';
@@ -58,8 +60,8 @@
}
this.enable = Fusion.Widget.SelectWithin.prototype.enable;
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON, this.enable.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF, this.enable.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON, OpenLayers.Function.bind(this.enable, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF, OpenLayers.Function.bind(this.enable, this));
this.disable();
},
@@ -124,4 +126,4 @@
}
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/SelectionInfo.js
===================================================================
--- sandbox/aboudreault/widgets/SelectionInfo.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/SelectionInfo.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -43,15 +43,15 @@
* & is &
* **********************************************************************/
-Fusion.Widget.SelectionInfo = Class.create();
-Fusion.Widget.SelectionInfo.prototype = {
+Fusion.Widget.SelectionInfo = OpenLayers.Class(Fusion.Widget,
+{
defaultTemplate: 'selectionInfo',
domSpan: null,
initialize : function(widgetTag) {
//console.log('SelectionInfo.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
-
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
var json = widgetTag.extension;
@@ -60,12 +60,12 @@
this.domSpan = document.createElement('span');
this.domSpan.className = 'spanSelectionInfo';
- this.domSpan.innerHTML = OpenLayers.String.translate(this.emptyText);
+ this.domSpan.innerHTML = OpenLayers.i18n(this.emptyText);
this.domObj.innerHTML = '';
this.domObj.appendChild(this.domSpan);
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON, this.update.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF, this.update.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON, OpenLayers.Function.bind(this.update, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF, OpenLayers.Function.bind(this.update, this));
},
update: function() {
@@ -79,10 +79,10 @@
if (this.template) {
this.domSpan.innerHTML = this.template.replace('{0}',nFeatures).replace('{1}',nLayers);
} else {
- this.domSpan.innerHTML = OpenLayers.String.translate(this.defaultTemplate,nFeatures,nLayers);
+ this.domSpan.innerHTML = OpenLayers.i18n(this.defaultTemplate,{'features':nFeatures,'layers':nLayers});
}
} else {
- this.domSpan.innerHTML = OpenLayers.String.translate(this.emptyText);
+ this.domSpan.innerHTML = OpenLayers.i18n(this.emptyText);
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/SelectionPanel.js
===================================================================
--- sandbox/aboudreault/widgets/SelectionPanel.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/SelectionPanel.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,20 +30,23 @@
*
* **********************************************************************/
-Fusion.Widget.SelectionPanel = Class.create();
-Fusion.Widget.SelectionPanel.prototype = {
+Fusion.Widget.SelectionPanel = OpenLayers.Class(Fusion.Widget,
+{
initialize : function(widgetTag) {
//console.log('SelectionPanel.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
this.defPrevTaskIcon = 'images/icon_back.gif';
this.defNextTaskIcon = 'images/icon_forward.gif';
var json = widgetTag.extension;
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON, this.updateSelection.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF, this.clearSelection.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON,
+ OpenLayers.Function.bind(this.updateSelection, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF,
+ OpenLayers.Function.bind(this.clearSelection, this));
var d = document.createElement('div');
@@ -53,12 +56,14 @@
this.layerList = document.createElement('select');
this.layerList.className = 'layerSelector';
this.toolbar.appendChild(this.layerList);
- Event.observe(this.layerList, 'change', this.renderSelectionFeatures.bind(this));
+ Event.observe(this.layerList, 'change',
+ OpenLayers.Function.bind(this.renderSelectionFeatures, this));
this.featureList = document.createElement('select');
this.featureList.className = 'featureSelector';
this.toolbar.appendChild(this.featureList);
- Event.observe(this.featureList, 'change', this.renderFeature.bind(this));
+ Event.observe(this.featureList, 'change',
+ OpenLayers.Function.bind(this.renderFeature, this));
this.featureDiv = document.createElement('div');
this.featureDiv.className = 'selectionPanelContent';
@@ -77,12 +82,13 @@
this.featureList.options.length = 0;
this.oSelection = null;
Element.addClassName(this.featureDiv, 'noSelection');
- this.featureDiv.innerHTML = OpenLayers.String.translate('noSelection');
+ this.featureDiv.innerHTML = OpenLayers.i18n('noSelection');
},
updateSelection: function() {
//console.log('update selection');
- this.getMap().getSelection(this.renderSelectionLayers.bind(this));
+ this.getMap().getSelection(
+ OpenLayers.Function.bind(this.renderSelectionLayers, this));
},
renderSelectionLayers: function(oSelection) {
@@ -147,10 +153,10 @@
var thead = document.createElement('thead');
var tr = document.createElement('tr');
var th = document.createElement('th');
- th.innerHTML = OpenLayers.String.translate('attribute');
+ th.innerHTML = OpenLayers.i18n('attribute');
tr.appendChild(th);
var th = document.createElement('th');
- th.innerHTML = OpenLayers.String.translate('value');
+ th.innerHTML = OpenLayers.i18n('value');
tr.appendChild(th);
thead.appendChild(tr);
table.appendChild(thead);
@@ -173,4 +179,4 @@
this.featureDiv.innerHTML = '';
this.featureDiv.appendChild(table);
}
-};
+});
Modified: sandbox/aboudreault/widgets/TaskPane.js
===================================================================
--- sandbox/aboudreault/widgets/TaskPane.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/TaskPane.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -29,8 +29,8 @@
* A utility widget that holds output from other widgets.
****************************************************************************/
-Fusion.Widget.TaskPane = Class.create();
-Fusion.Widget.TaskPane.prototype =
+
+Fusion.Widget.TaskPane = OpenLayers.Class(Fusion.Widget,
{
aExecutedTasks: null, //array of URLs for tasks execcuted in the TaskPane
nCurrentTask: 0,
@@ -42,7 +42,8 @@
initialize : function(widgetTag)
{
//console.log('TaskPane.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
this.aExecutedTasks = [];
this.defHomeIcon = 'images/icon_home.png';
@@ -69,32 +70,32 @@
tmpDiv.setAttribute('id', divName);
this.toolbar = new Jx.Toolbar(tmpDiv,{left:0});
- this.homeAction = new Jx.Action(this.goHome.bind(this));
+ this.homeAction = new Jx.Action(OpenLayers.Function.bind(this.goHome, this));
this.toolbar.add(new Jx.Button(this.homeAction,
{
image: this.defHomeIcon,
- tooltip: OpenLayers.String.translate('taskHome')
+ tooltip: OpenLayers.i18n('taskHome')
}
));
- this.prevAction = new Jx.Action(this.gotoPrevTask.bind(this));
+ this.prevAction = new Jx.Action(OpenLayers.Function.bind(this.gotoPrevTask, this));
this.toolbar.add(new Jx.Button(this.prevAction,
{
image: this.defPrevTaskIcon,
- tooltip: OpenLayers.String.translate('prevTask')
+ tooltip: OpenLayers.i18n('prevTask')
}
));
- this.nextAction = new Jx.Action(this.gotoNextTask.bind(this));
+ this.nextAction = new Jx.Action(OpenLayers.Function.bind(this.gotoNextTask, this));
this.toolbar.add(new Jx.Button(this.nextAction,
{
image: this.defNextTaskIcon,
- tooltip: OpenLayers.String.translate('nextTask')
+ tooltip: OpenLayers.i18n('nextTask')
}
));
this.taskMenu = new Jx.Menu({image: this.defTaskListIcon,
- label: OpenLayers.String.translate('taskList'),
+ label: OpenLayers.i18n('taskList'),
right:0});
Element.addClassName(this.taskMenu.domObj, 'taskMenu');
Element.addClassName(this.taskMenu.button.domObj, 'jxButtonContentLeft');
@@ -108,7 +109,7 @@
this.iframe.setAttribute('frameborder', 0);
this.iframe.style.border = '0px solid #fff';
this.oTaskPane = new Jx.Panel({toolbar: tmpDiv,
- label: OpenLayers.String.translate('taskPane'),
+ label: OpenLayers.i18n('taskPane'),
content: this.iframe
});
Element.addClassName(this.domObj, 'taskPanePanel');
@@ -119,8 +120,8 @@
//is added to the DOM
this.oTaskPane.domObj.resize();
- Fusion.registerForEvent(Fusion.Event.FUSION_INITIALIZED, this.setTaskMenu.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.setContent.bind(this,this.initialTask));
+ Fusion.registerForEvent(Fusion.Event.FUSION_INITIALIZED, OpenLayers.Function.bind(this.setTaskMenu, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, OpenLayers.Function.bind(this.setContent, this,this.initialTask));
},
updateButtons: function() {
@@ -186,4 +187,4 @@
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/ViewOptions.js
===================================================================
--- sandbox/aboudreault/widgets/ViewOptions.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/ViewOptions.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -29,8 +29,7 @@
* A widget to allow selection of the display units for various widgets
****************************************************************************/
-Fusion.Widget.ViewOptions = Class.create();
-Fusion.Widget.ViewOptions.prototype =
+Fusion.Widget.ViewOptions = OpenLayers.Class(Fusion.Widget, Fusion.Tool.MenuBase,
{
displayUnits: false,
options : {
@@ -41,8 +40,10 @@
initialize : function(widgetTag) {
//console.log('ViewOptions.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
- Object.inheritFrom(this, Fusion.Tool.MenuBase.prototype, []);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
+ Fusion.Tool.MenuBase.prototype.initialize.apply(this, []);
+
//this.enable();
var json = widgetTag.extension;
@@ -50,13 +51,13 @@
//set up the root menu
for (var key in this.options) {
- var action = new Jx.Action(this.setViewOptions.bind(this, this.options[key]));
- var menuItem = new Jx.MenuItem(action, {label: OpenLayers.String.translate(key)} );
+ var action = new Jx.Action(OpenLayers.Function.bind(this.setViewOptions, this, this.options[key]));
+ var menuItem = new Jx.MenuItem(action, {label: OpenLayers.i18n(key)} );
this.oMenu.add(menuItem);
}
this.displayUnits = json.DisplayUnits ? json.DisplayUnits[0] : false;
- this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.setMapUnits.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, OpenLayers.Function.bind(this.setMapUnits, this));
},
//action to perform when the button is clicked
@@ -82,4 +83,4 @@
}
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/ViewSize.js
===================================================================
--- sandbox/aboudreault/widgets/ViewSize.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/ViewSize.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -29,8 +29,9 @@
* Display the size of the current view in user-definable units
****************************************************************************/
-Fusion.Widget.ViewSize = Class.create();
-Fusion.Widget.ViewSize.prototype = {
+
+Fusion.Widget.ViewSize = OpenLayers.Class(Fusion.Widget,
+{
defaultTemplate: 'x: {x}, y: {y}',
domSpan: null,
@@ -38,8 +39,8 @@
units: Fusion.UNKNOWN,
initialize : function(widgetTag) {
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
-
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
+
this.emptyText = this.domObj.innerHTML;
var json = widgetTag.extension;
@@ -54,9 +55,9 @@
this.domObj.innerHTML = '';
this.domObj.appendChild(this.domSpan);
- this.getMap().registerForEvent(Fusion.Event.MAP_RESIZED, this.updateViewSize.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, this.setUnits.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, this.updateViewSize.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_RESIZED, OpenLayers.Function.bind(this.updateViewSize, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_LOADED, OpenLayers.Function.bind(this.setUnits, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_EXTENTS_CHANGED, OpenLayers.Function.bind(this.updateViewSize, this));
this.registerParameter('Units');
},
@@ -67,8 +68,9 @@
var gw = map.pixToGeoMeasure(p.w);
var gh = map.pixToGeoMeasure(p.h);
if (this.units != Fusion.UNKNOWN) {
- gw = Fusion.fromMeter(this.units, gw * map._fMetersperunit);
- gh = Fusion.fromMeter(this.units, gh * map._fMetersperunit);
+ var convFactor = map.getMetersPerUnit();
+ gw = Fusion.fromMeter(this.units, gw * convFactor);
+ gh = Fusion.fromMeter(this.units, gh * convFactor);
}
if (this.precision >= 0) {
var factor = Math.pow(10,this.precision);
@@ -93,4 +95,4 @@
this.updateViewSize();
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/Zoom.js
===================================================================
--- sandbox/aboudreault/widgets/Zoom.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/Zoom.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,8 +30,8 @@
*
* **********************************************************************/
-Fusion.Widget.Zoom = Class.create();
-Fusion.Widget.Zoom.prototype =
+
+Fusion.Widget.Zoom = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase,
{
nTolerance : 5,
nFactor : 2,
@@ -40,9 +40,10 @@
initialize : function(widgetTag)
{
//console.log('Zoom.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, true]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, true]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
+
this.asCursor = ["url('images/zoomin.cur'),auto",'-moz-zoom-in', 'auto'];
var json = widgetTag.extension;
this.nTolerance = json.Tolerance ? json.Tolerance[0] : this.nTolerance;
@@ -51,7 +52,7 @@
this.zoomInCursor = ["url('images/zoomin.cur'),auto",'-moz-zoom-in', 'auto'];
this.zoomOutCursor = ["url('images/zoomout.cur'),auto",'-moz-zoom-out', 'auto'];
- this.keypressWatcher = this.keypressHandler.bind(this);
+ this.keypressWatcher = OpenLayers.Function.bind(this.keypressHandler, this);
this.map = this.getMap().oMapOL;
this.handler = new OpenLayers.Handler.Box(this, {done: this.execute}, {keyMask:0});
@@ -184,4 +185,4 @@
this.handler.activate();
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/ZoomOnClick.js
===================================================================
--- sandbox/aboudreault/widgets/ZoomOnClick.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/ZoomOnClick.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,15 +30,16 @@
*
* **********************************************************************/
-Fusion.Widget.ZoomOnClick = Class.create();
-Fusion.Widget.ZoomOnClick.prototype =
+
+Fusion.Widget.ZoomOnClick = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase,
{
- nFactor: 2,
+ nFactor: 4,
initialize : function(widgetTag)
{
//console.log('ZoomOnClick.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
var json = widgetTag.extension;
this.nFactor = parseFloat(json.Factor ? json.Factor[0] : this.nFactor);
@@ -61,4 +62,4 @@
this.nFactor = value;
}
}
-};
+});
Modified: sandbox/aboudreault/widgets/ZoomToSelection.js
===================================================================
--- sandbox/aboudreault/widgets/ZoomToSelection.js 2008-05-26 18:52:23 UTC (rev 1412)
+++ sandbox/aboudreault/widgets/ZoomToSelection.js 2008-05-29 14:21:40 UTC (rev 1413)
@@ -30,21 +30,22 @@
*
* **********************************************************************/
-Fusion.Widget.ZoomToSelection = Class.create();
-Fusion.Widget.ZoomToSelection.prototype = {
+Fusion.Widget.ZoomToSelection = OpenLayers.Class(Fusion.Widget, Fusion.Tool.ButtonBase,
+{
initialize : function(widgetTag) {
//console.log('ZoomToSelection.initialize');
- Object.inheritFrom(this, Fusion.Widget.prototype, [widgetTag, false]);
- Object.inheritFrom(this, Fusion.Tool.ButtonBase.prototype, []);
+ Fusion.Widget.prototype.initialize.apply(this, [widgetTag, false]);
+ Fusion.Tool.ButtonBase.prototype.initialize.apply(this, []);
+
var json = widgetTag.extension;
this.maxDimension = json.MaximumZoomDimension ? json.MaximumZoomDimension[0] : -1;
this.zoomFactor = json.ZoomFactor ? json.ZoomFactor[0] : 2;
this.enable = Fusion.Widget.ZoomToSelection.prototype.enable;
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON, this.enable.bind(this));
- this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF, this.disable.bind(this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_ON, OpenLayers.Function.bind(this.enable, this));
+ this.getMap().registerForEvent(Fusion.Event.MAP_SELECTION_OFF, OpenLayers.Function.bind(this.disable, this));
},
/**
@@ -52,7 +53,7 @@
* zoomToSelection is called when the selection is ready.
*/
execute : function() {
- this.getMap().getSelection(this.zoomToSelection.bind(this));
+ this.getMap().getSelection(OpenLayers.Function.bind(this.zoomToSelection, this));
},
/**
@@ -84,4 +85,4 @@
}
}
-};
+});
More information about the fusion-commits
mailing list